SignallingRef
Resource
with Fiber
cancellation works as well, I think it's almost single liner or smth
AsyncLogger
example:
Resource
.make {
for {
queue <- ConcurrentQueue.withConfig[F, LoggerMessage](queueCapacity, ChannelType.MPSC)
logger = AsyncLogger(queue, timeWindow, inner)
fiber <- logger.runF //it returns a fiber with inf timer loop
} yield {
(fiber, logger)
}
} {
case (fiber, _) => fiber.cancel //on resource release we should cancel the fiber
}
.map {
case (_, logger) => logger
}
WIP
for now, but the main logic is there. I will try to finish this next week.
I didn’t call it directly. I have a function logAndReturn
that takes error: SomeError
and return SomeError
. In this function, I call Logger[F].error
to log error messages and then return SomeError
.
So in the service layer for instance, when logAndReturn
is called, className/functionName of WithLogger#logAndReturn
is printed out. But I want the service className is printed out
def logAndReturn(e: SomeError)(implicit pos: io.odin.meta.Position): F[SomeError]
Essentially, in the case when implicit is missing it's automatically derived here:
https://github.com/valskalla/odin/blob/master/core/src/main/scala/io/odin/meta/Position.scala#L14-L24
using macro of sourcefile library
I modified the Position like thisobject Position {
implicit def derivePosition(
implicit fileName: sourcecode.File,
packageName: sourcecode.Pkg,
line: sourcecode.Line
): Position = io.odin.meta.Position(fileName.value, fileName.value, packageName.value, line.value)
}
and I got the className printed out as I want.
Thank you so much :)
Hi @bi0h4ck
You have couple of options.
One is to pass around Logger[IO]
(or any other effect) and call it with finalizing .unsafeRunSync()
(or async version) to evaluate right away. That way you might use the single instance of logger which would make your life easier.
Or use slf4j with LoggerBinder:
https://github.com/valskalla/odin#slf4j-bridge
F
as long as possible, because logging itself is a side-effect and it's way easier to i.e. test it when you have each call as a value
WriterTLogger[WriterTIO]
can't be assigned as a Logger[WriterTIO]
@kubukoz
Nope, there is no logstash integration. At Zalando we ship logs with a separate agent as a part of Kubernetes deployment, so it never was a priority for us to have such functionality in this lib.
However, it's not the first time I hear that question, so I'm open for contributions :)
@kubukoz
I think I solved that issue with StaticLoggerBinder
.
You need a plain Java class:
package org.slf4j.impl;
import oh.boi.ExternalLogger;
public class StaticLoggerBinder extends ExternalLogger {
public static String REQUESTED_API_VERSION = "1.7";
private static StaticLoggerBinder instance = new StaticLoggerBinder();
public static StaticLoggerBinder getSingleton() {
return instance;
}
}
together with a Scala one:
package oh.boi
import cats.effect.{ContextShift, Clock, Effect, IO, Timer}
import io.odin._
import io.odin.slf4j.OdinLoggerBinder
import scala.concurrent.ExecutionContext
class ExternalLogger extends OdinLoggerBinder[IO] {
val ec: ExecutionContext = scala.concurrent.ExecutionContext.global
implicit val timer: Timer[IO] = IO.timer(ec)
implicit val clock: Clock[IO] = timer.clock
implicit val cs: ContextShift[IO] = IO.contextShift(ec)
implicit val F: Effect[IO] = IO.ioEffect
val loggers: PartialFunction[String, Logger[IO]] = {
case "some.external.package.SpecificClass" =>
consoleLogger[IO](minLevel = Level.Warn) //disable noisy external logs
case _ => //if wildcard case isn't provided, default logger is no-op
consoleLogger[IO]()
}
}