Skip to content

Commit

Permalink
add scalajs support
Browse files Browse the repository at this point in the history
  • Loading branch information
Julien Sirocchi committed Sep 4, 2023
1 parent e85f74e commit 245bf85
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 160 deletions.
102 changes: 52 additions & 50 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ val scala_212 = "2.12.18"
val scala_213 = "2.13.11"
val scala_3 = "3.3.0"

val versionOf = new {
val V = new {
val cats = "2.9.0"
val catsEffect = "3.5.1"
val fs2 = "3.8.0"
Expand All @@ -11,46 +11,26 @@ val versionOf = new {
val log4s = "1.10.0"
val scalaCheck = "1.17.0"
val scalaTest = "3.2.16"
val zio = "2.0.15"
val scribe = "3.11.9"
val zio = "2.0.15"
}

lazy val coreDependencies = Seq(
"org.log4s" %% "log4s" % versionOf.log4s,
"com.outr" %% "scribe" % versionOf.scribe
).map(_.withSources)

lazy val fs2Dependencies = Seq(
"org.log4s" %% "log4s" % versionOf.log4s,
"com.outr" %% "scribe" % versionOf.scribe,
"org.typelevel" %% "cats-core" % versionOf.cats,
"org.typelevel" %% "cats-effect" % versionOf.catsEffect,
"co.fs2" %% "fs2-core" % versionOf.fs2
).map(_.withSources)

lazy val zioDependencies = Seq(
"org.log4s" %% "log4s" % versionOf.log4s,
"com.outr" %% "scribe" % versionOf.scribe,
"dev.zio" %% "zio" % versionOf.zio
).map(_.withSources)

lazy val interopDependencies = Seq(
"org.typelevel" %% "log4cats-core" % versionOf.log4cats,
"org.typelevel" %% "log4cats-slf4j" % versionOf.log4cats % Test,
"org.typelevel" %% "cats-effect" % versionOf.catsEffect % Test
).map(_.withSources)

lazy val testDependencies = Seq(
"org.scalacheck" %% "scalacheck" % versionOf.scalaCheck % Test,
"org.scalatest" %% "scalatest" % versionOf.scalaTest % Test,
"org.log4s" %% "log4s-testing" % versionOf.log4s % Test
)

lazy val compilerPluginsDependencies = Seq(
compilerPlugin(
"org.typelevel" %% "kind-projector" % versionOf.kindProjector cross CrossVersion.full
val D = new {
lazy val `cats-core` = Def.setting("org.typelevel" %%% "cats-core" % V.cats)
lazy val `cats-effect` = Def.setting("org.typelevel" %%% "cats-effect" % V.catsEffect)
lazy val `fs2-core` = Def.setting("co.fs2" %%% "fs2-core" % V.fs2)
lazy val `kind-projector` = Def.setting(
compilerPlugin("org.typelevel" %%% "kind-projector" % V.kindProjector cross CrossVersion.full)
)
)
lazy val `log4cats-core` = Def.setting("org.typelevel" %%% "log4cats-core" % V.log4cats)
lazy val `log4cats-testing` = Def.setting("org.typelevel" %%% "log4cats-testing" % V.log4cats)
lazy val log4s = Def.setting("org.log4s" %%% "log4s" % V.log4s)
lazy val `log4s-testing` = Def.setting("org.log4s" %%% "log4s-testing" % V.log4s)
lazy val scalacheck = Def.setting("org.scalacheck" %%% "scalacheck" % V.scalaCheck)
lazy val scalatest = Def.setting("org.scalatest" %%% "scalatest" % V.scalaTest)
lazy val scribe = Def.setting("com.outr" %%% "scribe" % V.scribe)
lazy val zio = Def.setting("dev.zio" %%% "zio" % V.zio)
}

ThisBuild / tlBaseVersion := "0.17"
ThisBuild / tlCiReleaseBranches := Seq("master")
Expand All @@ -68,46 +48,68 @@ ThisBuild / githubWorkflowJavaVersions := Seq(
ThisBuild / githubWorkflowBuildMatrixExclusions := Seq()
ThisBuild / Test / parallelExecution := false

ThisBuild / libraryDependencies ++= testDependencies
ThisBuild / libraryDependencies ++= Seq(
D.scalacheck.value % Test,
D.scalatest.value % Test
)
ThisBuild / libraryDependencies ++= {
if (tlIsScala3.value) Seq.empty else compilerPluginsDependencies
if (tlIsScala3.value) Seq.empty else Seq(D.`kind-projector`.value)
}

lazy val root = tlCrossRootProject
.aggregate(core, fs2, zio, interop)
.settings(
addCommandAlias("fmt", "scalafmt;Test/scalafmt;scalafmtSbt"),
addCommandAlias("checkFormat", "scalafmtCheck;Test/scalafmtCheck;scalafmtSbtCheck"),
addCommandAlias("check", "checkFormat;clean;test")
addCommandAlias("fmt", "scalafmt; Test/scalafmt; scalafmtSbt"),
addCommandAlias("checkFormat", "scalafmtCheck; Test/scalafmtCheck; scalafmtSbtCheck"),
addCommandAlias("check", "checkFormat; clean; test")
)

lazy val core = project
lazy val core = crossProject(JVMPlatform, JSPlatform)
.crossType(CrossType.Pure)
.in(file("core"))
.settings(
name := "log-effect-core",
libraryDependencies ++= coreDependencies
libraryDependencies ++= Seq(D.log4s.value, D.scribe.value)
)

lazy val fs2 = project
lazy val fs2 = crossProject(JVMPlatform, JSPlatform)
.crossType(CrossType.Pure)
.in(file("fs2"))
.dependsOn(core)
.settings(
name := "log-effect-fs2",
libraryDependencies ++= fs2Dependencies
libraryDependencies ++= Seq(
D.`cats-core`.value,
D.`cats-effect`.value,
D.`fs2-core`.value,
D.log4s.value,
D.scribe.value
)
)

lazy val zio = project
lazy val zio = crossProject(JVMPlatform, JSPlatform)
.crossType(CrossType.Pure)
.in(file("zio"))
.dependsOn(core)
.settings(
name := "log-effect-zio",
libraryDependencies ++= zioDependencies
libraryDependencies ++= Seq(
D.log4s.value,
D.`log4s-testing`.value % Test,
D.scribe.value,
D.zio.value
)
)

lazy val interop = project
lazy val interop = crossProject(JVMPlatform, JSPlatform)
.crossType(CrossType.Pure)
.in(file("interop"))
.dependsOn(core, fs2)
.settings(
name := "log-effect-interop",
libraryDependencies ++= interopDependencies
libraryDependencies ++= Seq(
D.`cats-effect`.value % Test,
D.`log4cats-core`.value,
D.`log4cats-testing`.value % Test
)
)
3 changes: 1 addition & 2 deletions fs2/src/test/scala/log/effect/fs2/TestLogCapture.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,14 @@ package fs2
import java.io.{ByteArrayOutputStream, PrintStream}

import cats.effect.IO
import cats.effect.unsafe.implicits.global

trait TestLogCapture {

protected final def capturedConsoleOutOf(aWrite: IO[Unit]): String = {
val lowerStream = new ByteArrayOutputStream()
val outStream = new PrintStream(lowerStream)

Console.withOut(outStream)(aWrite.unsafeRunSync())
Console.withOut(outStream)(aWrite.syncStep(Int.MaxValue).unsafeRunSync())

lowerStream.toString
}
Expand Down
8 changes: 0 additions & 8 deletions interop/src/test/resources/logback-test.xml

This file was deleted.

34 changes: 15 additions & 19 deletions interop/src/test/scala/InteropLogSelectorTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,12 @@

import cats.effect.{IO, Resource, Sync}
import cats.syntax.flatMap._
import org.typelevel.log4cats.SelfAwareStructuredLogger
import org.typelevel.log4cats.slf4j.Slf4jLogger
import log.effect.fs2.LogSelector
import log.effect.interop.TestLogCapture
import org.typelevel.log4cats.testing.StructuredTestingLogger
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpecLike
import org.slf4j.Logger

final class InteropLogSelectorTest extends AnyWordSpecLike with Matchers with TestLogCapture {
final class InteropLogSelectorTest extends AnyWordSpecLike with Matchers {

private[this] sealed trait ALoggingClient[F[_]] {
def address: String
Expand All @@ -49,34 +46,33 @@ final class InteropLogSelectorTest extends AnyWordSpecLike with Matchers with Te
)(_ => F.unit)
}

private[this] def testLogger[F[_]: Sync]: F[StructuredTestingLogger[F]] =
Sync[F].pure(StructuredTestingLogger.impl())

"Log selector can infer the correct log if a log4cats Logger is in scope" in {
import log.effect.interop.log4cats._

def buildLog4catsLogger[F[_]: Sync](logger: Logger): F[SelfAwareStructuredLogger[F]] =
Slf4jLogger.fromSlf4j[F](logger)

def useLoggingClient[F[_]: Sync](address: String)(logger: Logger): F[Unit] =
buildLog4catsLogger[F](logger) >>= { implicit l =>
def useLoggingClient[F[_]: Sync](address: String): F[StructuredTestingLogger[F]] =
testLogger[F].flatTap { implicit l =>
ALoggingClient[F](address).use(_.useIt)
}

val logged = capturedLog4sOutOf(useLoggingClient[IO]("an address")).map(_.message)
val logged =
useLoggingClient[IO]("an address").flatMap(_.logged).syncStep(Int.MaxValue).unsafeRunSync()

logged shouldBe Seq("this is a test")
logged shouldBe Right(Seq(StructuredTestingLogger.INFO("this is a test", None, Map.empty)))
}

"Log selector will default to no logs if no log4cats Logger is in scope" in {

def buildLog4catsLogger[F[_]: Sync](logger: Logger): F[SelfAwareStructuredLogger[F]] =
Slf4jLogger.fromSlf4j[F](logger)

def useLoggingClient[F[_]: Sync](address: String)(logger: Logger): F[Unit] =
buildLog4catsLogger[F](logger) >>= { _ =>
def useLoggingClient[F[_]: Sync](address: String): F[StructuredTestingLogger[F]] =
testLogger[F].flatTap { _ =>
ALoggingClient[F](address).use(_.useIt)
}

val logged = capturedLog4sOutOf(useLoggingClient[IO]("an address"))
val logged =
useLoggingClient[IO]("an address").flatMap(_.logged).syncStep(Int.MaxValue).unsafeRunSync()

logged shouldBe Seq()
logged shouldBe Right(Seq())
}
}
66 changes: 31 additions & 35 deletions interop/src/test/scala/InteropTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@

import cats.effect.{Resource, Sync}
import log.effect.LogWriter
import log.effect.interop.TestLogCapture
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpecLike
import org.typelevel.log4cats.SelfAwareStructuredLogger

import scala.annotation.nowarn

Expand All @@ -45,12 +43,11 @@ object RedisClient {
}

@nowarn("msg=local method [a-zA-Z0-9]+ in value <local InteropTest> is never used")
final class InteropTest extends AnyWordSpecLike with Matchers with TestLogCapture {
final class InteropTest extends AnyWordSpecLike with Matchers {

"A LogWriter instance can be derived from a log4cats Logger" in {
import cats.effect.IO
import cats.effect.unsafe.implicits.global
import org.typelevel.log4cats.slf4j.Slf4jLogger
import org.typelevel.log4cats.testing.StructuredTestingLogger
import log.effect.internal.Show

final class A()
Expand All @@ -59,37 +56,36 @@ final class InteropTest extends AnyWordSpecLike with Matchers with TestLogCaptur
(_: A) => "an A"
}

val logged = capturedLog4sOutOf { logger =>
import log.effect.interop.log4cats._

implicit val buildMessageLogger: SelfAwareStructuredLogger[IO] =
Slf4jLogger.fromSlf4j[IO](logger).unsafeRunSync()

val lw = implicitly[LogWriter[IO]]

lw.trace("a message") >>
lw.trace(new Exception("an exception")) >>
lw.trace("a message", new Exception("an exception")) >>
lw.trace(new A()) >>
lw.debug("a message") >>
lw.debug(new Exception("an exception")) >>
lw.debug("a message", new Exception("an exception")) >>
lw.debug(new A()) >>
lw.info("a message") >>
lw.info(new Exception("an exception")) >>
lw.info("a message", new Exception("an exception")) >>
lw.info(new A()) >>
lw.warn("a message") >>
lw.warn(new Exception("an exception")) >>
lw.warn("a message", new Exception("an exception")) >>
lw.warn(new A()) >>
lw.error("a message") >>
lw.error(new Exception("an exception")) >>
lw.error("a message", new Exception("an exception")) >>
lw.error(new A())
}
implicit val testLogger = StructuredTestingLogger.impl[IO]()

import log.effect.interop.log4cats._

val lw = implicitly[LogWriter[IO]]

val logs = lw.trace("a message") >>
lw.trace(new Exception("an exception")) >>
lw.trace("a message", new Exception("an exception")) >>
lw.trace(new A()) >>
lw.debug("a message") >>
lw.debug(new Exception("an exception")) >>
lw.debug("a message", new Exception("an exception")) >>
lw.debug(new A()) >>
lw.info("a message") >>
lw.info(new Exception("an exception")) >>
lw.info("a message", new Exception("an exception")) >>
lw.info(new A()) >>
lw.warn("a message") >>
lw.warn(new Exception("an exception")) >>
lw.warn("a message", new Exception("an exception")) >>
lw.warn(new A()) >>
lw.error("a message") >>
lw.error(new Exception("an exception")) >>
lw.error("a message", new Exception("an exception")) >>
lw.error(new A())

val loggedQty = (logs >> testLogger.logged.map(_.size)).syncStep(Int.MaxValue).unsafeRunSync()

logged.size shouldBe 20
loggedQty shouldBe Right(20)
}

"The readme interop example compiles" in {
Expand Down
45 changes: 0 additions & 45 deletions interop/src/test/scala/log/effect/interop/TestLogCapture.scala

This file was deleted.

4 changes: 3 additions & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
addSbtPlugin("org.typelevel" % "sbt-typelevel" % "0.4.22")
addSbtPlugin("org.portable-scala" % "sbt-scala-native-crossproject" % "1.3.2")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.13.2")
addSbtPlugin("org.typelevel" % "sbt-typelevel" % "0.4.22")

0 comments on commit 245bf85

Please sign in to comment.