Contextual logging
Contextual logging is provided by LoggingContext
typeclass.
LoggingContext
is a typeclass, as its name suggest, provides propagation of logging context across multiple loggers and
log messages. It allows you to add additional arguments to all log messages produced inside given code block. Typical
example is Correlation-Id
(sometimes also known as Trace-Id
) HTTP header. When an HTTP request comes in, we assign
unique random string to it (Correlation-Id
). Using LoggingContext
we can easily make sure that this string appears in
all log messages related to the HTTP request.
There are plenty use cases where you might want to include common argument in all related log messages: user id, file name or any other entity.
Here is a simple example:
import cats.Monad
import cats.syntax.all._
import slog4s._
def foo[F[_]:Monad:LoggingContext](loggerFactory: LoggerFactory[F]): F[Unit] = {
val logger = loggerFactory.make("foo")
LoggingContext[F].withArg("correlation_id", "generated-correlation-id")
.use {
logger.info("Hello from foo!") >> bar(loggerFactory)
}
}
def bar[F[_]:LoggingContext](loggerFactory: LoggerFactory[F]): F[Unit] = {
val logger = loggerFactory.make("bar")
logger.info("Hellow from bar!")
}
No we just need to get LoggingContext
and LoggerFactory
instances. We will use slf4j module for that. We will also
use ReaderT[IO, Slf4jArgs, ?]
as our effect type because the implementation requires our effect implement
ApplicationLocal
typeclass. There are more efficient implementations for different effect types that relies on other
mechanisms (for curious ones: it TaskLocal
for Monix and FiberRef
for ZIO)
import cats.data._
import cats.effect._
import cats.mtl.instances.local._
import slog4s.shared._
import slog4s.slf4j._
type Result[T] = ReaderT[IO, Slf4jArgs, T]
val loggingRuntime = Slf4jFactory[Result].make(ContextRuntime[Result, Slf4jArgs])
import loggingRuntime._
No we can finally run it:
// we start with empty additional arguments
foo(loggerFactory).run(Slf4jArgs.empty).unsafeRunSync()
Output:
{
"@timestamp" : "2023-02-24T17:57:19.521+01:00",
"@version" : "1",
"correlation_id" : "generated-correlation-id",
"file" : "contextual-logging.md",
"level" : "INFO",
"level_value" : 20000,
"line" : 30,
"logger_name" : "foo",
"message" : "Hello from foo!",
"thread_name" : "Thread-18"
}