Simple logging for your services
Key features
Supported for every popular style
You can use tofu.logging
in any style you want:
- Tagless Final style;
- Simple
cats.effect.IO
or(monix|zio).Task
andReaderT
; ZIO
and ZLayers — with the help of dedicated moduletofu-zio-logging
andZLogs
;- Even with
Future
s (although it's kinda in the past).
Concise syntax
With the implicit instance of Logging
one can log messages with ease:
import tofu.logging._
import tofu.syntax.logging._
val error = new Throwable("Oh no.")
def log[F[_] : Logging : Monad] = for {
_ <- info"Hi! I'm logging"
_ <- warn"Hello again!"
_ <- error"It's me, error!"
_ <- errorCause"So sad, I've got an error"(error)
} yield ()
Structured and controllable
You can easily put any necessary values into the structure of the log message with Loggable
; also you can fully
control what is logged and what is not:
import derevo._
import tofu.logging._
@derive(Loggable)
case class Payment(id: String, @hidden cardNumber: String, amount: Long)
def log[F[_] : Logging : Monad](payment: Payment) = info"Got payment $payment"
Given that there's a defined Loggable
instance for this context and provided logger is context aware (e.g. created
with contextual
method), every logged message will contain information about context, for example:
{
"message": "Got payment payment",
"level": "INFO",
"payment": {
"id": "131234234",
"amount": 432
}
}
Note that card number is not present at all as it was @hidden
.
Context support
Let's say your effect type has some context — it could be trace id or some domain info:
import cats._
import cats.effect._
case class TraceId(id: Long)
type TracedIO[A] = ReaderT[TraceId, IO, A]
tofu.logging can extract it and automatically add into the structure of every log message:
class MyService[F[_] : Logging] {
def sayHello: F[Unit] = info"Hello!"
}
val ioservice = new MyService[IO]
val tracedService = new MyService[TracedIO]
(Note the absence of anything related to context in MyService, logging doest it all itself.)
Now if we run tracedService.sayHello
the log message structure will contain the trace id:
{
"message": "Hello!",
"level": "INFO",
"trace.id": 64534
}
and if we run ioService.sayHello
the message will be clean:
{
"message": "Hello!",
"level": "INFO"
}
More on that can be found on the dedicated recipe page.