Skip to content

Instantly share code, notes, and snippets.

View vhutov's full-sized avatar

Vladyslav Hutov vhutov

View GitHub Profile
class WrappedRunnable(runnable: Runnable, context: LoggingContext) extends Runnable {
override def run(): Unit = {
LoggingContext.localContext.value = context
runnable.run()
}
}
object Concurrent extends IOApp {
override def run(args: List[String]): IO[ExitCode] = {
(0 to 10).toList
.parTraverse(run)
.as(ExitCode.Success)
}
object Sequential extends IOApp {
private val log: Logger[IO] = Slf4jLogger.getLogger[IO].mdc
override def run(args: List[String]): IO[ExitCode] = {
for {
_ <- log.info("Start")
user <- op.withLogContext(_.id("1"))
_ <- log.info(s"result: $user")
_ <- log.info("End")
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 =>
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))
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())
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]
}
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
}
@vhutov
vhutov / ThreadLocalExample.scala
Created February 2, 2020 13:28
ThreadLocalExample
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 = {
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] =