The logging methods have changed. We no longer take in caller information using compiler services, but a set of parameters used to format log messages. In practice this is a non-breaking change (apart from a few very rare places we used the logger in a special way).
The change was done to support the modern logging styles of popular frameworks, that use template and arguments to create richer logs. So instead of writing e.g. _logger.Information($"Hello from {sender}") which produces a string, the new style enables _logger.Information("Hello from {sender}", sender) which can produce different types of logs depending on the underlying implementation.
The loggers are now typed - meaning that they are linked to a type that produces the log messages. This allows more familiar filtering mechanisms, than based on filename. In practice this means that there is a new ILogger<T> interface that can be used explicitly, or is used under the hood with dependency injection. The DI is setup so that it takes the declaring type as the type parameter when using the ILogger interface. In rare circumstances when the normal DI container is not used (e.g. AspNetCore middlewares) - it is not possible to determine the declaring type, so a special ILogger<UnknownLogMessageSource> that writes an extra warning to the logs is bound to ILogger in the container, and will be used as a backup.
The logger is no longer a singleton, as there is one per type. The new interface ILoggerManager creates new loggers for each type. This should normally not be used, as the DI system takes care of creating the loggers automatically.
ILoggerManager
This type is responsible for creating the actual loggers - and keep track of all created loggers. Under the hood, it creates a logger that writes log messages to a set of ILogMessageWriter.
The manager creates instances ILogMessageWriter by asking a set of ILogMessageWriterCreator. These creators are expected to return a writer for each type - that will write the actual log messages. An implementation for the Microsoft ILoggerFactory is included in the Dolittle.Logging.Microsoft package.
You can add writer creators by calling AddLogMessageWriterCreators(...) on the manager. This will create new writers for all the already created loggers as well as loggers created later.
When the logger manager is first created, it will start capturing log messages internally. When the first writer creators are added using AddLogMessageWriterCreators(...), all the captured logs are flushed to new writers from those creators - and further capturing stops. This has been done to allow logging during container setup, to infrastructure that cannot be setup until the container is built.
ILogAppender and related types are now gone, as they are superseded by the ILogMessageWriter. This means that there is no longer any actual writing of messages anywhere - we leave that up to later stages. The Built.CLI program uses the ILoggerFactory implementation from Microsoft.Extensions.Logging to write its logs to the standard output.
In the process, a few things had to be changed in the Booting project related to BootStages and how the logger was used. And also the Autofac DI system has a special module for injecting the correct ILogger<T> when a dependency of ILogger is used. Also a few improvements was made to the BootContainer to handle a some more complicated DI cases, and support the same special behaviour for ILogger.
What has changed:
ILogger
:_logger.Information($"Hello from {sender}")
which produces a string, the new style enables_logger.Information("Hello from {sender}", sender)
which can produce different types of logs depending on the underlying implementation.ILogger<T>
interface that can be used explicitly, or is used under the hood with dependency injection. The DI is setup so that it takes the declaring type as the type parameter when using theILogger
interface. In rare circumstances when the normal DI container is not used (e.g. AspNetCore middlewares) - it is not possible to determine the declaring type, so a specialILogger<UnknownLogMessageSource>
that writes an extra warning to the logs is bound toILogger
in the container, and will be used as a backup.ILoggerManager
creates new loggers for each type. This should normally not be used, as the DI system takes care of creating the loggers automatically.ILoggerManager
ILogMessageWriter
.ILogMessageWriter
by asking a set ofILogMessageWriterCreator
. These creators are expected to return a writer for each type - that will write the actual log messages. An implementation for the MicrosoftILoggerFactory
is included in theDolittle.Logging.Microsoft
package.AddLogMessageWriterCreators(...)
on the manager. This will create new writers for all the already created loggers as well as loggers created later.AddLogMessageWriterCreators(...)
, all the captured logs are flushed to new writers from those creators - and further capturing stops. This has been done to allow logging during container setup, to infrastructure that cannot be setup until the container is built.ILogAppender
and related types are now gone, as they are superseded by theILogMessageWriter
. This means that there is no longer any actual writing of messages anywhere - we leave that up to later stages. The Built.CLI program uses theILoggerFactory
implementation from Microsoft.Extensions.Logging to write its logs to the standard output.In the process, a few things had to be changed in the Booting project related to BootStages and how the logger was used. And also the Autofac DI system has a special module for injecting the correct
ILogger<T>
when a dependency ofILogger
is used. Also a few improvements was made to theBootContainer
to handle a some more complicated DI cases, and support the same special behaviour forILogger
.┆Issue is synchronized with this Asana task