diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml
new file mode 100644
index 00000000..84e2aac0
--- /dev/null
+++ b/.github/workflows/pull-request.yaml
@@ -0,0 +1,46 @@
+name: CI
+on:
+ - pull_request
+jobs:
+ format:
+ name: Format
+ strategy:
+ matrix:
+ os:
+ - ubuntu-20.04
+ scala:
+ - 2.13.4
+ java:
+ - adopt@1.11
+ runs-on: ${{ matrix.os }}
+ steps:
+ - name: Branch Checkout
+ uses: actions/checkout@v2
+ - name: Install Java And Sbt
+ uses: olafurpg/setup-scala@v10
+ with:
+ java-version: adopt@1.11
+ - name: Check with Scalafmt
+ run: sbt ++${{ matrix.scala }} checkFormat
+ build:
+ name: Build
+ strategy:
+ matrix:
+ os:
+ - ubuntu-20.04
+ scala:
+ - 2.12.12
+ - 2.13.4
+ java:
+ - adopt@1.11
+ - adopt@1.15
+ runs-on: ${{ matrix.os }}
+ steps:
+ - name: Branch Checkout
+ uses: actions/checkout@v2
+ - name: Install Java And Sbt
+ uses: olafurpg/setup-scala@v10
+ with:
+ java-version: ${{ matrix.java }}
+ - name: Test - [${{ matrix.java }}] [${{ matrix.scala }}]
+ run: sbt ++${{ matrix.scala }} ciBuild
diff --git a/.travis.yml b/.travis.yml
index 156882c9..f845dcfb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -27,7 +27,7 @@ stages:
if: type != pull_request AND tag IS present AND NOT fork
scala_212: &scala_212 2.12.12
-scala_213: &scala_213 2.13.3
+scala_213: &scala_213 2.13.4
jdk_lts: &jdk_lts openjdk11
jdk_latest: &jdk_latest openjdk15
diff --git a/README.md b/README.md
index c8be3ef4..afe6b729 100644
--- a/README.md
+++ b/README.md
@@ -43,38 +43,27 @@ Currently Log Effect supports the following backends
## Dependencies
-| | Cats | Fs2 | Cats Effect | Log Effect Core |
+| | Cats | Fs2 | Cats Effect | Log Effect Core |
| ------------------------:| ----:| ---:| -----------:| -----------------:|
-| [![Maven Central](https://img.shields.io/maven-central/v/io.laserdisc/log-effect-fs2_2.13.svg?label=log-effect-fs2&colorB=2282c3)](https://maven-badges.herokuapp.com/maven-central/io.laserdisc/log-effect-fs2_2.13) | 2.2.0 | 2.4.4 | 2.2.0 | [![Maven Central](https://img.shields.io/maven-central/v/io.laserdisc/log-effect-core_2.12.svg?label=%20&colorB=9311fc)](https://maven-badges.herokuapp.com/maven-central/io.laserdisc/log-effect-core_2.12) |
-| v0.8.0 | 1.6.1 | 1.0.5 | 1.3.1 | v0.8.0 |
-| v0.3.5 | 1.4.0 | 1.0.0-M5 | 1.0.0 | v0.3.5 |
-| v0.2.2 | 1.2.0 | 0.10.5 | 0.10.1 | v0.2.2 |
-| v0.1.14 | 1.2.0 | 0.10.5 | | v0.1.14 |
+| [![Maven Central](https://img.shields.io/maven-central/v/io.laserdisc/log-effect-fs2_2.13.svg?label=log-effect-fs2&colorB=2282c3)](https://maven-badges.herokuapp.com/maven-central/io.laserdisc/log-effect-fs2_2.13) | 2.3.0 | 2.4.6 | 2.3.0 | [![Maven Central](https://img.shields.io/maven-central/v/io.laserdisc/log-effect-core_2.12.svg?label=%20&colorB=9311fc)](https://maven-badges.herokuapp.com/maven-central/io.laserdisc/log-effect-core_2.12) |
-| | Zio | Scalaz ZIO | Log Effect Core |
-| ------------------------:| ---:| ----------:| -----------------:|
-| [![Maven Central](https://img.shields.io/maven-central/v/io.laserdisc/log-effect-zio_2.13.svg?label=log-effect-zio&colorB=fb0005)](https://maven-badges.herokuapp.com/maven-central/io.laserdisc/log-effect-zio_2.13) | 1.0.1 | | [![Maven Central](https://img.shields.io/maven-central/v/io.laserdisc/log-effect-core_2.12.svg?label=%20&colorB=9311fc)](https://maven-badges.herokuapp.com/maven-central/io.laserdisc/log-effect-core_2.12) |
-| v0.8.0 | 1.0.0-RC9 | | v0.8.0 |
-| v0.7.0 | | 1.0-RC4 | v0.7.0 |
-| v0.3.5 | | 0.2.7 | v0.3.5 |
+| | Zio | Log Effect Core |
+| ------------------------:| ---:| ---------------:|
+| [![Maven Central](https://img.shields.io/maven-central/v/io.laserdisc/log-effect-zio_2.13.svg?label=log-effect-zio&colorB=fb0005)](https://maven-badges.herokuapp.com/maven-central/io.laserdisc/log-effect-zio_2.13) | 1.0.3 | [![Maven Central](https://img.shields.io/maven-central/v/io.laserdisc/log-effect-core_2.12.svg?label=%20&colorB=9311fc)](https://maven-badges.herokuapp.com/maven-central/io.laserdisc/log-effect-core_2.12) |
-| | Log4cats | Log Effect Core |
+| | Log4cats | Log Effect Core |
| ------------------------:| --------:| -----------------:|
| [![Maven Central](https://img.shields.io/maven-central/v/io.laserdisc/log-effect-interop_2.13.svg?label=log-effect-interop&colorB=009933)](https://maven-badges.herokuapp.com/maven-central/io.laserdisc/log-effect-interop_2.13) | 1.1.1 | [![Maven Central](https://img.shields.io/maven-central/v/io.laserdisc/log-effect-core_2.13.svg?label=%20&colorB=9311fc)](https://maven-badges.herokuapp.com/maven-central/io.laserdisc/log-effect-core_2.13) |
-| | Cats | Cats Effect | Log4s | Scribe |
-| ------------------------:| -----:| -----------:| ------:| ------:|
-| [![Maven Central](https://img.shields.io/maven-central/v/io.laserdisc/log-effect-core_2.13.svg?label=log-effect-core&colorB=9311fc)](https://maven-badges.herokuapp.com/maven-central/io.laserdisc/log-effect-core_2.13) | | | 1.8.2 | 2.7.12 |
-| v0.8.0 | | | 1.8.2 | 2.7.8 |
-| v0.3.5 | | | 1.6.1 | |
-| v0.2.2 | 1.2.0 | | 1.6.1 | |
-| v0.1.14 | 1.2.0 | 0.10.1 | 1.6.1 | |
+| | Log4s | Scribe |
+| ------------------------:| ------:| ------:|
+| [![Maven Central](https://img.shields.io/maven-central/v/io.laserdisc/log-effect-core_2.13.svg?label=log-effect-core&colorB=9311fc)](https://maven-badges.herokuapp.com/maven-central/io.laserdisc/log-effect-core_2.13) | 1.9.0 | 3.1.3 |
@@ -83,153 +72,181 @@ Currently Log Effect supports the following backends
### Get Logs
#### Cats Effect Sync
-To get an instance of `LogWriter` for **Cats Effect**'s `Sync` the options below are available
-```scala
-import java.util.{ logging => jul }
+To get an instance of `LogWriter` for **Cats Effect**'s `Sync` the options below are available (see [here](./fs2/src/main/scala/log/effect/fs2/SyncLogWriter.scala))
-import cats.effect.Sync
-import cats.syntax.functor._
-import log.effect.fs2.SyncLogWriter._
-import log.effect.{ LogLevels, LogWriter }
-import org.{ log4s => l4s }
-
-sealed abstract class App[F[_]](implicit F: Sync[F]) {
- val log4s1: F[LogWriter[F]] =
- F.delay(l4s.getLogger("test")) map log4sLog[F]
+*full compiling example [here](./fs2/src/test/scala/ReadmeConstructionCodeSnippetsTest.scala)*
+```scala
+val log4s1: F[LogWriter[F]] =
+F.delay(l4s.getLogger("test")) map log4sLog[F]
- val log4s2: F[LogWriter[F]] = log4sLog("a logger")
+val log4s2: F[LogWriter[F]] = log4sLog("a logger")
- val log4s3: F[LogWriter[F]] = {
- case class LoggerClass()
- log4sLog(classOf[LoggerClass])
- }
+val log4s3: F[LogWriter[F]] = {
+case class LoggerClass()
+log4sLog(classOf[LoggerClass])
+}
- val jul1: F[LogWriter[F]] =
- F.delay(jul.Logger.getLogger("a logger")) map julLog[F]
+val jul1: F[LogWriter[F]] =
+F.delay(jul.Logger.getLogger("a logger")) map julLog[F]
- val jul2: F[LogWriter[F]] = julLog
+val jul2: F[LogWriter[F]] = julLog
- val scribe1: F[LogWriter[F]] =
- F.delay(scribe.Logger("a logger")) map scribeLog[F]
+val scribe1: F[LogWriter[F]] =
+F.delay(scribe.Logger("a logger")) map scribeLog[F]
- val scribe2: F[LogWriter[F]] = scribeLog("a logger")
+val scribe2: F[LogWriter[F]] = scribeLog("a logger")
- val scribe3: F[LogWriter[F]] = {
- case class LoggerClass()
- scribeLog(classOf[LoggerClass])
- }
+val scribe3: F[LogWriter[F]] = {
+case class LoggerClass()
+scribeLog(classOf[LoggerClass])
+}
- val console1: LogWriter[F] = consoleLog
+val console1: LogWriter[F] = consoleLog
- val console2: LogWriter[F] = consoleLogUpToLevel(LogLevels.Warn)
+val console2: LogWriter[F] = consoleLogUpToLevel(LogLevels.Warn)
- val noOp: LogWriter[F] = noOpLog[F]
-}
+val noOp: LogWriter[F] = noOpLog[F]
```
#### Fs2 Stream
-Simirarly, to get instances of `LogWriter` for **Fs2**'s `Stream` the constructors below are available
-```scala
-import java.util.{ logging => jul }
+Similarly, to get instances of `LogWriter` for **Fs2**'s `Stream` the constructors below are available [here](./fs2/src/main/scala/log/effect/fs2/SyncLogWriter.scala)
-import cats.effect.Sync
-import cats.syntax.flatMap._
-import fs2.Stream
-import log.effect.fs2.Fs2LogWriter._
-import log.effect.{ LogLevels, LogWriter }
-import org.{ log4s => l4s }
-
-sealed abstract class App[F[_]](implicit F: Sync[F]) {
- val log4s1: fs2.Stream[F, LogWriter[F]] =
- Stream.eval(F.delay(l4s.getLogger("test"))) >>= log4sLogStream[F]
+*full compiling example [here](./fs2/src/test/scala/ReadmeConstructionCodeSnippetsTest.scala)*
+```scala
+val log4s1: fs2.Stream[F, LogWriter[F]] =
+Stream.eval(F.delay(l4s.getLogger("test"))) >>= log4sLogStream[F]
- val log4s2: fs2.Stream[F, LogWriter[F]] = log4sLogStream("a logger")
+val log4s2: fs2.Stream[F, LogWriter[F]] = log4sLogStream("a logger")
- val log4s3: fs2.Stream[F, LogWriter[F]] = {
- case class LoggerClass()
- log4sLogStream(classOf[LoggerClass])
- }
+val log4s3: fs2.Stream[F, LogWriter[F]] = {
+case class LoggerClass()
+log4sLogStream(classOf[LoggerClass])
+}
- val jul1: fs2.Stream[F, LogWriter[F]] =
- Stream.eval(F.delay(jul.Logger.getLogger("a logger"))) >>= julLogStream[F]
+val jul1: fs2.Stream[F, LogWriter[F]] =
+Stream.eval(F.delay(jul.Logger.getLogger("a logger"))) >>= julLogStream[F]
- val jul2: fs2.Stream[F, LogWriter[F]] = julLogStream
+val jul2: fs2.Stream[F, LogWriter[F]] = julLogStream
- val scribe1: fs2.Stream[F, LogWriter[F]] =
- Stream.eval(F.delay(scribe.Logger("a logger"))) >>= scribeLogStream[F]
+val scribe1: fs2.Stream[F, LogWriter[F]] =
+Stream.eval(F.delay(scribe.Logger("a logger"))) >>= scribeLogStream[F]
- val scribe2: fs2.Stream[F, LogWriter[F]] = scribeLogStream("a logger")
+val scribe2: fs2.Stream[F, LogWriter[F]] = scribeLogStream("a logger")
- val scribe3: fs2.Stream[F, LogWriter[F]] = {
- case class LoggerClass()
- scribeLogStream(classOf[LoggerClass])
- }
+val scribe3: fs2.Stream[F, LogWriter[F]] = {
+case class LoggerClass()
+scribeLogStream(classOf[LoggerClass])
+}
- val console1: fs2.Stream[F, LogWriter[F]] = consoleLogStream
+val console1: fs2.Stream[F, LogWriter[F]] = consoleLogStream
- val console2: fs2.Stream[F, LogWriter[F]] = consoleLogStreamUpToLevel(LogLevels.Warn)
+val console2: fs2.Stream[F, LogWriter[F]] = consoleLogStreamUpToLevel(LogLevels.Warn)
- val noOp: fs2.Stream[F, LogWriter[F]] = noOpLogStream
-}
+val noOp: fs2.Stream[F, LogWriter[F]] = noOpLogStream
```
*See [here](https://github.com/laserdisc-io/laserdisc#example-usage) for an example whit [Laserdisc](https://github.com/laserdisc-io/laserdisc)*
#### Zio Task
-To create instances for `ZIO` some useful constructors can be found [here](https://github.com/laserdisc-io/log-effect/blob/master/zio/src/main/scala/log/effect/zio/ZioLogWriter.scala). Note as they exploit the power and expressiveness of the RIO pattern as shown below
+To create instances for `ZIO` some useful constructors can be found [here](./zio/src/main/scala/log/effect/zio/ZioLogWriter.scala). Note as they exploit the power and expressiveness of `RLayer` an the `RIO` pattern as shown below.
+
+##### Create LogWriter as a Layer
+*full compiling example [here](./zio/src/test/scala/ReadmeLayerConstructionCodeSnippetsTest.scala)*
```scala
-import java.util.{ logging => jul }
+// Case 1: from a possible config
+val logNameLiveFromConfig: ULayer[ZLogName] =
+ aConfigLive >>> ZLayer.fromFunctionM { env =>
+ ZIO.succeed(LogName(env.get[AConfig].logName))
+ }
-import log.effect.zio.ZioLogWriter._
-import log.effect.{ LogLevels, LogWriter }
-import org.{ log4s => l4s }
-import zio.{ RIO, Task }
+val log4sCase1: TaskLayer[ZLogWriter] =
+ logNameLiveFromConfig >>> log4sLayerFromName
-sealed abstract class App {
- def someZioProgramUsingLogs: RIO[LogWriter[Task], Unit]
+val scribeCase1: TaskLayer[ZLogWriter] =
+ logNameLiveFromConfig >>> scribeLayerFromName
- val log4s1: Task[Unit] =
- Task.effect(l4s.getLogger("a logger")) >>= { logger =>
- (log4sFromLogger >>> someZioProgramUsingLogs) provide logger
- }
+// Case 2: from a name
+val log4sCase2: TaskLayer[ZLogWriter] =
+ logNameLive >>> log4sLayerFromName
- val log4s2: Task[Unit] =
- (log4sFromName >>> someZioProgramUsingLogs) provide "a logger name"
+val scribeCase2: TaskLayer[ZLogWriter] =
+ logNameLive >>> scribeLayerFromName
- val log4s3: Task[Unit] = {
- case class LoggerClass();
- (log4sFromClass >>> someZioProgramUsingLogs) provide classOf[LoggerClass]
- }
+// Case 3: from a logger
+val log4sCase3: TaskLayer[ZLogWriter] =
+ log4sLoggerLive >>> log4sLayerFromLogger
- val jul1: Task[Unit] =
- Task.effect(jul.Logger.getLogger("a logger")) >>= { logger =>
- (julFromLogger >>> someZioProgramUsingLogs) provide logger
- }
+val julCase3: TaskLayer[ZLogWriter] =
+ julLoggerLive >>> julLayerFromLogger
- val jul2: Task[Unit] =
- julGlobal >>> someZioProgramUsingLogs
+val scribeCase3: TaskLayer[ZLogWriter] =
+ scribeLoggerLive >>> scribeLayerFromLogger
- val scribe1: Task[Unit] =
- Task.effect(scribe.Logger("a logger")) >>= { logger =>
- (scribeFromLogger >>> someZioProgramUsingLogs) provide logger
- }
+// Case 4: from a class
+val log4sCase4: TaskLayer[ZLogWriter] =
+ classLive >>> log4sLayerFromClass
- val scribe2: Task[Unit] =
- (scribeFromName >>> someZioProgramUsingLogs) provide "a logger name"
+val scribeCase4: TaskLayer[ZLogWriter] =
+ classLive >>> scribeLayerFromClass
+```
- val scribe3: Task[Unit] = {
- case class LoggerClass();
- (scribeFromClass >>> someZioProgramUsingLogs) provide classOf[LoggerClass]
+##### Create LogWriter as RIO
+*full compiling example [here](./zio/src/test/scala/ReadmeRioConstructionCodeSnippetsTest.scala)*
+```scala
+// Case 1: from a possible config in a Layer (gives a Layer)
+val log4sCase1: RLayer[Has[AConfig], ZLogWriter] =
+ ZLayer.fromServiceM { config =>
+ log4sFromName.provide(config.logName)
+ }
+val scribe4sCase1: RLayer[Has[AConfig], ZLogWriter] =
+ ZLayer.fromServiceM { config =>
+ scribeFromName.provide(config.logName)
}
- val console1: Task[Unit] =
- someZioProgramUsingLogs provide consoleLog
-
- val console2: Task[Unit] =
- someZioProgramUsingLogs provide consoleLogUpToLevel(LogLevels.Warn)
+// Case 2: from a name
+val log4sCase2: Task[Unit] =
+ (log4sFromName >>> someZioProgramUsingLogs) provide aLogName
+
+val scribeCase2: Task[Unit] =
+ (scribeFromName >>> someZioProgramUsingLogs) provide aLogName
+
+// Case 3: from a logger
+val log4sCase3: Task[Unit] =
+ Task.effect(l4s.getLogger(aLogName)) >>= { logger =>
+ (log4sFromLogger >>> someZioProgramUsingLogs) provide logger
+ }
+val julCase3: Task[Unit] =
+ Task.effect(jul.Logger.getLogger(aLogName)) >>= { logger =>
+ (julFromLogger >>> someZioProgramUsingLogs) provide logger
+ }
+val scribeCase3: Task[Unit] =
+ Task.effect(scribe.Logger(aLogName)) >>= { logger =>
+ (scribeFromLogger >>> someZioProgramUsingLogs) provide logger
+ }
- val noOp: Task[Unit] =
- someZioProgramUsingLogs provide noOpLog
+// Case 4: from a class
+val log4sCase4: Task[Unit] = {
+ case class LoggerClass();
+ (log4sFromClass >>> someZioProgramUsingLogs) provide classOf[LoggerClass]
+}
+val scribeCase4: Task[Unit] = {
+ case class LoggerClass();
+ (scribeFromClass >>> someZioProgramUsingLogs) provide classOf[LoggerClass]
}
+
+// Case 5 (Jul): from global logger object
+val julCase5: Task[Unit] =
+ julGlobal >>> someZioProgramUsingLogs
+
+// Case 6: console logger
+val console1: Task[Unit] =
+ someZioProgramUsingLogs provide consoleLog
+
+val console2: Task[Unit] =
+ someZioProgramUsingLogs provide consoleLogUpToLevel(LogLevels.Warn)
+
+// Case 7: No-op logger
+val noOp: Task[Unit] =
+ someZioProgramUsingLogs provide noOpLog
```
diff --git a/build.sbt b/build.sbt
index f8f36ea9..72cbdd0e 100644
--- a/build.sbt
+++ b/build.sbt
@@ -1,3 +1,17 @@
+lazy val versionOf = new {
+ val cats = "2.3.0"
+ val catsEffect = "2.3.0"
+ val fs2 = "2.4.6"
+ val kindProjector = "0.11.1"
+ val log4cats = "1.1.1"
+ val log4s = "1.9.0"
+ val scalaCheck = "1.15.1"
+ val scalaTest = "3.2.3"
+ val zio = "1.0.3"
+ val scribe = "3.1.3"
+ val silencer = "1.7.1"
+}
+
lazy val scala212Options = Seq(
"-deprecation",
"-encoding",
@@ -40,20 +54,6 @@ lazy val scala213Options = scala212Options diff Seq(
"-Xfuture"
)
-lazy val versionOf = new {
- val cats = "2.2.0"
- val catsEffect = "2.2.0"
- val fs2 = "2.4.6"
- val kindProjector = "0.11.1"
- val log4cats = "1.1.1"
- val log4s = "1.9.0"
- val scalaCheck = "1.15.1"
- val scalaTest = "3.2.3"
- val zio = "1.0.3"
- val scribe = "3.1.1"
- val silencer = "1.7.1"
-}
-
lazy val coreDependencies = Seq(
"org.log4s" %% "log4s" % versionOf.log4s,
"com.outr" %% "scribe" % versionOf.scribe
@@ -134,7 +134,7 @@ lazy val root = project
.settings(
name := "log-effect",
publishArtifact := false,
- addCommandAlias("format", ";scalafmt;test:scalafmt;scalafmtSbt"),
+ addCommandAlias("fmt", ";scalafmt;test:scalafmt;scalafmtSbt"),
addCommandAlias(
"checkFormat",
";scalafmtCheck;test:scalafmtCheck;scalafmtSbtCheck"
diff --git a/core/src/main/scala/log/effect/LogLevel.scala b/core/src/main/scala/log/effect/LogLevel.scala
index 19a87dc6..c56788d6 100644
--- a/core/src/main/scala/log/effect/LogLevel.scala
+++ b/core/src/main/scala/log/effect/LogLevel.scala
@@ -9,56 +9,50 @@ sealed trait LogLevel extends Product with Serializable
object LogLevel extends LogLevelSyntax {
import LogLevels._
- implicit val logLevelShow: Show[LogLevel] =
- new Show[LogLevel] {
- def show(t: LogLevel): String =
- t match {
- case l: Trace => showFor(l).show(l)
- case l: Debug => showFor(l).show(l)
- case l: Info => showFor(l).show(l)
- case l: Warn => showFor(l).show(l)
- case l: Error => showFor(l).show(l)
- }
- }
+ implicit val logLevelShow: Show[LogLevel] = {
+ case l: Trace => showFor(l).show(l)
+ case l: Debug => showFor(l).show(l)
+ case l: Info => showFor(l).show(l)
+ case l: Warn => showFor(l).show(l)
+ case l: Error => showFor(l).show(l)
+ }
implicit val logLevelOrdering: Ordering[LogLevel] =
- new Ordering[LogLevel] {
- def compare(x: LogLevel, y: LogLevel): Int =
- x match {
- case Trace =>
- y match {
- case Trace => 0
- case Debug | Info | Warn | Error => -1
- }
-
- case Debug =>
- y match {
- case Trace => 1
- case Debug => 0
- case Info | Warn | Error => -1
- }
-
- case Info =>
- y match {
- case Trace | Debug => 1
- case Info => 0
- case Warn | Error => -1
- }
-
- case Warn =>
- y match {
- case Trace | Debug | Info => 1
- case Warn => 0
- case Error => -1
- }
-
- case Error =>
- y match {
- case Trace | Debug | Info | Warn => 1
- case Error => 0
- }
- }
- }
+ (x: LogLevel, y: LogLevel) =>
+ x match {
+ case Trace =>
+ y match {
+ case Trace => 0
+ case Debug | Info | Warn | Error => -1
+ }
+
+ case Debug =>
+ y match {
+ case Trace => 1
+ case Debug => 0
+ case Info | Warn | Error => -1
+ }
+
+ case Info =>
+ y match {
+ case Trace | Debug => 1
+ case Info => 0
+ case Warn | Error => -1
+ }
+
+ case Warn =>
+ y match {
+ case Trace | Debug | Info => 1
+ case Warn => 0
+ case Error => -1
+ }
+
+ case Error =>
+ y match {
+ case Trace | Debug | Info | Warn => 1
+ case Error => 0
+ }
+ }
@silent private def showFor[A](a: A)(implicit ev: Show[A]): Show[A] = ev
}
@@ -83,36 +77,26 @@ object LogLevels {
case object Trace extends LogLevel {
implicit val traceShow: Show[Trace] =
- new Show[Trace] {
- def show(t: Trace): String = "TRACE"
- }
+ (_: Trace) => "TRACE"
}
case object Debug extends LogLevel {
implicit val debugShow: Show[Debug] =
- new Show[Debug] {
- def show(t: Debug): String = "DEBUG"
- }
+ (_: Debug) => "DEBUG"
}
case object Info extends LogLevel {
implicit val infoShow: Show[Info] =
- new Show[Info] {
- def show(t: Info): String = "INFO"
- }
+ (_: Info) => "INFO"
}
case object Warn extends LogLevel {
implicit val warnShow: Show[Warn] =
- new Show[Warn] {
- def show(t: Warn): String = "WARN"
- }
+ (_: Warn) => "WARN"
}
case object Error extends LogLevel {
implicit val errorShow: Show[Error] =
- new Show[Error] {
- def show(t: Error): String = "ERROR"
- }
+ (_: Error) => "ERROR"
}
}
diff --git a/core/src/main/scala/log/effect/LogWriter.scala b/core/src/main/scala/log/effect/LogWriter.scala
index 0c2c3de6..dc29396d 100644
--- a/core/src/main/scala/log/effect/LogWriter.scala
+++ b/core/src/main/scala/log/effect/LogWriter.scala
@@ -6,7 +6,7 @@ import log.effect.internal.{Id, Show}
import scala.language.implicitConversions
trait LogWriter[F[_]] {
- def write[A: Show, L <: LogLevel: Show](level: L, a: =>A): F[Unit]
+ def write[A: Show](level: LogLevel, a: =>A): F[Unit]
}
object LogWriter extends LogWriterSyntax {
diff --git a/core/src/main/scala/log/effect/LogWriterConstructor.scala b/core/src/main/scala/log/effect/LogWriterConstructor.scala
index 03e1f771..4c4b9959 100644
--- a/core/src/main/scala/log/effect/LogWriterConstructor.scala
+++ b/core/src/main/scala/log/effect/LogWriterConstructor.scala
@@ -18,7 +18,7 @@ object LogWriterConstructor {
val construction: G[l4s.Logger] => G[LogWriter[F]] =
_ map { l4sLogger =>
new LogWriter[F] {
- def write[A: Show, L <: LogLevel: Show](level: L, a: =>A): F[Unit] = {
+ def write[A: Show](level: LogLevel, a: =>A): F[Unit] = {
val beLevel = level match {
case LogLevels.Trace => l4s.Trace
case LogLevels.Debug => l4s.Debug
@@ -45,7 +45,7 @@ object LogWriterConstructor {
val construction: G[jul.Logger] => G[LogWriter[F]] =
_ map { julLogger =>
new LogWriter[F] {
- def write[A: Show, L <: LogLevel: Show](level: L, a: =>A): F[Unit] = {
+ def write[A: Show](level: LogLevel, a: =>A): F[Unit] = {
val beLevel = level match {
case LogLevels.Trace => jul.Level.FINEST
case LogLevels.Debug => jul.Level.FINE
@@ -78,7 +78,7 @@ object LogWriterConstructor {
val construction: G[scribe.Logger] => G[LogWriter[F]] =
_ map { scribeLogger =>
new LogWriter[F] {
- def write[A: Show, L <: LogLevel: Show](level: L, a: =>A): F[Unit] = {
+ def write[A: Show](level: LogLevel, a: =>A): F[Unit] = {
val beLevel = level match {
case LogLevels.Trace => scribe.Level.Trace
case LogLevels.Debug => scribe.Level.Debug
@@ -107,7 +107,7 @@ object LogWriterConstructor {
new LogWriter[F] {
private val minLogLevel = ll
- def write[A: Show, L <: LogLevel: Show](level: L, a: =>A): F[Unit] =
+ def write[A: Show](level: LogLevel, a: =>A): F[Unit] =
if (level >= minLogLevel)
F.suspend(
println(
@@ -123,7 +123,7 @@ object LogWriterConstructor {
val construction: Unit => Id[LogWriter[Id]] =
_ =>
new LogWriter[Id] {
- def write[A: Show, L <: LogLevel: Show](level: L, a: =>A): Unit = ()
+ def write[A: Show](level: LogLevel, a: =>A): Unit = ()
}
}
}
diff --git a/fs2/src/main/scala/log/effect/fs2/SyncLogWriter.scala b/fs2/src/main/scala/log/effect/fs2/SyncLogWriter.scala
index 87d60732..bbe5b421 100644
--- a/fs2/src/main/scala/log/effect/fs2/SyncLogWriter.scala
+++ b/fs2/src/main/scala/log/effect/fs2/SyncLogWriter.scala
@@ -62,8 +62,8 @@ object SyncLogWriter {
implicit final class NoOpLogF(private val `_`: LogWriter[Id]) extends AnyVal {
def liftF[F[_]: Applicative]: LogWriter[F] =
new LogWriter[F] {
- private[this] val unit = Applicative[F].unit
- def write[A: Show, L <: LogLevel: Show](level: L, a: =>A): F[Unit] = unit
+ private[this] val unit = Applicative[F].unit
+ def write[A: Show](level: LogLevel, a: =>A): F[Unit] = unit
}
}
}
diff --git a/fs2/src/main/scala/log/effect/fs2/mtl/readerT.scala b/fs2/src/main/scala/log/effect/fs2/mtl/readerT.scala
index ff5ac18b..bbe8863d 100644
--- a/fs2/src/main/scala/log/effect/fs2/mtl/readerT.scala
+++ b/fs2/src/main/scala/log/effect/fs2/mtl/readerT.scala
@@ -10,7 +10,7 @@ object readerT {
implicit LW: LogWriter[F]
): LogWriter[ReaderT[F, Env, *]] =
new LogWriter[ReaderT[F, Env, *]] {
- def write[A: Show, L <: LogLevel: Show](level: L, a: =>A): ReaderT[F, Env, Unit] =
+ def write[A: Show](level: LogLevel, a: =>A): ReaderT[F, Env, Unit] =
ReaderT.liftF[F, Env, Unit](LW.write(level, a))
}
}
diff --git a/interop/src/main/scala/log/effect/interop/Log4catsInterop.scala b/interop/src/main/scala/log/effect/interop/Log4catsInterop.scala
index d5daf6ee..b10d39ab 100644
--- a/interop/src/main/scala/log/effect/interop/Log4catsInterop.scala
+++ b/interop/src/main/scala/log/effect/interop/Log4catsInterop.scala
@@ -9,7 +9,7 @@ import log.effect.internal.syntax._
private[interop] trait Log4catsInterop0 extends Log4catsInterop1 {
implicit def logWriterFromLogger[F[_]](implicit ev: Logger[F]): LogWriter[F] =
new LogWriter[F] {
- def write[A: Show, L <: LogLevel: Show](level: L, a: =>A): F[Unit] =
+ def write[A: Show](level: LogLevel, a: =>A): F[Unit] =
(level, a) match {
case (Trace, Failure(msg, th)) => ev.trace(th)(msg)
case (Trace, other) => ev.trace(other.show)
@@ -28,7 +28,7 @@ private[interop] trait Log4catsInterop0 extends Log4catsInterop1 {
private[interop] trait Log4catsInterop1 {
implicit def logWriterFromMessageLogger[F[_]](implicit ev: MessageLogger[F]): LogWriter[F] =
new LogWriter[F] {
- def write[A: Show, L <: LogLevel: Show](level: L, a: =>A): F[Unit] =
+ def write[A: Show](level: LogLevel, a: =>A): F[Unit] =
level match {
case Trace => ev.trace(a.show)
case Debug => ev.debug(a.show)
diff --git a/zio/src/main/scala/log/effect/zio/ZioLogWriter.scala b/zio/src/main/scala/log/effect/zio/ZioLogWriter.scala
index ada9eb80..bf54d533 100644
--- a/zio/src/main/scala/log/effect/zio/ZioLogWriter.scala
+++ b/zio/src/main/scala/log/effect/zio/ZioLogWriter.scala
@@ -3,13 +3,23 @@ package zio
import java.util.{logging => jul}
-import _root_.zio.{IO, RIO, Task, UIO, URIO, ZIO}
+import _root_.zio._
+import com.github.ghik.silencer.silent
import log.effect.internal.{EffectSuspension, Id, Show}
import org.{log4s => l4s}
object ZioLogWriter {
import instances._
+ final case class LogName(x: String) extends AnyVal
+
+ final type ZLogName = Has[LogName]
+ final type ZLogClass[A] = Has[Class[A]]
+ final type ZLog4sLogger = Has[l4s.Logger]
+ final type ZJulLogger = Has[jul.Logger]
+ final type ZScribeLogger = Has[scribe.Logger]
+ final type ZLogWriter = Has[LogWriter[Task]]
+
val log4sFromLogger: URIO[l4s.Logger, LogWriter[Task]] =
ZIO.access(log4sLogger => LogWriter.pureOf[Task](log4sLogger))
@@ -46,6 +56,44 @@ object ZioLogWriter {
val noOpLog: LogWriter[Task] =
LogWriter.of[Id](()).liftT
+ // Needed for 2.12.12 where these warnings still appear
+ @silent("a type was inferred to be `Any`; this may indicate a programming error.")
+ val log4sLayerFromName: RLayer[ZLogName, ZLogWriter] =
+ ZLayer.fromServiceM(name => log4sFromName provide name.x)
+
+ @silent("a type was inferred to be `Any`; this may indicate a programming error.")
+ val log4sLayerFromLogger: RLayer[ZLog4sLogger, ZLogWriter] =
+ ZLayer.fromServiceM(log4sLogger => log4sFromLogger provide log4sLogger)
+
+ @silent("a type was inferred to be `Any`; this may indicate a programming error.")
+ def log4sLayerFromClass[A: Tag]: RLayer[ZLogClass[A], ZLogWriter] =
+ ZLayer.fromServiceM(c => log4sFromClass provide c)
+
+ @silent("a type was inferred to be `Any`; this may indicate a programming error.")
+ val julLayerFromLogger: RLayer[ZJulLogger, ZLogWriter] =
+ ZLayer.fromServiceM(julLogger => julFromLogger provide julLogger)
+
+ @silent("a type was inferred to be `Any`; this may indicate a programming error.")
+ val scribeLayerFromName: RLayer[ZLogName, ZLogWriter] =
+ ZLayer.fromServiceM(name => scribeFromName provide name.x)
+
+ @silent("a type was inferred to be `Any`; this may indicate a programming error.")
+ val scribeLayerFromLogger: RLayer[ZScribeLogger, ZLogWriter] =
+ ZLayer.fromServiceM(scribeLogger => scribeFromLogger provide scribeLogger)
+
+ @silent("a type was inferred to be `Any`; this may indicate a programming error.")
+ def scribeLayerFromClass[A: Tag]: RLayer[ZLogClass[A], ZLogWriter] =
+ ZLayer.fromServiceM(c => scribeFromClass provide c)
+
+ val consoleLogLayer: ULayer[ZLogWriter] =
+ ZLayer.succeed(consoleLog)
+
+ def consoleLogLayerUpToLevel[LL <: LogLevel](minLevel: LL): ULayer[ZLogWriter] =
+ ZLayer.succeed(consoleLogUpToLevel(minLevel))
+
+ val noOpLogLayer: ULayer[ZLogWriter] =
+ ZLayer.succeed(noOpLog)
+
private[this] object instances {
private[zio] implicit final val taskEffectSuspension: EffectSuspension[Task] =
new EffectSuspension[Task] {
@@ -57,15 +105,18 @@ object ZioLogWriter {
def suspend[A](a: =>A): UIO[A] = IO.effectTotal(a)
}
- private[zio] implicit final def functorInstances[R, E]: internal.Functor[ZIO[R, E, *]] =
- new internal.Functor[ZIO[R, E, *]] {
+ private[zio] implicit final def functorInstances[
+ R,
+ E
+ ]: log.effect.internal.Functor[ZIO[R, E, *]] =
+ new log.effect.internal.Functor[ZIO[R, E, *]] {
def fmap[A, B](f: A => B): ZIO[R, E, A] => ZIO[R, E, B] = _ map f
}
implicit final class NoOpLogT(private val `_`: LogWriter[Id]) extends AnyVal {
def liftT: LogWriter[Task] =
new LogWriter[Task] {
- override def write[A: Show, L <: LogLevel: Show](level: L, a: =>A): Task[Unit] = Task.unit
+ override def write[A: Show](level: LogLevel, a: =>A): Task[Unit] = Task.unit
}
}
}
diff --git a/zio/src/test/scala/ReadmeConstructionCodeSnippetsTest.scala b/zio/src/test/scala/ReadmeConstructionCodeSnippetsTest.scala
deleted file mode 100644
index 76c1da48..00000000
--- a/zio/src/test/scala/ReadmeConstructionCodeSnippetsTest.scala
+++ /dev/null
@@ -1,61 +0,0 @@
-import com.github.ghik.silencer.silent
-import org.scalatest.matchers.should.Matchers
-import org.scalatest.wordspec.AnyWordSpecLike
-
-@silent final class ReadmeConstructionCodeSnippetsTest extends AnyWordSpecLike with Matchers {
- "Zio construction snippets should compile" in {
- import java.util.{logging => jul}
-
- import log.effect.zio.ZioLogWriter._
- import log.effect.{LogLevels, LogWriter}
- import org.{log4s => l4s}
- import zio.{RIO, Task}
-
- sealed abstract class App {
- def someZioProgramUsingLogs: RIO[LogWriter[Task], Unit]
-
- val log4s1: Task[Unit] =
- Task.effect(l4s.getLogger("a logger")) >>= { logger =>
- (log4sFromLogger >>> someZioProgramUsingLogs) provide logger
- }
-
- val log4s2: Task[Unit] =
- (log4sFromName >>> someZioProgramUsingLogs) provide "a logger name"
-
- val log4s3: Task[Unit] = {
- case class LoggerClass();
- (log4sFromClass >>> someZioProgramUsingLogs) provide classOf[LoggerClass]
- }
-
- val jul1: Task[Unit] =
- Task.effect(jul.Logger.getLogger("a logger")) >>= { logger =>
- (julFromLogger >>> someZioProgramUsingLogs) provide logger
- }
-
- val jul2: Task[Unit] =
- julGlobal >>> someZioProgramUsingLogs
-
- val scribe1: Task[Unit] =
- Task.effect(scribe.Logger("a logger")) >>= { logger =>
- (scribeFromLogger >>> someZioProgramUsingLogs) provide logger
- }
-
- val scribe2: Task[Unit] =
- (scribeFromName >>> someZioProgramUsingLogs) provide "a logger name"
-
- val scribe3: Task[Unit] = {
- case class LoggerClass();
- (scribeFromClass >>> someZioProgramUsingLogs) provide classOf[LoggerClass]
- }
-
- val console1: Task[Unit] =
- someZioProgramUsingLogs provide consoleLog
-
- val console2: Task[Unit] =
- someZioProgramUsingLogs provide consoleLogUpToLevel(LogLevels.Warn)
-
- val noOp: Task[Unit] =
- someZioProgramUsingLogs provide noOpLog
- }
- }
-}
diff --git a/zio/src/test/scala/ReadmeLayerConstructionCodeSnippetsTest.scala b/zio/src/test/scala/ReadmeLayerConstructionCodeSnippetsTest.scala
new file mode 100644
index 00000000..d986a8c8
--- /dev/null
+++ b/zio/src/test/scala/ReadmeLayerConstructionCodeSnippetsTest.scala
@@ -0,0 +1,81 @@
+import com.github.ghik.silencer.silent
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpecLike
+
+@silent final class ReadmeLayerConstructionCodeSnippetsTest extends AnyWordSpecLike with Matchers {
+ "Zio Layer construction snippets should compile" in {
+ import java.util.{logging => jul}
+
+ import log.effect.zio.ZioLogWriter._
+ import org.{log4s => l4s}
+ import zio._
+
+ object Setup {
+ private val aLogName = "a logger"
+ private val aLog4sLogger = l4s.getLogger("a log4s logger")
+ private val aJulLogger = jul.Logger.getLogger("a jul logger")
+ private val aScribeLogger = scribe.Logger("a Scribe logger")
+
+ final case class LoggerClass()
+ final case class AConfig(logName: String)
+
+ final val aConfigLive: ULayer[ZEnv with Has[AConfig]] =
+ ZEnv.live ++ ZLayer.succeed(AConfig(aLogName))
+
+ final val logNameLive: ULayer[ZEnv with ZLogName] =
+ ZEnv.live ++ ZLayer.succeed(LogName(aLogName))
+
+ final val log4sLoggerLive: ULayer[ZEnv with ZLog4sLogger] =
+ ZEnv.live ++ ZLayer.succeed(aLog4sLogger)
+
+ final val julLoggerLive: ULayer[ZEnv with ZJulLogger] =
+ ZEnv.live ++ ZLayer.succeed(aJulLogger)
+
+ final val scribeLoggerLive: ULayer[ZEnv with ZScribeLogger] =
+ ZEnv.live ++ ZLayer.succeed(aScribeLogger)
+
+ final val classLive: ULayer[ZEnv with ZLogClass[LoggerClass]] =
+ ZEnv.live ++ ZLayer.succeed(classOf[LoggerClass])
+ }
+
+ sealed abstract class App {
+ import Setup._
+
+ // Case 1: from a possible config
+ val logNameLiveFromConfig: ULayer[ZLogName] =
+ aConfigLive >>> ZLayer.fromFunctionM { env =>
+ ZIO.succeed(LogName(env.get[AConfig].logName))
+ }
+
+ val log4sCase1: TaskLayer[ZLogWriter] =
+ logNameLiveFromConfig >>> log4sLayerFromName
+
+ val scribeCase1: TaskLayer[ZLogWriter] =
+ logNameLiveFromConfig >>> scribeLayerFromName
+
+ // Case 2: from a name
+ val log4sCase2: TaskLayer[ZLogWriter] =
+ logNameLive >>> log4sLayerFromName
+
+ val scribeCase2: TaskLayer[ZLogWriter] =
+ logNameLive >>> scribeLayerFromName
+
+ // Case 3: from a logger
+ val log4sCase3: TaskLayer[ZLogWriter] =
+ log4sLoggerLive >>> log4sLayerFromLogger
+
+ val julCase3: TaskLayer[ZLogWriter] =
+ julLoggerLive >>> julLayerFromLogger
+
+ val scribeCase3: TaskLayer[ZLogWriter] =
+ scribeLoggerLive >>> scribeLayerFromLogger
+
+ // Case 4: from a class
+ val log4sCase4: TaskLayer[ZLogWriter] =
+ classLive >>> log4sLayerFromClass
+
+ val scribeCase4: TaskLayer[ZLogWriter] =
+ classLive >>> scribeLayerFromClass
+ }
+ }
+}
diff --git a/zio/src/test/scala/ReadmeRioConstructionCodeSnippetsTest.scala b/zio/src/test/scala/ReadmeRioConstructionCodeSnippetsTest.scala
new file mode 100644
index 00000000..a7c4fbfe
--- /dev/null
+++ b/zio/src/test/scala/ReadmeRioConstructionCodeSnippetsTest.scala
@@ -0,0 +1,80 @@
+import com.github.ghik.silencer.silent
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpecLike
+
+@silent final class ReadmeRioConstructionCodeSnippetsTest extends AnyWordSpecLike with Matchers {
+ "Zio RIO construction snippets should compile" in {
+ import java.util.{logging => jul}
+
+ import log.effect.zio.ZioLogWriter._
+ import log.effect.{LogLevels, LogWriter}
+ import org.{log4s => l4s}
+ import zio._
+
+ object Setup {
+ final case class AConfig(logName: String)
+ final val aLogName = "a logger"
+ final def someZioProgramUsingLogs: RIO[LogWriter[Task], Unit] = ???
+ }
+
+ sealed abstract class App {
+ import Setup._
+
+ // Case 1: from a possible config in a Layer (gives a Layer)
+ val log4sCase1: RLayer[Has[AConfig], ZLogWriter] =
+ ZLayer.fromServiceM { config =>
+ log4sFromName.provide(config.logName)
+ }
+ val scribe4sCase1: RLayer[Has[AConfig], ZLogWriter] =
+ ZLayer.fromServiceM { config =>
+ scribeFromName.provide(config.logName)
+ }
+
+ // Case 2: from a name
+ val log4sCase2: Task[Unit] =
+ (log4sFromName >>> someZioProgramUsingLogs) provide aLogName
+
+ val scribeCase2: Task[Unit] =
+ (scribeFromName >>> someZioProgramUsingLogs) provide aLogName
+
+ // Case 3: from a logger
+ val log4sCase3: Task[Unit] =
+ Task.effect(l4s.getLogger(aLogName)) >>= { logger =>
+ (log4sFromLogger >>> someZioProgramUsingLogs) provide logger
+ }
+ val julCase3: Task[Unit] =
+ Task.effect(jul.Logger.getLogger(aLogName)) >>= { logger =>
+ (julFromLogger >>> someZioProgramUsingLogs) provide logger
+ }
+ val scribeCase3: Task[Unit] =
+ Task.effect(scribe.Logger(aLogName)) >>= { logger =>
+ (scribeFromLogger >>> someZioProgramUsingLogs) provide logger
+ }
+
+ // Case 4: from a class
+ val log4sCase4: Task[Unit] = {
+ case class LoggerClass();
+ (log4sFromClass >>> someZioProgramUsingLogs) provide classOf[LoggerClass]
+ }
+ val scribeCase4: Task[Unit] = {
+ case class LoggerClass();
+ (scribeFromClass >>> someZioProgramUsingLogs) provide classOf[LoggerClass]
+ }
+
+ // Case 5 (Jul): from global logger object
+ val julCase5: Task[Unit] =
+ julGlobal >>> someZioProgramUsingLogs
+
+ // Case 6: console logger
+ val console1: Task[Unit] =
+ someZioProgramUsingLogs provide consoleLog
+
+ val console2: Task[Unit] =
+ someZioProgramUsingLogs provide consoleLogUpToLevel(LogLevels.Warn)
+
+ // Case 7: No-op logger
+ val noOp: Task[Unit] =
+ someZioProgramUsingLogs provide noOpLog
+ }
+ }
+}