From 6cbfffca109606bfe58640047d781d8bf29e7814 Mon Sep 17 00:00:00 2001 From: davidl Date: Fri, 27 May 2022 20:24:38 +0200 Subject: [PATCH 1/4] Json appender reworked --- .../scala/zio/logging/JsonLogFormatSpec.scala | 139 ++++++++++++++++++ .../src/main/scala/internal/JsonEscape.scala | 25 ++++ .../src/main/scala/internal/LogAppender.scala | 98 ++++++++++++ .../main/scala/zio/logging/LogFormat.scala | 35 +++++ 4 files changed, 297 insertions(+) create mode 100644 core/jvm/src/test/scala/zio/logging/JsonLogFormatSpec.scala create mode 100644 core/shared/src/main/scala/internal/JsonEscape.scala diff --git a/core/jvm/src/test/scala/zio/logging/JsonLogFormatSpec.scala b/core/jvm/src/test/scala/zio/logging/JsonLogFormatSpec.scala new file mode 100644 index 00000000..4909fd5a --- /dev/null +++ b/core/jvm/src/test/scala/zio/logging/JsonLogFormatSpec.scala @@ -0,0 +1,139 @@ +package zio.logging + +import zio.logging.LogFormat.{ line, _ } +import zio.logging.internal.JsonEscape +import zio.test._ +import zio.{ Cause, FiberId, LogLevel, Trace } + +object JsonLogFormatSpec extends ZIOSpecDefault { + private val nonEmptyString = Gen.stringBounded(1, 5)(Gen.alphaNumericChar) + + val spec: Spec[Environment, Any] = suite("JsonLogFormatSpec")( + test("line") { + val format = line + check(nonEmptyString) { line => + val result = format + .toJsonLogger( + Trace.empty, + FiberId.None, + LogLevel.Info, + () => line, + Cause.empty, + Map.empty, + Nil, + Map.empty + ) + assertTrue(result == s"""{"text_content":"${JsonEscape(line)}"}""") + } + }, + test("annotation") { + val format = annotation("test") + check(Gen.string) { annotationValue => + val result = format.toJsonLogger( + Trace.empty, + FiberId.None, + LogLevel.Info, + () => "", + Cause.empty, + Map.empty, + Nil, + Map("test" -> annotationValue) + ) + assertTrue(result == s"""{"test":"${JsonEscape(annotationValue)}"}""") + } + }, + test("annotation (structured)") { + val format = annotation(LogAnnotation.UserId) + check(Gen.string) { annotationValue => + val result = format.toJsonLogger( + Trace.empty, + FiberId.None, + LogLevel.Info, + () => "", + Cause.empty, + Map(logContext -> LogContext.empty.annotate(LogAnnotation.UserId, annotationValue)), + Nil, + Map.empty + ) + assertTrue(result == s"""{"user_id":"${JsonEscape(annotationValue)}"}""") + } + }, + test("empty annotation") { + val format = annotation("test") + val result = format.toJsonLogger( + Trace.empty, + FiberId.None, + LogLevel.Info, + () => "", + Cause.empty, + Map.empty, + Nil, + Map.empty + ) + assertTrue(result == "{}") + }, + test("several labels") { + val format = label("msg", line) + label("fiber", fiberId) + check(Gen.string, Gen.int) { (line, fiberId) => + val result = format.toJsonLogger( + Trace.empty, + FiberId(fiberId, 1, Trace.empty), + LogLevel.Info, + () => line, + Cause.empty, + Map.empty, + Nil, + Map.empty + ) + val msg = JsonEscape(line) + val fiber = s"zio-fiber-${JsonEscape(fiberId.toString)}" + assertTrue(result == s"""{"msg":"$msg","fiber":"$fiber"}""") + } + }, + test("nested labels") { + val format = label("msg", line) + label("nested", label("fiber", fiberId) + annotation("test")) + check(Gen.alphaNumericString, Gen.int, nonEmptyString) { (line, fiberId, annotationValue) => + val result = format.toJsonLogger( + Trace.empty, + FiberId(fiberId, 1, Trace.empty), + LogLevel.Info, + () => line, + Cause.empty, + Map.empty, + Nil, + Map("test" -> annotationValue) + ) + val msg = JsonEscape(line) + val fiber = s"zio-fiber-${JsonEscape(fiberId.toString)}" + val ann = JsonEscape(annotationValue) + assertTrue(result == s"""{"msg":"$msg","nested":{"fiber":"$fiber","test":"$ann"}}""") + } + }, + test("mixed structured / unstructured ") { + val format = + label("msg", line) + text("hi") + + label( + "nested", + label("fiber", fiberId |-| text("abc") + label("third", text("3"))) + annotation("test") + ) + text(" there") + check(Gen.alphaNumericString, Gen.int, nonEmptyString) { (line, fiberId, annotationValue) => + val result = format.toJsonLogger( + Trace.empty, + FiberId(fiberId, 1, Trace.empty), + LogLevel.Info, + () => line, + Cause.empty, + Map.empty, + Nil, + Map("test" -> annotationValue) + ) + val msg = JsonEscape(line) + val fiber = s"zio-fiber-${JsonEscape(fiberId.toString)}" + val ann = JsonEscape(annotationValue) + assertTrue( + result == s"""{"text_content":"hi there","msg":"$msg","nested":{"fiber":{"text_content":"$fiber abc","third":"3"},"test":"$ann"}}""" + ) + } + } + ) +} diff --git a/core/shared/src/main/scala/internal/JsonEscape.scala b/core/shared/src/main/scala/internal/JsonEscape.scala new file mode 100644 index 00000000..fe631a07 --- /dev/null +++ b/core/shared/src/main/scala/internal/JsonEscape.scala @@ -0,0 +1,25 @@ +package zio.logging.internal + +import scala.collection.mutable + +object JsonEscape { + def apply(s: String): String = + escape(s, new mutable.StringBuilder()).toString() + + private def escape(s: String, sb: mutable.StringBuilder): mutable.StringBuilder = { + if (s != null || s.isEmpty) + for { c <- s } c match { + case '\\' => sb.append('\\').append(c) + case '"' => sb.append('\\').append(c) + case '/' => sb.append('\\').append(c) + case '\b' => sb.append("\\b") + case '\t' => sb.append("\\t") + case '\n' => sb.append("\\n") + case '\f' => sb.append("\\f") + case '\r' => sb.append("\\r") + case ctrl if ctrl < ' ' => sb.append("\\u").append("000").append(Integer.toHexString(ctrl.toInt)) + case _ => sb.append(c) + } + sb + } +} diff --git a/core/shared/src/main/scala/internal/LogAppender.scala b/core/shared/src/main/scala/internal/LogAppender.scala index 86e50b87..42393744 100644 --- a/core/shared/src/main/scala/internal/LogAppender.scala +++ b/core/shared/src/main/scala/internal/LogAppender.scala @@ -16,6 +16,9 @@ package zio.logging.internal import zio._ +import zio.logging.internal.JsonEscape + +import scala.collection.mutable /** * A [[LogAppender]] is a low-level interface designed to be the bridge between @@ -62,6 +65,11 @@ private[logging] trait LogAppender { self => */ def closeKeyOpenValue(): Unit + /** + * Marks the close of the log entry + */ + def closeLogEntry(): Unit + /** * Marks the close of the value of a key/value pair. */ @@ -72,6 +80,11 @@ private[logging] trait LogAppender { self => */ def openKey(): Unit + /** + * Marks the start of the log entry + */ + def openLogEntry(): Unit + /** * Modifies the way text is appended to the log. */ @@ -91,9 +104,13 @@ private[logging] object LogAppender { def closeKeyOpenValue(): Unit = self.closeKeyOpenValue() + def closeLogEntry(): Unit = self.closeLogEntry() + def closeValue(): Unit = self.closeValue() def openKey(): Unit = self.openKey() + + def openLogEntry(): Unit = self.openLogEntry() } /** @@ -109,8 +126,89 @@ private[logging] object LogAppender { def closeKeyOpenValue(): Unit = appendText("=") + def closeLogEntry(): Unit = () + def closeValue(): Unit = () def openKey(): Unit = () + + def openLogEntry(): Unit = () + } + + def json(textAppender: String => Any): LogAppender = new LogAppender { self => + class State( + var root: Boolean = false, + var separateKeyValue: Boolean = false, + var writingKey: Boolean = false, + val content: mutable.StringBuilder = new mutable.StringBuilder, + val textContent: mutable.StringBuilder = new mutable.StringBuilder + ) + + val stack = new mutable.Stack[State]() + def current: State = stack.top + + def appendCause(cause: Cause[Any]): Unit = appendText(cause.prettyPrint) + + def appendNumeric[A](numeric: A): Unit = appendText(numeric.toString) + + def appendText(text: String): Unit = + if (current.writingKey) current.content.append(text) + else current.textContent.append(text) + + def beginStructure(root: Boolean = false): Unit = + stack.push(new State(root = root)) + + def endStructure(): mutable.StringBuilder = { + val result = new StringBuilder + + if (current.content.isEmpty && !current.root) { + // Simple value + result.append("\"").append(JsonEscape(current.textContent.toString())).append("\"") + } else { + // Structure + result.append("{") + + if (current.textContent.nonEmpty) { + result.append(""""text_content":""") + result.append("\"").append(JsonEscape(current.textContent.toString())).append("\"") + } + + if (current.content.nonEmpty) { + if (current.textContent.nonEmpty) result.append(",") + result.append(current.content) + } + + result.append("}") + } + + stack.pop() + result + } + + def closeKeyOpenValue(): Unit = { + current.writingKey = false + current.content.append("""":""") + beginStructure() + } + + def closeLogEntry(): Unit = + textAppender(endStructure().toString()) + + def closeValue(): Unit = { + val result = endStructure() + current.content.append(result) + } + + def openKey(): Unit = { + if (current.separateKeyValue) current.content.append(",") + current.separateKeyValue = true + current.writingKey = true + current.content.append("\"") + } + + def openLogEntry(): Unit = { + stack.clear() + beginStructure(true) + } } } diff --git a/core/shared/src/main/scala/zio/logging/LogFormat.scala b/core/shared/src/main/scala/zio/logging/LogFormat.scala index 7b32802f..7d98b44f 100644 --- a/core/shared/src/main/scala/zio/logging/LogFormat.scala +++ b/core/shared/src/main/scala/zio/logging/LogFormat.scala @@ -116,6 +116,41 @@ trait LogFormat { self => final def spaced(other: LogFormat): LogFormat = this |-| other + /** + * Converts this log format into a json logger, which accepts text input, and + * produces json output. + */ + final def toJsonLogger: ZLogger[String, String] = ( + trace: Trace, + fiberId: FiberId, + logLevel: LogLevel, + message: () => String, + cause: Cause[Any], + context: Map[FiberRef[_], Any], + spans: List[LogSpan], + annotations: Map[String, String] + ) => { + val logEntryFormat = + LogFormat.make { (builder, trace, fiberId, level, line, fiberRefs, cause, spans, annotations) => + builder.openLogEntry() + try self.unsafeFormat(builder)(trace, fiberId, level, line, fiberRefs, cause, spans, annotations) + finally builder.closeLogEntry() + } + + val builder = new StringBuilder() + logEntryFormat.unsafeFormat(LogAppender.json(builder.append(_)))( + trace, + fiberId, + logLevel, + message, + cause, + context, + spans, + annotations + ) + builder.toString() + } + /** * Converts this log format into a text logger, which accepts text input, and * produces text output. From c20f52d3e1687bc5241bbd9e1b9bcc341411e7bb Mon Sep 17 00:00:00 2001 From: davidl Date: Sat, 28 May 2022 10:56:40 +0200 Subject: [PATCH 2/4] Cleanup and json loggers --- .../src/main/scala/internal/LogAppender.scala | 54 +++++---- .../src/main/scala/zio/logging/package.scala | 111 ++++++++++++------ 2 files changed, 111 insertions(+), 54 deletions(-) diff --git a/core/shared/src/main/scala/internal/LogAppender.scala b/core/shared/src/main/scala/internal/LogAppender.scala index 42393744..20b4cf26 100644 --- a/core/shared/src/main/scala/internal/LogAppender.scala +++ b/core/shared/src/main/scala/internal/LogAppender.scala @@ -141,36 +141,48 @@ private[logging] object LogAppender { var separateKeyValue: Boolean = false, var writingKey: Boolean = false, val content: mutable.StringBuilder = new mutable.StringBuilder, - val textContent: mutable.StringBuilder = new mutable.StringBuilder - ) + var textContent: mutable.StringBuilder = new mutable.StringBuilder + ) { + def appendContent(str: CharSequence): Unit = { content.append(str); () } + def appendTextContent(str: CharSequence): Unit = { textContent.append(str); () } + } + + val stack = new mutable.Stack[State]() - val stack = new mutable.Stack[State]() def current: State = stack.top - def appendCause(cause: Cause[Any]): Unit = appendText(cause.prettyPrint) + override def appendCause(cause: Cause[Any]): Unit = appendText(cause.prettyPrint) - def appendNumeric[A](numeric: A): Unit = appendText(numeric.toString) + override def appendNumeric[A](numeric: A): Unit = appendText(numeric.toString) - def appendText(text: String): Unit = - if (current.writingKey) current.content.append(text) - else current.textContent.append(text) + override def appendText(text: String): Unit = + if (current.writingKey) current.appendContent(text) + else current.appendTextContent(text) def beginStructure(root: Boolean = false): Unit = stack.push(new State(root = root)) def endStructure(): mutable.StringBuilder = { - val result = new StringBuilder + val result = new mutable.StringBuilder + + val cleanedTextContent = { + // Do a little cleanup to handle default log formats (quoted and spaced) + if (current.textContent.startsWith("\"") && current.textContent.endsWith("\"")) + current.textContent = current.textContent.drop(1).dropRight(1) + if (current.textContent.forall(_ == ' ')) current.textContent.clear() + current.textContent.toString() + } if (current.content.isEmpty && !current.root) { // Simple value - result.append("\"").append(JsonEscape(current.textContent.toString())).append("\"") + result.append("\"").append(JsonEscape(cleanedTextContent)).append("\"") } else { // Structure result.append("{") if (current.textContent.nonEmpty) { result.append(""""text_content":""") - result.append("\"").append(JsonEscape(current.textContent.toString())).append("\"") + result.append("\"").append(JsonEscape(cleanedTextContent)).append("\"") } if (current.content.nonEmpty) { @@ -185,28 +197,30 @@ private[logging] object LogAppender { result } - def closeKeyOpenValue(): Unit = { + override def closeKeyOpenValue(): Unit = { current.writingKey = false - current.content.append("""":""") + current.appendContent("""":""") beginStructure() } - def closeLogEntry(): Unit = + override def closeLogEntry(): Unit = { textAppender(endStructure().toString()) + () + } - def closeValue(): Unit = { + override def closeValue(): Unit = { val result = endStructure() - current.content.append(result) + current.appendContent(result) } - def openKey(): Unit = { - if (current.separateKeyValue) current.content.append(",") + override def openKey(): Unit = { + if (current.separateKeyValue) current.appendContent(",") current.separateKeyValue = true current.writingKey = true - current.content.append("\"") + current.appendContent("\"") } - def openLogEntry(): Unit = { + override def openLogEntry(): Unit = { stack.clear() beginStructure(true) } diff --git a/core/shared/src/main/scala/zio/logging/package.scala b/core/shared/src/main/scala/zio/logging/package.scala index fe84a22f..b0fc4a5c 100644 --- a/core/shared/src/main/scala/zio/logging/package.scala +++ b/core/shared/src/main/scala/zio/logging/package.scala @@ -15,6 +15,7 @@ */ package zio +import java.io.PrintStream import java.nio.charset.{ Charset, StandardCharsets } import java.nio.file.Path @@ -43,32 +44,26 @@ package object logging { def console( format: LogFormat = LogFormat.colored, logLevel: LogLevel = LogLevel.Info - ): ZLayer[Any, Nothing, Unit] = { - val stringLogger = format.toLogger.map { line => - try java.lang.System.out.println(line) - catch { - case t: VirtualMachineError => throw t - case _: Throwable => () - } - }.filterLogLevel(_ >= logLevel) + ): ZLayer[Any, Nothing, Unit] = + makeConsole(format.toLogger, java.lang.System.out, logLevel) - Runtime.addLogger(stringLogger) - } + def consoleJson( + format: LogFormat = LogFormat.default, + logLevel: LogLevel = LogLevel.Info + ): ZLayer[Any, Nothing, Unit] = + makeConsole(format.toJsonLogger, java.lang.System.out, logLevel) def consoleErr( format: LogFormat = LogFormat.default, logLevel: LogLevel = LogLevel.Info - ): ZLayer[Any, Nothing, Unit] = { - val stringLogger = format.toLogger.map { line => - try java.lang.System.err.println(line) - catch { - case t: VirtualMachineError => throw t - case _: Throwable => () - } - }.filterLogLevel(_ >= logLevel) + ): ZLayer[Any, Nothing, Unit] = + makeConsole(format.toLogger, java.lang.System.err, logLevel) - Runtime.addLogger(stringLogger) - } + def consoleErrJson( + format: LogFormat = LogFormat.default, + logLevel: LogLevel = LogLevel.Info + ): ZLayer[Any, Nothing, Unit] = + makeConsole(format.toJsonLogger, java.lang.System.err, logLevel) def file( destination: Path, @@ -79,7 +74,19 @@ package object logging { bufferedIOSize: Option[Int] = None ): ZLayer[Any, Nothing, Unit] = Runtime.addLogger( - makeStringLogger(destination, format, logLevel, charset, autoFlushBatchSize, bufferedIOSize) + makeStringLogger(destination, format.toLogger, logLevel, charset, autoFlushBatchSize, bufferedIOSize) + ) + + def fileJson( + destination: Path, + format: LogFormat = LogFormat.default, + logLevel: LogLevel = LogLevel.Info, + charset: Charset = StandardCharsets.UTF_8, + autoFlushBatchSize: Int = 1, + bufferedIOSize: Option[Int] = None + ): ZLayer[Any, Nothing, Unit] = + Runtime.addLogger( + makeStringLogger(destination, format.toJsonLogger, logLevel, charset, autoFlushBatchSize, bufferedIOSize) ) def fileAsync( @@ -90,24 +97,42 @@ package object logging { autoFlushBatchSize: Int = 1, bufferedIOSize: Option[Int] = None ): ZLayer[Any, Nothing, Unit] = - ZLayer.scoped { - for { - queue <- Queue.bounded[UIO[Any]](1000) - stringLogger = - makeAsyncStringLogger(destination, format, logLevel, charset, autoFlushBatchSize, bufferedIOSize, queue) - _ <- FiberRef.currentLoggers.locallyScopedWith(_ + stringLogger) - _ <- queue.take.flatMap(task => task.ignore).forever.forkScoped - } yield () - } + makeFileAsync(destination, format.toLogger, logLevel, charset, autoFlushBatchSize, bufferedIOSize) + + def fileAsyncJson( + destination: Path, + format: LogFormat = LogFormat.default, + logLevel: LogLevel = LogLevel.Info, + charset: Charset = StandardCharsets.UTF_8, + autoFlushBatchSize: Int = 1, + bufferedIOSize: Option[Int] = None + ): ZLayer[Any, Nothing, Unit] = + makeFileAsync(destination, format.toJsonLogger, logLevel, charset, autoFlushBatchSize, bufferedIOSize) val removeDefaultLoggers: ZLayer[Any, Nothing, Unit] = { implicit val trace = Trace.empty ZLayer.scoped(FiberRef.currentLoggers.locallyScopedWith(_ -- Runtime.defaultLoggers)) } + private def makeConsole( + logger: ZLogger[String, String], + stream: PrintStream, + logLevel: LogLevel + ): ZLayer[Any, Nothing, Unit] = { + val stringLogger = logger.map { line => + try stream.println(line) + catch { + case t: VirtualMachineError => throw t + case _: Throwable => () + } + }.filterLogLevel(_ >= logLevel) + + Runtime.addLogger(stringLogger) + } + private def makeStringLogger( destination: Path, - format: LogFormat, + logger: ZLogger[String, String], logLevel: LogLevel, charset: Charset, autoFlushBatchSize: Int, @@ -116,7 +141,7 @@ package object logging { val logWriter = new internal.FileWriter(destination, charset, autoFlushBatchSize, bufferedIOSize) val stringLogger: ZLogger[String, Any] = - format.toLogger.map { (line: String) => + logger.map { (line: String) => try logWriter.append(line) catch { case t: VirtualMachineError => throw t @@ -127,9 +152,27 @@ package object logging { stringLogger } + private def makeFileAsync( + destination: Path, + logger: ZLogger[String, String], + logLevel: LogLevel, + charset: Charset, + autoFlushBatchSize: Int, + bufferedIOSize: Option[Int] + ): ZLayer[Any, Nothing, Unit] = + ZLayer.scoped { + for { + queue <- Queue.bounded[UIO[Any]](1000) + stringLogger = + makeAsyncStringLogger(destination, logger, logLevel, charset, autoFlushBatchSize, bufferedIOSize, queue) + _ <- FiberRef.currentLoggers.locallyScopedWith(_ + stringLogger) + _ <- queue.take.flatMap(task => task.ignore).forever.forkScoped + } yield () + } + private def makeAsyncStringLogger( destination: Path, - format: LogFormat, + logger: ZLogger[String, String], logLevel: LogLevel, charset: Charset, autoFlushBatchSize: Int, @@ -139,7 +182,7 @@ package object logging { val logWriter = new internal.FileWriter(destination, charset, autoFlushBatchSize, bufferedIOSize) val stringLogger: ZLogger[String, Any] = - format.toLogger.map { (line: String) => + logger.map { (line: String) => Runtime.default.unsafeRun(queue.offer(ZIO.succeed { try logWriter.append(line) catch { From b4e1b72ce7263b65b027ae706d963cbf90f47231 Mon Sep 17 00:00:00 2001 From: davidl Date: Sat, 28 May 2022 11:04:14 +0200 Subject: [PATCH 3/4] Remove build warning --- core/shared/src/main/scala/internal/LogAppender.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/shared/src/main/scala/internal/LogAppender.scala b/core/shared/src/main/scala/internal/LogAppender.scala index 20b4cf26..12d06b1e 100644 --- a/core/shared/src/main/scala/internal/LogAppender.scala +++ b/core/shared/src/main/scala/internal/LogAppender.scala @@ -16,7 +16,6 @@ package zio.logging.internal import zio._ -import zio.logging.internal.JsonEscape import scala.collection.mutable @@ -159,8 +158,7 @@ private[logging] object LogAppender { if (current.writingKey) current.appendContent(text) else current.appendTextContent(text) - def beginStructure(root: Boolean = false): Unit = - stack.push(new State(root = root)) + def beginStructure(root: Boolean = false): Unit = { stack.push(new State(root = root)); () } def endStructure(): mutable.StringBuilder = { val result = new mutable.StringBuilder From 43f5edb4083e946616b068a272c30039327dc689 Mon Sep 17 00:00:00 2001 From: davidl Date: Wed, 29 Jun 2022 15:18:44 +0200 Subject: [PATCH 4/4] Updates after merge errors --- .../scala/zio/logging/JsonLogFormatSpec.scala | 19 +++++++++++-------- .../main/scala/zio/logging/LogFormat.scala | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/core/jvm/src/test/scala/zio/logging/JsonLogFormatSpec.scala b/core/jvm/src/test/scala/zio/logging/JsonLogFormatSpec.scala index 4909fd5a..a8f9e8ac 100644 --- a/core/jvm/src/test/scala/zio/logging/JsonLogFormatSpec.scala +++ b/core/jvm/src/test/scala/zio/logging/JsonLogFormatSpec.scala @@ -3,7 +3,7 @@ package zio.logging import zio.logging.LogFormat.{ line, _ } import zio.logging.internal.JsonEscape import zio.test._ -import zio.{ Cause, FiberId, LogLevel, Trace } +import zio.{ Cause, FiberId, FiberRefs, LogLevel, Trace } object JsonLogFormatSpec extends ZIOSpecDefault { private val nonEmptyString = Gen.stringBounded(1, 5)(Gen.alphaNumericChar) @@ -19,7 +19,7 @@ object JsonLogFormatSpec extends ZIOSpecDefault { LogLevel.Info, () => line, Cause.empty, - Map.empty, + FiberRefs.empty, Nil, Map.empty ) @@ -35,7 +35,7 @@ object JsonLogFormatSpec extends ZIOSpecDefault { LogLevel.Info, () => "", Cause.empty, - Map.empty, + FiberRefs.empty, Nil, Map("test" -> annotationValue) ) @@ -51,7 +51,10 @@ object JsonLogFormatSpec extends ZIOSpecDefault { LogLevel.Info, () => "", Cause.empty, - Map(logContext -> LogContext.empty.annotate(LogAnnotation.UserId, annotationValue)), + FiberRefs.empty.updatedAs(FiberId.Runtime(0, 0, Trace.empty))( + logContext, + LogContext.empty.annotate(LogAnnotation.UserId, annotationValue) + ), Nil, Map.empty ) @@ -66,7 +69,7 @@ object JsonLogFormatSpec extends ZIOSpecDefault { LogLevel.Info, () => "", Cause.empty, - Map.empty, + FiberRefs.empty, Nil, Map.empty ) @@ -81,7 +84,7 @@ object JsonLogFormatSpec extends ZIOSpecDefault { LogLevel.Info, () => line, Cause.empty, - Map.empty, + FiberRefs.empty, Nil, Map.empty ) @@ -99,7 +102,7 @@ object JsonLogFormatSpec extends ZIOSpecDefault { LogLevel.Info, () => line, Cause.empty, - Map.empty, + FiberRefs.empty, Nil, Map("test" -> annotationValue) ) @@ -123,7 +126,7 @@ object JsonLogFormatSpec extends ZIOSpecDefault { LogLevel.Info, () => line, Cause.empty, - Map.empty, + FiberRefs.empty, Nil, Map("test" -> annotationValue) ) diff --git a/core/shared/src/main/scala/zio/logging/LogFormat.scala b/core/shared/src/main/scala/zio/logging/LogFormat.scala index f7326dcf..8688aea4 100644 --- a/core/shared/src/main/scala/zio/logging/LogFormat.scala +++ b/core/shared/src/main/scala/zio/logging/LogFormat.scala @@ -126,7 +126,7 @@ trait LogFormat { self => logLevel: LogLevel, message: () => String, cause: Cause[Any], - context: Map[FiberRef[_], Any], + context: FiberRefs, spans: List[LogSpan], annotations: Map[String, String] ) => {