diff --git a/core/shared/src/main/scala/zio/logging/LogFilter.scala b/core/shared/src/main/scala/zio/logging/LogFilter.scala
index 2b08663f..26c34de4 100644
--- a/core/shared/src/main/scala/zio/logging/LogFilter.scala
+++ b/core/shared/src/main/scala/zio/logging/LogFilter.scala
@@ -16,7 +16,7 @@
package zio.logging
import zio.prelude.Equal
-import zio.{ Cause, Config, FiberId, FiberRefs, LogLevel, LogSpan, Trace }
+import zio.{ Cause, Config, FiberId, FiberRefs, LogLevel, LogSpan, NonEmptyChunk, Trace, ZIO }
import scala.annotation.tailrec
@@ -278,6 +278,9 @@ object LogFilter {
}
implicit val equal: Equal[LogLevelByNameConfig] = Equal.default
+
+ def load(configPath: NonEmptyChunk[String]): ZIO[Any, Config.Error, LogLevelByNameConfig] =
+ ZIO.config(LogLevelByNameConfig.config.nested(configPath.head, configPath.tail: _*))
}
def apply[M, V](
diff --git a/docs/slf4j1-bridge.md b/docs/slf4j1-bridge.md
index df921d35..65ac0821 100644
--- a/docs/slf4j1-bridge.md
+++ b/docs/slf4j1-bridge.md
@@ -9,14 +9,23 @@ It is possible to use `zio-logging` for SLF4J loggers, usually third-party non-Z
libraryDependencies += "dev.zio" %% "zio-logging-slf4j-bridge" % "@VERSION@"
```
-and use the `Slf4jBridge.initialize` layer when setting up logging:
+and use one of the `Slf4jBridge` layers when setting up logging:
```scala
import zio.logging.slf4j.Slf4jBridge
-program.provideCustom(Slf4jBridge.initialize)
+program.provideCustom(Slf4jBridge.init())
```
+`Slf4jBridge` layers:
+* `Slf4jBridge.init(configPath: NonEmptyChunk[String] = logFilterConfigPath)` - setup with `LogFilter` from [filter configuration](log-filter.md#configuration), default configuration path: `logger.filter`, default `LogLevel` is `INFO`
+* `Slf4jBridge.init(filter: LogFilter[Any])` - setup with given `LogFilter`
+* `Slf4jBridge.initialize` - setup without filtering
+
+Need for log filtering in slf4j bridge: libraries with slf4j loggers, may have conditional logic for logging,
+which using functions like [org.slf4j.Logger.isTraceEnabled()](https://github.com/qos-ch/slf4j/blob/master/slf4j-api/src/main/java/org/slf4j/Logger.java#L170).
+logging parts may contain message and log parameters construction, which may be expensive and degrade performance of application.
+
SLF4J logger name is stored in log annotation with key `logger_name` (`zio.logging.loggerNameAnnotationKey`), following log format
@@ -38,7 +47,7 @@ SLF4J bridge with custom logger can be setup:
import zio.logging.slf4j.Slf4jBridge
import zio.logging.consoleJsonLogger
-val logger = Runtime.removeDefaultLoggers >>> consoleJsonLogger() >+> Slf4jBridge.initialize
+val logger = Runtime.removeDefaultLoggers >>> consoleJsonLogger() >+> Slf4jBridge.init()
```
@@ -55,7 +64,6 @@ ZIO logging. Enabling both causes circular logging and makes no sense.
```scala
package zio.logging.example
-import zio.logging.slf4j.bridge.Slf4jBridge
import zio.logging.{ ConsoleLoggerConfig, LogAnnotation, LogFilter, LogFormat, LoggerNameExtractor, consoleJsonLogger }
import zio.{ ExitCode, LogLevel, Runtime, Scope, ZIO, ZIOAppArgs, ZIOAppDefault, ZLayer }
@@ -65,6 +73,12 @@ object Slf4jBridgeExampleApp extends ZIOAppDefault {
private val slf4jLogger = org.slf4j.LoggerFactory.getLogger("SLF4J-LOGGER")
+ private val logFilterConfig = LogFilter.LogLevelByNameConfig(
+ LogLevel.Info,
+ "zio.logging.slf4j" -> LogLevel.Debug,
+ "SLF4J-LOGGER" -> LogLevel.Warning
+ )
+
private val logFormat = LogFormat.label(
"name",
LoggerNameExtractor.loggerNameAnnotationOrTrace.toLogFormat()
@@ -72,10 +86,10 @@ object Slf4jBridgeExampleApp extends ZIOAppDefault {
LogAnnotation.TraceId
) + LogFormat.default
+ private val loggerConfig = ConsoleLoggerConfig(logFormat, logFilterConfig)
+
override val bootstrap: ZLayer[ZIOAppArgs, Any, Any] =
- Runtime.removeDefaultLoggers >>> consoleJsonLogger(
- ConsoleLoggerConfig(logFormat, logFilterConfig)
- ) >+> Slf4jBridge.initialize
+ Runtime.removeDefaultLoggers >>> consoleJsonLogger(loggerConfig) >+> Slf4jBridge.init(loggerConfig.toFilter)
private val uuids = List.fill(2)(UUID.randomUUID())
@@ -83,7 +97,9 @@ object Slf4jBridgeExampleApp extends ZIOAppDefault {
for {
_ <- ZIO.logInfo("Start")
_ <- ZIO.foreachPar(uuids) { u =>
- ZIO.succeed(slf4jLogger.warn("Test {}!", "WARNING")) @@ LogAnnotation.UserId(
+ ZIO.succeed(slf4jLogger.info("Test {}!", "INFO")) *> ZIO.succeed(
+ slf4jLogger.warn("Test {}!", "WARNING")
+ ) @@ LogAnnotation.UserId(
u.toString
)
} @@ LogAnnotation.TraceId(UUID.randomUUID())
@@ -95,10 +111,10 @@ object Slf4jBridgeExampleApp extends ZIOAppDefault {
Expected Console Output:
```
-{"name":"zio.logging.slf4j.bridge.Slf4jBridgeExampleApp","timestamp":"2023-05-15T20:14:20.712983+02:00","level":"INFO","thread":"zio-fiber-6","message":"Start"}
-{"name":"SLF4J-LOGGER","user_id":"81e517bb-c69b-4187-a6e9-9911c427994c","trace_id":"bd317853-2b88-43d3-84dc-109e7e0eba70","timestamp":"2023-05-15T20:14:20.76863+02:00 ","level":"WARN","thread":"zio-fiber-9","message":"Test WARNING!"}
-{"name":"SLF4J-LOGGER","user_id":"844f97ef-7f09-469b-9f4b-765887beea9a","trace_id":"bd317853-2b88-43d3-84dc-109e7e0eba70","timestamp":"2023-05-15T20:14:20.768628+02:00","level":"WARN","thread":"zio-fiber-10","message":"Test WARNING!"}
-{"name":"zio.logging.slf4j.bridge.Slf4jBridgeExampleApp","timestamp":"2023-05-15T20:14:20.777529+02:00","level":"DEBUG","thread":"zio-fiber-6","message":"Done"}
+{"name":"zio.logging.slf4j.bridge.Slf4jBridgeExampleApp","timestamp":"2024-02-16T08:10:45.373807+01:00","level":"INFO","thread":"zio-fiber-6","message":"Start"}
+{"name":"SLF4J-LOGGER","user_id":"d13f90ad-6b0a-45fd-bf94-1db7a0d8c0b7","trace_id":"561300a9-e6f1-4f61-8dcc-dfef476dab20","timestamp":"2024-02-16T08:10:45.421448+01:00","level":"WARN","thread":"zio-fiber-10","message":"Test WARNING!"}
+{"name":"SLF4J-LOGGER","user_id":"0f28521f-ac8f-4d8e-beeb-13c85c90c041","trace_id":"561300a9-e6f1-4f61-8dcc-dfef476dab20","timestamp":"2024-02-16T08:10:45.421461+01:00","level":"WARN","thread":"zio-fiber-9","message":"Test WARNING!"}
+{"name":"zio.logging.slf4j.bridge.Slf4jBridgeExampleApp","timestamp":"2024-02-16T08:10:45.428162+01:00","level":"DEBUG","thread":"zio-fiber-6","message":"Done"}
```
## Feature changes
diff --git a/docs/slf4j2-bridge.md b/docs/slf4j2-bridge.md
index 7ddddf5c..4f862b80 100644
--- a/docs/slf4j2-bridge.md
+++ b/docs/slf4j2-bridge.md
@@ -9,14 +9,23 @@ It is possible to use `zio-logging` for SLF4J loggers, usually third-party non-Z
libraryDependencies += "dev.zio" %% "zio-logging-slf4j2-bridge" % "@VERSION@"
```
-and use the `Slf4jBridge.initialize` layer when setting up logging:
+and use one of the `Slf4jBridge` layers when setting up logging:
```scala
import zio.logging.slf4j.Slf4jBridge
-program.provideCustom(Slf4jBridge.initialize)
+program.provideCustom(Slf4jBridge.init())
```
+`Slf4jBridge` layers:
+* `Slf4jBridge.init(configPath: NonEmptyChunk[String] = logFilterConfigPath)` - setup with `LogFilter` from [filter configuration](log-filter.md#configuration), default configuration path: `logger.filter`, default `LogLevel` is `INFO`
+* `Slf4jBridge.init(filter: LogFilter[Any])` - setup with given `LogFilter`
+* `Slf4jBridge.initialize` - setup without filtering
+
+Need for log filtering in slf4j bridge: libraries with slf4j loggers, may have conditional logic for logging,
+which using functions like [org.slf4j.Logger.isTraceEnabled()](https://github.com/qos-ch/slf4j/blob/master/slf4j-api/src/main/java/org/slf4j/Logger.java#L170).
+logging parts may contain message and log parameters construction, which may be expensive and degrade performance of application.
+
SLF4J logger name is stored in log annotation with key `logger_name` (`zio.logging.loggerNameAnnotationKey`), following log format
@@ -49,7 +58,7 @@ SLF4J bridge with custom logger can be setup:
import zio.logging.slf4j.Slf4jBridge
import zio.logging.consoleJsonLogger
-val logger = Runtime.removeDefaultLoggers >>> consoleJsonLogger() >+> Slf4jBridge.initialize
+val logger = Runtime.removeDefaultLoggers >>> consoleJsonLogger() >+> Slf4jBridge.init()
```
@@ -69,7 +78,6 @@ You can find the source code [here](https://github.com/zio/zio-logging/tree/mast
```scala
package zio.logging.example
-import zio.logging.slf4j.bridge.Slf4jBridge
import zio.logging.{ ConsoleLoggerConfig, LogAnnotation, LogFilter, LogFormat, LoggerNameExtractor, consoleJsonLogger }
import zio.{ ExitCode, LogLevel, Runtime, Scope, ZIO, ZIOAppArgs, ZIOAppDefault, ZLayer }
@@ -92,10 +100,10 @@ object Slf4jBridgeExampleApp extends ZIOAppDefault {
LogAnnotation.TraceId
) + LogFormat.default
+ private val loggerConfig = ConsoleLoggerConfig(logFormat, logFilterConfig)
+
override val bootstrap: ZLayer[ZIOAppArgs, Any, Any] =
- Runtime.removeDefaultLoggers >>> consoleJsonLogger(
- ConsoleLoggerConfig(logFormat, logFilterConfig)
- ) >+> Slf4jBridge.initialize
+ Runtime.removeDefaultLoggers >>> consoleJsonLogger(loggerConfig) >+> Slf4jBridge.init(loggerConfig.toFilter)
private val uuids = List.fill(2)(UUID.randomUUID())
@@ -103,7 +111,9 @@ object Slf4jBridgeExampleApp extends ZIOAppDefault {
for {
_ <- ZIO.logInfo("Start")
_ <- ZIO.foreachPar(uuids) { u =>
- ZIO.succeed(slf4jLogger.warn("Test {}!", "WARNING")) @@ LogAnnotation.UserId(
+ ZIO.succeed(slf4jLogger.info("Test {}!", "INFO")) *> ZIO.succeed(
+ slf4jLogger.warn("Test {}!", "WARNING")
+ ) @@ LogAnnotation.UserId(
u.toString
)
} @@ LogAnnotation.TraceId(UUID.randomUUID())
@@ -115,8 +125,8 @@ object Slf4jBridgeExampleApp extends ZIOAppDefault {
Expected Console Output:
```
-{"name":"zio.logging.slf4j.bridge.Slf4jBridgeExampleApp","timestamp":"2023-05-15T20:14:20.712983+02:00","level":"INFO","thread":"zio-fiber-6","message":"Start"}
-{"name":"SLF4J-LOGGER","user_id":"81e517bb-c69b-4187-a6e9-9911c427994c","trace_id":"bd317853-2b88-43d3-84dc-109e7e0eba70","timestamp":"2023-05-15T20:14:20.76863+02:00 ","level":"WARN","thread":"zio-fiber-9","message":"Test WARNING!"}
-{"name":"SLF4J-LOGGER","user_id":"844f97ef-7f09-469b-9f4b-765887beea9a","trace_id":"bd317853-2b88-43d3-84dc-109e7e0eba70","timestamp":"2023-05-15T20:14:20.768628+02:00","level":"WARN","thread":"zio-fiber-10","message":"Test WARNING!"}
-{"name":"zio.logging.slf4j.bridge.Slf4jBridgeExampleApp","timestamp":"2023-05-15T20:14:20.777529+02:00","level":"DEBUG","thread":"zio-fiber-6","message":"Done"}
+{"name":"zio.logging.slf4j.bridge.Slf4jBridgeExampleApp","timestamp":"2024-02-16T08:10:45.373807+01:00","level":"INFO","thread":"zio-fiber-6","message":"Start"}
+{"name":"SLF4J-LOGGER","user_id":"d13f90ad-6b0a-45fd-bf94-1db7a0d8c0b7","trace_id":"561300a9-e6f1-4f61-8dcc-dfef476dab20","timestamp":"2024-02-16T08:10:45.421448+01:00","level":"WARN","thread":"zio-fiber-10","message":"Test WARNING!"}
+{"name":"SLF4J-LOGGER","user_id":"0f28521f-ac8f-4d8e-beeb-13c85c90c041","trace_id":"561300a9-e6f1-4f61-8dcc-dfef476dab20","timestamp":"2024-02-16T08:10:45.421461+01:00","level":"WARN","thread":"zio-fiber-9","message":"Test WARNING!"}
+{"name":"zio.logging.slf4j.bridge.Slf4jBridgeExampleApp","timestamp":"2024-02-16T08:10:45.428162+01:00","level":"DEBUG","thread":"zio-fiber-6","message":"Done"}
```
diff --git a/examples/slf4j2-bridge/src/main/scala/zio/logging/example/Slf4jBridgeExampleApp.scala b/examples/slf4j2-bridge/src/main/scala/zio/logging/example/Slf4jBridgeExampleApp.scala
index d7043cca..bdcf4ab5 100644
--- a/examples/slf4j2-bridge/src/main/scala/zio/logging/example/Slf4jBridgeExampleApp.scala
+++ b/examples/slf4j2-bridge/src/main/scala/zio/logging/example/Slf4jBridgeExampleApp.scala
@@ -38,10 +38,10 @@ object Slf4jBridgeExampleApp extends ZIOAppDefault {
LogAnnotation.TraceId
) + LogFormat.default
+ private val loggerConfig = ConsoleLoggerConfig(logFormat, logFilterConfig)
+
override val bootstrap: ZLayer[ZIOAppArgs, Any, Any] =
- Runtime.removeDefaultLoggers >>> consoleJsonLogger(
- ConsoleLoggerConfig(logFormat, logFilterConfig)
- ) >+> Slf4jBridge.initialize
+ Runtime.removeDefaultLoggers >>> consoleJsonLogger(loggerConfig) >+> Slf4jBridge.init(loggerConfig.toFilter)
private val uuids = List.fill(2)(UUID.randomUUID())
@@ -49,7 +49,9 @@ object Slf4jBridgeExampleApp extends ZIOAppDefault {
for {
_ <- ZIO.logInfo("Start")
_ <- ZIO.foreachPar(uuids) { u =>
- ZIO.succeed(slf4jLogger.warn("Test {}!", "WARNING")) @@ LogAnnotation.UserId(
+ ZIO.succeed(slf4jLogger.info("Test {}!", "INFO")) *> ZIO.succeed(
+ slf4jLogger.warn("Test {}!", "WARNING")
+ ) @@ LogAnnotation.UserId(
u.toString
)
} @@ LogAnnotation.TraceId(UUID.randomUUID())
diff --git a/slf4j-bridge/src/main/java/org/slf4j/helpers/ZioLoggerBase.java b/slf4j-bridge/src/main/java/org/slf4j/helpers/ZioLoggerBase.java
index d5544ae9..e9c1ad1f 100644
--- a/slf4j-bridge/src/main/java/org/slf4j/helpers/ZioLoggerBase.java
+++ b/slf4j-bridge/src/main/java/org/slf4j/helpers/ZioLoggerBase.java
@@ -26,6 +26,8 @@ public ZioLoggerBase(String name) {
abstract protected void log(Level level, Marker marker, String messagePattern, Object[] arguments, Throwable throwable);
+ abstract protected boolean isEnabled(String name, Level level);
+
private void logWithThrowable(Level level, Marker marker, String msg, Throwable t) {
log(level, marker, msg, null, t);
}
@@ -54,140 +56,190 @@ private void logWithArgs(Level level, Marker marker, String msg, Object[] args)
@Override
public boolean isTraceEnabled() {
- return true;
+ return isEnabled(name, Level.TRACE);
}
@Override
public boolean isDebugEnabled() {
- return true;
+ return isEnabled(name, Level.DEBUG);
}
@Override
public boolean isErrorEnabled() {
- return true;
+ return isEnabled(name, Level.ERROR);
}
@Override
public boolean isWarnEnabled() {
- return true;
+ return isEnabled(name, Level.WARN);
}
@Override
public boolean isInfoEnabled() {
- return true;
+ return isEnabled(name, Level.INFO);
}
@Override
public void trace(String msg) {
- logWithThrowable(Level.TRACE, null, msg, null);
+ if (isTraceEnabled()) {
+ logWithThrowable(Level.TRACE, null, msg, null);
+ }
}
@Override
public void trace(String format, Object arg) {
- logWithArg(Level.TRACE, null, format, arg);
+ if (isTraceEnabled()) {
+ logWithArg(Level.TRACE, null, format, arg);
+ }
}
@Override
public void trace(String format, Object arg1, Object arg2) {
- logWithArgs(Level.TRACE, null, format, arg1, arg2);
+ if (isTraceEnabled()) {
+ logWithArgs(Level.TRACE, null, format, arg1, arg2);
+ }
}
@Override
public void trace(String format, Object... arguments) {
- logWithArgs(Level.TRACE, null, format, arguments);
+ if (isTraceEnabled()) {
+ logWithArgs(Level.TRACE, null, format, arguments);
+ }
}
@Override
public void trace(String msg, Throwable t) {
- logWithThrowable(Level.TRACE, null, msg, t);
+ if (isTraceEnabled()) {
+ logWithThrowable(Level.TRACE, null, msg, t);
+ }
}
public void debug(String msg) {
- logWithThrowable(Level.DEBUG, null, msg, null);
+ if (isDebugEnabled()) {
+ logWithThrowable(Level.DEBUG, null, msg, null);
+ }
}
public void debug(String format, Object arg) {
- logWithArg(Level.DEBUG, null, format, arg);
+ if (isDebugEnabled()) {
+ logWithArg(Level.DEBUG, null, format, arg);
+ }
}
public void debug(String format, Object arg1, Object arg2) {
- logWithArgs(Level.DEBUG, null, format, arg1, arg2);
+ if (isDebugEnabled()) {
+ logWithArgs(Level.DEBUG, null, format, arg1, arg2);
+ }
}
public void debug(String format, Object... arguments) {
- logWithArgs(Level.DEBUG, null, format, arguments);
+ if (isDebugEnabled()) {
+ logWithArgs(Level.DEBUG, null, format, arguments);
+ }
}
public void debug(String msg, Throwable t) {
- logWithThrowable(Level.DEBUG, null, msg, t);
+ if (isDebugEnabled()) {
+ logWithThrowable(Level.DEBUG, null, msg, t);
+ }
}
public void info(String msg) {
- logWithThrowable(Level.INFO, null, msg, null);
+ if (isInfoEnabled()) {
+ logWithThrowable(Level.INFO, null, msg, null);
+ }
}
public void info(String format, Object arg) {
- logWithArg(Level.INFO, null, format, arg);
+ if (isInfoEnabled()) {
+ logWithArg(Level.INFO, null, format, arg);
+ }
}
public void info(String format, Object arg1, Object arg2) {
- logWithArgs(Level.INFO, null, format, arg1, arg2);
+ if (isInfoEnabled()) {
+ logWithArgs(Level.INFO, null, format, arg1, arg2);
+ }
}
public void info(String format, Object... arguments) {
- logWithArgs(Level.INFO, null, format, arguments);
+ if (isInfoEnabled()) {
+ logWithArgs(Level.INFO, null, format, arguments);
+ }
}
public void info(String msg, Throwable t) {
- logWithThrowable(Level.INFO, null, msg, t);
+ if (isInfoEnabled()) {
+ logWithThrowable(Level.INFO, null, msg, t);
+ }
}
public void warn(String msg) {
- logWithThrowable(Level.WARN, null, msg, null);
+ if (isWarnEnabled()) {
+ logWithThrowable(Level.WARN, null, msg, null);
+ }
}
public void warn(String format, Object arg) {
- logWithArg(Level.WARN, null, format, arg);
+ if (isWarnEnabled()) {
+ logWithArg(Level.WARN, null, format, arg);
+ }
}
public void warn(String format, Object arg1, Object arg2) {
- logWithArgs(Level.WARN, null, format, arg1, arg2);
+ if (isWarnEnabled()) {
+ logWithArgs(Level.WARN, null, format, arg1, arg2);
+ }
}
public void warn(String format, Object... arguments) {
- logWithArgs(Level.WARN, null, format, arguments);
+ if (isWarnEnabled()) {
+ logWithArgs(Level.WARN, null, format, arguments);
+ }
}
public void warn(String msg, Throwable t) {
- logWithThrowable(Level.WARN, null, msg, t);
+ if (isWarnEnabled()) {
+ logWithThrowable(Level.WARN, null, msg, t);
+ }
}
public void error(String msg) {
- logWithThrowable(Level.ERROR, null, msg, null);
+ if (isErrorEnabled()) {
+ logWithThrowable(Level.ERROR, null, msg, null);
+ }
}
public void error(String format, Object arg) {
- logWithArg(Level.ERROR, null, format, arg);
+ if (isErrorEnabled()) {
+ logWithArg(Level.ERROR, null, format, arg);
+ }
}
public void error(String format, Object arg1, Object arg2) {
- logWithArgs(Level.ERROR, null, format, arg1, arg2);
+ if (isErrorEnabled()) {
+ logWithArgs(Level.ERROR, null, format, arg1, arg2);
+ }
}
public void error(String format, Object... arguments) {
- logWithArgs(Level.ERROR, null, format, arguments);
+ if (isErrorEnabled()) {
+ logWithArgs(Level.ERROR, null, format, arguments);
+ }
}
public void error(String msg, Throwable t) {
- logWithThrowable(Level.ERROR, null, msg, t);
+ if (isErrorEnabled()) {
+ logWithThrowable(Level.ERROR, null, msg, t);
+ }
}
}
\ No newline at end of file
diff --git a/slf4j-bridge/src/main/scala/org/slf4j/impl/LoggerRuntime.scala b/slf4j-bridge/src/main/scala/org/slf4j/impl/LoggerRuntime.scala
index e481f8e1..ac342f00 100644
--- a/slf4j-bridge/src/main/scala/org/slf4j/impl/LoggerRuntime.scala
+++ b/slf4j-bridge/src/main/scala/org/slf4j/impl/LoggerRuntime.scala
@@ -28,4 +28,6 @@ trait LoggerRuntime {
arguments: Array[AnyRef],
throwable: Throwable
): Unit
+
+ def isEnabled(name: String, level: Level): Boolean
}
diff --git a/slf4j-bridge/src/main/scala/org/slf4j/impl/ZioLogger.scala b/slf4j-bridge/src/main/scala/org/slf4j/impl/ZioLogger.scala
index 0fb052a9..29459812 100644
--- a/slf4j-bridge/src/main/scala/org/slf4j/impl/ZioLogger.scala
+++ b/slf4j-bridge/src/main/scala/org/slf4j/impl/ZioLogger.scala
@@ -28,4 +28,6 @@ final class ZioLogger(name: String, factory: ZioLoggerFactory) extends ZioLogger
throwable: Throwable
): Unit =
factory.log(name, level, marker, messagePattern, arguments, throwable)
+
+ override protected def isEnabled(name: String, level: Level): Boolean = factory.isEnabled(name, level)
}
diff --git a/slf4j-bridge/src/main/scala/org/slf4j/impl/ZioLoggerFactory.scala b/slf4j-bridge/src/main/scala/org/slf4j/impl/ZioLoggerFactory.scala
index 2bbe8ca5..5c920899 100644
--- a/slf4j-bridge/src/main/scala/org/slf4j/impl/ZioLoggerFactory.scala
+++ b/slf4j-bridge/src/main/scala/org/slf4j/impl/ZioLoggerFactory.scala
@@ -39,6 +39,9 @@ class ZioLoggerFactory extends ILoggerFactory {
): Unit =
if (runtime != null) runtime.log(name, level, marker, messagePattern, arguments, throwable)
+ private[impl] def isEnabled(name: String, level: Level): Boolean =
+ if (runtime != null) runtime.isEnabled(name, level) else false
+
override def getLogger(name: String): Logger =
loggers.getOrElseUpdate(name, new ZioLogger(name, this))
}
diff --git a/slf4j-bridge/src/main/scala/zio/logging/slf4j/bridge/Slf4jBridge.scala b/slf4j-bridge/src/main/scala/zio/logging/slf4j/bridge/Slf4jBridge.scala
index da30aa72..f0fb19cf 100644
--- a/slf4j-bridge/src/main/scala/zio/logging/slf4j/bridge/Slf4jBridge.scala
+++ b/slf4j-bridge/src/main/scala/zio/logging/slf4j/bridge/Slf4jBridge.scala
@@ -16,30 +16,61 @@
package zio.logging.slf4j.bridge
import org.slf4j.impl.ZioLoggerFactory
-import zio.{ Runtime, Semaphore, Unsafe, ZIO, ZLayer }
+import zio.logging.LogFilter
+import zio.{ Config, NonEmptyChunk, Runtime, Semaphore, Unsafe, ZIO, ZLayer }
object Slf4jBridge {
+ val logFilterConfigPath: NonEmptyChunk[String] = zio.logging.loggerConfigPath :+ "filter"
+
/**
* initialize SLF4J bridge
*/
- def initialize: ZLayer[Any, Nothing, Unit] =
- Runtime.enableCurrentFiber ++ layer
+ def initialize: ZLayer[Any, Nothing, Unit] = init(LogFilter.acceptAll)
+
+ /**
+ * initialize SLF4J bridge with `LogFilter`
+ * @param filter Log filter
+ */
+ def init(filter: LogFilter[Any]): ZLayer[Any, Nothing, Unit] = Runtime.enableCurrentFiber ++ layer(filter)
+
+ /**
+ * initialize SLF4J bridge with `LogFilter` from configuration
+ * @param configPath configuration path
+ */
+ def init(configPath: NonEmptyChunk[String] = logFilterConfigPath): ZLayer[Any, Config.Error, Unit] =
+ Runtime.enableCurrentFiber ++ layer(configPath)
/**
* initialize SLF4J bridge without `FiberRef` propagation
*/
- def initializeWithoutFiberRefPropagation: ZLayer[Any, Nothing, Unit] = layer
+ def initializeWithoutFiberRefPropagation: ZLayer[Any, Nothing, Unit] = initWithoutFiberRefPropagation(
+ LogFilter.acceptAll
+ )
+
+ /**
+ * initialize SLF4J bridge with `LogFilter`, without `FiberRef` propagation
+ * @param filter Log filter
+ */
+ def initWithoutFiberRefPropagation(filter: LogFilter[Any]): ZLayer[Any, Nothing, Unit] = layer(filter)
private val initLock = Semaphore.unsafe.make(1)(Unsafe.unsafe)
- private def layer: ZLayer[Any, Nothing, Unit] =
- ZLayer {
- for {
- runtime <- ZIO.runtime[Any]
- _ <- initLock.withPermit {
- ZIO.succeed(ZioLoggerFactory.initialize(new ZioLoggerRuntime(runtime)))
- }
- } yield ()
- }
+ private def layer(filter: LogFilter[Any]): ZLayer[Any, Nothing, Unit] =
+ ZLayer(make(filter))
+
+ private def layer(configPath: NonEmptyChunk[String]): ZLayer[Any, Config.Error, Unit] =
+ ZLayer(make(configPath))
+
+ def make(filter: LogFilter[Any]): ZIO[Any, Nothing, Unit] =
+ for {
+ runtime <- ZIO.runtime[Any]
+ _ <- initLock.withPermit {
+ ZIO.succeed(ZioLoggerFactory.initialize(new ZioLoggerRuntime(runtime, filter)))
+ }
+ } yield ()
+
+ def make(configPath: NonEmptyChunk[String] = logFilterConfigPath): ZIO[Any, Config.Error, Unit] =
+ LogFilter.LogLevelByNameConfig.load(configPath).flatMap(c => make(c.toFilter))
+
}
diff --git a/slf4j-bridge/src/main/scala/zio/logging/slf4j/bridge/ZioLoggerRuntime.scala b/slf4j-bridge/src/main/scala/zio/logging/slf4j/bridge/ZioLoggerRuntime.scala
index 864b2cd1..745d50ba 100644
--- a/slf4j-bridge/src/main/scala/zio/logging/slf4j/bridge/ZioLoggerRuntime.scala
+++ b/slf4j-bridge/src/main/scala/zio/logging/slf4j/bridge/ZioLoggerRuntime.scala
@@ -19,9 +19,10 @@ import org.slf4j.Marker
import org.slf4j.event.Level
import org.slf4j.helpers.MessageFormatter
import org.slf4j.impl.LoggerRuntime
+import zio.logging.LogFilter
import zio.{ Cause, Fiber, FiberId, FiberRef, FiberRefs, LogLevel, Runtime, Trace, Unsafe }
-final class ZioLoggerRuntime(runtime: Runtime[Any]) extends LoggerRuntime {
+final class ZioLoggerRuntime(runtime: Runtime[Any], filter: LogFilter[Any]) extends LoggerRuntime {
override def log(
name: String,
@@ -69,6 +70,22 @@ final class ZioLoggerRuntime(runtime: Runtime[Any]) extends LoggerRuntime {
fiberRuntime.log(() => msg, cause, Some(logLevel), trace)
}
+
+ override def isEnabled(name: String, level: Level): Boolean = {
+ val logLevel = ZioLoggerRuntime.logLevelMapping(level)
+
+ filter(
+ Trace(name, "", 0),
+ FiberId.None,
+ logLevel,
+ () => "",
+ Cause.empty,
+ FiberRefs.empty,
+ List.empty,
+ Map(zio.logging.loggerNameAnnotationKey -> name)
+ )
+ }
+
}
object ZioLoggerRuntime {
diff --git a/slf4j-bridge/src/test/scala/zio/logging/slf4j/bridge/Slf4jBridgeExampleApp.scala b/slf4j-bridge/src/test/scala/zio/logging/slf4j/bridge/Slf4jBridgeExampleApp.scala
index 489d8b44..60898855 100644
--- a/slf4j-bridge/src/test/scala/zio/logging/slf4j/bridge/Slf4jBridgeExampleApp.scala
+++ b/slf4j-bridge/src/test/scala/zio/logging/slf4j/bridge/Slf4jBridgeExampleApp.scala
@@ -22,10 +22,10 @@ object Slf4jBridgeExampleApp extends ZIOAppDefault {
LogAnnotation.TraceId
) + LogFormat.default
+ private val loggerConfig = ConsoleLoggerConfig(logFormat, logFilterConfig)
+
override val bootstrap: ZLayer[ZIOAppArgs, Any, Any] =
- Runtime.removeDefaultLoggers >>> consoleJsonLogger(
- ConsoleLoggerConfig(logFormat, logFilterConfig)
- ) >+> Slf4jBridge.initialize
+ Runtime.removeDefaultLoggers >>> consoleJsonLogger(loggerConfig) >+> Slf4jBridge.init(loggerConfig.toFilter)
private val uuids = List.fill(2)(UUID.randomUUID())
@@ -33,7 +33,9 @@ object Slf4jBridgeExampleApp extends ZIOAppDefault {
for {
_ <- ZIO.logInfo("Start")
_ <- ZIO.foreachPar(uuids) { u =>
- ZIO.succeed(slf4jLogger.warn("Test {}!", "WARNING")) @@ LogAnnotation.UserId(
+ ZIO.succeed(slf4jLogger.info("Test {}!", "INFO")) *> ZIO.succeed(
+ slf4jLogger.warn("Test {}!", "WARNING")
+ ) @@ LogAnnotation.UserId(
u.toString
)
} @@ LogAnnotation.TraceId(UUID.randomUUID())
diff --git a/slf4j-bridge/src/test/scala/zio/logging/slf4j/bridge/Slf4jBridgeSpec.scala b/slf4j-bridge/src/test/scala/zio/logging/slf4j/bridge/Slf4jBridgeSpec.scala
index d03247d8..89e9d14e 100644
--- a/slf4j-bridge/src/test/scala/zio/logging/slf4j/bridge/Slf4jBridgeSpec.scala
+++ b/slf4j-bridge/src/test/scala/zio/logging/slf4j/bridge/Slf4jBridgeSpec.scala
@@ -2,8 +2,9 @@ package zio.logging.slf4j.bridge
import org.slf4j.MarkerFactory
import org.slf4j.impl.StaticMarkerBinder
+import zio.logging.LogFilter
import zio.test._
-import zio.{ Cause, Chunk, LogLevel, ZIO, ZIOAspect }
+import zio.{ Cause, Chunk, ConfigProvider, LogLevel, Runtime, ZIO, ZIOAspect }
object Slf4jBridgeSpec extends ZIOSpecDefault {
@@ -142,6 +143,87 @@ object Slf4jBridgeSpec extends ZIOSpecDefault {
)
)
)
- }.provide(Slf4jBridge.initializeWithoutFiberRefPropagation)
+ }.provide(Slf4jBridge.initializeWithoutFiberRefPropagation),
+ test("logs through slf4j with filter") {
+ filterTest
+ }.provide(
+ Slf4jBridge.init(
+ LogFilter.logLevelByName(
+ LogLevel.Debug,
+ "test.logger" -> LogLevel.Info,
+ "test.test.logger" -> LogLevel.Warning
+ )
+ )
+ ),
+ test("logs through slf4j with filter from config") {
+ filterTest
+ }.provide {
+ val configProvider: ConfigProvider = ConfigProvider.fromMap(
+ Map(
+ "logger/filter/rootLevel" -> "DEBUG",
+ "logger/filter/mappings/test.logger" -> "INFO",
+ "logger/filter/mappings/test.test.logger" -> "WARN"
+ ),
+ "/"
+ )
+ Runtime.setConfigProvider(configProvider) >>> Slf4jBridge.init()
+ }
) @@ TestAspect.sequential
+
+ def filterTest: ZIO[Any, Nothing, TestResult] =
+ for {
+ _ <- (for {
+ logger1 <- ZIO.attempt(org.slf4j.LoggerFactory.getLogger("test.abc"))
+ logger2 <- ZIO.attempt(org.slf4j.LoggerFactory.getLogger("test.logger.def"))
+ logger3 <- ZIO.attempt(org.slf4j.LoggerFactory.getLogger("test.test.logger.xyz"))
+ _ <- ZIO.attempt(logger1.debug("test debug message"))
+ _ <- ZIO.attempt(logger1.warn("test warn message"))
+ _ <- ZIO.attempt(logger2.debug("hello2 {} debug", "world"))
+ _ <- ZIO.attempt(logger2.warn("hello2 {} warn", "world"))
+ _ <- ZIO.attempt(logger3.info("hello3 {} info", "world"))
+ _ <- ZIO.attempt(logger3.warn("hello3 {} warn", "world"))
+ } yield ()).exit
+ output <- ZTestLogger.logOutput
+ lines = output.map { logEntry =>
+ LogEntry(
+ logEntry.spans.map(_.label),
+ logEntry.logLevel,
+ logEntry.annotations,
+ logEntry.message(),
+ logEntry.cause
+ )
+ }
+ } yield assertTrue(
+ lines == Chunk(
+ LogEntry(
+ List("test.abc"),
+ LogLevel.Debug,
+ Map(zio.logging.loggerNameAnnotationKey -> "test.abc"),
+ "test debug message",
+ Cause.empty
+ ),
+ LogEntry(
+ List("test.abc"),
+ LogLevel.Warning,
+ Map(zio.logging.loggerNameAnnotationKey -> "test.abc"),
+ "test warn message",
+ Cause.empty
+ ),
+ LogEntry(
+ List("test.logger.def"),
+ LogLevel.Warning,
+ Map(zio.logging.loggerNameAnnotationKey -> "test.logger.def"),
+ "hello2 world warn",
+ Cause.empty
+ ),
+ LogEntry(
+ List("test.test.logger.xyz"),
+ LogLevel.Warning,
+ Map(zio.logging.loggerNameAnnotationKey -> "test.test.logger.xyz"),
+ "hello3 world warn",
+ Cause.empty
+ )
+ )
+ )
+
}
diff --git a/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/Logger.java b/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/Logger.java
index 00dc666a..6d84bf34 100644
--- a/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/Logger.java
+++ b/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/Logger.java
@@ -40,51 +40,51 @@ protected void handleNormalizedLoggingCall(Level level, Marker marker, String me
@Override
public boolean isTraceEnabled() {
- return true;
+ return factory.isEnabled(name, Level.TRACE);
}
@Override
public boolean isTraceEnabled(Marker marker) {
- return true;
+ return isTraceEnabled();
}
@Override
public boolean isDebugEnabled() {
- return true;
+ return factory.isEnabled(name, Level.DEBUG);
}
@Override
public boolean isDebugEnabled(Marker marker) {
- return true;
+ return isDebugEnabled();
}
@Override
public boolean isInfoEnabled() {
- return true;
+ return factory.isEnabled(name, Level.INFO);
}
@Override
public boolean isInfoEnabled(Marker marker) {
- return true;
+ return isInfoEnabled();
}
@Override
public boolean isWarnEnabled() {
- return true;
+ return factory.isEnabled(name, Level.WARN);
}
@Override
public boolean isWarnEnabled(Marker marker) {
- return true;
+ return isWarnEnabled();
}
@Override
public boolean isErrorEnabled() {
- return true;
+ return factory.isEnabled(name, Level.ERROR);
}
@Override
public boolean isErrorEnabled(Marker marker) {
- return true;
+ return isErrorEnabled();
}
}
diff --git a/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/LoggerFactory.java b/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/LoggerFactory.java
index 230d0267..23ee925e 100644
--- a/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/LoggerFactory.java
+++ b/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/LoggerFactory.java
@@ -38,6 +38,14 @@ void log(String name, Level level, Marker marker, String messagePattern, Object[
}
}
+ boolean isEnabled(String name, Level level) {
+ if (runtime != null) {
+ return runtime.isEnabled(name, level);
+ } else {
+ return false;
+ }
+ }
+
@Override
public org.slf4j.Logger getLogger(String name) {
return loggers.computeIfAbsent(name, n -> new Logger(n, this));
diff --git a/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/LoggerRuntime.java b/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/LoggerRuntime.java
index 4354c881..522bda95 100644
--- a/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/LoggerRuntime.java
+++ b/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/LoggerRuntime.java
@@ -20,4 +20,6 @@
interface LoggerRuntime {
void log(String name, Level level, Marker marker, String messagePattern, Object[] arguments, Throwable throwable);
+
+ boolean isEnabled(String name, Level level);
}
diff --git a/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/Slf4jBridge.scala b/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/Slf4jBridge.scala
index e22cd298..9240b145 100644
--- a/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/Slf4jBridge.scala
+++ b/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/Slf4jBridge.scala
@@ -15,34 +15,66 @@
*/
package zio.logging.slf4j.bridge
-import zio.{ Runtime, Semaphore, Unsafe, ZIO, ZLayer }
+import zio.logging.LogFilter
+import zio.{ Config, NonEmptyChunk, Runtime, Semaphore, Unsafe, ZIO, ZLayer }
object Slf4jBridge {
+ val logFilterConfigPath: NonEmptyChunk[String] = zio.logging.loggerConfigPath :+ "filter"
+
/**
* initialize SLF4J bridge
*/
- def initialize: ZLayer[Any, Nothing, Unit] = Runtime.enableCurrentFiber ++ layer
+ def initialize: ZLayer[Any, Nothing, Unit] = init(LogFilter.acceptAll)
+
+ /**
+ * initialize SLF4J bridge with `LogFilter`
+ * @param filter Log filter
+ */
+ def init(filter: LogFilter[Any]): ZLayer[Any, Nothing, Unit] = Runtime.enableCurrentFiber ++ layer(filter)
+
+ /**
+ * initialize SLF4J bridge with `LogFilter` from configuration
+ * @param configPath configuration path
+ */
+ def init(configPath: NonEmptyChunk[String] = logFilterConfigPath): ZLayer[Any, Config.Error, Unit] =
+ Runtime.enableCurrentFiber ++ layer(configPath)
/**
* initialize SLF4J bridge without `FiberRef` propagation
*/
- def initializeWithoutFiberRefPropagation: ZLayer[Any, Nothing, Unit] = layer
+ def initializeWithoutFiberRefPropagation: ZLayer[Any, Nothing, Unit] = initWithoutFiberRefPropagation(
+ LogFilter.acceptAll
+ )
+
+ /**
+ * initialize SLF4J bridge with `LogFilter`, without `FiberRef` propagation
+ * @param filter Log filter
+ */
+ def initWithoutFiberRefPropagation(filter: LogFilter[Any]): ZLayer[Any, Nothing, Unit] = layer(filter)
private val initLock = Semaphore.unsafe.make(1)(Unsafe.unsafe)
- private def layer: ZLayer[Any, Nothing, Unit] =
- ZLayer {
- for {
- runtime <- ZIO.runtime[Any]
- _ <- initLock.withPermit {
- ZIO.succeed(
- org.slf4j.LoggerFactory
- .getILoggerFactory()
- .asInstanceOf[LoggerFactory]
- .attachRuntime(new ZioLoggerRuntime(runtime))
- )
- }
- } yield ()
- }
+ private def layer(filter: LogFilter[Any]): ZLayer[Any, Nothing, Unit] =
+ ZLayer(make(filter))
+
+ private def layer(configPath: NonEmptyChunk[String]): ZLayer[Any, Config.Error, Unit] =
+ ZLayer(make(configPath))
+
+ def make(filter: LogFilter[Any]): ZIO[Any, Nothing, Unit] =
+ for {
+ runtime <- ZIO.runtime[Any]
+ _ <- initLock.withPermit {
+ ZIO.succeed(
+ org.slf4j.LoggerFactory
+ .getILoggerFactory()
+ .asInstanceOf[LoggerFactory]
+ .attachRuntime(new ZioLoggerRuntime(runtime, filter))
+ )
+ }
+ } yield ()
+
+ def make(configPath: NonEmptyChunk[String] = logFilterConfigPath): ZIO[Any, Config.Error, Unit] =
+ LogFilter.LogLevelByNameConfig.load(configPath).flatMap(c => make(c.toFilter))
+
}
diff --git a/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/ZioLoggerRuntime.scala b/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/ZioLoggerRuntime.scala
index a959b901..bbf43ab1 100644
--- a/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/ZioLoggerRuntime.scala
+++ b/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/ZioLoggerRuntime.scala
@@ -18,9 +18,10 @@ package zio.logging.slf4j.bridge
import org.slf4j.Marker
import org.slf4j.event.Level
import org.slf4j.helpers.MessageFormatter
+import zio.logging.LogFilter
import zio.{ Cause, Fiber, FiberId, FiberRef, FiberRefs, LogLevel, Runtime, Trace, Unsafe }
-final class ZioLoggerRuntime(runtime: Runtime[Any]) extends LoggerRuntime {
+final class ZioLoggerRuntime(runtime: Runtime[Any], filter: LogFilter[Any]) extends LoggerRuntime {
override def log(
name: String,
@@ -68,6 +69,22 @@ final class ZioLoggerRuntime(runtime: Runtime[Any]) extends LoggerRuntime {
fiberRuntime.log(() => msg, cause, Some(logLevel), trace)
}
+
+ override def isEnabled(name: String, level: Level): Boolean = {
+ val logLevel = ZioLoggerRuntime.logLevelMapping(level)
+
+ filter(
+ Trace(name, "", 0),
+ FiberId.None,
+ logLevel,
+ () => "",
+ Cause.empty,
+ FiberRefs.empty,
+ List.empty,
+ Map(zio.logging.loggerNameAnnotationKey -> name)
+ )
+ }
+
}
object ZioLoggerRuntime {
diff --git a/slf4j2-bridge/src/test/scala/zio/logging/slf4j/bridge/Slf4jBridgeExampleApp.scala b/slf4j2-bridge/src/test/scala/zio/logging/slf4j/bridge/Slf4jBridgeExampleApp.scala
index 06c7ff16..fec9497a 100644
--- a/slf4j2-bridge/src/test/scala/zio/logging/slf4j/bridge/Slf4jBridgeExampleApp.scala
+++ b/slf4j2-bridge/src/test/scala/zio/logging/slf4j/bridge/Slf4jBridgeExampleApp.scala
@@ -22,10 +22,10 @@ object Slf4jBridgeExampleApp extends ZIOAppDefault {
LogAnnotation.TraceId
) + LogFormat.default
+ private val loggerConfig = ConsoleLoggerConfig(logFormat, logFilterConfig)
+
override val bootstrap: ZLayer[ZIOAppArgs, Any, Any] =
- Runtime.removeDefaultLoggers >>> consoleJsonLogger(
- ConsoleLoggerConfig(logFormat, logFilterConfig)
- ) >+> Slf4jBridge.initialize
+ Runtime.removeDefaultLoggers >>> consoleJsonLogger(loggerConfig) >+> Slf4jBridge.init(loggerConfig.toFilter)
private val uuids = List.fill(2)(UUID.randomUUID())
@@ -33,7 +33,9 @@ object Slf4jBridgeExampleApp extends ZIOAppDefault {
for {
_ <- ZIO.logInfo("Start")
_ <- ZIO.foreachPar(uuids) { u =>
- ZIO.succeed(slf4jLogger.warn("Test {}!", "WARNING")) @@ LogAnnotation.UserId(
+ ZIO.succeed(slf4jLogger.info("Test {}!", "INFO")) *> ZIO.succeed(
+ slf4jLogger.warn("Test {}!", "WARNING")
+ ) @@ LogAnnotation.UserId(
u.toString
)
} @@ LogAnnotation.TraceId(UUID.randomUUID())
diff --git a/slf4j2-bridge/src/test/scala/zio/logging/slf4j/bridge/Slf4jBridgeSpec.scala b/slf4j2-bridge/src/test/scala/zio/logging/slf4j/bridge/Slf4jBridgeSpec.scala
index c4dd09bb..c052a8c4 100644
--- a/slf4j2-bridge/src/test/scala/zio/logging/slf4j/bridge/Slf4jBridgeSpec.scala
+++ b/slf4j2-bridge/src/test/scala/zio/logging/slf4j/bridge/Slf4jBridgeSpec.scala
@@ -1,7 +1,8 @@
package zio.logging.slf4j.bridge
+import zio.logging.LogFilter
import zio.test._
-import zio.{ Cause, Chunk, LogLevel, ZIO, ZIOAspect }
+import zio.{ Cause, Chunk, ConfigProvider, LogLevel, Runtime, ZIO, ZIOAspect }
object Slf4jBridgeSpec extends ZIOSpecDefault {
@@ -137,6 +138,87 @@ object Slf4jBridgeSpec extends ZIOSpecDefault {
)
)
)
- }.provide(Slf4jBridge.initializeWithoutFiberRefPropagation)
+ }.provide(Slf4jBridge.initializeWithoutFiberRefPropagation),
+ test("logs through slf4j with filter") {
+ filterTest
+ }.provide(
+ Slf4jBridge.init(
+ LogFilter.logLevelByName(
+ LogLevel.Debug,
+ "test.logger" -> LogLevel.Info,
+ "test.test.logger" -> LogLevel.Warning
+ )
+ )
+ ),
+ test("logs through slf4j with filter from config") {
+ filterTest
+ }.provide {
+ val configProvider: ConfigProvider = ConfigProvider.fromMap(
+ Map(
+ "logger/filter/rootLevel" -> "DEBUG",
+ "logger/filter/mappings/test.logger" -> "INFO",
+ "logger/filter/mappings/test.test.logger" -> "WARN"
+ ),
+ "/"
+ )
+ Runtime.setConfigProvider(configProvider) >>> Slf4jBridge.init()
+ }
) @@ TestAspect.sequential
+
+ def filterTest: ZIO[Any, Nothing, TestResult] =
+ for {
+ _ <- (for {
+ logger1 <- ZIO.attempt(org.slf4j.LoggerFactory.getLogger("test.abc"))
+ logger2 <- ZIO.attempt(org.slf4j.LoggerFactory.getLogger("test.logger.def"))
+ logger3 <- ZIO.attempt(org.slf4j.LoggerFactory.getLogger("test.test.logger.xyz"))
+ _ <- ZIO.attempt(logger1.debug("test debug message"))
+ _ <- ZIO.attempt(logger1.warn("test warn message"))
+ _ <- ZIO.attempt(logger2.debug("hello2 {} debug", "world"))
+ _ <- ZIO.attempt(logger2.warn("hello2 {} warn", "world"))
+ _ <- ZIO.attempt(logger3.info("hello3 {} info", "world"))
+ _ <- ZIO.attempt(logger3.warn("hello3 {} warn", "world"))
+ } yield ()).exit
+ output <- ZTestLogger.logOutput
+ lines = output.map { logEntry =>
+ LogEntry(
+ logEntry.spans.map(_.label),
+ logEntry.logLevel,
+ logEntry.annotations,
+ logEntry.message(),
+ logEntry.cause
+ )
+ }
+ } yield assertTrue(
+ lines == Chunk(
+ LogEntry(
+ List("test.abc"),
+ LogLevel.Debug,
+ Map(zio.logging.loggerNameAnnotationKey -> "test.abc"),
+ "test debug message",
+ Cause.empty
+ ),
+ LogEntry(
+ List("test.abc"),
+ LogLevel.Warning,
+ Map(zio.logging.loggerNameAnnotationKey -> "test.abc"),
+ "test warn message",
+ Cause.empty
+ ),
+ LogEntry(
+ List("test.logger.def"),
+ LogLevel.Warning,
+ Map(zio.logging.loggerNameAnnotationKey -> "test.logger.def"),
+ "hello2 world warn",
+ Cause.empty
+ ),
+ LogEntry(
+ List("test.test.logger.xyz"),
+ LogLevel.Warning,
+ Map(zio.logging.loggerNameAnnotationKey -> "test.test.logger.xyz"),
+ "hello3 world warn",
+ Cause.empty
+ )
+ )
+ )
+
}