Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 2 additions & 34 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,10 @@ jobs:
strategy:
matrix:
os: [ubuntu-22.04]
scala: [2.13, 2.12, 3]
scala: [2.13, 3]
java: [temurin@8, temurin@11]
project: [rootJS, rootJVM, rootNative]
exclude:
- scala: 2.12
java: temurin@11
- scala: 3
java: temurin@11
- project: rootJS
Expand Down Expand Up @@ -192,36 +190,6 @@ jobs:
tar xf targets.tar
rm targets.tar

- name: Download target directories (2.12, rootJS)
uses: actions/download-artifact@v4
with:
name: target-${{ matrix.os }}-${{ matrix.java }}-2.12-rootJS

- name: Inflate target directories (2.12, rootJS)
run: |
tar xf targets.tar
rm targets.tar

- name: Download target directories (2.12, rootJVM)
uses: actions/download-artifact@v4
with:
name: target-${{ matrix.os }}-${{ matrix.java }}-2.12-rootJVM

- name: Inflate target directories (2.12, rootJVM)
run: |
tar xf targets.tar
rm targets.tar

- name: Download target directories (2.12, rootNative)
uses: actions/download-artifact@v4
with:
name: target-${{ matrix.os }}-${{ matrix.java }}-2.12-rootNative

- name: Inflate target directories (2.12, rootNative)
run: |
tar xf targets.tar
rm targets.tar

- name: Download target directories (3, rootJS)
uses: actions/download-artifact@v4
with:
Expand Down Expand Up @@ -322,7 +290,7 @@ jobs:
- name: Submit Dependencies
uses: scalacenter/sbt-dependency-submission@v2
with:
modules-ignore: rootjs_2.13 rootjs_2.12 rootjs_3 docs_2.13 docs_2.12 docs_3 rootjvm_2.13 rootjvm_2.12 rootjvm_3 rootnative_2.13 rootnative_2.12 rootnative_3
modules-ignore: rootjs_2.13 rootjs_3 docs_2.13 docs_3 rootjvm_2.13 rootjvm_3 rootnative_2.13 rootnative_3
configs-ignore: test scala-tool scala-doc-tool test-internal

validate-steward:
Expand Down
14 changes: 11 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import com.typesafe.tools.mima.core._

val Scala213 = "2.13.16"
val Scala212 = "2.12.20"
val Scala3 = "3.3.6"

ThisBuild / tlBaseVersion := "2.7"
ThisBuild / crossScalaVersions := Seq(Scala213, Scala212, Scala3)
ThisBuild / crossScalaVersions := Seq(Scala213, Scala3)
ThisBuild / scalaVersion := Scala213
ThisBuild / startYear := Some(2018)
ThisBuild / developers := List(
Expand All @@ -28,6 +27,7 @@ ThisBuild / tlVersionIntroduced := Map("3" -> "2.1.1")

val catsV = "2.13.0"
val catsEffectV = "3.7.0-RC1"
val catsMtlV = "1.6.0"
val slf4jV = "1.7.36"
val munitCatsEffectV = "2.2.0-RC1"
val logbackClassicV = "1.2.13"
Expand All @@ -47,11 +47,19 @@ lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform)
name := "log4cats-core",
libraryDependencies ++= Seq(
"org.typelevel" %%% "cats-core" % catsV,
"org.typelevel" %%% "cats-effect-std" % catsEffectV
"org.typelevel" %%% "cats-effect-std" % catsEffectV,
"org.typelevel" %%% "cats-mtl" % catsMtlV
),
libraryDependencies ++= {
if (tlIsScala3.value) Seq.empty
else Seq("org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided)
},
scalacOptions ++= {
if (!tlIsScala3.value) Seq.empty
else
Seq(
"""-Wconf:src=org/typelevel/log4cats/LocalLogger.scala&msg=overrides concrete. non-deprecated definition:s"""
)
}
)
.nativeSettings(commonNativeSettings)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* Copyright 2018 Typelevel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.typelevel.log4cats

import cats.mtl.{Ask, LiftKind, Local}
import cats.syntax.functor.*
import cats.syntax.traverse.*
import cats.{Applicative, Show}

import scala.collection.immutable.ArraySeq

/**
* Log context stored in a [[cats.mtl.Local `Local`]], as well as potentially additional log context
* provided by [[cats.mtl.Ask `Ask`s]].
*/
sealed trait LocalLogContext[F[_]] {

/**
* @return
* the current log context stored [[cats.mtl.Local locally]], as well as the context from any
* provided [[cats.mtl.Ask `Ask`]]s
*/
private[log4cats] def currentLogContext: F[Map[String, String]]

/**
* @return
* the given effect modified to have the provided context stored [[cats.mtl.Local locally]]
*/
private[log4cats] def withAddedContext[A](ctx: Map[String, String])(fa: F[A]): F[A]

/**
* @return
* the given effect modified to have the provided context stored [[cats.mtl.Local locally]]
*/
private[log4cats] final def withAddedContext[A](ctx: (String, Show.Shown)*)(fa: F[A]): F[A] =
withAddedContext {
ctx.view.map { case (k, v) => k -> v.toString }.toMap
}(fa)

/**
* Modifies this [[cats.mtl.Local local]] log context to include the context provided by the given
* [[cats.mtl.Ask `Ask`]] with higher priority than all of its current context; that is, if both
* the `Ask` and this local log context provide values for some key, the value from the `Ask` will
* be used. The context is asked for at every logging operation.
*/
def withHighPriorityAskedContext(ask: Ask[F, Map[String, String]]): LocalLogContext[F]

/**
* Modifies this [[cats.mtl.Local local]] log context to include the context provided by the given
* [[cats.mtl.Ask `Ask`]] with lower priority than all of its current context; that is, if both
* the `Ask` and this local log context provide values for some key, the value from this local log
* context will be used. The context is asked for at every logging operation.
*/
def withLowPriorityAskedContext(ask: Ask[F, Map[String, String]]): LocalLogContext[F]

/** Lifts this [[cats.mtl.Local local]] log context from `F` to `G`. */
def liftTo[G[_]](implicit lift: LiftKind[F, G]): LocalLogContext[G]
}

object LocalLogContext {
private[this] type AskContext[F[_]] = Ask[F, Map[String, String]]

private[this] final class MultiAskContext[F[_]] private[MultiAskContext] (
asks: Seq[AskContext[F]] /* never empty */
) extends AskContext[F] {
implicit def applicative: Applicative[F] = asks.head.applicative
def ask[E2 >: Map[String, String]]: F[E2] =
asks
.traverse(_.ask[Map[String, String]])
.map[Map[String, String]](_.reduceLeft(_ ++ _))
.widen // tparam on `map` and `widen` to make scala 3 happy
def prependLowPriority(ask: AskContext[F]): MultiAskContext[F] =
new MultiAskContext(ask +: asks)
def appendHighPriority(ask: AskContext[F]): MultiAskContext[F] =
new MultiAskContext(asks :+ ask)
}

private[this] object MultiAskContext {
def apply[F[_]](ask: AskContext[F]): MultiAskContext[F] =
ask match {
case multi: MultiAskContext[F] => multi
case other => new MultiAskContext(ArraySeq(other))
}
}

private[this] final class Impl[F[_]](
localCtx: Local[F, Map[String, String]],
askCtx: AskContext[F]
) extends LocalLogContext[F] {
private[log4cats] def currentLogContext: F[Map[String, String]] =
askCtx.ask[Map[String, String]]
private[log4cats] def withAddedContext[A](ctx: Map[String, String])(fa: F[A]): F[A] =
localCtx.local(fa)(_ ++ ctx)

def withHighPriorityAskedContext(ask: Ask[F, Map[String, String]]): LocalLogContext[F] =
new Impl(
localCtx,
MultiAskContext(askCtx).appendHighPriority(ask)
)

def withLowPriorityAskedContext(ask: Ask[F, Map[String, String]]): LocalLogContext[F] =
new Impl(
localCtx,
MultiAskContext(askCtx).prependLowPriority(ask)
)

def liftTo[G[_]](implicit lift: LiftKind[F, G]): LocalLogContext[G] = {
val localF = localCtx
val askF = askCtx
val localG = localF.liftTo[G]
val askG =
if (askF eq localF) localG
else askF.liftTo[G]
new Impl(localG, askG)
}
}

/** @return a `LocalLogContext` backed by the given implicit [[cats.mtl.Local `Local`]] */
def fromLocal[F[_]](implicit localCtx: Local[F, Map[String, String]]): LocalLogContext[F] =
new Impl(localCtx, localCtx)
}
Loading