Logging from disconnected Business logic
Hey all, I have an outstanding requirement that I've played around with off and on over the last few months.
I have a LoggingService that handles communicating errors to backend servers, writing to file, etc. The log server has a LogServiceInstance for each job running and it captures messages to specific locations based on the jobs context. The jobs run through a bunch of code I have control of (The job manager, the job service, etc.) All of that is fine and I can obviously capture the log records to the proper places. The actual business logic has it's own class (LogWriter) that I have subjugated to write to actions I subscribe to (SystemLog and ServiceLog) , much of this business logic is not controlled by me, so all of that code just instantiates a new LogWriter() whenever it needs to write a message. They don't have any idea what the job id, log id, or anything I use to direct the logs from within that business logic. Any ideas on what I could try to capture these messages, The closest I ever got was with AsyncLocal, but when you got deep enough it would eventually lose the context and go back to writing to the system log because the async context would change. It runs multiple jobs at once so I can't just use a singleton or static (unless there is some trick to it I don't know) I can't pass the log id into the business logic, It has to work with new LogWriter() and they call it whenever they need to so that's where this get's challenging. There may not be an easy solution or I might have gotten to the point where the obvious solution is just evading me.. so hoping someone has an idea of something I can try. Thank you in advance!
I have a LoggingService that handles communicating errors to backend servers, writing to file, etc. The log server has a LogServiceInstance for each job running and it captures messages to specific locations based on the jobs context. The jobs run through a bunch of code I have control of (The job manager, the job service, etc.) All of that is fine and I can obviously capture the log records to the proper places. The actual business logic has it's own class (LogWriter) that I have subjugated to write to actions I subscribe to (SystemLog and ServiceLog) , much of this business logic is not controlled by me, so all of that code just instantiates a new LogWriter() whenever it needs to write a message. They don't have any idea what the job id, log id, or anything I use to direct the logs from within that business logic. Any ideas on what I could try to capture these messages, The closest I ever got was with AsyncLocal, but when you got deep enough it would eventually lose the context and go back to writing to the system log because the async context would change. It runs multiple jobs at once so I can't just use a singleton or static (unless there is some trick to it I don't know) I can't pass the log id into the business logic, It has to work with new LogWriter() and they call it whenever they need to so that's where this get's challenging. There may not be an easy solution or I might have gotten to the point where the obvious solution is just evading me.. so hoping someone has an idea of something I can try. Thank you in advance!
7 Replies
So is the job id etc. known from top-down? In that case I could imagine you can create a dedicated logger which receives some of these enrichements and just appends them to whatever is being logged on that specific instance
Kind of what ILogger<T> does with scopes
Yeah, the problem I run into is
Job1 ->
ServiceInstance - Initial LogWriter AsyncLocal is instanciated and actions are subscribed to and message logged here work perfectly fine ->
BusinessLogicA -This is an entirely different classlibrary and may call any number of other business logic classes all of which use the generic new LogWriter();
So I have it all, up until I leave that AsyncLocal Class. Those business logic classes which are millions of lines of code, have no idea what a job number or log id is
Does it have to be an AsyncLocal though, or could you also just pass this context as a concrete parameter to a sub-logger so it could survive past async execution context flow boundaries?
It doesn't have to be AsyncLocal, I just can't modify all of the business logic classes. They pretty much have to operate with just new(). Unfortunately they weren't created with any real structure so no BaseClass I can just add the log or job id to
Ohh, I see, the "new LogWriter()" is actually being instantiated by the code outside of your control. I thought you would just pass this onto this code and you might be able to hide the log context under an API which does not make any of these concerns public, but if you're not in control of what's being passed around...
So there's no chance you're able to tweak the instantiation of these logwriter (embedding the context in a factory or a service locator), or touching any of the underlying layers?
I wish, there is literally thousands of them I'd have to modify and test unfortunately. It might end up being what I (well, someone) has to do, but I was hoping to find a less tedious solution. At least at that point it could be redesigned to follow a better pattern.
Yeah, that sounds very tricky. I guess in the long run migrating to ILogger is a good bet in general