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 4c54bd793..0348257cc 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 @@ -18,6 +18,8 @@ package zio.logging.slf4j.bridge import org.slf4j.impl.ZioLoggerFactory import zio.{ Runtime, ZIO, ZLayer } +import java.util.concurrent.locks.ReentrantLock + object Slf4jBridge { /** @@ -46,11 +48,17 @@ object Slf4jBridge { def initialize(nameAnnotationKey: String): ZLayer[Any, Nothing, Unit] = Runtime.enableCurrentFiber ++ layer(nameAnnotationKey) + private val initLock: ReentrantLock = new ReentrantLock() + private def layer(nameAnnotationKey: String): ZLayer[Any, Nothing, Unit] = ZLayer { ZIO.runtime[Any].flatMap { runtime => ZIO.succeed { - ZioLoggerFactory.initialize(new ZioLoggerRuntime(runtime, nameAnnotationKey)) + initLock.lock() + try + ZioLoggerFactory.initialize(new ZioLoggerRuntime(runtime, nameAnnotationKey)) + finally + initLock.unlock() } } } 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 ac71f0609..4d5d2d365 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 @@ -5,6 +5,8 @@ import org.slf4j.impl.StaticMarkerBinder import zio.test._ import zio.{ Cause, Chunk, LogLevel, ZIO, ZIOAspect } +import java.util.UUID + object Slf4jBridgeSpec extends ZIOSpecDefault { final case class LogEntry( @@ -17,6 +19,17 @@ object Slf4jBridgeSpec extends ZIOSpecDefault { override def spec = suite("Slf4jBridge")( + test("parallel init") { + val uuids = List.fill(5)(UUID.randomUUID()) + for { + _ <- + ZIO.foreachPar(uuids) { u => + ZIO + .succeed(org.slf4j.LoggerFactory.getLogger("SLF4J-LOGGER").warn("Test {} {}!", "WARNING", u.toString)) + .provide(Slf4jBridge.initialize) + } + } yield assertTrue(true) + }, test("logs through slf4j - legacy logger name annotation key") { val testFailure = new RuntimeException("test error") for { 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 51e455425..74ff8897e 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 @@ -17,6 +17,8 @@ package zio.logging.slf4j.bridge import zio.{ Runtime, ZIO, ZLayer } +import java.util.concurrent.locks.ReentrantLock + object Slf4jBridge { /** @@ -29,14 +31,20 @@ object Slf4jBridge { */ def initializeWithoutFiberRefPropagation: ZLayer[Any, Nothing, Unit] = layer + private val initLock: ReentrantLock = new ReentrantLock() + private def layer: ZLayer[Any, Nothing, Unit] = ZLayer { ZIO.runtime[Any].flatMap { runtime => ZIO.succeed { - org.slf4j.LoggerFactory - .getILoggerFactory() - .asInstanceOf[LoggerFactory] - .attacheRuntime(new ZioLoggerRuntime(runtime)) + initLock.lock() + try + org.slf4j.LoggerFactory + .getILoggerFactory() + .asInstanceOf[LoggerFactory] + .attacheRuntime(new ZioLoggerRuntime(runtime)) + finally + initLock.unlock() } } } 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 34af42417..2bc04eefa 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 @@ -3,6 +3,8 @@ package zio.logging.slf4j.bridge import zio.test._ import zio.{ Cause, Chunk, LogLevel, ZIO, ZIOAspect } +import java.util.UUID + object Slf4jBridgeSpec extends ZIOSpecDefault { final case class LogEntry( @@ -15,6 +17,17 @@ object Slf4jBridgeSpec extends ZIOSpecDefault { override def spec = suite("Slf4jBridge")( + test("parallel init") { + val uuids = List.fill(5)(UUID.randomUUID()) + for { + _ <- + ZIO.foreachPar(uuids) { u => + ZIO + .succeed(org.slf4j.LoggerFactory.getLogger("SLF4J-LOGGER").warn("Test {} {}!", "WARNING", u.toString)) + .provide(Slf4jBridge.initialize) + } + } yield assertTrue(true) + }, test("logs through slf4j") { val testFailure = new RuntimeException("test error") for {