Используйте Serilog в библиотеке классов из внешней сборки, без внедрения зависимостей в основное приложение.
Я работаю над проектом, в котором основное приложение (приложение Windows Forms) уже доступно и не использует внедрение зависимостей. Это основное приложение создает экземпляры некоторых внешних компонентов (доступных во внешней сборке библиотеки классов, на которую ссылается основное приложение), напрямую вызывая их конструктор. С другой стороны, эти компоненты используют внедрение зависимостей для создания экземпляров своих дальнейших зависимостей. Основное приложение:
public MainForm()
{
InitializeComponent();
var appName = "abc";
var myExtComp = new MyExtComponent(appName);
...
}
или
public MainForm()
{
InitializeComponent();
var appName = "abc";
var myExtWebComp = new MyExtWebComponent(appName);
...
}
Существует 2 вида внешних компонентов, один из которых является «обычным» внешним вспомогательным компонентом:
public MyExtComponent(string appName)
{
Log.Logger = ConfigureLogger(appName);
IHostBuilder builder = = Host.CreateDefaultBuilder();
builder.UseSerilog();
InitMyExtCompServices(builder);
IHost host = builder.Build();
host.RunAsync();
}
private void InitMyExtCompServices(IHostBuilder builder)
{
builder
.ConfigureServices((context, services) =>
{
services.AddSingleton<IMyService, MyService>();
...
}
}
public class MyService: IMyService
{
private readonly ILoggerFactory loggerFactory;
private readonly ILogger<MyService> logger;
public MyService(ILoggerFactory LoggerFactory)
{
loggerFactory = LoggerFactory ?? throw new ArgumentNullException(nameof(LoggerFactory));
logger = loggerFactory.CreateLogger<MyService>();
}
...
}
а другой содержит несколько веб-контроллеров:
public MyExtWebComponent(string appName)
{
Log.Logger = ConfigureLogger(appName);
WebApplicationBuilder webBuilder = WebApplication.CreateBuilder();
IHostBuilder builder = webBuilder.Host;
builder.UseSerilog();
InitMyExtWebCompServices(webBuilder);
var app = webBuilder.Build();
InitWebServerApplication(app);
app.RunAsync();
}
private void InitMyExtWebCompServices(WebApplicationBuilder webBuilder)
{
var webHostBuilder = webBuilder.WebHost;
webHostBuilder.ConfigureKestrel(o =>
{
...
});
// Add services to the container
var services = webBuilder.Services;
services.AddCors(...);
...
services.AddMvc().AddApplicationPart(...);
services.AddControllers();
...
}
private void InitWebServerApplication(WebApplication app)
{
app.UseCors(...);
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
[ApiController]
public class MyController : ControllerBase
{
private readonly ILoggerFactory loggerFactory;
private readonly ILogger<MyController> _logger;
public MyController(ILoggerFactory loggerFactory)
{
loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
_logger = loggerFactory.CreateLogger<MyController>();
}
...
}
В обоих случаях настроен регистратор serilog:
public ILogger ConfigureLogger(string appName)
{
var logPath = Environment.GetEnvironmentVariable("LOG_PATH", EnvironmentVariableTarget.Machine) ??
$@"c:\Logs\{appName}";
var logFileNameFormat =
Environment.GetEnvironmentVariable("LOG_FILE_NAME_FORMAT", EnvironmentVariableTarget.Machine) ??
$@"traces.log";
var logLevelFileStr =
Environment.GetEnvironmentVariable("LOG_LEVEL_FILE", EnvironmentVariableTarget.Machine) ?? $"Debug";
var logLevelFile = LogEventLevel.Debug;
try
{
logLevelFile = (LogEventLevel)Enum.Parse(typeof(LogEventLevel), logLevelFileStr);
}
catch (Exception exc)
{
}
var logFileNameTemplate = $@"{logPath}\{logFileNameFormat}";
var fileOutputTemplate = "{Timestamp:dd-MM-yyyy HH:mm:ss.fff zzz}:: {Level:u3}:: {Message:lj}{NewLine}";
var consoleOutputTemplate =
"{Timestamp:dd-MM-yyyy HH:mm:ss.fff zzz}:: {Level:u3}:: {Message:lj}{Properties}{NewLine}";
// defining Serilog configs
return new LoggerConfiguration()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
.Enrich.WithExceptionDetails()
.Enrich.FromLogContext()
.WriteTo.Async(a => a.Console(outputTemplate: consoleOutputTemplate, theme: SystemConsoleTheme.Colored))
.WriteTo.Async(a => a.File(
path: logFileNameTemplate,
restrictedToMinimumLevel: LogEventLevel.Debug,
rollingInterval: RollingInterval.Day,
retainedFileCountLimit: 30,
shared: true,
flushToDiskInterval: TimeSpan.FromSeconds(3),
outputTemplate: fileOutputTemplate
)) // Wrap any file sinks in an Async sink
.CreateLogger();
}
Во внешних компонентах все выполняется нормально, но я не могу ничего зарегистрировать в serilog. Сгенерированные файлы журнала, например, не имеют записей журнала, хотя logger.LogDebug() (и т. д.) вызывается во внешних компонентах. Как должен быть настроен serilog в приведенном выше сценарии, чтобы получать журналы из внешних сборок, содержащих указанные компоненты?