package com.hunorkovacs.catsi import cats.effect.Sync import cats.Applicative import org.log4s.{getLogger, Logger => Log4sLogger} trait Logger[F[_]] { def trace(str: String): F[Unit] def debug(str: String): F[Unit] def info(str: String): F[Unit] def warning(str: String): F[Unit] def error(str: String): F[Unit] def error(str: String, t: Throwable): F[Unit] val underlying: Option[Log4sLogger] def to[G[_] : Sync]: Logger[G] def subLogger(name: String): Logger[F] } object Logger { def apply[F[_] : Logger]: Logger[F] = implicitly[Logger[F]] def logger[F[_] : Sync](name: String): Logger[F] = loggerInst[F](getLogger(name)) def loggerInst[F[_] : Sync](log: Log4sLogger): Logger[F] = new Logger[F] { override val underlying: Option[Log4sLogger] = Some(log) override def trace(str: String): F[Unit] = Sync[F].delay { log.trace(str) } override def debug(str: String): F[Unit] = Sync[F].delay { log.debug(str) } override def info(str: String): F[Unit] = Sync[F].delay { log.info(str) } override def warning(str: String): F[Unit] = Sync[F].delay { log.warn(str) } override def error(str: String): F[Unit] = Sync[F].delay { log.error(str) } override def error(str: String, t: Throwable): F[Unit] = Sync[F].delay { log.error(t)(str) } override def to[G[_] : Sync]: Logger[G] = loggerInst[G](log) override def subLogger(name: String): Logger[F] = loggerInst(getLogger(s"${log.name}.$name")) } def noop[F[_] : Applicative]: Logger[F] = new Logger[F] { override def trace(str: String): F[Unit] = Applicative[F].unit override def debug(str: String): F[Unit] = Applicative[F].unit override def info(str: String): F[Unit] = Applicative[F].unit override def warning(str: String): F[Unit] = Applicative[F].unit override def error(str: String): F[Unit] = Applicative[F].unit override def error(str: String, t: Throwable): F[Unit] = Applicative[F].unit override val underlying: Option[Log4sLogger] = None override def to[G[_] : Sync]: Logger[G] = null override def subLogger(name: String): Logger[F] = this } }