.NET 로그와 트레이스 상호 연관 (Correlating .NET Logs and Traces)
.NET 애플리케이션의 로그에 트레이스 및 스팬 ID를 주입해 Datadog에서 로그와 트레이스를 연결하는 방법을 안내해요.
출처: 문서
본문
로깅 라이브러리와 .NET 트레이싱 구성을 설정해 트레이스 및 스팬 ID가 애플리케이션 로그에 주입되도록 할 수 있어요. 이렇게 하면 로그 데이터와 상호 연관된 애플리케이션 성능 모니터링 데이터를 얻을 수 있어요.
애플리케이션 트레이스와 로그를 상호 연관할 때 최상의 경험과 유용한 컨텍스트를 위해 Unified Service Tagging으로 .NET Tracer를 구성해요.
.NET Tracer는 다음 로깅 라이브러리를 지원해요:
- Serilog (v1.4+)
- log4net
- NLog
- Microsoft.Extensions.Logging (v1.28.6에 추가)
로그 수집 구성
Datadog Agent에서 로그 수집이 구성되어 있고, 지정된 파일을 테일링하기 위한 Logs Agent 구성이 로그 파이프라인이 로그 파일을 파싱할 수 있도록 source: csharp로 설정되어 있는지 확인해요. 자세한 내용은 C# 로그 수집을 참조하세요. source가 csharp 이외의 값으로 설정되어 있다면 상호 연관이 올바르게 작동하도록 적절한 로그 처리 파이프라인에 트레이스 리매퍼를 추가해야 할 수 있어요.
경고: 자동 로그 수집은 JSON으로 형식화된 로그에서만 작동해요. 또는 커스텀 파싱 규칙을 사용해요.
로그에서 주입 구성
로그 메시지에 상호 연관 식별자를 주입하려면 로깅 라이브러리의 지침을 따르세요.
참고: 더 많은 예시는 dd-trace-dotnet의 샘플을 참조하세요.
Serilog
참고: .NET Tracer 버전 2.0.1부터 Serilog 로깅 라이브러리용 자동 주입은 애플리케이션이 자동 계측으로 계측되어야 해요.
로그 메시지에 상호 연관 식별자를 자동으로 주입하려면:
-
다음 트레이서 설정으로 .NET Tracer를 구성해요:
DD_ENVDD_SERVICEDD_VERSION
-
.NET Tracer 설치 지침에 따라 앱의 자동 계측 트레이싱을 활성화해요.
log4net
참고: .NET Tracer 버전 1.29.0부터 log4net 로깅 라이브러리용 자동 주입은 애플리케이션이 자동 계측으로 계측되어야 해요.
로그 메시지에 상호 연관 식별자를 자동으로 주입하려면:
-
다음 트레이서 설정으로 .NET Tracer를 구성해요:
DD_ENVDD_SERVICEDD_VERSION
-
.NET Tracer 설치 지침에 따라 앱의 자동 계측 트레이싱을 활성화해요.
-
로깅 출력에
dd.env,dd.service,dd.version,dd.trace_id,dd.span_id로그 속성을 추가해요. 이는 이러한 속성을 개별적으로 포함하거나 모든 로그 속성을 포함해 수행할 수 있어요. 두 접근 방식 모두 다음 예시 코드에 나와 있어요:
<layout type="log4net.Layout.SerializedLayout, log4net.Ext.Json">
<decorator type="log4net.Layout.Decorators.StandardTypesDecorator, log4net.Ext.Json" />
<default />
<!--명시적 기본 멤버-->
<remove value="ndc" />
<!--기본 사전 형식화된 메시지 멤버 제거-->
<remove value="message" />
<!--원시 메시지 추가-->
<member value="message:messageobject" />
<!-- Datadog 속성 포함 -->
<!-- EITHER value='<property_name>' 로 개별 속성 포함 -->
<member value='dd.env' />
<member value='dd.service' />
<member value='dd.version' />
<member value='dd.trace_id' />
<member value='dd.span_id' />
<!-- OR value='properties' 로 모든 속성 포함 -->
<member value='properties'/>
</layout>
추가 예시는 GitHub의 log4net 자동 트레이스 ID 주입 프로젝트를 참조하세요.
NLog
참고: .NET Tracer 버전 2.0.1부터 NLog 로깅 라이브러리용 자동 주입은 애플리케이션이 자동 계측으로 계측되어야 해요.
로그 메시지에 상호 연관 식별자를 자동으로 주입하려면:
-
다음 트레이서 설정으로 .NET Tracer를 구성해요:
DD_ENVDD_SERVICEDD_VERSION
-
.NET Tracer 설치 지침에 따라 앱의 자동 계측 트레이싱을 활성화해요.
-
NLog 5.0+ 버전의 다음 예시 코드처럼 매핑된 진단 컨텍스트(MDC)를 활성화해요:
<!-- ScopeContext 속성을 내보내려면 includeScopeProperties="true" 추가 -->
<layout xsi:type="JsonLayout" includeScopeProperties="true">
<attribute name="date" layout="${longdate}" />
<attribute name="level" layout="${level:upperCase=true}"/>
<attribute name="message" layout="${message}" />
<attribute name="exception" layout="${exception:format=ToString}" />
</layout>
NLog 4.6+ 버전:
<!-- MDC 속성을 내보내려면 includeMdlc="true" 추가 -->
<layout xsi:type="JsonLayout" includeMdlc="true">
<attribute name="date" layout="${longdate}" />
<attribute name="level" layout="${level:upperCase=true}"/>
<attribute name="message" layout="${message}" />
<attribute name="exception" layout="${exception:format=ToString}" />
</layout>
NLog 4.5 버전:
<!-- MDC 속성을 내보내려면 includeMdlc="true" 추가 -->
<layout xsi:type="JsonLayout" includeMdlc="true">
<attribute name="date" layout="${longdate}" />
<attribute name="level" layout="${level:upperCase=true}"/>
<attribute name="message" layout="${message}" />
<attribute name="exception" layout="${exception:format=ToString}" />
</layout>
추가 예시는 GitHub에서 NLog 4.0, NLog 4.5 또는 NLog 4.6을 사용하는 자동 트레이스 ID 주입 프로젝트를 참조하세요.
Microsoft.Extensions.Logging
로그 메시지에 상호 연관 식별자를 자동으로 주입하려면:
-
다음 트레이서 설정으로 .NET Tracer를 구성해요:
DD_ENVDD_SERVICEDD_VERSION
-
.NET Tracer 설치 지침에 따라 앱의 자동 계측 트레이싱을 활성화해요.
-
예시 코드에 나와 있듯이 로깅 공급자에 대해 로그 스코프를 활성화해요. 로그 스코프를 지원하는 공급자에만 상호 연관 식별자가 주입돼요.
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.AddFile(opts =>
{
opts.IncludeScopes = true; // 상호 연관 식별자가 추가되도록 스코프를 반드시 포함해야 함
opts.FormatterName = "json";
});
}
로그를 작성할 때 활성 트레이스가 있으면 dd_trace_id 및 dd_span_id 속성으로 트레이스 및 스팬 ID가 애플리케이션 로그에 자동으로 주입돼요. 활성 트레이스가 없으면 dd_env, dd_service, dd_version 속성만 주입돼요.
참고: Serilog.Extensions.Hosting 또는 Serilog.Extensions.Logging 패키지처럼 기본 LoggerFactory 구현을 대체하는 로깅 라이브러리를 사용한다면 프레임워크별 지침을 따르세요 (이 예시에서는 Serilog 참조).
추가 예시는 GitHub의 Microsoft.Extensions.Logging 자동 트레이스 ID 주입 프로젝트를 참조하세요.
다음으로 자동 또는 수동 주입을 위한 설정을 완료해요.
자동 주입
자동 상호 연관 식별자 주입을 활성화하려면 DD_LOGS_INJECTION이 활성화되어 있는지 확인해요.
버전 3.24.0부터 DD_LOGS_INJECTION은 기본적으로 활성화돼요. 이전 버전에서는 .NET Tracer의 환경 변수에 DD_LOGS_INJECTION=true를 설정해요.
다른 방법으로 .NET Tracer를 구성하려면 .NET Tracer 구성을 참조하세요.
상호 연관 식별자 주입을 구성한 후 로그 수집을 구성하려면 C# 로그 수집을 참조하세요.
참고: 트레이스를 로그와 상호 연관하려면 로그의 트레이스 ID로 dd_trace_id를 파싱하도록 트레이스 ID 리매퍼를 설정해야 할 수 있어요. 자세한 내용은 연관된 로그가 트레이스 ID 패널에 표시되지 않음을 참조하세요.
참고: 버전 2.35.0부터 이 서비스가 실행되는 곳에서 Agent Remote Configuration이 활성화되어 있다면 Catalog UI에서 DD_LOGS_INJECTION을 설정할 수 있어요.
수동 주입
트레이스를 로그와 수동으로 상호 연관하려면 로그에 상호 연관 식별자를 추가할 수 있어요.
| 필수 키 | 설명 |
|---|---|
dd.env |
SDK의 env를 전역으로 구성. 설정하지 않으면 ""으로 기본값 지정. |
dd.service |
루트 서비스 이름을 전역으로 구성. 설정하지 않으면 애플리케이션 이름 또는 IIS 사이트 이름으로 기본값 지정. |
dd.version |
서비스의 version을 전역으로 구성. 설정하지 않으면 ""으로 기본값 지정. |
dd.trace_id |
로그 문 중 활성 트레이스 ID (64비트 10진수로 표시). 트레이스가 없으면 0으로 기본값 지정. |
dd.span_id |
로그 문 중 활성 스팬 ID (64비트 10진수로 표시). 트레이스가 없으면 0으로 기본값 지정. |
참고: 로그를 파싱하기 위해 Datadog 로그 통합을 사용하지 않는다면 커스텀 로그 파싱 규칙이 dd.trace_id와 dd.span_id를 문자열로 파싱해야 해요. 정보는 연관된 로그가 트레이스 ID 패널에 표시되지 않음을 참조하세요.
참고: ILogger를 통해 Serilog, Nlog 또는 log4net을 사용한다면 BeginScope()로 이러한 속성을 구성하는 Microsoft.Extensions.Logging 섹션을 참조하세요.
시작 단계를 완료한 후 수동 로그 강화 설정을 마무리해요:
-
프로젝트에서
Datadog.TraceNuGet 패키지를 참조해요. -
CorrelationIdentifierAPI를 사용해 상호 연관 식별자를 검색하고 스팬이 활성 상태인 동안 로그 컨텍스트에 추가해요.
마지막으로 로그 수집을 구성하려면 C# 로그 수집을 참조하세요.
예시:
Serilog
참고: Serilog 라이브러리는 메시지 속성 이름이 유효한 C# 식별자일 것을 요구해요. 필요한 속성 이름은 dd_env, dd_service, dd_version, dd_trace_id, dd_span_id예요.
using Datadog.Trace;
using Serilog.Context;
// 이 블록 전에 스팬이 시작되고 활성화되어 있어야 함.
using (LogContext.PushProperty("dd_env", CorrelationIdentifier.Env))
using (LogContext.PushProperty("dd_service", CorrelationIdentifier.Service))
using (LogContext.PushProperty("dd_version", CorrelationIdentifier.Version))
using (LogContext.PushProperty("dd_trace_id", CorrelationIdentifier.TraceId.ToString()))
using (LogContext.PushProperty("dd_span_id", CorrelationIdentifier.SpanId.ToString()))
{
// 로그를 기록
}
log4net
using Datadog.Trace;
using log4net;
// 이 블록 전에 스팬이 시작되고 활성화되어 있어야 함.
try
{
LogicalThreadContext.Properties["dd.env"] = CorrelationIdentifier.Env;
LogicalThreadContext.Properties["dd.service"] = CorrelationIdentifier.Service;
LogicalThreadContext.Properties["dd.version"] = CorrelationIdentifier.Version;
LogicalThreadContext.Properties["dd.trace_id"] = CorrelationIdentifier.TraceId.ToString();
LogicalThreadContext.Properties["dd.span_id"] = CorrelationIdentifier.SpanId.ToString();
// 로그를 기록
}
finally
{
LogicalThreadContext.Properties.Remove("dd.env");
LogicalThreadContext.Properties.Remove("dd.service");
LogicalThreadContext.Properties.Remove("dd.version");
LogicalThreadContext.Properties.Remove("dd.trace_id");
LogicalThreadContext.Properties.Remove("dd.span_id");
}
NLog
using Datadog.Trace;
using NLog;
// 이 블록 전에 스팬이 시작되고 활성화되어 있어야 함.
using (MappedDiagnosticsLogicalContext.SetScoped("dd.env", CorrelationIdentifier.Env))
using (MappedDiagnosticsLogicalContext.SetScoped("dd.service", CorrelationIdentifier.Service))
using (MappedDiagnosticsLogicalContext.SetScoped("dd.version", CorrelationIdentifier.Version))
using (MappedDiagnosticsLogicalContext.SetScoped("dd.trace_id", CorrelationIdentifier.TraceId.ToString()))
using (MappedDiagnosticsLogicalContext.SetScoped("dd.span_id", CorrelationIdentifier.SpanId.ToString()))
{
// 로그를 기록
}
Microsoft.Extensions.Logging
using Datadog.Trace;
using Microsoft.Extensions.Logging;
ILogger _logger;
// 이 블록 전에 스팬이 시작되고 활성화되어 있어야 함.
using(_logger.BeginScope(new Dictionary<string, object>
{
{"dd.env", CorrelationIdentifier.Env},
{"dd.service", CorrelationIdentifier.Service},
{"dd.version", CorrelationIdentifier.Version},
{"dd.trace_id", CorrelationIdentifier.TraceId.ToString()},
{"dd.span_id", CorrelationIdentifier.SpanId.ToString()},
}))
{
// 로그를 기록
}
다음 로그 공급자에 대해 BeginScope를 사용해 구조화된 로그 메시지를 만드는 방법에 대해 자세히 읽어볼 수 있어요:
- Serilog: The semantics of ILogger.BeginScope()
- NLog: NLog properties with Microsoft Extension Logging
- log4net: Using BeginScope