Skip to content

Instantly share code, notes, and snippets.

@sergkh
Last active February 2, 2023 14:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sergkh/5e36351ba5c7f75f5505422cdc9fb3c2 to your computer and use it in GitHub Desktop.
Save sergkh/5e36351ba5c7f75f5505422cdc9fb3c2 to your computer and use it in GitHub Desktop.
package com.fidesmo.logging
import cats.effect.IO
import org.typelevel.log4cats.slf4j.Slf4jLogger
import com.fidesmo.dto.RequestId
trait Logging {
import Logging._
private val logger = Slf4jLogger.getLoggerFromClass[IO](getClass())
object log {
def trace(msg: String, ctx: LogContext*): IO[Unit] =
logger.info(combine(ctx))(msg)
def debug(msg: String, ctx: LogContext*): IO[Unit] =
logger.info(combine(ctx))(msg)
def info(msg: String, ctx: LogContext*): IO[Unit] =
logger.info(combine(ctx))(msg)
def warn(msg: String, ctx: LogContext*): IO[Unit] =
logger.warn(combine(ctx))(msg)
def warn(msg: String, e: Throwable, ctx: LogContext*): IO[Unit] =
logger.warn(combine(ctx), e)(msg)
def error(msg: String, e: Throwable, ctx: LogContext*): IO[Unit] =
logger.error(combine(ctx), e)(msg)
}
}
object Logging {
type LogContext = Map[String, String]
trait ContextExtractor[T] {
def extract(t: T): LogContext
}
object ContextExtractor {
def apply[T](fn: => T => LogContext): ContextExtractor[T] = new ContextExtractor[T]() { def extract(t: T): LogContext = fn(t) }
}
implicit def tupleToContext(t: (String, Any)): LogContext = Map(t._1 -> t._2.toString)
implicit def fromExtractor[T: ContextExtractor](t: T): LogContext = implicitly[ContextExtractor[T]].extract(t)
private[logging] def combine(ctx: Seq[LogContext]): LogContext = if(ctx.isEmpty) Map.empty[String, String] else ctx.reduce(_ ++ _)
}
object Example extends App with Logging {
import Logging._
import cats.effect.unsafe.implicits.global
import com.fidesmo.models.AppId
import com.fidesmo.models.ServiceId
case class Session(appId: AppId, serviceId: ServiceId, osType: String)
// some of them can be put into scala-commons for instance
implicit val appIdContext = ContextExtractor[AppId](app => Map("appId" -> app.toString))
implicit val serviceIdContext = ContextExtractor[ServiceId](s => Map("serviceId" -> s.toString))
implicit val requestIdContext = ContextExtractor[RequestId](s => Map("requestId" -> s.id))
implicit val sessionContext = ContextExtractor[Session](s => Map("appId" -> s.appId.toString(), "serviceId" -> s.serviceId.toString(), "os" -> osType))
log.debug("Test").unsafeRunSync()
log.info("Test", AppId("0011223344"), ServiceId("test"), "customField" -> "test").unsafeRunSync()
val session = Session(AppId("0011223344"), ServiceId("test"), "JCOP 10")
log.info("Test", session, RequestId("test")).unsafeRunSync()
// Without all the magic the last example in log4cats would look like this:
// logger.info(sessionToMap(session) ++ Map("requestId" -> requestId))("message").unsafeRunSync()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment