Skip to content

Commit 98db273

Browse files
committed
Close #461 - Add LoggerFLogHandler to support doobie's LogHandler
1 parent 82e1082 commit 98db273

File tree

10 files changed

+291
-40
lines changed

10 files changed

+291
-40
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
scala:
2525
- { name: "Scala 2", version: "2.12.18", binary-version: "2.12", java-version: "11", java-distribution: "temurin", report: "" }
2626
- { name: "Scala 2", version: "2.13.11", binary-version: "2.13", java-version: "11", java-distribution: "temurin", report: "report" }
27-
- { name: "Scala 3", version: "3.0.2", binary-version: "3", 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@v4

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
scala:
2525
- { name: "Scala 2", version: "2.12.18", binary-version: "2.12", java-version: "11", java-distribution: "temurin", report: "" }
2626
- { name: "Scala 2", version: "2.13.11", 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: "" }
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@v4

build.sbt

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -70,27 +70,29 @@ lazy val loggerF = (project in file("."))
7070
.settings(noPublish)
7171
.aggregate(
7272
coreJvm,
73-
// coreJs,
73+
coreJs,
7474
slf4jLoggerJvm,
75-
// slf4jLoggerJs,
75+
slf4jLoggerJs,
7676
log4sLoggerJvm,
77-
// log4sLoggerJs,
77+
log4sLoggerJs,
7878
log4jLoggerJvm,
79-
// log4jLoggerJs,
79+
log4jLoggerJs,
8080
sbtLoggingJvm,
81-
// sbtLoggingJs,
81+
sbtLoggingJs,
8282
catsJvm,
83-
// catsJs,
83+
catsJs,
8484
logbackMdcMonix3Jvm,
85-
// logbackMdcMonix3Js,
85+
logbackMdcMonix3Js,
86+
doobie1Jvm,
87+
doobie1Js,
8688
testKitJvm,
87-
// testKitJs,
89+
testKitJs,
8890
catsEffectJvm,
89-
// catsEffectJs,
91+
catsEffectJs,
9092
catsEffect3Jvm,
91-
// catsEffect3Js,
93+
catsEffect3Js,
9294
monixJvm,
93-
// monixJs,
95+
monixJs,
9496
)
9597

9698
lazy val core =
@@ -276,6 +278,28 @@ lazy val logbackMdcMonix3 = module(ProjectName("logback-mdc-monix3"), crossPr
276278
lazy val logbackMdcMonix3Jvm = logbackMdcMonix3.jvm
277279
lazy val logbackMdcMonix3Js = logbackMdcMonix3.js
278280

281+
lazy val doobie1 = module(ProjectName("doobie1"), crossProject(JVMPlatform, JSPlatform))
282+
.settings(
283+
description := "Logger for F[_] - for Doobie v1",
284+
libraryDependencies ++= Seq(
285+
libs.doobieFree,
286+
libs.tests.effectieCatsEffect3,
287+
libs.tests.extrasHedgehogCatsEffect3,
288+
) ++ libs.tests.hedgehogLibs,
289+
libraryDependencies := libraryDependenciesRemoveScala3Incompatible(
290+
scalaVersion.value,
291+
libraryDependencies.value,
292+
),
293+
)
294+
.dependsOn(
295+
core,
296+
cats,
297+
testKit % Test,
298+
slf4jLogger % Test,
299+
)
300+
lazy val doobie1Jvm = doobie1.jvm
301+
lazy val doobie1Js = doobie1.js
302+
279303
lazy val testKit =
280304
module(ProjectName("test-kit"), crossProject(JVMPlatform, JSPlatform))
281305
.settings(
@@ -514,7 +538,7 @@ lazy val props =
514538
final val GitHubUsername = "Kevin-Lee"
515539
final val RepoName = "logger-f"
516540

517-
final val Scala3Versions = List("3.0.2")
541+
final val Scala3Versions = List("3.3.0")
518542
final val Scala2Versions = List("2.13.11", "2.12.18")
519543

520544
// final val ProjectScalaVersion = Scala3Versions.head
@@ -550,6 +574,8 @@ lazy val props =
550574

551575
val Monix3Version = "3.4.0"
552576

577+
val Doobie1Version = "1.0.0-RC4"
578+
553579
final val LoggerF1Version = "1.20.0"
554580

555581
final val ExtrasVersion = "0.25.0"
@@ -593,10 +619,14 @@ lazy val libs =
593619

594620
lazy val logbackScalaInterop = "io.kevinlee" % "logback-scala-interop" % props.LogbackScalaInteropVersion
595621

622+
lazy val doobieFree = "org.tpolecat" %% "doobie-free" % props.Doobie1Version
623+
596624
lazy val tests = new {
597625

598626
lazy val monix = "io.monix" %% "monix" % props.Monix3Version % Test
599627

628+
lazy val effectieCatsEffect3 = "io.kevinlee" %% "effectie-cats-effect3" % props.EffectieVersion % Test
629+
600630
lazy val effectieMonix3 = "io.kevinlee" %% "effectie-monix3" % props.EffectieVersion % Test
601631

602632
lazy val hedgehogLibs: List[ModuleID] = List(
@@ -625,14 +655,7 @@ def prefixedProjectName(name: String) = s"${props.RepoName}${if (name.isEmpty) "
625655
def libraryDependenciesRemoveScala3Incompatible(
626656
scalaVersion: String,
627657
libraries: Seq[ModuleID],
628-
): Seq[ModuleID] =
629-
(
630-
if (scalaVersion.startsWith("3."))
631-
libraries
632-
.filterNot(props.removeDottyIncompatible)
633-
else
634-
libraries
635-
)
658+
): Seq[ModuleID] = libraries
636659

637660
lazy val mavenCentralPublishSettings: SettingsDefinition = List(
638661
/* 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+
}

0 commit comments

Comments
 (0)