-
ASP.NET CORE Serilog 설정 및 사용프로그래밍 2024. 10. 17. 12:45
ASP.NET Core에서 Serilog를 사용하여 logging 하는 방법에 대해 알아보자.
먼저 Serilog 관련 패키지를 설치해야 한다.
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" /> <PackageReference Include="Serilog.Enrichers.Environment" Version="3.0.1" /> <PackageReference Include="Serilog.Enrichers.Process" Version="3.0.0" /> <PackageReference Include="Serilog.Enrichers.Thread" Version="4.0.0" /> <PackageReference Include="Serilog.Formatting.Elasticsearch" Version="10.0.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="8.0.2" /> <PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" /> <PackageReference Include="Serilog.Sinks.Debug" Version="3.0.0" /> <PackageReference Include="Serilog.Sinks.Elasticsearch" Version="10.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
Enrichers는 로깅 부분에 기록될 사항중
EnvironmentName ProcessId ThreadId
등을 기록할 때 사용된다.
Sinks는 출력 부분으로 각각 Console, Debug, File 등을 의미한다.
설정 코드를 보자.
builder.Host.UseSerilog((context, services, config) => { config.ReadFrom.Configuration(context.Configuration); });
위 코드는 appsettings.json 또는 appsettings.Development.json 파일을 읽어 Key가 "Serilog"인 부분이 적용되겠다.
그렇다면 json 파일의 설정을 보자.
"Serilog": { "Using": [ "Serilog.Enrichers.Environment", "Serilog.Enrichers.Process", "Serilog.Enrichers.Thread", "Serilog.Sinks.ElasticSearch" ], "MinimumLevel": { "Default": "Verbose", "Override": { "Microsoft": "Information", "Microsoft.Hosting.Lifetime": "Information", "System": "Information", "Hangfire": "Warning", "Microsoft.EntityFrameworkCore": "Debug", "Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information" } }, "WriteTo": [ { "Name": "Console", "Args": { "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {Level:u3}] {Message:lj} {NewLine}{Properties:j}{NewLine}{Exception}" } }, { "Name": "File", "Args": { "path": "Logs/log.txt", "rollingInterval": "Day", "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {Level:u3}] {Message:lj} {NewLine}{Properties:j}{NewLine}{Exception}" } }, { "Name": "Elasticsearch", "Args": { "nodeUris": "[url]", "indexFormat": "[index 형식 지정]", "templateName": "[template 명]", "inlineFields": true, "autoRegisterTemplate": true, "customFormatter": "Serilog.Formatting.Elasticsearch.ExceptionAsObjectJsonFormatter, Serilog.Formatting.Elasticsearch" } } ], "Enrich": [ "FromLogContext", "WithMachineName", "WithEnvironmentName", "WithProcessId", "WithThreadId" ], "Properties": { "Application": "Demo.Api" } },
위와 같이 되겠다.
WriteTo 부분을 보면 Console, File, Elasticsearch를 지원하도록 되어 있다.
console과 file은 outputTemplate에 따라 기록되고 elasticsearch의 경우 서비스에 별도의 형식을 지정해야 할 수도 있다.
( elasticsearch는 데모 만료로 확인이 불가했다.)
위와 같이 설정하였다면 이제 콘솔에 로깅 문자가 보일 것이다.
기본적으로 serilog는 구조화 로깅으로 프로그램에서 설정 내역에 따라 출력을 확인할 수 있다.
(기본 동작 로그 및 라이프 사이클에 따른 로그도 확인 할 수 있다.)
또한 Microsoft.Extensions.Logging을 사용하여 기본 로깅을 처리할 수 있다.
예제를 보자.
public abstract class BackgroundServiceBase<TSelf>(ILogger<TSelf> logger) : BackgroundService where TSelf : class { protected ILogger Logger = logger; protected string SelfName = typeof(TSelf).Name; } public abstract class BackgroundServiceBase<TSelf, TRequest>( ILogger<TSelf> logger, IServiceScopeFactory serviceScopeFactory, int interval = 500) : BackgroundServiceBase<TSelf>(logger) where TSelf : class where TRequest : class { private readonly IServiceScopeFactory _serviceScopeFactory = serviceScopeFactory; protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { if (Logger.IsEnabled(LogLevel.Information)) { Logger.LogInformation("{name} Worker running at: {time}", this.SelfName, DateTimeOffset.Now); } try { var item = await ExecuteProduceAsync(stoppingToken); if (item.xIsNotEmpty()) { await ExecuteConsumeAsync(item, stoppingToken); } } catch (Exception e) { Logger.LogError(e, "{name} Worker Error: {message}", this.SelfName, e.Message); } await Task.Delay(interval, stoppingToken); } } protected abstract Task<TRequest> ExecuteProduceAsync(CancellationToken cancellationToken); protected abstract Task ExecuteConsumeAsync(TRequest request, CancellationToken stoppingToken); }
위 코드는 BackgroundService를 상속하여 Custom한 코드이다.
여기서 ILogger를 상속하여 처리하게 되는데, 기본적으로 Microsoft.Exetions.Logging을 사용하고 있다.
필자는 이전에 Serilog.Logger 인스턴스를 상속받는 방식으로 개발하였고 이는 틀린 방법이므로 꼭 위와 같이 선언하여 사용하길 바란다.
출력 결과는 아래와 같다.
{"SourceContext":"Demo.Kafka.Consumer.Workers.MetadataWorker","MachineName":"DESKTOP-xxxxxx","EnvironmentName":"Development","ProcessId":143692,"ThreadId":21,"Application":"Demo.Kafka.Consumer"} [2024-10-10 15:28:23.028 +09:00 INF] MetadataWorker Worker running at: "2024-10-10T15:28:23.0282896+09:00" {"SourceContext":"Demo.Kafka.Consumer.Workers.MetadataWorker","MachineName":"DESKTOP-xxxxxx","EnvironmentName":"Development","ProcessId":143692,"ThreadId":21,"Application":"Demo.Kafka.Consumer"} [2024-10-10 15:28:23.545 +09:00 INF] MetadataWorker Worker running at: "2024-10-10T15:28:23.5456503+09:00"
위와 같은 출력 결과를 볼 수 있을 것이다.
만약 Serilog에 추가적 속성 선언이 필요하다면 Middleware나 Filter에 아래와 같이 할 수 있다.
using (LogContext.PushProperty("[선언명]", "[값]")) { await next(); }
위와 같이 할 경우 로깅에서 선언명 속성이 추가된 것을 확인 할 수 있다.
구조화 로깅이 필요하다면 Serilog를 사용하자.
운영 배포 로깅을 한다면 elasticsearch를 사용하는 것을 권장한다.
도움이 되길 바라며...
'프로그래밍' 카테고리의 다른 글
ASP.NET CORE 8에서의 Exception 처리 (0) 2024.10.21 AWS Secrets Manager에 대하여 (0) 2024.10.21 ASP.NET CORE에서의 JWT 처리 (0) 2024.10.16 SignalR Redis Backplane (0) 2024.10.16 EF CORE의 상태 변경 (1) 2024.10.16