Skip to content

Commit b240807

Browse files
committed
Close #461 - Add LoggerFLogHandler to support doobie's LogHandler
1 parent dc5ee2c commit b240807

File tree

11 files changed

+287
-36
lines changed

11 files changed

+287
-36
lines changed

.github/workflows/build.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ jobs:
1919
strategy:
2020
matrix:
2121
scala:
22-
- { name: "Scala 2", version: "2.12.13", binary-version: "2.12", java-version: "11", java-distribution: "temurin", report: "" }
23-
- { name: "Scala 2", version: "2.13.6", binary-version: "2.13", java-version: "11", java-distribution: "temurin", report: "report" }
24-
- { name: "Scala 3", version: "3.0.2", binary-version: "3", java-version: "11", java-distribution: "temurin", report: "" }
22+
- { name: "Scala 2", version: "2.12.18", binary-version: "2.12", java-version: "11", java-distribution: "temurin", report: "" }
23+
- { name: "Scala 2", version: "2.13.11", binary-version: "2.13", java-version: "11", java-distribution: "temurin", report: "report" }
24+
- { name: "Scala 3", version: "3.3.0", binary-version: "3", java-version: "11", java-distribution: "temurin", report: "" }
2525

2626
steps:
2727
- uses: actions/checkout@v3

.github/workflows/coverage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
strategy:
1919
matrix:
2020
scala:
21-
- { name: "Scala 2", version: "2.13.6", binary-version: "2.13", java-version: "11", java-distribution: "temurin", report: "report" }
21+
- { name: "Scala 2", version: "2.13.11", binary-version: "2.13", java-version: "11", java-distribution: "temurin", report: "report" }
2222

2323
steps:
2424
- uses: actions/checkout@v3

.github/workflows/release.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ jobs:
2222
strategy:
2323
matrix:
2424
scala:
25-
- { name: "Scala 2", version: "2.12.13", binary-version: "2.12", java-version: "11", java-distribution: "temurin", report: "" }
26-
- { name: "Scala 2", version: "2.13.6", binary-version: "2.13", java-version: "11", java-distribution: "temurin", report: "" }
27-
- { name: "Scala 3", version: "3.0.2", binary-version: "3", java-version: "11", java-distribution: "temurin", report: "" }
25+
- { name: "Scala 2", version: "2.12.18", binary-version: "2.12", java-version: "11", java-distribution: "temurin", report: "" }
26+
- { name: "Scala 2", version: "2.13.11", binary-version: "2.13", java-version: "11", java-distribution: "temurin", report: "" }
27+
- { name: "Scala 3", version: "3.3.0", binary-version: "3", java-version: "11", java-distribution: "temurin", report: "" }
2828

2929
steps:
3030
- uses: actions/checkout@v3

build.sbt

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ lazy val loggerF = (project in file("."))
8181
catsJs,
8282
logbackMdcMonix3Jvm,
8383
logbackMdcMonix3Js,
84+
doobie1Jvm,
85+
doobie1Js,
8486
testKitJvm,
8587
testKitJs,
8688
catsEffectJvm,
@@ -273,6 +275,28 @@ lazy val logbackMdcMonix3 = module(ProjectName("logback-mdc-monix3"), crossPr
273275
lazy val logbackMdcMonix3Jvm = logbackMdcMonix3.jvm
274276
lazy val logbackMdcMonix3Js = logbackMdcMonix3.js
275277

278+
lazy val doobie1 = module(ProjectName("doobie1"), crossProject(JVMPlatform, JSPlatform))
279+
.settings(
280+
description := "Logger for F[_] - for Doobie v1",
281+
libraryDependencies ++= Seq(
282+
libs.doobieFree,
283+
libs.tests.effectieCatsEffect3,
284+
libs.tests.extrasHedgehogCatsEffect3,
285+
) ++ libs.tests.hedgehogLibs,
286+
libraryDependencies := libraryDependenciesRemoveScala3Incompatible(
287+
scalaVersion.value,
288+
libraryDependencies.value,
289+
),
290+
)
291+
.dependsOn(
292+
core,
293+
cats,
294+
testKit % Test,
295+
slf4jLogger % Test,
296+
)
297+
lazy val doobie1Jvm = doobie1.jvm
298+
lazy val doobie1Js = doobie1.js
299+
276300
lazy val testKit =
277301
module(ProjectName("test-kit"), crossProject(JVMPlatform, JSPlatform))
278302
.settings(
@@ -509,8 +533,8 @@ lazy val props =
509533
final val GitHubUsername = "Kevin-Lee"
510534
final val RepoName = "logger-f"
511535

512-
final val Scala3Versions = List("3.0.2")
513-
final val Scala2Versions = List("2.13.6", "2.12.13")
536+
final val Scala3Versions = List("3.3.0")
537+
final val Scala2Versions = List("2.13.11", "2.12.18")
514538

515539
// final val ProjectScalaVersion = Scala3Versions.head
516540
final val ProjectScalaVersion = Scala2Versions.head
@@ -545,6 +569,8 @@ lazy val props =
545569

546570
val Monix3Version = "3.4.0"
547571

572+
val Doobie1Version = "1.0.0-RC4"
573+
548574
final val LoggerF1Version = "1.20.0"
549575

550576
final val ExtrasVersion = "0.25.0"
@@ -587,10 +613,14 @@ lazy val libs =
587613

588614
lazy val logbackScalaInterop = "io.kevinlee" % "logback-scala-interop" % props.LogbackScalaInteropVersion
589615

616+
lazy val doobieFree = "org.tpolecat" %% "doobie-free" % props.Doobie1Version
617+
590618
lazy val tests = new {
591619

592620
lazy val monix = "io.monix" %% "monix" % props.Monix3Version % Test
593621

622+
lazy val effectieCatsEffect3 = "io.kevinlee" %% "effectie-cats-effect3" % props.EffectieVersion % Test
623+
594624
lazy val effectieMonix3 = "io.kevinlee" %% "effectie-monix3" % props.EffectieVersion % Test
595625

596626
lazy val hedgehogLibs: List[ModuleID] = List(
@@ -619,14 +649,7 @@ def prefixedProjectName(name: String) = s"${props.RepoName}${if (name.isEmpty) "
619649
def libraryDependenciesRemoveScala3Incompatible(
620650
scalaVersion: String,
621651
libraries: Seq[ModuleID],
622-
): Seq[ModuleID] =
623-
(
624-
if (scalaVersion.startsWith("3."))
625-
libraries
626-
.filterNot(props.removeDottyIncompatible)
627-
else
628-
libraries
629-
)
652+
): Seq[ModuleID] = libraries
630653

631654
lazy val mavenCentralPublishSettings: SettingsDefinition = List(
632655
/* Publish to Maven Central { */

modules/logger-f-cats/shared/src/main/scala-3/loggerf/instances/show.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import loggerf.core.ToLog
77
* @since 2022-02-19
88
*/
99
trait show {
10-
inline given showToLog[A: Show]: ToLog[A] = Show[A].show(_)
10+
given showToLog[A: Show]: ToLog[A] with {
11+
inline def toLogMessage(a: A): String = Show[A].show(a)
12+
}
1113
}
1214

1315
object show extends show

modules/logger-f-core/shared/src/main/scala-3/loggerf/core/ToLog.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,7 @@ object ToLog {
1515
@SuppressWarnings(Array("org.wartremover.warts.ToString"))
1616
def fromToString[A]: ToLog[A] = _.toString
1717

18-
inline given stringToLog: ToLog[String] = identity(_)
18+
given stringToLog: ToLog[String] with {
19+
inline def toLogMessage(a: String): String = a
20+
}
1921
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package loggerf.doobie1
2+
3+
import cats.syntax.all._
4+
import doobie.util.log
5+
import doobie.util.log.LogHandler
6+
import loggerf.core.Log
7+
import loggerf.syntax.all._
8+
9+
/** @author Kevin Lee
10+
* @since 2023-07-28
11+
*/
12+
object LoggerFLogHandler {
13+
def apply[F[*]: Log]: LogHandler[F] = new LoggerFLogHandlerF[F]
14+
15+
// format: off
16+
final private class LoggerFLogHandlerF[F[*]: Log] extends LogHandler[F] {
17+
override def run(logEvent: log.LogEvent): F[Unit] = logEvent match {
18+
case log.Success(sql, args, label, e1, e2) =>
19+
logS_(
20+
show"""Successful Statement Execution:
21+
|
22+
| ${sql.linesIterator.dropWhile(_.trim.isEmpty).mkString("\n ")}
23+
|
24+
| arguments = [${args.mkString(", ")}]
25+
| label = $label
26+
| elapsed = ${e1.toMillis} ms exec + ${e2.toMillis} ms processing (${(e1 + e2).toMillis} ms total)
27+
|""".stripMargin
28+
)(info)
29+
30+
case log.ProcessingFailure(sql, args, label, e1, e2, failure) =>
31+
logS_(
32+
show"""Failed Resultset Processing:
33+
|
34+
| ${sql.linesIterator.dropWhile(_.trim.isEmpty).mkString("\n ")}
35+
|
36+
| arguments = [${args.mkString(", ")}]
37+
| label = $label
38+
| elapsed = ${e1.toMillis} ms exec + ${e2.toMillis} ms processing (failed) (${(e1 + e2).toMillis} ms total)
39+
| failure = ${failure.getMessage}
40+
|""".stripMargin
41+
)(error)
42+
43+
case log.ExecFailure(sql, args, label, e1, failure) =>
44+
logS_(
45+
show"""Failed Statement Execution:
46+
|
47+
| ${sql.linesIterator.dropWhile(_.trim.isEmpty).mkString("\n ")}
48+
|
49+
| arguments = [${args.mkString(", ")}]
50+
| label = $label
51+
| elapsed = ${e1.toMillis} ms exec (failed)
52+
| failure = ${failure.getMessage}
53+
|""".stripMargin
54+
)(error)
55+
}
56+
}
57+
// format: on
58+
}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
package loggerf.doobie1
2+
3+
import cats.effect._
4+
import doobie.util.log.{ExecFailure, ProcessingFailure, Success}
5+
import effectie.instances.ce3.fx.ioFx
6+
import extras.hedgehog.ce3.syntax.runner._
7+
import hedgehog._
8+
import hedgehog.runner._
9+
import loggerf.instances.cats.logF
10+
import loggerf.testing.CanLog4Testing
11+
import loggerf.testing.CanLog4Testing.OrderedMessages
12+
13+
import scala.concurrent.duration._
14+
15+
/** @author Kevin Lee
16+
* @since 2023-07-29
17+
*/
18+
object LoggerFLogHandlerSpec extends Properties {
19+
20+
override def tests: List[Prop] = List(
21+
property("testSuccess", testSuccess),
22+
property("testExecFailure", testExecFailure),
23+
property("testProcessingFailure", testProcessingFailure),
24+
)
25+
26+
def testSuccess: Property =
27+
for {
28+
columns <- Gen.string(Gen.alpha, Range.linear(3, 10)).list(Range.linear(1, 5)).log("columns")
29+
table <- Gen.string(Gen.alpha, Range.linear(3, 10)).log("table")
30+
args <- Gen.string(Gen.alpha, Range.linear(3, 10)).list(Range.linear(0, 5)).log("args")
31+
label <- Gen.string(Gen.alpha, Range.linear(3, 10)).log("label")
32+
exec <- Gen.int(Range.linear(10, 3000)).log("exec")
33+
processing <- Gen.int(Range.linear(10, 3000)).log("processing")
34+
} yield runIO {
35+
implicit val canLog: CanLog4Testing = CanLog4Testing()
36+
37+
val expected =
38+
OrderedMessages(
39+
Vector(
40+
(
41+
0,
42+
loggerf.Level.info,
43+
s"""Successful Statement Execution:
44+
|
45+
| SELECT ${columns.mkString(", ")} FROM $table
46+
|
47+
| arguments = ${args.mkString("[", ", ", "]")}
48+
| label = $label
49+
| elapsed = ${exec.toString} ms exec + ${processing.toString} ms processing (${(exec + processing).toString} ms total)
50+
|""".stripMargin,
51+
)
52+
)
53+
)
54+
55+
LoggerFLogHandler[IO]
56+
.run(
57+
Success(
58+
s"SELECT ${columns.mkString(", ")} FROM $table",
59+
args,
60+
label,
61+
exec.milliseconds,
62+
processing.milliseconds,
63+
)
64+
) *> IO {
65+
val actual = canLog.getOrderedMessages
66+
actual ==== expected
67+
}
68+
}
69+
70+
def testExecFailure: Property =
71+
for {
72+
columns <- Gen.string(Gen.alpha, Range.linear(3, 10)).list(Range.linear(1, 5)).log("columns")
73+
table <- Gen.string(Gen.alpha, Range.linear(3, 10)).log("table")
74+
args <- Gen.string(Gen.alpha, Range.linear(3, 10)).list(Range.linear(0, 5)).log("args")
75+
label <- Gen.string(Gen.alpha, Range.linear(3, 10)).log("label")
76+
exec <- Gen.int(Range.linear(10, 3000)).log("exec")
77+
errMessage <- Gen.string(Gen.alpha, Range.linear(3, 10)).log("errMessage")
78+
} yield runIO {
79+
implicit val canLog: CanLog4Testing = CanLog4Testing()
80+
81+
val expectedException = new RuntimeException(errMessage)
82+
83+
val expected =
84+
OrderedMessages(
85+
Vector(
86+
(
87+
0,
88+
loggerf.Level.error,
89+
s"""Failed Statement Execution:
90+
|
91+
| SELECT ${columns.mkString(", ")} FROM $table
92+
|
93+
| arguments = ${args.mkString("[", ", ", "]")}
94+
| label = $label
95+
| elapsed = ${exec.toString} ms exec (failed)
96+
| failure = ${expectedException.getMessage}
97+
|""".stripMargin,
98+
)
99+
)
100+
)
101+
102+
LoggerFLogHandler[IO]
103+
.run(
104+
ExecFailure(
105+
s"SELECT ${columns.mkString(", ")} FROM $table",
106+
args,
107+
label,
108+
exec.milliseconds,
109+
expectedException,
110+
)
111+
) *> IO {
112+
val actual = canLog.getOrderedMessages
113+
actual ==== expected
114+
}
115+
}
116+
117+
def testProcessingFailure: Property =
118+
for {
119+
columns <- Gen.string(Gen.alpha, Range.linear(3, 10)).list(Range.linear(1, 5)).log("columns")
120+
table <- Gen.string(Gen.alpha, Range.linear(3, 10)).log("table")
121+
args <- Gen.string(Gen.alpha, Range.linear(3, 10)).list(Range.linear(0, 5)).log("args")
122+
label <- Gen.string(Gen.alpha, Range.linear(3, 10)).log("label")
123+
exec <- Gen.int(Range.linear(10, 3000)).log("exec")
124+
processing <- Gen.int(Range.linear(10, 3000)).log("processing")
125+
errMessage <- Gen.string(Gen.alpha, Range.linear(3, 10)).log("errMessage")
126+
} yield runIO {
127+
implicit val canLog: CanLog4Testing = CanLog4Testing()
128+
129+
val expectedException = new RuntimeException(errMessage)
130+
131+
val expected =
132+
OrderedMessages(
133+
Vector(
134+
(
135+
0,
136+
loggerf.Level.error,
137+
s"""Failed Resultset Processing:
138+
|
139+
| SELECT ${columns.mkString(", ")} FROM $table
140+
|
141+
| arguments = ${args.mkString("[", ", ", "]")}
142+
| label = $label
143+
| elapsed = ${exec.toString} ms exec + ${processing.toString} ms processing (failed) (${(exec + processing).toString} ms total)
144+
| failure = ${expectedException.getMessage}
145+
|""".stripMargin,
146+
)
147+
)
148+
)
149+
150+
LoggerFLogHandler[IO]
151+
.run(
152+
ProcessingFailure(
153+
s"SELECT ${columns.mkString(", ")} FROM $table",
154+
args,
155+
label,
156+
exec.milliseconds,
157+
processing.milliseconds,
158+
expectedException,
159+
)
160+
) *> IO {
161+
val actual = canLog.getOrderedMessages
162+
actual ==== expected
163+
}
164+
}
165+
166+
}

modules/logger-f-logback-mdc-monix3/shared/src/main/scala/loggerf/logger/logback/Monix3MdcAdapter.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,18 @@ object Monix3MdcAdapter extends Monix3MdcAdapterOps
4444

4545
trait Monix3MdcAdapterOps {
4646

47-
@SuppressWarnings(Array("org.wartremover.warts.Null"))
47+
@SuppressWarnings(Array("org.wartremover.warts.Null", "scalafix:DisableSyntax.null"))
4848
protected def initialize0(monix3MdcAdapter: Monix3MdcAdapter): Monix3MdcAdapter = {
4949
val field = classOf[MDC].getDeclaredField("mdcAdapter")
5050
field.setAccessible(true)
51-
field.set(null, monix3MdcAdapter) // scalafix:ok DisableSyntax.null
51+
field.set(null, monix3MdcAdapter)
5252
field.setAccessible(false)
5353
monix3MdcAdapter
5454
}
5555

56-
@SuppressWarnings(Array("org.wartremover.warts.AsInstanceOf"))
56+
@SuppressWarnings(Array("org.wartremover.warts.AsInstanceOf", "scalafix:DisableSyntax.asInstanceOf"))
5757
protected def getLoggerContext(): LoggerContext =
58-
LoggerFactory.getILoggerFactory.asInstanceOf[LoggerContext] // scalafix:ok DisableSyntax.asInstanceOf
58+
LoggerFactory.getILoggerFactory.asInstanceOf[LoggerContext]
5959

6060
def initialize(): Monix3MdcAdapter =
6161
initializeWithMonix3MdcAdapterAndLoggerContext(new Monix3MdcAdapter, getLoggerContext())

0 commit comments

Comments
 (0)