-
Notifications
You must be signed in to change notification settings - Fork 81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Slf4j bridge - fiber propagation #718
Conversation
@justcoon Great working pushing this forward! I think the question here is whether we need to support propagating all If we really do want to support propagating all |
@adamgfraser also user of library itself can create own FiberRef, which may be used in logging but i am not sure if there are some functions in |
@justcoon Okay, I think we can propagate the object Example extends ZIOAppDefault {
/**
* Accesses the current `FiberRefs` of the fiber executing this code. This
* will only return the current `FiberRefs` if called from code being
* executed by a ZIO fiber with `RuntimeFlag.CurrentFiber` enabled.
*/
def unsafeGetFiberRefs()(implicit unsafe: Unsafe): Option[FiberRefs] = {
val currentFiber = Fiber._currentFiber.get()
if (currentFiber eq null) None
else Some(currentFiber.unsafe.getFiberRefs())
}
override val bootstrap =
Runtime.enableCurrentFiber
val run =
for {
fiberRef <- FiberRef.make(0)
_ <- fiberRef.update(_ + 42)
_ <- ZIO.debug(unsafeGetFiberRefs()(Unsafe.unsafe))
} yield ()
} |
docs/slf4j1-bridge.md
Outdated
@@ -41,6 +41,10 @@ import zio.logging.consoleJsonLogger | |||
val logger = Runtime.removeDefaultLoggers >>> consoleJsonLogger() >+> Slf4jBridge.initialize | |||
``` | |||
|
|||
To enable log annotations and span propagation to underlying code which using SLF4J api, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we build the current fiber integration integration into an existing layer such as Slf4jBridge.initialize
? It is great to have the ability to customize when necessary but it is also good to make common use cases easy and enableCurrentFiber
is really an implementation detail where if the user is going to do something that requires it (basically propagating context from FiberRef
values to ThreadLocal
values we should just do it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think we can put it to Slf4jBridge.initialize
however there should be option to disable that as enableCurrentFiber
may have impact to performance
which probably ends in something like
object Slf4jBridge {
def initialize(propagateFibers: Boolean = true): ZLayer[Any, Nothing, Unit] = ???
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. I might split it into two layers so it can be a val
and you don't need the empty parentheses when you call it.
object Slf4jBridge {
val initialize: ZLayer[Any, Nothing, Unit] =
???
val initializeWithoutFiberRefPropagation: ZLayer[Any, Nothing, Unit] =
???
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i added layers as you proposed, probably it is good that this propagation is enabled by default,
however it is also changing default behavior
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@justcoon Sounds good.My thought is that EnableCurrentFiber
is necessary for integration between FiberRef
and ThreadLocal
values and that is exactly what you are asking us to do with the Slf4jBridge
so that makes sense as the default and will give the "correct", though potentially not as performant value, so that should be the default. But if you think we should do it the other way definitely open to your thoughts on that.
Otherwise looks good to me subject to my comment about avoiding unnecessary ZIO workflows which we will handle separately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thank you very much for hints and review
@@ -43,7 +43,13 @@ class ZioLoggerFactory extends ILoggerFactory { | |||
private[impl] def run(f: ZIO[Any, Nothing, Any]): Unit = | |||
if (runtime != null) { | |||
zio.Unsafe.unsafe { implicit u => | |||
runtime.unsafe.run(f) | |||
runtime.unsafe.run { | |||
val fiberRefs = Fiber.currentFiber().map(_.asInstanceOf[Fiber.Runtime[_, _]].unsafe.getFiberRefs()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are within the ZIO name space so you could just use _currentFiber
here to avoid the need for the cast. I will also look at specializing the return type of currentFiber
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i changed it slf4j v2 bridge to use _currentFiber
, as it is in zio namespace
runtime.unsafe.run { | ||
val fiberRefs = Fiber.currentFiber().map(_.asInstanceOf[Fiber.Runtime[_, _]].unsafe.getFiberRefs()) | ||
fiberRefs match { | ||
case Some(fiberRefs) => ZIO.setFiberRefs(fiberRefs) *> f |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This pattern of running a ZIO workflow just to log something is not very efficient. We can get the current loggers from the current FiberRefs
and then we can just use those loggers to log directly without going through a ZIO workflow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, i think you are right, we can probably do it better,
probably by using Fiber.log
but i propose to do it in next PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Much cleaner without the need for any new operators!
Made a couple of suggestions for further improvements.
FiberRefs
propagation usingThreadLocal