Skip to content

Core concepts

tofu.logging consists of three main things:

This is a type class that describes how an arbitrary instance of type A should be presented in the log messages.

Loggable instances could be derived automatically using derevo:

import tofu.logging.derivation._
import derevo.derive
@derive(loggable)
case class Data(id: Long, weight: Int, name: String)

This annotation puts the instance of Loggable[Data] into the (generated if not present) companion object Data. When the message is logged, the fields of Data will be put into the result (e.g. JSON).

This derivation can be configured with annotations hidden, masked and unembed:

import tofu.logging.derivation._
import derevo.derive
@derive(loggable)
case class ClientData(name: String, surname: String)
@derive(loggable)
case class Payment(id: Long, @masked(MaskMode.Erase) cardNumber: String, @unembed name: ClientData)

A message info"This is $payment" would look like that:

{
"@timestamp": "2021-08-20T17:13:39.787Z",
"loggerName": "some-logger",
"threadName": "ioapp-compute-0",
"level": "INFO",
"message": "This is Payment: Payment{id=3234,cardNumber=...,name=ClientData{name=foo,surname=bar}}",
"id": 3234,
"cardNumber": "...",
"name": "foo",
"surname": "bar"
}

Logging[F] is a trait that describes logging capabilities of F.

trait Logging[F[_]] {
def info(message: String, values: LoggedValue*): F[Unit]
//...
}

It has a tagged version ServiceLogging[F, Service] which can be used for some Service and carry this information on the typelevel.

Trait Logs[I, F] is a factory of the Logging[F] instances which decides how created Logging will behave.

As the creation of arbitrary logging instance could potentially have some side effects, operations of this trait are effectual:

trait Logs[I[_], F[_]] {
def byName(name: String): I[Logging[F]]
def forService[Svc]: I[Logging[F]]
//...
}

The name method parameter (or type tag for Svc type parameter) is used in the underlying logger and then displayed in the log messages.

Nevertheless, some Logging instances can be created safely with no side effects, so one could use Logging.Make which creates plain Logging[F]. It uses the default backend by Slf4j and Delay typeclass.