-
Notifications
You must be signed in to change notification settings - Fork 103
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
.NET Core 2.0 minimum level handling/roadmap #98
Comments
Couple notes:
|
👍 Btw, plain upgrade to .net core 2.0 preserving |
@skomis-mm: But on WebHostBuilder().ConfigureLogging(...) with asp.net core 2.0 you don't have direct access to |
Thanks for all the weigh-in, folks! I think the extra I've done some more digging, and have had good results with: public static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console(theme: AnsiConsoleTheme.Code)
.CreateLogger();
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.ConfigureServices(collection => collection.AddSingleton<ILoggerFactory>(new SerilogLoggerFactory()))
.Build();
host.Run();
}
Why I like this:
Factory: public class SerilogLoggerFactory : ILoggerFactory
{
readonly SerilogLoggerProvider _provider;
public SerilogLoggerFactory(Serilog.ILogger logger = null, bool dispose = false)
{
_provider = new SerilogLoggerProvider(logger, dispose);
}
public void Dispose()
{
_provider.Dispose();
}
public ILogger CreateLogger(string categoryName)
{
return _provider.CreateLogger(categoryName);
}
public void AddProvider(ILoggerProvider provider)
{
SelfLog.WriteLine("Ignoring added logger provider {0}", provider);
}
} I'm going to PR the quick-fix into 2.0, and create another PR with the factory and updated docs for a 3.0. Thoughts/feedback welcome 👍 |
Updated public static int Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console(theme: AnsiConsoleTheme.Code)
.CreateLogger();
try
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.UseSerilog()
.Build();
host.Run();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Unhandled exception");
return 1;
}
finally
{
Log.CloseAndFlush();
}
} |
I think you'd want |
Would it be a terrible idea to have an overload That way, the configuration we give you in the lambda can be preconfigured with some sensible M.E.L defaults. It feels like a way to encourage people into the happy path of making sure the basic settings aren't going to get in their way, but still gives them all the necessary opt-outs. |
Yes, coupling serolig to our host would be terrible. |
@anurse thanks for the ideas! The minimum level is just an example - could use anything in there 👍 - I've just PR'd an updated sample showing how this can work with JSON config as well: https://github.com/nblumhardt/serilog-extensions-logging/blob/a95aed3de69f18e3e36019afb53b26dab84a2282/samples/SimpleWebSample/Program.cs The advantage of creating the Serilog logger outside of all the web hosting/DI stuff is that a lot of failures really do happen early in start-up, and this way we can log them. (Throwing constructors, DI registration problems, type loading problems...).
What kinds of defaults do you mean? Serilog already has its own sensible defaults, which would apply here :-) @davidfowl thanks for taking a look. I think the UX is the right one; we might want to ship it in a separate package, but, there's no reason for Serilog to have a clunkier experience than AI (with its |
@nblumhardt I would vote against replacing These integrations are combination of hosting startup and logger providers being resolved from DI by |
Hey @pakrym - thanks for the feedback.
The user can opt into these through Serilog, e.g. https://github.com/serilog/serilog-sinks-applicationinsights, and via the file logger for Azure App Services. It's cool to have it all set up out of the box, but in the balance vs. a better Serilog experience for all sinks, it seems like requiring an extra LOC for AI integration is pretty reasonable. We've so far done everything we can to make the MEL/Serilog experience great for everyone regardless of sinks, preferred APIs, etc., and if there's a better way we can give this experience I'm all-in to support it. MEL v2 seems to be a step back for user experience with Serilog, though, so I really want to fix that ahead of all other considerations. Right now replacing the Although MEL's heading much more towards being an implementation, rather than a facade, in v2, can we reverse that trend? What would it take to offer Serilog as an option for the core log routing/handling out of the box? Could we still enable things like AI integration by default? Definitely open to ideas. |
(Footnote: exploring the case for enabling Serilog as a first-class option out-of-the-box: https://www.nuget.org/packages?q=Tags%3A%22serilog%22 - there's a tonne of functionality out there we could help people connect with, instead of reinventing all of this all over again for MEL.) |
Thats a big hammer. I'd rather work on fixing anything we can tactically and telling people to use the existing ILoggerFactory extension method rather than doing this.
A few things come to mind:
What's the benefit here? I'm not sure this saves anything. |
Another thing that is worrying about relying too much on a single implementation is that the abstraction needs to be flexible enough to work for multiple logger provider implementations (like DI). That obviously can be solved even if serilog is the "default" choice. |
In my mind, when using Serilog purely as a sink for M.E.L, you'd want the Minimum Level filter "removed" (or set to the broadest form) from Serilog, because it's really confusing to have to deal with both versions. That's what I'm referring to with sensible M.E.L defaults.
How is a |
Thanks for all the replies, appreciate you taking the time. Here are my thoughts:
👍
That's the problem here, though - once MEL implements its own levels, filters and so-on, it's another implementation, not an abstraction. Being able to swap in Serilog completely (even as an option, not necessarily a default), would help keep assumptions about the logging implementation explicit.
I'm assuming that having AI out of the box is one of the goals of the experience, or at least the template. Being able to meet those goals (or whatever other aims there are for the default experience) while relying on another logging implementation seems like it will be important.
As a framework user, here's what I want, personally, out of logging and the framework in general:
If using Serilog means effectively running two logging frameworks in process, it's going to be a hard sell. People are already very sensitive about complexity and perf in the logging pipeline. Ditto for correctness - if my logging works one way through MEL's interfaces, and another way through Serilog's, how am I going to be sure my logging is actually working correctly? Removing Serilog from the equation here would be the only way to ensure all logging ends up at the intended targets. You can see what I'm getting at here - any intrinsic penalty for using Serilog will seriously hurt this project in the long run. Even this would be defensible if the alternative was equally functional - but in reality, users will end up making do with a currently much less capable logging solution just to remove the friction and complexity that the APIs would force upon us. Where things stand right now, it seems like the only solution likely to work is to support a world where users can choose MEL, Serilog, or NLog on equal terms. Replacing Hence it'd be great to turn the discussion towards: if we're going to have Serilog, MEL and NLog on an equal footing, what problems does that create for anyone else, and how can we (Serilog, NLog, others) help to solve them? |
Just re-reading:
In case that is easy to read the wrong way :-) I don't mean to shut down the discussion, only that there's another way to look at this that could be more fruitful. |
I don't buy that conclusion. We went down this path in the beginning of 2.0 and it broke scenarios where existing providers (like app insights and EF) had to know what logger factory was registered so that they could add the right provider. It's very similar to DI in that, if a library needs add registrations to the container, they don't want to write bindings for each DI container. What you're suggesting takes us down that path and I don't think it's a very successful one. |
Thanks for the follow-up. Just so I can understand your point better - I know about the AI provider but haven't looked at any for EF. Where does EF integrate into the logging pipeline currently? |
A few thoughts. In the Serilog ecosystem, we often see users choose to use Serilog and go all in. Previously I have viewed a log provider analogous to a Serilog Sink (please correct my understanding), and as such it is a similar construct. I have not seen many instances that attempted to use MEL, with multiple providers and Serilog with multiple sinks. e.g.
Rather, they opt to setup Serilog and extend from there. e.g.
As such, I think we should have hooks/sytantic sugar to get a developer up and running in this way. In this case Secondly, I am trying to understand how this discussion relates/impacts the alternative setup mentioned here Most of this discussion has focused around the use of the following:
Are there any considerations required for the e.g.
Finally, there seems to be an undertone/push to preserve previous AI integration work that occurred in 1.x. It has been mentioned a few times in the comments above. Is there any reason for this? |
You may not have seen it but it happens all of the time. The moment a library needs to consume logs you're in a bind. That library now needs to know what logger factory was configured by the application in order to work.
The undertone is about libraries that want to consume logs without knowing about a specific logger implementation. Right now you can produce logs by using Now, if there was no provider abstraction for MEL at all the you would always need another library (like serilog) to consume. FWIW we went deep down this rabbit hole early in 2.0 aspnet/Logging#420 (comment). We came to the conclusion that it was too breaking with low ROI. Finally see aspnet/Hosting#1071 for the issue I described above. |
Thanks @davidfowl for the concrete example. |
Thanks guys. There's a lot of history, and many rabbit-holes already explored, but we still need to course-correct:
Problem (4.) isn't enough to discount (3.) as a way forward. .NET Core is all about being lean-and-mean. A healthy ecosystem requires that Serilog, NLog and others can provide a completely first-class developer experience without friction or bloat. It's (5.) we have to fill in. As at v2, we're all okay: we can merge #101 and provide It's not clear if there will be any high-level scenarios we miss: Serilog's had AI integration for ages, for example, and we can look at PRs to close any gaps. Right now, Serilog supports many, many providers, including AI, the console (with JSON highlighting and themes!), event log, etc. On the configuration side, we support not just As a fallback, we also provide integration with So... I think we should review and merge #101 ASAP. Following on close behind, though, we should:
Sounds like a plan? |
That sounds good! We'll be able to keep parity with what 1.0 has today.
This line of code is the problem https://github.com/serilog/serilog-extensions-logging/pull/101/files#diff-76102dabbdfef9091d353926bc8bdfb8R42. People that call UseSerilog will all of a sudden break the end to end AI integration experience we expose, but maybe that's fine as it isn't the default OOTB story. You'll also break EF's internal logging infrastructure https://github.com/aspnet/EntityFrameworkCore/blob/f4c9f4c4be0e6f159506e583eda0ba68536356b2/src/EFCore.Design/Design/Internal/DbContextOperations.cs#L101. It'll also break anybody else calling AddProvider in their Startup class. As part of this change you should decide if this should throw rather than no-op. I don't know what's better, I can only tell you we've been down this road and it wasn't worth the effort. |
In the EF case, it seems like they'd continue to work if we just forwarded everything straight through to them.... I wonder if that's option 3? (EF subscribing to logs itself is a really weird integration, BTW - are they trying to do correlation on behalf of the log collector? I need to learn more about what's going on in there..) |
(Just waking up the tree, it looks like the EF stuff is design-time , so may not turn out to be too much worry. I'll flick them a note/link to this discussion anyway. Thanks!) |
I just want to say UseSerilog is not useful to me as someone who wants to use MEL, I just needed a sync from Serilog. I have other syncs like Console and AI that I want to use MEL, only for special elastic search do I need serilog. |
The current provider works with .NET Core 2.0, but the APIs have shifted since the 1.x version and I'm not confident we've got a decent story here now.
.NET Core 2.0 has its own internal "minimum level" that will be set to Information regardless of what we do in Serilog, unless we play in the JSON configuration system introduced with that version:
datalust/seq-extensions-logging#22
The net effect will be that apps using Serilog today will have to either separately specify
ILoggingBuilder.SetMinimumLevel()
in addition to the Serilog minimum level, or add a"Serilog.Extensions.Logging.SerilogLoggerProvider"
element to the"Logging"
configuration section in appsettings.json with level configuration specific to Serilog, even if this duplicates what's already been set throughLoggerConfiguration
.(We can improve this experience by adding
[ProviderAlias("Serilog")]
toSerilogLoggerProvider
, but, it just wins us a shorter key under"Logging"
, no other improvement in level handling.)The conundrum we're facing is: the Serilog level and level overrides are set via
LoggerConfiguration
. When we callloggingBuilder.AddSerilog()
, we don't communicate to .NET Core that we're handling our own levels. So, the framework will apply anInformation
filter, regardless.I'm not sure what ways forward are open to us; it doesn't look like .NET Core 2.0 allows any level configuration to take place via Serilog (
MinimumLevel
,MinimumLevel.Override()
) without the user duplicating all of that configuration now throughMicrosoft.Extensions.Logging
's APIs.(About all I can come up with is taking the nuclear option and completely replacing the whole logging subsystem with a Serilog one, but that will paint us into a corner of another kind.)
Needing some guidance here - any help appreciated @pakrym @davidfowl & co.
The text was updated successfully, but these errors were encountered: