Skip to content

커스텀 로거

NeoDEEX의 Fox Loggging이 기본으로 제공하는 로거들 외에 추가적인 로거가 필요하다면 직접 커스텀 로거를 작성할 수 있습니다.

커스텀 로거를 작성하기 위해서는 IFoxLog 인터페이스를 구현하는 로거와 IFoxLoggerProvider 인터페이스를 구현하는 로거 프로바이더를 작성해야 합니다.

Tip

구성 설정을 사용하지 않는 로거라면 로거 프로바이더를 작성할 필요는 없습니다.

로거 베이스 클래스

IFoxLog 인터페이스와 IFoxLoggerProvider 인터페이스를 직접 구현하여 커스텀 로거와 커스텀 로거 프로바이더를 작성할 수도 있지만 Fox Logging에서 제공하는 베이스 클래스를 사용하여 보다 쉽게 로거와 로거 프로바이더를 작성할 수도 있습니다.

FoxLoggerBase 클래스

Fox Logging은 커스텀 로거의 작성을 지원하기 위해 FoxLoggerBase 추상 클래스(abstract class)를 제공합니다. FoxLoggerBase 클래스는 IFoxLog 인터페이스를 위한 대부분의 구현을 제공합니다. 실제로 Fox Logging이 기본으로 제공하는 FoxConsoleLogger, FoxDebugLogger, FoxTextFileLogger 등이 모두 FoxLoggerBase 클래스에서 파생되었습니다.

FoxLoggerBase 클래스는 IFoxLog 인터페이스의 모든 메서드를 구현하며 각 로거가 실제 로그를 기록하는데 필요한 2개의 메서드를 추상 메서드를 제공합니다.

protected abstract void WriteLogMessage(string source, FoxLogLevel level, string? message);
protected abstract void WriteLog(string source, FoxLogLevel level, object? data);

커스텀 로거 클래스는 FoxLogBase 클래스를 베이스 클래스로 사용하고 WriteLogMessage 메서드와 WriteLog 메서드를 구현하기만 하면 됩니다. WriteLogMessage 메서드는 텍스트 기반의 로그 메시지를 로그에 기록하는 메서드이며, WriteLog 메서드는 객체로 전달된 로그 데이터를 로그에 기록하는 메서드 입니다.

protected abstract void WriteLogMessage(string source, FoxLogLevel level, string? message);
protected abstract void WriteLog(string source, FoxLogLevel level, object? data);

일반적으로 콘솔 로거, 디버그 로거, 텍스트 파일 로거와 같이 텍스트 기반 로거는 WriteLogMessage 메서드에서 로그를 기록하고 WriteLog 메서드는 data 매개변수를 문자열로 변환하여 WriteLogMessage 메서드를 호출하도록 구현합니다. 텍스트 기반이 아닌 특정 데이터 객체를 로그에 기록하는 로거는 WriteLog 메서드에서 로그를 기록하고 WriteLogMessage 에서는 로그를 기록하지 않습니다.

Note

FoxDbAccess 클래스는 쿼리 수행 정보를 FoxDbProfileInfo 객체에 기록하여 IFoxLog.Write 메서드를 호출(Fox DB Profile)합니다. 따라서 이 정보를 텍스트가 아닌 DB에 기록하기 위해서는 WriteLog 메서드 내에서 DB에 기록하는 코드를 구현하는 커스텀 로거를 작성해야 하며, 이 커스텀 로거WriteLogMessage 메서드에서는 아무런 작업도 수행하지 않습니다.

FoxLoggerProviderBase 클래스

Fox Logging은 FoxLoggerBase 클래스와 유사하게 IFoxLoggerProvider 인터페이스를 구현하는 FoxLoggerPvoiderBase 클래스를 제공합니다. 커스텀 로거 프로바이더는 FoxLoggerProviderBase 클래스를 베이스 클래스로 사용하고 OnCreateLogger 추상 메서드를 구현하기만 하면 됩니다.

protected abstract IFoxLog OnCreateLogger(string loggerName, FoxLoggerPropertyCollection properties);

OnCreateLogger 메서드에 전달되는 FoxLoggerPropertyCollection 객체는 로깅 구성 설정의 "properties" 속성의 값들을 컬렉션으로 전달합니다. FoxLoggerPropertyCollection 객체는 "properties" 속성의 설정을 키/값으로 전달하며 foreach 문을 사용하여 다음과 같이 속성 값들을 로거 설정에 사용할 수 있습니다.

foreach(string key in properties)
{
    string value = properties[key];
    if (key == "property1")
    {
        logger.Property1 = value;
    }
    else if (key == "property2")
    {
        logger.Property2 = Int32.Parse(value);
    }
    else
    {
        FoxLoggerProviderBase.ThrowPropertyNameException(logger, key);
    }
}

Note

Fox Logging에서 전통적으로 로거 속성의 이름은 대소문자를 구별하지 않는 것을 선호 합니다.

"logging:providers" 섹션과 "logging:loggers" 섹션에서 모두 "properties" 속성이 명시되었다면 FoxLogManager 는 두 속성을 병합하며 동일한 로거 속성이 존재하는 경우, "logging:loggers" 섹션의 로거 생성 설정을 사용합니다. 이렇게 조합된 로거 생성 속성이 FoxLoggerPropertyCollection 객체로 구성되어 OnCreateLogger 메서드로 전달됩니다.

FoxLoggerProviderBase 클래스는 로거 생성 속성들에서 알 수 없는 속성 이름이나 속성 값에 대해 예외를 발생시켜 주는 ThrowProeprtyNameException 정적 메서드와 ThrowPropertyValueException 정적 메서드를 헬퍼 메서드로 제공합니다.

커스텀 로거 구현

커스텀 로거를 구체적으로 구현하는 전체 예제는 커스텀 로거 예제에서 찾을 수 있습니다. 이 예제는 한번의 WriteLog 호출로 콘솔 로거와 텍스트 파일 로거에 모두 기록하는 CustomLogger 클래스의 구현 예제 입니다.

public class CustomLogger : FoxLoggerBase
{
    private IFoxLog? _consoleLogger;
    private IFoxLog? _fileLogger;

    public string? FileLoggerName { get; internal set; }
    public string? ConsoleLogerName { get; internal set; }

    public CustomLogger(string name)
        : base(name)
    {
    }

    private void EnsureLogger()
    {
        // FoxLogManager.GetLogger를 호출하여 _consoleLogger 및 _fileLogger 초기화
        // 상세 코드는 github 예제 코드 참조
    }

    protected override void WriteLog(string source, FoxLogLevel level, object? data)
    {
        this.WriteLogMessage(source, level, data?.ToString());
    }

    protected override void WriteLogMessage(string source, FoxLogLevel level, string? message)
    {
        EnsureLogger();
        _consoleLogger?.Write(source, level, message);
        _fileLogger?.Write(source, level, message);
    }
}

위 코드 조각에서 WriteLog 메서드는 객체(data 매개변수)로 전달된 로그 데이터를 문자열로 변환하여 WriteLogMessage 메서드를 호출합니다.

커스텀 로거 프로바이더 구현

커스텀 로거 프로바이더는 구성 설정으로부터 콘솔 로거 이름과 파일 로거 이름을 제공 받으며 이 이름을 로거 속성에 설정합니다.

internal class CustomLoggerProvider : FoxLoggerProviderBase
{
    public CustomLoggerProvider(string name, FoxLoggerPropertyCollection properties)
        : base(name, properties)
    {
    }

    protected override IFoxLog OnCreateLogger(string loggerName, FoxLoggerPropertyCollection properties)
    {
        CustomLogger logger = new(loggerName);
        foreach(string key in properties)
        {
            string value = properties[key];
            if (String.Compare(key, "console", StringComparison.OrdinalIgnoreCase) == 0)
            {
                logger.ConsoleLogerName = value;
            }
            else if (String.Compare(key, "file", StringComparison.OrdinalIgnoreCase) == 0)
            {
                logger.FileLoggerName = value;
            }
            else
            {
                FoxLoggerProviderBase.ThrowPropertyNameException(logger, key);
            }
        }
        return logger;
    }
}

커스텀 로거 구성 설정

커스텀 로거를 로깅 구성 설정을 통해 사용하고자 하는 경우, 로거 프로바이더의 타입을 명시할 때 반드시 어셈블리 명이 포함되어야 합니다. Fox Logging 에서 기본으로 제공하는 로거들은 어셈블리 이름을 명시하지 않아도 되지만 커스텀 로거의 경우, 커스텀 로거 프로바이더 타입이 어느 어셈블리에 존재하는지를 FoxLogManager 가 알 수 없기 때문에 로거 프로바이더 타입에 어셈블리 이름을 명시해야 합니다.

{
  "logging": {
    "providers": {
      "CustomProvider": {
      "providerType": "LoggerLib.CustomLoggerProvider, LoggerLib",
      }
    },
    "loggers": {
      "CusomLogger": {
        "providerName": "CustomProvider",
        "properties": {
          "console": "ConsoleLogger",
          "text": "TextFileLogger"
        }
      }
    }
  }
}

Summary

NeoDEEX의 Fox Logging 기능은 기본 제공 로거 외에도 사용자가 직접 커스텀 로거를 구현할 수 있도록 유연한 구조를 제공합니다. 커스텀 로거를 작성하려면 IFoxLog 인터페이스를 구현한 로거 클래스와, 필요에 따라 IFoxLoggerProvider 인터페이스를 구현한 프로바이더 클래스가 필요합니다.

Fox Logging은 개발 편의를 위해 FoxLoggerBaseFoxLoggerProviderBase 라는 베이스 클래스를 제공하며, 이들을 상속하여 핵심 메서드만 구현하면 손쉽게 커스텀 로거를 만들 수 있습니다. 특히 WriteLogMessageWriteLog 메서드를 통해 텍스트 기반 또는 객체 기반 로그 처리를 유연하게 구성할 수 있습니다.

커스텀 로거 예제에서는 콘솔 로거와 텍스트 파일 로거를 동시에 사용하는 CustomLogger 클래스와, 해당 로거를 생성하는 CustomLoggerProvider 구현을 보여줍니다. 커스텀 로거를 설정 파일에 등록할 때는 반드시 프로바이더 타입에 어셈블리 이름을 포함해야 하며, 속성 병합 및 예외 처리도 지원됩니다.

이 구조를 활용하면 다양한 로그 저장 방식(데이터베이스, 파일, 외부 시스템 등)에 맞춰 확장 가능한 로깅 시스템을 구축할 수 있습니다.