Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LogAppender for java platform/system logger #493

Merged
merged 9 commits into from
Sep 11, 2022
Merged
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
12 changes: 10 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ jobs:
fetch-depth: 0
- name: Setup Scala and Java
uses: olafurpg/setup-scala@v13
with:
java-version: [email protected]
- name: Cache scala dependencies
uses: coursier/cache-action@v6
- name: Lint code
Expand All @@ -36,6 +38,8 @@ jobs:
uses: actions/[email protected]
- name: Setup Scala and Java
uses: olafurpg/setup-scala@v13
with:
java-version: [email protected]
- name: Cache scala dependencies
uses: coursier/cache-action@v6
- name: Check Document Generation
Expand All @@ -62,12 +66,16 @@ jobs:
- name: Cache scala dependencies
uses: coursier/cache-action@v6
- name: Mima Checks
if: ${{ !startsWith(matrix.scala, '3.') }}
if: ${{ !startsWith(matrix.scala, '3.') && endsWith(matrix.java, '.11') }}
run: ./sbt ++${{ matrix.scala }}! mimaChecks
- name: Run tests
if: ${{ endsWith(matrix.java, '.11') }}
run: sbt ++${{ matrix.scala }}! test${{ matrix.platform }}
- name: Run tests JVM8
if: ${{ endsWith(matrix.java, '.8') && matrix.platform == 'JVM' }}
run: sbt ++${{ matrix.scala }}! testJVM8
- name: Compile additional subprojects
if: ${{ startsWith(matrix.scala, '2.12.') || startsWith(matrix.scala, '2.13.') }}
if: ${{ ( startsWith(matrix.scala, '2.12.') || startsWith(matrix.scala, '2.13.') ) && endsWith(matrix.java, '.11') }}
run: sbt ++${{ matrix.scala }}! examples/compile docs/compile benchmarks/compile

ci:
Expand Down
28 changes: 23 additions & 5 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ inThisBuild(
)
)

val ZioVersion = "2.0.0"
val ZioVersion = "2.0.2"
val scalaJavaTimeVersion = "2.3.0"
val slf4jVersion = "1.7.36"
val logbackVersion = "1.2.11"
Expand All @@ -30,10 +30,15 @@ addCommandAlias("fix", "; all compile:scalafix test:scalafix; all scalafmtSbt sc
addCommandAlias("check", "; scalafmtSbtCheck; scalafmtCheckAll; compile:scalafix --check; test:scalafix --check")

addCommandAlias(
"testJVM",
"testJVM8",
";coreJVM/test;slf4j/test;slf4jBridge/test"
)

addCommandAlias(
"testJVM",
";coreJVM/test;slf4j/test;jpl/test;slf4jBridge/test"
)

addCommandAlias(
"testJS",
";coreJS/test"
Expand All @@ -49,7 +54,7 @@ lazy val root = project
.settings(
publish / skip := true
)
.aggregate(coreJVM, coreJS, slf4j, slf4jBridge, benchmarks, docs, examples)
.aggregate(coreJVM, coreJS, slf4j, slf4jBridge, jpl, benchmarks, docs, examples)

lazy val core = crossProject(JSPlatform, JVMPlatform)
.crossType(CrossType.Full)
Expand Down Expand Up @@ -106,6 +111,19 @@ lazy val slf4jBridge = project
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)

lazy val jpl = project
.in(file("jpl"))
.dependsOn(coreJVM)
.settings(stdSettings("zio-logging-jpl"))
.settings(mimaSettings(failOnProblem = true))
.settings(
libraryDependencies ++= Seq(
"dev.zio" %%% "zio-test" % ZioVersion % Test,
"dev.zio" %%% "zio-test-sbt" % ZioVersion % Test
),
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)

lazy val benchmarks = project
.in(file("benchmarks"))
.settings(stdSettings("zio-logging-benchmarks"))
Expand All @@ -131,12 +149,12 @@ lazy val docs = project
docusaurusCreateSite := docusaurusCreateSite.dependsOn(Compile / unidoc).value,
docusaurusPublishGhpages := docusaurusPublishGhpages.dependsOn(Compile / unidoc).value
)
.dependsOn(coreJVM, slf4j)
.dependsOn(coreJVM, slf4j, jpl)
.enablePlugins(MdocPlugin, DocusaurusPlugin, ScalaUnidocPlugin)

lazy val examples = project
.in(file("examples"))
.dependsOn(slf4j)
.dependsOn(slf4j, jpl)
.settings(stdSettings("zio-logging-examples"))
.settings(
publish / skip := true,
Expand Down
4 changes: 2 additions & 2 deletions core/shared/src/main/scala/zio/logging/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ package object logging {
* to all log messages emitted by the `myResponseHandler(request)` effect.
*/
val logContext: FiberRef[LogContext] =
zio.Unsafe.unsafeCompat { implicit u =>
zio.Unsafe.unsafe { implicit u =>
FiberRef.unsafe.make(LogContext.empty, ZIO.identityFn[LogContext], (old, newV) => old ++ newV)
}

Expand Down Expand Up @@ -182,7 +182,7 @@ package object logging {

val stringLogger: ZLogger[String, Any] =
logger.map { (line: String) =>
zio.Unsafe.unsafeCompat { implicit u =>
zio.Unsafe.unsafe { implicit u =>
Runtime.default.unsafe.run(queue.offer(ZIO.succeed {
try logWriter.writeln(line)
catch {
Expand Down
84 changes: 81 additions & 3 deletions docs/overview/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,18 @@ _ZIO Logging_ is the official logging library for ZIO 2 applications, with integ
libraryDependencies += "dev.zio" %% "zio-logging" % version
```

If you need `slf4j` integration use `zio-logging-slf4j` instead:
If you need [`slf4j`](https://www.slf4j.org/) integration use `zio-logging-slf4j` instead:

```scala
libraryDependencies += "dev.zio" %% "zio-logging-slf4j" % version
```

If you need [`Java Platform/System Logger`](https://openjdk.org/jeps/264) integration use `zio-logging-jpl` instead:

```scala
libraryDependencies += "dev.zio" %% "zio-logging-jpl" % version
```

### Log Format

A `LogFormat` represents a DSL to describe the format of text log messages.
Expand Down Expand Up @@ -79,12 +85,35 @@ Default `slf4j` logger setup:
* all annotations are placed into MDC context
* cause is logged as throwable

Custom slf4j logger name set by aspect:
Custom logger name set by aspect:

```scala
ZIO.logInfo("Starting user operation") @@ SLF4J.loggerName("zio.logging.example.UserOperation")
```

### Java Platform/System logger

`jpl` logger layer:

```scala
import zio.logging.backend.JPL

val logger = Runtime.removeDefaultLoggers >>> JPL.jpl
```

Default `jpl` logger setup:
* logger name (by default) is extracted from `zio.Trace`
* for example, trace `zio.logging.example.Slf4jAnnotationApp.run(Slf4jSimpleApp.scala:17)` will have `zio.logging.example.Slf4jSimpleApp` as logger name
* NOTE: custom logger name may be set by `JPL.loggerName` aspect
* all annotations are placed at the beginning of log message
* cause is logged as throwable

Custom logger name set by aspect:

```scala
ZIO.logInfo("Starting user operation") @@ JPL.loggerName("zio.logging.example.UserOperation")
```


## Examples

Expand Down Expand Up @@ -164,7 +193,6 @@ Expected console output:
{"timestamp":"2022-07-15T20:19:03.566659+02:00","level":"INFO","thread":"zio-fiber-6","message":"Done"}
```


### Slf4j logger name and annotations

```scala
Expand Down Expand Up @@ -226,6 +254,56 @@ Expected Console Output:
20:52:39.846 [ZScheduler-Worker-3] trace_id= user_id= INFO zio.logging.example.Slf4jSimpleApp Done
```

### Java Platform/System logger name and annotations

```scala
package zio.logging.example

import zio.logging.LogAnnotation
import zio.logging.backend.JPL
import zio.{ExitCode, Runtime, Scope, ZIO, ZIOAppDefault, _}

import java.util.UUID

object JplSimpleApp extends ZIOAppDefault {

private val logger = Runtime.removeDefaultLoggers >>> JPL.jpl

private val users = List.fill(2)(UUID.randomUUID())

override def run: ZIO[Scope, Any, ExitCode] =
(for {
_ <- ZIO.logInfo("Start")
traceId <- ZIO.succeed(UUID.randomUUID())
_ <- ZIO.foreachPar(users) { uId =>
{
ZIO.logInfo("Starting user operation") *>
ZIO.sleep(500.millis) *>
ZIO.logInfo("Stopping user operation")
} @@ ZIOAspect.annotated("user", uId.toString)
} @@ LogAnnotation.TraceId(traceId) @@ JPL.loggerName("zio.logging.example.UserOperation")
_ <- ZIO.logInfo("Done")
} yield ExitCode.success).provide(logger)

}

```

Expected Console Output:
```
Aug 18, 2022 6:51:10 PM zio.logging.backend.JPL$$anon$2 $anonfun$closeLogEntry$1
INFO: Start
Aug 18, 2022 6:51:10 PM zio.logging.backend.JPL$$anon$2 $anonfun$closeLogEntry$1
INFO: jpl_logger_name=zio.logging.example.UserOperation user=d0c3b1ac-d0f5-4879-b398-3dab5efdc9d4 trace_id=92e5e9fd-71b6-4491-a97d-101d367bc64e Starting user operation
Aug 18, 2022 6:51:10 PM zio.logging.backend.JPL$$anon$2 $anonfun$closeLogEntry$1
INFO: jpl_logger_name=zio.logging.example.UserOperation user=f4327982-c838-4c03-8839-49ebc95f2b6b trace_id=92e5e9fd-71b6-4491-a97d-101d367bc64e Starting user operation
Aug 18, 2022 6:51:10 PM zio.logging.backend.JPL$$anon$2 $anonfun$closeLogEntry$1
INFO: jpl_logger_name=zio.logging.example.UserOperation user=d0c3b1ac-d0f5-4879-b398-3dab5efdc9d4 trace_id=92e5e9fd-71b6-4491-a97d-101d367bc64e Stopping user operation
Aug 18, 2022 6:51:10 PM zio.logging.backend.JPL$$anon$2 $anonfun$closeLogEntry$1
INFO: jpl_logger_name=zio.logging.example.UserOperation user=f4327982-c838-4c03-8839-49ebc95f2b6b trace_id=92e5e9fd-71b6-4491-a97d-101d367bc64e Stopping user operation
Aug 18, 2022 6:51:10 PM zio.logging.backend.JPL$$anon$2 $anonfun$closeLogEntry$1
INFO: Done
```

### Slf4j bridge
It is possible to use `zio-logging` for SLF4j loggers, usually third-party non-ZIO libraries. To do so, import
Expand Down
24 changes: 24 additions & 0 deletions examples/src/main/scala/zio/logging/example/JplExampleApp.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package zio.logging.example

import zio.logging.backend.JPL
import zio.{ ExitCode, Runtime, Scope, URIO, ZIO, ZIOAppDefault }

object JplExampleApp extends ZIOAppDefault {

private val logger = Runtime.removeDefaultLoggers >>> JPL.jpl

private def ping(address: String): URIO[PingService, Unit] =
PingService
.ping(address)
.tap(result => ZIO.logInfo(s"ping: $address - result: $result"))
.tapErrorCause(error => ZIO.logErrorCause(s"ping: $address - error", error))
.unit
.ignore

override def run: ZIO[Scope, Any, ExitCode] =
(for {
_ <- ping("127.0.0.1")
_ <- ping("x8.8.8.8")
} yield ExitCode.success).provide(LivePingService.layer ++ logger)

}
29 changes: 29 additions & 0 deletions examples/src/main/scala/zio/logging/example/JplSimpleApp.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package zio.logging.example

import zio.logging.LogAnnotation
import zio.logging.backend.JPL
import zio.{ ExitCode, Runtime, Scope, ZIO, ZIOAppDefault, _ }

import java.util.UUID

object JplSimpleApp extends ZIOAppDefault {

private val logger = Runtime.removeDefaultLoggers >>> JPL.jpl

private val users = List.fill(2)(UUID.randomUUID())

override def run: ZIO[Scope, Any, ExitCode] =
(for {
_ <- ZIO.logInfo("Start")
traceId <- ZIO.succeed(UUID.randomUUID())
_ <- ZIO.foreachPar(users) { uId =>
{
ZIO.logInfo("Starting user operation") *>
ZIO.sleep(500.millis) *>
ZIO.logInfo("Stopping user operation")
} @@ ZIOAspect.annotated("user", uId.toString)
} @@ LogAnnotation.TraceId(traceId) @@ JPL.loggerName("zio.logging.example.UserOperation")
_ <- ZIO.logInfo("Done")
} yield ExitCode.success).provide(logger)

}
Loading