From c151fea3b4a77704d3e04414823435e85b67e388 Mon Sep 17 00:00:00 2001 From: Peter Kotula Date: Mon, 21 Oct 2024 18:49:26 +0200 Subject: [PATCH] slf4j2-bridge - annotations for logger --- build.sbt | 2 +- .../org/slf4j/impl/ZioLoggerFactory.scala | 2 +- .../java/zio/logging/slf4j/bridge/Logger.java | 101 ------------------ .../logging/slf4j/bridge/LoggerFactory.java | 55 ---------- .../slf4j/bridge/ZioSLF4JServiceProvider.java | 2 +- .../logging/slf4j/bridge/LoggerData.scala} | 11 +- .../logging/slf4j/bridge/LoggerRuntime.scala | 32 ++++++ .../logging/slf4j/bridge/Slf4jBridge.scala | 2 +- .../zio/logging/slf4j/bridge/ZioLogger.scala | 59 ++++++++++ .../slf4j/bridge/ZioLoggerFactory.scala | 46 ++++++++ .../slf4j/bridge/ZioLoggerRuntime.scala | 12 +-- 11 files changed, 150 insertions(+), 174 deletions(-) delete mode 100644 slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/Logger.java delete mode 100644 slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/LoggerFactory.java rename slf4j2-bridge/src/main/{java/zio/logging/slf4j/bridge/LoggerRuntime.java => scala/zio/logging/slf4j/bridge/LoggerData.scala} (65%) create mode 100644 slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/LoggerRuntime.scala create mode 100644 slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/ZioLogger.scala create mode 100644 slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/ZioLoggerFactory.scala diff --git a/build.sbt b/build.sbt index 32586ea9..36fce16e 100644 --- a/build.sbt +++ b/build.sbt @@ -139,7 +139,7 @@ lazy val slf4j2Bridge = project .settings(enableZIO()) .settings(mimaSettings(failOnProblem = true)) .settings( - compileOrder := CompileOrder.JavaThenScala, + compileOrder := CompileOrder.ScalaThenJava, javacOptions := jpmsOverwriteModulePath((Compile / dependencyClasspath).value.map(_.data))(javacOptions.value), javaOptions := jpmsOverwriteModulePath((Compile / dependencyClasspath).value.map(_.data))(javaOptions.value), Compile / doc / sources := Seq.empty // module-info.java compilation issue 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 bca0f357..e96d4a8c 100644 --- a/slf4j-bridge/src/main/scala/org/slf4j/impl/ZioLoggerFactory.scala +++ b/slf4j-bridge/src/main/scala/org/slf4j/impl/ZioLoggerFactory.scala @@ -22,7 +22,7 @@ import zio.logging.slf4j.bridge.LoggerData import java.util.concurrent.ConcurrentHashMap import scala.jdk.CollectionConverters._ -class ZioLoggerFactory extends ILoggerFactory { +final class ZioLoggerFactory extends ILoggerFactory { private var runtime: LoggerRuntime = null private val loggers = new ConcurrentHashMap[String, Logger]().asScala 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 deleted file mode 100644 index 37dc2c54..00000000 --- a/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/Logger.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2019-2024 John A. De Goes and the ZIO Contributors - * - * 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 zio.logging.slf4j.bridge; - -import org.slf4j.Marker; -import org.slf4j.event.Level; -import org.slf4j.event.LoggingEvent; -import org.slf4j.helpers.AbstractLogger; -import org.slf4j.spi.LoggingEventAware; - -import java.util.Collections; - -final class Logger extends AbstractLogger implements LoggingEventAware { - - private LoggerFactory factory; - - Logger(String name, LoggerFactory factory) { - this.name = name; - this.factory = factory; - } - - @Override - protected String getFullyQualifiedCallerName() { - return null; - } - - @Override - protected void handleNormalizedLoggingCall(Level level, Marker marker, String messagePattern, Object[] arguments, Throwable throwable) { - factory.log(name, level, messagePattern, arguments, throwable, Collections.emptyList()); - } - - @Override - public boolean isTraceEnabled() { - return factory.isEnabled(name, Level.TRACE); - } - - @Override - public boolean isTraceEnabled(Marker marker) { - return isTraceEnabled(); - } - - @Override - public boolean isDebugEnabled() { - return factory.isEnabled(name, Level.DEBUG); - } - - @Override - public boolean isDebugEnabled(Marker marker) { - return isDebugEnabled(); - } - - @Override - public boolean isInfoEnabled() { - return factory.isEnabled(name, Level.INFO); - } - - @Override - public boolean isInfoEnabled(Marker marker) { - return isInfoEnabled(); - } - - @Override - public boolean isWarnEnabled() { - return factory.isEnabled(name, Level.WARN); - } - - @Override - public boolean isWarnEnabled(Marker marker) { - return isWarnEnabled(); - } - - @Override - public boolean isErrorEnabled() { - return factory.isEnabled(name, Level.ERROR); - } - - @Override - public boolean isErrorEnabled(Marker marker) { - return isErrorEnabled(); - } - - @Override - public void log(LoggingEvent event) { - if (factory.isEnabled(name, event.getLevel())) { - factory.log(name, event.getLevel(), event.getMessage(), event.getArgumentArray(), event.getThrowable(), event.getKeyValuePairs()); - } - } -} 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 deleted file mode 100644 index 6c489cb3..00000000 --- a/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/LoggerFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2019-2024 John A. De Goes and the ZIO Contributors - * - * 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 zio.logging.slf4j.bridge; - -import org.slf4j.ILoggerFactory; -import org.slf4j.Marker; -import org.slf4j.event.KeyValuePair; -import org.slf4j.event.Level; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -final class LoggerFactory implements ILoggerFactory { - - private Map loggers = new ConcurrentHashMap(); - - private LoggerRuntime runtime = null; - - void attachRuntime(LoggerRuntime runtime) { - this.runtime = runtime; - } - - void log(String name, Level level, String messagePattern, Object[] arguments, Throwable throwable, List keyValues) { - if (runtime != null) { - runtime.log(name, level, messagePattern, arguments, throwable, keyValues); - } - } - - 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/ZioSLF4JServiceProvider.java b/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/ZioSLF4JServiceProvider.java index 2045e58e..d1817247 100644 --- a/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/ZioSLF4JServiceProvider.java +++ b/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/ZioSLF4JServiceProvider.java @@ -52,7 +52,7 @@ public String getRequestedApiVersion() { @Override public void initialize() { markerFactory = new BasicMarkerFactory(); - loggerFactory = new LoggerFactory(); + loggerFactory = new ZioLoggerFactory(); mdcAdapter = new BasicMDCAdapter(); } } diff --git a/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/LoggerRuntime.java b/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/LoggerData.scala similarity index 65% rename from slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/LoggerRuntime.java rename to slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/LoggerData.scala index 02eab4ff..98106cef 100644 --- a/slf4j2-bridge/src/main/java/zio/logging/slf4j/bridge/LoggerRuntime.java +++ b/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/LoggerData.scala @@ -13,15 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package zio.logging.slf4j.bridge; +package zio.logging.slf4j.bridge -import org.slf4j.event.KeyValuePair; -import org.slf4j.event.Level; +final case class LoggerData(name: String) { -import java.util.List; + lazy val annotations: Map[String, String] = Map(zio.logging.loggerNameAnnotationKey -> name) -interface LoggerRuntime { - void log(String name, Level level, String messagePattern, Object[] arguments, Throwable throwable, List keyValues); - - boolean isEnabled(String name, Level level); } diff --git a/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/LoggerRuntime.scala b/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/LoggerRuntime.scala new file mode 100644 index 00000000..f1f54f1c --- /dev/null +++ b/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/LoggerRuntime.scala @@ -0,0 +1,32 @@ +/* + * Copyright 2019-2024 John A. De Goes and the ZIO Contributors + * + * 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 zio.logging.slf4j.bridge + +import org.slf4j.event.{ KeyValuePair, Level } + +trait LoggerRuntime { + + def log( + logger: LoggerData, + level: Level, + messagePattern: String, + arguments: Array[AnyRef], + throwable: Throwable, + keyValues: java.util.List[KeyValuePair] + ): Unit + + def isEnabled(logger: LoggerData, level: Level): Boolean +} 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 9240b145..d994d3b5 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 @@ -68,7 +68,7 @@ object Slf4jBridge { ZIO.succeed( org.slf4j.LoggerFactory .getILoggerFactory() - .asInstanceOf[LoggerFactory] + .asInstanceOf[ZioLoggerFactory] .attachRuntime(new ZioLoggerRuntime(runtime, filter)) ) } diff --git a/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/ZioLogger.scala b/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/ZioLogger.scala new file mode 100644 index 00000000..af906c39 --- /dev/null +++ b/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/ZioLogger.scala @@ -0,0 +1,59 @@ +package zio.logging.slf4j.bridge + +import org.slf4j.Marker +import org.slf4j.event.{ KeyValuePair, Level, LoggingEvent } +import org.slf4j.helpers.AbstractLogger +import org.slf4j.spi.LoggingEventAware + +import java.util.Collections; + +final class ZioLogger private[bridge] (name: String, factory: ZioLoggerFactory) + extends AbstractLogger + with LoggingEventAware { + + private val data: LoggerData = LoggerData(name) + + override def getName: String = name + + override protected def getFullyQualifiedCallerName: String = null + + override protected def handleNormalizedLoggingCall( + level: Level, + marker: Marker, + messagePattern: String, + arguments: Array[AnyRef], + throwable: Throwable + ): Unit = + factory.log(data, level, messagePattern, arguments, throwable, Collections.emptyList[KeyValuePair]()) + + override def isTraceEnabled: Boolean = factory.isEnabled(data, Level.TRACE) + + override def isTraceEnabled(marker: Marker): Boolean = isTraceEnabled + + override def isDebugEnabled: Boolean = factory.isEnabled(data, Level.DEBUG) + + override def isDebugEnabled(marker: Marker): Boolean = isDebugEnabled + + override def isInfoEnabled: Boolean = factory.isEnabled(data, Level.INFO) + + override def isInfoEnabled(marker: Marker): Boolean = isInfoEnabled + + override def isWarnEnabled: Boolean = factory.isEnabled(data, Level.WARN) + + override def isWarnEnabled(marker: Marker): Boolean = isWarnEnabled + + override def isErrorEnabled: Boolean = factory.isEnabled(data, Level.ERROR) + + override def isErrorEnabled(marker: Marker): Boolean = isErrorEnabled + + override def log(event: LoggingEvent): Unit = + if (factory.isEnabled(data, event.getLevel)) + factory.log( + data, + event.getLevel, + event.getMessage, + event.getArgumentArray, + event.getThrowable, + event.getKeyValuePairs + ) +} diff --git a/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/ZioLoggerFactory.scala b/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/ZioLoggerFactory.scala new file mode 100644 index 00000000..65977e80 --- /dev/null +++ b/slf4j2-bridge/src/main/scala/zio/logging/slf4j/bridge/ZioLoggerFactory.scala @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2024 John A. De Goes and the ZIO Contributors + * + * 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 zio.logging.slf4j.bridge + +import org.slf4j.event.{ KeyValuePair, Level } +import org.slf4j.{ ILoggerFactory, Logger } + +import java.util.concurrent.ConcurrentHashMap +import scala.jdk.CollectionConverters._ + +final class ZioLoggerFactory extends ILoggerFactory { + private var runtime: LoggerRuntime = null + private val loggers = new ConcurrentHashMap[String, Logger]().asScala + + private[bridge] def attachRuntime(runtime: LoggerRuntime): Unit = + this.runtime = runtime + + private[bridge] def log( + logger: LoggerData, + level: Level, + messagePattern: String, + arguments: Array[AnyRef], + throwable: Throwable, + keyValues: java.util.List[KeyValuePair] + ): Unit = + if (runtime != null) runtime.log(logger, level, messagePattern, arguments, throwable, keyValues) + + private[bridge] def isEnabled(logger: LoggerData, level: Level): Boolean = + if (runtime != null) runtime.isEnabled(logger, level) else false + + override def getLogger(name: String): Logger = + loggers.getOrElseUpdate(name, new ZioLogger(name, this)) +} 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 43ac3313..9511e18d 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 @@ -25,7 +25,7 @@ import scala.jdk.CollectionConverters._ final class ZioLoggerRuntime(runtime: Runtime[Any], filter: LogFilter[Any]) extends LoggerRuntime { override def log( - name: String, + logger: LoggerData, level: Level, messagePattern: String, arguments: Array[AnyRef], @@ -44,8 +44,8 @@ final class ZioLoggerRuntime(runtime: Runtime[Any], filter: LogFilter[Any]) exte runtime.fiberRefs.joinAs(fiberId)(currentFiber.unsafe.getFiberRefs()) } - val logSpan = zio.LogSpan(name, java.lang.System.currentTimeMillis()) - val loggerName = (zio.logging.loggerNameAnnotationKey -> name) + val logSpan = zio.LogSpan(logger.name, java.lang.System.currentTimeMillis()) + val loggerName = (zio.logging.loggerNameAnnotationKey -> logger.name) val logAnnotations = if (keyValues != null) { keyValues.asScala.map(kv => (kv.key, kv.value.toString)).toMap } else { @@ -76,18 +76,18 @@ final class ZioLoggerRuntime(runtime: Runtime[Any], filter: LogFilter[Any]) exte fiberRuntime.log(() => msg, cause, Some(logLevel), trace) } - override def isEnabled(name: String, level: Level): Boolean = { + override def isEnabled(logger: LoggerData, level: Level): Boolean = { val logLevel = ZioLoggerRuntime.logLevelMapping(level) filter( - Trace(name, "", 0), + Trace.empty, FiberId.None, logLevel, () => "", Cause.empty, FiberRefs.empty, List.empty, - Map(zio.logging.loggerNameAnnotationKey -> name) + logger.annotations ) }