-
Notifications
You must be signed in to change notification settings - Fork 2
Guarantee LoggingBaggageContextCarrier Logger metadata includes baggage #28
Comments
I know what you mean, it is up to the context's implementor to implement the context object "right" and you don't trust "them" (whoever implements the context object). That's fair but making the dance more and more explicit esp if we have End users should not be forced to think, ever, they should have only one thing to call and it should do the right thing. This is the rationale behind offering only It is better for force "do the right thing" on a few library authors, than every single use-site of such library. There are many users of swift who are new to a) programming b) swift or c) server systems, and they already have a lot to think about -- let's make the "i got some logger here, i'll just use it" the obvious and right thing to do. No more thinking if it's with or without baggage etc. The contexts should do the right thing. |
What is the end user going to be doing more though? Is it accessing the contents of a BaggageContext or creating BaggageContext to be passed down to another system. If it is the second then there is more of a chance they will create their own BaggageContext struct and then we have to trust they will set it up correctly. I'm not sure we can limit the creation of these objects to a few library authors. One other issue to take into account would be if I have a BaggageContextCarrier generated by library A and I want to generate the BaggageContextCarrier required for library B which includes additional context (maybe an EventLoop). I only have access to the Logger augmented with additional metadata from the BaggageContext in library A. So I would end up creating the library B BaggageContextCarrier with an augmented Logger plus the original BaggageContext. Library B BaggageContextCarrier would be carrying library A BaggageContext in both the Logger metadata and its BaggageContext. And when you ask for the Logger from library B it will attempt to augment an already augmented Logger. I hope that makes sense. |
Most often? Neither really: just keep passing it along. You get a baggage context on the "outermost" layer of some "call" or from a framework and you keep passing it around. At the "edge", meaning in an http request "handler" or in the "cli app main()" or somewhere like that you make a decision:
The They could pass that one and the name // defined in BaggageLogging
struct DefaultContext: BaggageContext, LoggingContext {
private let _logger: Logger
var logger: Logger { self._logger.with(baggage) }
var baggage: Baggage
init(logger: Logger, context: BaggageContext) { ... }
} Please also see and chime in here: #23 Disclaimer: My personal opinion is that using context for anything "required" as such to smuggle values between libraries is abusing the API, but there has been enough requests to consider doing this for With that in mind, let's explore your case:
To be honest this is where the abuse of the context parameters starts to creep in, but let's explore this in depth first.
You say "generated", but can we be specific what you mean? I suspect you mean "declared a specific context type and it accepts it in APIs"? This is wrong, it will not compose, specifically this:
Sounds to me like you are talking about "specific context types" This is not what APIs should accept. They can only accept the "reusable" ones, and declare what they want as If you then are: let c: LibA.Context // LoggingBaggageCarrier
func libB(context: LoggingBaggageCarrier & EventLoopPreferenceCarrier) then indeed one has to "create" the new one, however we can deal with this: import EventLoopPreferenceContext // however we'd call this...
// automatically conforms any Carrier
Yes, though... that is expected and has expected semantics as well though, doesn't it? context.baggage.value = "xxx"
var otherContext = DefaultContext(context.logger, context.baggage)
otherContext.baggage.otherValue = "yyy"
otherContext.logger.info() // value=xxx, other-value=yyy is the expected and correct outcome IMHO. Do you think otherwise or did I misunderstand your example? As a side note: yeah those "Carrier" things complicate things a bit... if it were up to me I guess we'd a) only carry baggage b) create loggers ad hoc and force them to accept a baggage c) logging to remove metadata; But that's a too drastic change to happen over night, so we're exploring the I don't have all the answers here, so thank you very much for the tickets and let's keep the discussion going. |
Instead of describing what is the issue I'll write some code. Here is LibA that is my framework. It has it's own Context struct which conforms to
Here is LibB my service library. Again it has a Context but this time it also conforms to EventLoopPreference as well as LoggingBaggageContextCarrier.
Here I create my framework and add a route that uses the
I need to create a new context to send to Maybe you should just disallow the construction of context carriers with other variables outside of the By providing a protocol instead of a struct though you are implying that the BaggageContextCarrier object can contain whatever you want (as long as it conforms to protocol). Also if you provide a struct (instead of, not in addition) you can resolve the original issue where you have to trust the creator of the BaggageContextCarrier object has set it up correctly. |
Sorry for being slow to come back here, digesting and looking at some other related things :) At the very heart of I'd I'd be absolutely on board with:
Indeed! As just context and logger must be married to oneother and pushing anything else into carriers is more an outcome of some frameworks who'd like to do that, but really it becomes hard to tame and "where does it end?" then... I think that would perhaps be our way... I will think some more soon, though likely only next week -- thank you for the use cases and discussions! |
+1 |
I think I've clarified a bit in my head and through discussions with people and this thread as well what we should be doing... really simplifying down to the metal here. I'll post a proposal PR hopefully tomorrow, thanks! |
With the current implementation of
LoggingBaggageContextCarrier
there is no guarantee that theLogger
it holds includes the baggage in it's metadata. It is down to the library author to ensure this is the case.If I accept a
LoggingBaggageContextCarrier
as a parameter to an interface function I cannot guarantee when I ask for the logger I will get a logger with metadata augmented with the baggage. Maybe it would be better to make it clearer and add aloggerWithBaggage
variable as an extension instead of assuming the baggage will be added to the Logger metadata.The text was updated successfully, but these errors were encountered: