This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def stage1(i: Int): IO[Int] = a() | |
def stage2(i: Int): IO[Int] = b() | |
def stage3(i: Int): IO[Int] = c().withContext(_.name("op")) | |
stage1(0) | |
.withContext(_.id(0)) // MDC {id: 0} | |
.flatMap(i => | |
stage2(i) | |
.withContext(_.value(i)) // MDC {id: 0, value: i} | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class LogContext { | |
val mdc: Map[String, String] = Map() | |
def update(k: String, v: String): LogContext = ??? | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
trait DataStore[F[_]] { | |
def get(id: String)(implicit ctx: LogContext) | |
def update[T](id: String, t: T)(implicit ctx: LogContext) | |
def delete(id: String)(implicit ctx: LogContext) | |
} | |
class MongoDataStore[F[_]: Async] extends DataStore[F] { | |
override def get(id: String)(implicit ctx: LogContext) | |
override def update[T](id: String, t: T)(implicit ctx: LogContext) | |
override def delete(id: String)(implicit ctx: LogContext) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object Logging { | |
type IOLog[A] = WriterT[IO, Vector[String], A] | |
val IOLog = WriterT | |
} | |
object Test { | |
def loggedFunc(): IOLog[Int] | |
def plainFunc(i: Int): IO[String] | |
def work(): IOLog[String] = |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
trait Service { | |
def cleanAPI(i: Int): String | |
} | |
object ServiceImplementation { | |
private val ctx: ThreadLocal[String] = new ThreadLocal[String] | |
def setAdditionalArg(arg: String): Unit = ctx.set(arg) | |
} | |
class ServiceImplementation { | |
def cleanAPI(i: Int): String = { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
trait Logger[F[_]] { | |
def error(message: => String): F[Unit] | |
def warn(message: => String): F[Unit] | |
// ... etc | |
def error(t: Throwable)(message: => String): F[Unit] | |
def warn(t: Throwable)(message: => String): F[Unit] | |
// ... etc | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
trait StructuredLogger[F[_]] extends Logger[F] { | |
def error(ctx: Map[String, String])(msg: => String): F[Unit] | |
def warn(ctx: Map[String, String])(msg: => String): F[Unit] | |
// ... | |
def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] | |
def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
case class LoggingContext(map: Map[String, String]) { | |
def id(id: String): LoggingContext = LoggingContext(map + ("id" -> id)) | |
def tpe(tpe: String): LoggingContext = LoggingContext(map + ("type" -> tpe)) | |
} | |
object LoggingContext { | |
def apply(): LoggingContext = LoggingContext(Map()) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MdcLogger[F[_]: Sync](logger: StructuredLogger[F]) extends Logger[F] { | |
@inline | |
private def withCtx(f: LoggingContext => F[Unit]): F[Unit] = | |
LoggingContext.get[F].flatMap(f) | |
override def error(t: Throwable)(message: => String): F[Unit] = | |
withCtx(c => logger.error(c.map, t)(message)) | |
override def error(message: => String): F[Unit] = | |
withCtx(c => logger.error(c.map)(message)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package object logging { | |
implicit class ContextAwareSync[F[_], A](fa: F[A])(implicit F: Sync[F]) { | |
def withLogContext(f: LoggingContext => LoggingContext): F[A] = | |
F.bracket { | |
LoggingContext.update(f) | |
} { _ => | |
fa | |
} { old => |