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

Close #498 - Change the LogMessage parameter in the log(F[A]) method from NotIgnorable to MaybeIgnorable #499

Merged
merged 1 commit into from
Nov 7, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,17 @@ trait Log[F[*]] {

def canLog: CanLog

def log[A](fa: F[A])(toLeveledMessage: A => LogMessage with NotIgnorable): F[A] =
def log[A](fa: F[A])(toLeveledMessage: A => LogMessage with MaybeIgnorable): F[A] =
flatMap0(fa) { a =>
toLeveledMessage(a) match {
case LogMessage.LeveledMessage(message, level) =>
flatMap0(EF.effectOf(canLog.getLogger(level)(message())))(_ => EF.pureOf(a))
case LogMessage.Ignore =>
EF.pureOf(a)
}
}

def log_[A](fa: F[A])(toLeveledMessage: A => LogMessage with NotIgnorable): F[Unit] =
def log_[A](fa: F[A])(toLeveledMessage: A => LogMessage with MaybeIgnorable): F[Unit] =
map0(log(fa)(toLeveledMessage))(_ => ())

def logS(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ trait LogSyntax {

import LogSyntax._

@inline def log[F[*], A](fa: F[A])(toLeveledMessage: A => LogMessage with NotIgnorable)(
@inline def log[F[*], A](fa: F[A])(toLeveledMessage: A => LogMessage with MaybeIgnorable)(
implicit L: Log[F]
): F[A] =
L.log(fa)(toLeveledMessage)

@inline def log_[F[*], A](fa: F[A])(toLeveledMessage: A => LogMessage with NotIgnorable)(
@inline def log_[F[*], A](fa: F[A])(toLeveledMessage: A => LogMessage with MaybeIgnorable)(
implicit L: Log[F]
): F[Unit] =
L.log_(fa)(toLeveledMessage)
Expand Down Expand Up @@ -93,10 +93,10 @@ trait LogSyntax {

object LogSyntax extends LogSyntax {
final class LogFOfASyntax[F[*], A](private val fa: F[A]) extends AnyVal {
@inline def log(toLeveledMessage: A => LogMessage with NotIgnorable)(implicit L: Log[F]): F[A] =
@inline def log(toLeveledMessage: A => LogMessage with MaybeIgnorable)(implicit L: Log[F]): F[A] =
LogSyntax.log(fa)(toLeveledMessage)

@inline def log_(toLeveledMessage: A => LogMessage with NotIgnorable)(implicit L: Log[F]): F[Unit] =
@inline def log_(toLeveledMessage: A => LogMessage with MaybeIgnorable)(implicit L: Log[F]): F[Unit] =
LogSyntax.log_(fa)(toLeveledMessage)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ import scala.annotation.implicitNotFound
// or
import loggerf.instances.cats.logF
---
-----
If this doesn't solve, you probably need a CanLog instance.
To create it, please check out the following document.

https://logger-f.kevinly.dev/docs/cats/import#canlog-logger

-----
If it doesn't solve, it's probably because of missing an Fx[F] instance.

You can simply import the Fx[F] instance of your effect library.
Please check out the message of @implicitNotFound annotation on effectie.core.Fx.

"""
)
trait Log[F[*]] {
Expand All @@ -31,15 +43,17 @@ trait Log[F[*]] {

def canLog: CanLog

def log[A](fa: F[A])(toLeveledMessage: A => LeveledMessage): F[A] =
def log[A](fa: F[A])(toLeveledMessage: A => LeveledMessage | Ignore.type): F[A] =
flatMap0(fa) { a =>
toLeveledMessage(a) match {
case LeveledMessage(message, level) =>
flatMap0(EF.effectOf(canLog.getLogger(level)(message())))(_ => EF.pureOf(a))
case Ignore =>
EF.pureOf(a)
}
}

def log_[A](fa: F[A])(toLeveledMessage: A => LeveledMessage): F[Unit] =
def log_[A](fa: F[A])(toLeveledMessage: A => LeveledMessage | Ignore.type): F[Unit] =
map0(log(fa)(toLeveledMessage))(_ => ())

def logS(message: => String)(toLeveledMessage: (String => LeveledMessage) with LeveledMessage.Leveled): F[String] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import scala.concurrent.Future
trait LogSyntax {

extension [F[*], A](fa: F[A]) {
def log(toLeveledMessage: A => LeveledMessage)(using L: Log[F]): F[A] =
def log(toLeveledMessage: A => LeveledMessage | Ignore.type)(using L: Log[F]): F[A] =
L.log(fa)(toLeveledMessage)

def log_(toLeveledMessage: A => LeveledMessage)(using L: Log[F]): F[Unit] =
def log_(toLeveledMessage: A => LeveledMessage | Ignore.type)(using L: Log[F]): F[Unit] =
L.log_(fa)(toLeveledMessage)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,18 @@ import java.util.concurrent.ExecutorService
import scala.concurrent.duration._
import scala.concurrent.{ExecutionContext, Future}

import loggerf.test_data
import loggerf.test_data.TestCases

/** @author Kevin Lee
* @since 2022-02-09
*/
object instancesSpec extends Properties {
override def tests: List[Test] = List(
property("test Log.log(F[A])", testLogFA),
property("test Log.log(F[A]) with matching cases", testLogFAWithMatchingCases),
property("test Log.log_(F[A])", testLog_FA),
property("test Log.log_(F[A]) with matching cases", testLog_FAWithMatchingCases),
property("test Log.logS(String)", testLogS),
property("test Log.logS_(String)", testLogS_()),
property("test Log.log(F[Option[A]])", testLogFOptionA),
Expand Down Expand Up @@ -56,9 +61,13 @@ object instancesSpec extends Properties {
def runLog[F[*]: Fx: Log: Monad]: F[Unit] =
(for {
_ <- Log[F].log(Fx[F].effectOf(debugMsg))(debug)
_ <- Log[F].log(Fx[F].effectOf(debugMsg))(ignoreA)
_ <- Log[F].log(Fx[F].effectOf(infoMsg))(info)
_ <- Log[F].log(Fx[F].effectOf(infoMsg))(ignoreA)
_ <- Log[F].log(Fx[F].effectOf(warnMsg))(warn)
_ <- Log[F].log(Fx[F].effectOf(warnMsg))(ignoreA)
_ <- Log[F].log(Fx[F].effectOf(errorMsg))(error)
_ <- Log[F].log(Fx[F].effectOf(errorMsg))(ignoreA)
} yield ())

val expected = LoggerForTesting(
Expand All @@ -81,6 +90,69 @@ object instancesSpec extends Properties {

}

def testLogFAWithMatchingCases: Property = for {
debugMsg <- Gen.string(Gen.unicode, Range.linear(1, 20)).log("debugMsg")
infoMsg <- Gen.string(Gen.unicode, Range.linear(1, 20)).log("infoMsg")
warnMsg <- Gen.string(Gen.unicode, Range.linear(1, 20)).log("warnMsg")
errorMsg <- Gen.string(Gen.unicode, Range.linear(1, 20)).log("errorMsg")
testCases <- test_data.Gens.genTestCases.log("testCases")
} yield {

implicit val logger: LoggerForTesting = LoggerForTesting()

def runLog[F[*]: Fx: Log: Monad]: F[Unit] = {
val fa1 = Log[F].log(Fx[F].effectOf(testCases)) {
case TestCases(_, _, true) =>
ignore
case TestCases(id, name, false) =>
debug(s"$debugMsg / id=${id.toString}, name=$name, not enabled")
}
val fa2 = Log[F].log(fa1) {
case TestCases(_, _, true) =>
ignore
case TestCases(id, name, false) =>
info(s"$infoMsg / id=${id.toString}, name=$name, not enabled")
}
val fa3 = Log[F].log(fa2) {
case TestCases(_, _, true) =>
ignore
case TestCases(id, name, false) =>
warn(s"$warnMsg / id=${id.toString}, name=$name, not enabled")
}
val fa4 = Log[F].log(fa3) {
case TestCases(_, _, true) =>
ignore
case TestCases(id, name, false) =>
error(s"$errorMsg / id=${id.toString}, name=$name, not enabled")
}
fa4 *> Fx[F].unitOf

}

val expected =
if (testCases.enabled)
LoggerForTesting()
else
LoggerForTesting(
debugMessages = Vector(s"$debugMsg / id=${testCases.id.toString}, name=${testCases.name}, not enabled"),
infoMessages = Vector(s"$infoMsg / id=${testCases.id.toString}, name=${testCases.name}, not enabled"),
warnMessages = Vector(s"$warnMsg / id=${testCases.id.toString}, name=${testCases.name}, not enabled"),
errorMessages = Vector(s"$errorMsg / id=${testCases.id.toString}, name=${testCases.name}, not enabled"),
)

implicit val es: ExecutorService = ConcurrentSupport.newExecutorService(2)
implicit val ec: ExecutionContext =
ConcurrentSupport.newExecutionContextWithLogger(es, ErrorLogger.printlnExecutionContextErrorLogger)

ConcurrentSupport.futureToValueAndTerminate(es, waitFor400Millis) {

runLog[Future]

}
logger ==== expected

}

def testLog_FA: Property = for {
debugMsg <- Gen.string(Gen.unicode, Range.linear(1, 20)).log("debugMsg")
infoMsg <- Gen.string(Gen.unicode, Range.linear(1, 20)).log("infoMsg")
Expand All @@ -93,9 +165,13 @@ object instancesSpec extends Properties {
def runLog[F[*]: Fx: Log: Monad]: F[Unit] =
Log[F]
.log_(Fx[F].effectOf(debugMsg))(debug)
.flatMap { _ => Log[F].log_(Fx[F].effectOf(debugMsg))(ignoreA) }
.flatMap { _ => Log[F].log_(Fx[F].effectOf(infoMsg))(info) }
.flatMap { _ => Log[F].log_(Fx[F].effectOf(infoMsg))(ignoreA) }
.flatMap { _ => Log[F].log_(Fx[F].effectOf(warnMsg))(warn) }
.flatMap { _ => Log[F].log_(Fx[F].effectOf(warnMsg))(ignoreA) }
.flatMap { _ => Log[F].log_(Fx[F].effectOf(errorMsg))(error) }
.flatMap { _ => Log[F].log_(Fx[F].effectOf(errorMsg))(ignoreA) }

val expected = LoggerForTesting(
debugMessages = Vector(debugMsg),
Expand All @@ -117,6 +193,65 @@ object instancesSpec extends Properties {

}

def testLog_FAWithMatchingCases: Property = for {
debugMsg <- Gen.string(Gen.unicode, Range.linear(1, 20)).log("debugMsg")
infoMsg <- Gen.string(Gen.unicode, Range.linear(1, 20)).log("infoMsg")
warnMsg <- Gen.string(Gen.unicode, Range.linear(1, 20)).log("warnMsg")
errorMsg <- Gen.string(Gen.unicode, Range.linear(1, 20)).log("errorMsg")
testCases <- test_data.Gens.genTestCases.log("testCases")
} yield {

implicit val logger: LoggerForTesting = LoggerForTesting()

def runLog[F[*]: Fx: Log: Monad]: F[Unit] = {
val fa = Fx[F].effectOf(testCases)
Log[F].log_(fa) {
case TestCases(_, _, true) =>
ignore
case TestCases(id, name, false) =>
debug(s"$debugMsg / id=${id.toString}, name=$name, not enabled")
} *> Log[F].log_(fa) {
case TestCases(_, _, true) =>
ignore
case TestCases(id, name, false) =>
info(s"$infoMsg / id=${id.toString}, name=$name, not enabled")
} *> Log[F].log_(fa) {
case TestCases(_, _, true) =>
ignore
case TestCases(id, name, false) =>
warn(s"$warnMsg / id=${id.toString}, name=$name, not enabled")
} *> Log[F].log_(fa) {
case TestCases(_, _, true) =>
ignore
case TestCases(id, name, false) =>
error(s"$errorMsg / id=${id.toString}, name=$name, not enabled")
}
}

val expected =
if (testCases.enabled)
LoggerForTesting()
else
LoggerForTesting(
debugMessages = Vector(s"$debugMsg / id=${testCases.id.toString}, name=${testCases.name}, not enabled"),
infoMessages = Vector(s"$infoMsg / id=${testCases.id.toString}, name=${testCases.name}, not enabled"),
warnMessages = Vector(s"$warnMsg / id=${testCases.id.toString}, name=${testCases.name}, not enabled"),
errorMessages = Vector(s"$errorMsg / id=${testCases.id.toString}, name=${testCases.name}, not enabled"),
)

implicit val es: ExecutorService = ConcurrentSupport.newExecutorService(2)
implicit val ec: ExecutionContext =
ConcurrentSupport.newExecutionContextWithLogger(es, ErrorLogger.printlnExecutionContextErrorLogger)

ConcurrentSupport.futureToValueAndTerminate(es, waitFor400Millis) {

runLog[Future]

}
logger ==== expected

}

def testLogS: Property = for {
debugMsg <- Gen.string(Gen.unicode, Range.linear(1, 20)).log("debugMsg")
infoMsg <- Gen.string(Gen.unicode, Range.linear(1, 20)).log("infoMsg")
Expand Down
Loading