Logger should have its own scope rather than a global wide scope on provider
quabug opened this issue · comments
consider something like this:
var foo = loggerFactory.CreateLogger("foo");
var bar = loggerFactory.CreateLogger("bar");
var fooScope = foo.BeginScope("A");
var barScope = bar.BeginScope("B");
foo.Log(...);
bar.Log(...);
barScope.Dispose();
fooScope.Dispose();
IMO, the scope of foo
and bar
should not effect each other.
The [serilog] scope is stored in the .NET ExecutionContext, which is Attached to the logical thread (and flows to child Tasks etc).
At the serilog level, you can make a contextual logger with properties attached using the .ForContext<>()
overloads - this layers a set of properties into the logger by holding them in a wrapper/decorator object that you can then pass inwards.
I'd suggest asking this as a question with some more details on what you have tried and are seeking exactly (and/or whether its critical for you to stay using the Microsoft.Extensions.Logging
APIs) on stackoverflow using a serilog
tag as you'll get way more eyes on it there than here.
The [serilog] scope is stored in the .NET ExecutionContext, which is Attached to the logical thread (and flows to child Tasks etc).
At the serilog level, you can make a contextual logger with properties attached using the
.ForContext<>()
overloads - this layers a set of properties into the logger by holding them in a wrapper/decorator object that you can then pass inwards.I'd suggest asking this as a question with some more details on what you have tried and are seeking exactly (and/or whether its critical for you to stay using the
Microsoft.Extensions.Logging
APIs) on stackoverflow using aserilog
tag as you'll get way more eyes on it there than here.
Thanks for your suggestion.
Make BeginScope
local to a logger or make it global is a design decision from my perspective.
And it is not about serilog itself, it is about how to design this BeginScope
interface.
Yes, I can achieve this by ForContext
method while creating a logger, but there's no way to call a custom ForContext
from Microsoft.Extensions.Logging
APIs, and it is practically a bad idea to create a new logger every time I need some "local" property on a logger.
I suspect it's not an either/or situation. MEL dictates a lot of how stuff works. I don't know all the details, but I can guarantee someone one SO will have a viable answer pretty quick.
and it is practically a bad idea to create a new logger every time I need some "local" property on a logger.
It's a pretty well-established pattern that's designed into Serilog. Yes, it allocates, but no, its not the same cost as making a 'new logger'.
So, in summary:
- there are two orthogonal mechanisms in Serilog, that work as designed; I'd be surprised if your situation is so unique that you have discovered a major new logging need not yet known to developers on .NET
- I am not certain how best to approach it given you are constrained by wanting to use MEL (or, I am guessing you are)
So... I'm suggesting the best place to work all this out is on SO - literally 3 people have read this now, whereas the reach on SO would be much broader. I am not trying to tell you to go away or that you are wrong to ask this - I am attempting to help you to help yourself.
Actually I have a fork of this project which make a local scope as describe here.
So this post is more like a suggestion/discussion of design decision than a question or a help needed...
Maybe the example is not clear, take this as another example:
class SomeClass
{
private ILogger _logger;
public SomeClass(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger("SomeClass"); // create a new logger with category name
_logger.BeginScope(this); // seems like push a scope into "logger", but actually a global-wide provider instead.
}
}
var foo = new SomeClass(loggerFactory);
var bar = new SomeClass(loggerFactory);
// now the scope for both foo and bar is:
// parent: foo -> child: bar
I found it is very confusion and hard to maintain a global wide scope which affect each other when I have an independent logger instance.
update: Begin/End style example
class SomeClass
{
private ILogger _logger;
private IDisposable _scope;
public SomeClass(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger("SomeClass");
}
public void BeginSometing()
{
_logger.BeginScope(this);
}
public void EndSomething()
{
_scope?.Dispose();
}
}
var foo = new SomeClass(loggerFactory);
var bar = new SomeClass(loggerFactory);
foo.BeginSomething();
bar.BeginSomething();
// now the scope for both foo and bar is:
// parent: foo -> child: bar