정적 메서드 호출로 Serilog 편하게 쓰기

정적 메서드 호출로 Serilog 편하게 쓰기

이철우

객체지향 언어 C#에는 '전역 변수’가 없습니다. 클래스 안에 정적 변수를 public으로 만들어 전역 변수처럼 씁니다. 프로그램을 배우며 가장 먼저 만나고 ‘어디에서나’ 호출할 수 있는

Console.WriteLine("Hello, world!");

에서 'WriteLine’이 클래스 Console의 ‘정적’ 메서드입니다. 화면에 로그 남기는 용도로 이 메서드를 사용하기도 합니다. 파일에 로그를 남기려면 스스로 구현하거나 다른 사람이 만든 것을 쓰는 데, 저는 Serilog를 골랐습니다.

의존성 주입없이, Console.WriteLine 메서드 처럼, ‘어디에서나’ 호출할 수 있기 때문입니다.

Serilog.Log.Information("Hello, world!");

이제 제가 사용하는 방법을 소개하겠습니다. 새로 닷넷 9.0 클래스 라이브러리 프로젝트 Utils를 임의의 솔루션에 더합니다. Nuget에서 패키지 Serilog (4.2.0), Serilog.Sinks.Async(2.1.0), Serilog.Sinks.Console(6.0.0), Serilog.Sinks.File(6.0.0)를 골라 프로젝트 Utils에 설치합니다.

클래스 SerilogSettings 를 Utils에 추가 합니다.

    // SerilogSettings.cs
    public static class SerilogSettings
    {
        private static string? _logFilePath;
        public static void Initializer(string logFilePath)
        {
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                //.WriteTo.Console()
                //.WriteTo.File(logFilePath, rollingInterval: RollingInterval.Day, restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Information)
                .WriteTo.Async(a => a.Console())
                .WriteTo.Async(a => a.File(logFilePath, rollingInterval: RollingInterval.Day, restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Information))
                .CreateLogger();

            Log.Logger.Information($"{nameof(Serilog)} {INITIALIZED} {logFilePath} {nameof(Initializer)} {nameof(SerilogSettings)}");

            _logFilePath = logFilePath;

            /* LogEventLevel
             * 
             * Verbose
             * Debug
             * Information : Default Level
             * Warning
             * Error
             * Fatal
             * 
             */
        }

        public static async Task Finalizer()
        {
            Log.Logger.Information($"{nameof(Serilog)} {FINALLIZING} {_logFilePath} {nameof(Finalizer)} {nameof(SerilogSettings)}");
            await Log.CloseAndFlushAsync().ConfigureAwait(false);
        }

        private static readonly string INITIALIZED = "Initialized.";
        private static readonly string FINALLIZING = "Finalizing...";
    }

이 프로젝트를 빌드하면, 서비스 Serilog를 사용할 준비가 된 것입니다. 이 서비스를 사용하기 위해 닷넷 9.0 콘솔 프로젝트 Test를 현재 솔루션에 더하고, Utils 프로젝트를 참조하고 Nuget에서 패키지 Serilog (4.2.0)를 설치합니다.

그리고 Program.cs를 아래와 같이 편집합니다.

// Program.cs

using Serilog;
using Test;
using Utils;

SerilogSettings.Initializer(@"D:\Log\Log_.txt");

Log.Information("Hello, World!");
Log.Error("Test error.");
Log.Information("Bye.");

await SerilogSettings.Finalizer().ConfigureAwait(false);

Test 프로젝트를 실행하면, 아래처럼 나타납니다. 아울러 Log_20250315.txt 파일에도 기록이 남습니다.

클래스 Person을 프로젝트 Test에 추가하고 생성자를 아래처럼 바꿉니다.

    // Person.cs

    public class Person
    {
        public Person()
        {
            Serilog.Log.Debug($"Created: {nameof(Person)}");
        }
    }

클래스 Person을 시험하기 위해 Program.cs을 아래처럼 바꿉니다.

// Program.cs

using Serilog;
using Test;
using Utils;

SerilogSettings.Initializer(@"D:\Log\Log_.txt");

Log.Information("Hello, World!");
var person = new Person();
Log.Information("Bye.");

await SerilogSettings.Finalizer().ConfigureAwait(false);

프로젝트 Test를 실행하면 아래처럼 됩니다.

만약 WPF 프로젝트(출력형태 Console)라면, 프로젝트 Utils를 참조하고 패키지 Serilog (4.2.0)를 설치하고 App.xaml.cs를 아래와 같이 바꿉니다.

// App.xaml.cs

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        SerilogSettings.Initializer(@"D:\Log\Log_.txt");
    }

    protected override async void OnExit(ExitEventArgs e)
    {
        await SerilogSettings.Finalizer().ConfigureAwait(false);
    }
}

의존성 주입하지 않고, 어디에서나 호출할 수 있는 Serilog, 정말 편합니다.

[참고] Configuration Basics

4개의 좋아요

Microsoft.Extensions.Logging을 사용하는게 best practice라고 생각합니다.

5개의 좋아요

저는 microsoft log에 대해 공부하고 싶진 않습니다~

2개의 좋아요

쓰레드를 읽으실 때 마이크로소프트가 제안하는 로깅 방법도 깉이 검토할 수 있도록 MSDN 덧글을 달았습니다.

2개의 좋아요

Logging in .NET: A Comparison of the Top 4 Libraries

저자 : Stanley Ulili

좋네요 가끔 다른 path 로 로그 적을때 유용하겠아여

1개의 좋아요