.NET 로깅 및 추적

코드를 계측하여 프로그램이 실행되는 동안 발생한 흥미로운 이벤트에 대한 기록 역할을 하는 로그를 생성할 수 있습니다. 애플리케이션의 동작을 이해하기 위해 로그를 검토할 수 있습니다. 로깅과 추적 모두 이 기술을 캡슐화합니다. .NET은 그 역사 동안 여러 가지 다양한 로깅 API를 누적해 왔으며 이 문서는 사용 가능한 옵션을 이해하는 데 도움이 될 것입니다.

"로깅"과 "추적"이라는 용어는 일반적으로 동의어입니다. 차이점은 로깅 출력이 항상 수집될 것으로 예상되므로 오버헤드가 낮아야 한다는 것입니다. 추적은 일반적으로 더 침입적이며 애플리케이션 및 .NET 런타임의 더 깊은 부분에서 더 많은 정보를 수집합니다. 특정 문제를 진단할 때 사용되거나 심층적인 성능 분석 시스템의 일부로 짧은 시간 동안 자동으로 사용됩니다.

추적 용어의 또 다른 핵심은 분산 추적입니다. 분산 추적은 요청 기반 시스템에 대한 개략적인 작업 및 타이밍 데이터를 수집하고 서비스 전체에서 요청을 상호 연결하여 전체 시스템에서 각 요청이 처리되는 방식에 대한 보기를 제공합니다.

로깅 API의 주요 차이점

구조적 로깅

로깅 API는 구조화되거나 구조화되지 않을 수 있습니다.

  • 구조화되지 않음: 로그 항목에는 인간이 볼 수 있도록 고안된 자유 형식 텍스트 콘텐츠가 있습니다.
  • 구조적: 로그 항목은 잘 정의된 스키마를 가지며 다양한 이진 파일 및 텍스트 형식으로 인코딩될 수 있습니다. 이러한 로그는 인간과 자동화 시스템 모두 쉽게 작업할 수 있도록 컴퓨터 번역 및 쿼리가 가능하도록 설계되었습니다.

구조적 로깅을 지원하는 API는 사소한 용도로 사용하는 것이 좋습니다. 유용성에는 거의 차이가 없이 더 많은 기능, 유연성 및 성능을 제공합니다.

구성

간단한 사용 사례의 경우 콘솔이나 파일에 직접 메시지를 쓰는 API를 사용할 수 있습니다. 그러나 대부분의 소프트웨어 프로젝트에서는 어떤 로그 이벤트가 기록되고 유지되는지 구성하는 것이 유용하다는 것을 알게 될 것입니다. 예를 들어, 로컬 개발 환경에서 실행할 때 쉽게 읽을 수 있도록 일반 텍스트를 콘솔에 출력할 수 있습니다. 그런 다음 애플리케이션이 프로덕션 환경에 배포되면 로그를 전용 데이터베이스나 롤링 파일 집합에 저장하도록 전환할 수 있습니다. 좋은 구성 옵션이 있는 API를 사용하면 이러한 전환이 쉬워지는 반면, 구성 옵션이 덜한 경우 변경하려면 모든 곳에서 계측 코드를 업데이트해야 합니다.

Sinks

대부분의 로깅 API를 사용하면 로그 메시지를 싱크라고 하는 다른 대상으로 보낼 수 있습니다. 일부 API에는 미리 만들어진 싱크가 많이 있는 반면 다른 API에는 소수만 있습니다. 미리 만들어진 싱크가 없는 경우 일반적으로 사용자 지정 싱크를 작성할 수 있는 확장성 API가 있습니다. 단, 이를 위해서는 코드를 좀 더 작성해야 합니다.

.NET 로깅 API

ILogger

대부분의 경우 기존 프로젝트에 로깅을 추가하든 새 프로젝트를 만들든 관계없이 ILogger 인프라가 좋은 기본 선택입니다. ILogger는 빠른 구조적 로깅, 유연한 구성, 그리고 ASP.NET 앱을 실행할 때 표시되는 콘솔을 포함한 공통 싱크 컬렉션을 지원합니다. 또한, ILogger 인터페이스는 풍부한 기능과 확장성을 제공하는 다양한 타사 로깅 구현에 대한 외관 역할을 할 수도 있습니다.

ILogger는 추가 분석을 위해 애플리케이션에서 다양한 APM 시스템으로 로그를 송신할 수 있는 .NET용 OpenTelemetry 구현에 대한 로깅 스토리를 제공합니다.

EventSource

EventSource는 구조화된 로깅을 갖춘 오래된 고성능 추적 API입니다. 원래는 ETW(Windows용 이벤트 추적)과 잘 통합되도록 설계되었지만 나중에 EventPipe 플랫폼 간 추적 및 사용자 지정 싱크용 EventListener를 지원하도록 확장되었습니다. ILogger에 비해 EventSource에는 미리 만들어진 로깅 싱크가 상대적으로 적고 별도의 구성 파일을 통해 구성할 수 있는 기본 지원 기능이 없습니다. ETW 또는 EventPipe 통합을 더욱 엄격하게 제어하려는 경우 EventSource가 적합하지만, 범용 로깅의 경우 ILogger가 더 유연하고 사용하기 쉽습니다.

Trace

System.Diagnostics.TraceSystem.Diagnostics.Debug는 .NET에서 가장 오래된 로깅 API입니다. 이러한 클래스에는 유연한 구성 API와 대규모 싱크 에코시스템이 있지만 구조화되지 않은 로깅만 지원됩니다. .NET Framework에서는 app.config 파일을 통해 구성할 수 있지만 .NET Core에는 기본 제공되는 파일 기반 구성 메커니즘이 없습니다. 일반적으로 디버거에서 실행되는 동안 개발자를 위한 진단 출력을 생성하는 데 사용됩니다. .NET 팀은 이전 버전과의 호환성을 위해 이러한 API를 계속 지원하지만 새로운 기능은 추가되지 않습니다. 이러한 API는 이미 이를 사용하고 있는 애플리케이션에 적합한 선택입니다. 로깅 API에 아직 커밋되지 않은 최신 앱의 경우 ILogger가 더 나은 기능을 제공할 수 있습니다.

특수 로깅 API

콘솔

System.Console 클래스에는 간단한 로깅 시나리오에 사용할 수 있는 WriteWriteLine 메서드가 있습니다. 이러한 API는 시작이 매우 쉽지만 솔루션은 범용 로깅 API만큼 유연하지 않습니다. 콘솔은 구조화되지 않은 로깅만 허용하며 사용하도록 설정할 로그 메시지를 선택하거나 다른 싱크로 대상을 변경하는 구성은 지원하지 않습니다. 콘솔 싱크와 함께 ILogger 또는 추적 API를 사용하면 추가 활동이 많이 필요하지 않으며 로깅을 구성 가능한 상태로 유지합니다.

DiagnosticSource

System.Diagnostics.DiagnosticSource는 로그 메시지가 스토리지에 직렬화되지 않고 프로세스 내에서 동기식으로 분석되는 로깅을 위한 것입니다. 이를 통해 원본과 수신기는 임의의 .NET 개체를 메시지로 교환할 수 있지만 대부분의 로깅 API에서는 로그 이벤트를 직렬화할 수 있어야 합니다. 또한 이 기술은 수신기가 효율적으로 구현되면 로그 이벤트를 수십 나노초 안에 처리할 수 있어 매우 빠릅니다. 이러한 API를 사용하는 도구는 API가 여기에 어떠한 제약 조건도 적용하지 않지만 프로세스 내 프로파일러처럼 작동하는 경우가 많습니다.

EventLog

System.Diagnostics.EventLog는 Windows EventLog에 메시지를 쓰는 Windows 전용 API입니다. 대부분의 경우 Windows에서 실행할 때 선택적 EventLog 싱크와 함께 ILogger를 사용하면 앱을 Windows OS에 긴밀하게 연결하지 않고도 비슷한 기능을 제공할 수 있습니다.