diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredLogger.scala b/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredLogger.scala index 0f025119..93a06346 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredLogger.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredLogger.scala @@ -43,9 +43,25 @@ import org.typelevel.log4cats.extras.DeferredLogger.DeferredLogMessage * } * } * }}} + * + * >>> WARNING: READ BEFORE USAGE! <<< + * https://github.com/typelevel/log4cats/blob/main/core/shared/src/main/scala/org/typelevel/log4cats/extras/README.md + * >>> WARNING: READ BEFORE USAGE! <<< */ trait DeferredLogger[F[_]] extends Logger[F] { + /** + * View the logs in the buffer. + * + * This is primarily useful for testing, and will not effect the behavior + * of calls to `log` + */ def inspect: F[Chain[DeferredLogMessage]] + + /** + * Log the deferred messages + * + * This may be called multiple times, and each log should only be logged once. + */ def log: F[Unit] } object DeferredLogger { diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredLoggerFactory.scala b/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredLoggerFactory.scala index 4c0cc303..37161b24 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredLoggerFactory.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredLoggerFactory.scala @@ -24,8 +24,33 @@ import cats.{~>, Functor} import org.typelevel.log4cats.extras.DeferredStructuredLogger.DeferredStructuredLogMessage import org.typelevel.log4cats.{LoggerFactory, SelfAwareStructuredLogger} +/** + * A `LoggerFactory` that does not immediately log. + * + * Effectively a `LoggerFactory` equivalent to `DeferredSelfAwareStructuredLogger`. + * As an implementation note, the `LoggerFactory` trait is constrained in such a way that + * this will produce `SelfAwareStructuredLogger`, rather than `DeferredSelfAwareStructuredLogger`, + * so if logging is desired it needs to be triggered using the `DeferredLoggerFactory`, rather than + * being able to trigger it from any of the produced loggers. + * + * >>> WARNING: READ BEFORE USAGE! <<< + * https://github.com/typelevel/log4cats/blob/main/core/shared/src/main/scala/org/typelevel/log4cats/extras/README.md + * >>> WARNING: READ BEFORE USAGE! <<< + */ trait DeferredLoggerFactory[F[_]] extends LoggerFactory[F] { + /** + * View the logs in the buffer. + * + * This is primarily useful for testing, and will not effect the behavior + * of calls to `log` + */ def inspect: F[Chain[DeferredStructuredLogMessage]] + + /** + * Log the deferred messages + * + * This may be called multiple times, and each log should only be logged once. + */ def log: F[Unit] override def getLoggerFromName(name: String): SelfAwareStructuredLogger[F] diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredSelfAwareStructuredLogger.scala b/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredSelfAwareStructuredLogger.scala index d1a08d2f..ab5ad332 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredSelfAwareStructuredLogger.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredSelfAwareStructuredLogger.scala @@ -33,9 +33,25 @@ import org.typelevel.log4cats.extras.DeferredStructuredLogger.{ /** * Similar to `DeferredStructuredLogger`, for `SelfAwareStructuredLogger` + * + * >>> WARNING: READ BEFORE USAGE! <<< + * https://github.com/typelevel/log4cats/blob/main/core/shared/src/main/scala/org/typelevel/log4cats/extras/README.md + * >>> WARNING: READ BEFORE USAGE! <<< */ trait DeferredSelfAwareStructuredLogger[F[_]] extends SelfAwareStructuredLogger[F] { + /** + * View the logs in the buffer. + * + * This is primarily useful for testing, and will not effect the behavior + * of calls to `log` + */ def inspect: F[Chain[DeferredStructuredLogMessage]] + + /** + * Log the deferred messages + * + * This may be called multiple times, and each log should only be logged once. + */ def log: F[Unit] override def mapK[G[_]](fk: F ~> G): DeferredSelfAwareStructuredLogger[G] = diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredStructuredLogger.scala b/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredStructuredLogger.scala index 10d46223..56c5bbed 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredStructuredLogger.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredStructuredLogger.scala @@ -43,9 +43,25 @@ import org.typelevel.log4cats.extras.DeferredStructuredLogger.DeferredStructured * } * } * }}} + * + * >>> WARNING: READ BEFORE USAGE! <<< + * https://github.com/typelevel/log4cats/blob/main/core/shared/src/main/scala/org/typelevel/log4cats/extras/README.md + * >>> WARNING: READ BEFORE USAGE! <<< */ trait DeferredStructuredLogger[F[_]] extends StructuredLogger[F] { + /** + * View the logs in the buffer. + * + * This is primarily useful for testing, and will not effect the behavior + * of calls to `log` + */ def inspect: F[Chain[DeferredStructuredLogMessage]] + + /** + * Log the deferred messages + * + * This may be called multiple times, and each log should only be logged once. + */ def log: F[Unit] } object DeferredStructuredLogger { diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/extras/README.md b/core/shared/src/main/scala/org/typelevel/log4cats/extras/README.md index ad50ed74..71a3e485 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/extras/README.md +++ b/core/shared/src/main/scala/org/typelevel/log4cats/extras/README.md @@ -1,11 +1,13 @@ -Important notes about `Writer*Logger`s -====================================== +Important caveats about the loggers in `org.typelevel.log4cats.extras` +====================================================================== + +`Writer*Logger` +--------------- The loggers provided here backed by `Writer` and `WriterT` come with some important caveats that you should be aware of before using. -General Notes -------------- +### General Notes > **Note** > These loggers tie their logs to the lifecycle of the return value, so they're generally only useful @@ -24,8 +26,7 @@ Better alternatives are provided by the `testing` module: - If a `SelfAwareStructuredLogger` is needed for test code, consider `org.typelevel.log4cats.testing.StructuredTestingLogger` over `WriterStructuredLogger` -`WriterLogger` / `WriterStructureLogger` ----------------------------------------- +### `WriterLogger` / `WriterStructureLogger` > **Warning** > Expect to lose logs if an exception occurs @@ -34,8 +35,7 @@ These are built using `Writer`, which does not directly interact with effects, s non-trivial amount of plumbing if you're planning on using them. Otherwise, if the logs don't matter in the presence of errors in the context you're using them, they're fine. -`WriterTLogger` / `WriterTStructuredLogger` -------------------------------------------- +### `WriterTLogger` / `WriterTStructuredLogger` These are built using `WriterT`, and are much easier to use with effects. Running the `WriterT` instance will yield a value of type `F[(G[LogMessage], A)]`. @@ -46,3 +46,13 @@ instance will yield a value of type `F[(G[LogMessage], A)]`. Unfortunately, because of the way that cancellation (and thus timeouts) is handled by `cats.effect.IO`, in practice `WriterT` isn't a great fit for anything which can timeout. +`Deferred*Logger` and `Deferred*LoggerFactory` +---------------------------------------------- + +The deferred `Logger` and `LoggerFactory` subclasses store their log messages in an unbounded +buffer. This is on the assumption that, if something is being logged, it matters enough to keep +around. + +This carries the risk of potentially unbounded memory usage. For example, in situations where +logging is done by code that is caught in an infinite loop. +