서버 사이드 커스텀 계측 (Server-Side Custom Instrumentation)
Datadog API와 OpenTelemetry를 사용해 애플리케이션 특화 관측 데이터를 포착하도록 커스텀 스팬, 태그, 계측을 추가하는 방법을 다뤄요. 자동 계측이 지원하지 않는 코드를 추적하거나, Datadog SDK 기능을 확장하거나, 계측을 더 세밀하게 제어해야 할 때 사용해요.
출처: 문서
본문
경고: C++는 OpenTelemetry API를 지원하지 않아요. C++ 커스텀 계측 문서를 보려면 API 드롭다운에서 Datadog를 선택하세요.
경고: Rust는 Datadog API를 지원하지 않아요. Rust 커스텀 계측 문서를 보려면 API 드롭다운에서 OpenTelemetry를 선택하세요.
경고: Elixir는 Datadog API를 지원하지 않아요. Elixir 커스텀 계측 문서를 보려면 API 드롭다운에서 OpenTelemetry를 선택하세요.
Datadog는 Elixir SDK를 제공하지 않아요. Datadog에 트레이스를 보내려면 OpenTelemetry SDK for Elixir을 사용하세요.
OpenTelemetry API를 사용한 커스텀 계측
OpenTelemetry API로 애플리케이션을 수동 계측하는 이유는 몇 가지가 있어요:
- Datadog가 지원하는 라이브러리 계측을 사용하지 않는 경우.
- Datadog SDK의 기능을 확장하고 싶은 경우.
- 애플리케이션 계측을 더 세밀하게 제어해야 하는 경우.
Datadog SDK는 이러한 목표를 달성하는 데 도움이 되는 여러 기법을 제공해요. 다음 섹션에서는 OpenTelemetry API를 커스텀 계측에 사용해 Datadog에 통합하는 방법을 보여줘요.
Java
설정
참고: OpenTelemetry는 1.24.0 이후 버전의 Java에서 지원돼요.
OpenTelemetry가 Datadog 트레이스 프로바이더를 사용하도록 구성하려면:
- 아직 자동 계측과 설정 지침을 읽지 않았다면 Java 설정 지침부터 시작하세요.
- OpenTelemetry API에만 의존하고(OpenTelemetry SDK에는 의존하지 않고) 있는지 확인하세요.
dd.trace.otel.enabled시스템 속성 또는DD_TRACE_OTEL_ENABLED환경 변수를true로 설정하세요.
스팬 태그 추가하기
커스텀 스팬 태그 추가하기
customer.id 같은 애플리케이션 코드 내 동적 값에 해당하는 커스텀 태그를 스팬에 추가해요.
import io.opentelemetry.api.trace.Span;
public void doSomething() {
Span span = Span.current();
span.setAttribute("user-name", "Some User");
}
모든 스팬에 전역으로 태그 추가하기
dd.tags 속성을 사용하면 애플리케이션의 모든 생성 스팬에 태그를 설정할 수 있어요. 이는 애플리케이션, 데이터센터 또는 Datadog에서 보고 싶은 다른 태그의 통계를 그룹화하는 데 유용해요.
java -javaagent:<DD-JAVA-AGENT-PATH>.jar \
-Ddd.tags=datacenter:njc,<TAG_KEY>:<TAG_VALUE> \
-jar <YOUR_APPLICATION_PATH>.jar
스팬에 오류 설정하기
스팬에 오류를 설정하려면 setStatus 메서드를 사용해요:
import static io.opentelemetry.api.trace.StatusCode.ERROR;
import io.opentelemetry.api.trace.Span;
public void doSomething() {
Span span = Span.current();
span.setStatus(ERROR, "Some error details...");
}
하위 스팬에서 루트 스팬에 태그·오류 설정하기
하위 스팬 안에서 루트 스팬에 태그나 오류를 설정하려면 OpenTelemetry Context API를 사용할 수 있어요:
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.ContextKey;
import io.opentelemetry.context.Scope;
public class Example {
private final static ContextKey<Span> CONTEXT_KEY =
ContextKey.named("opentelemetry-traces-local-root-span");
public void begin() {
Tracer tracer = GlobalOpenTelemetry.getTracer("my-scope", "0.1.0");
Span parentSpan = tracer.spanBuilder("begin").startSpan();
try (Scope scope = parentSpan.makeCurrent()) {
createChildSpan();
} finally {
parentSpan.end();
}
}
private void createChildSpan() {
Tracer tracer = GlobalOpenTelemetry.getTracer("my-scope", "0.1.0");
Span childSpan = tracer.spanBuilder("child-span").startSpan();
try {
Span rootSpan = Context.current().get(CONTEXT_KEY);
if (null != rootSpan) {
rootSpan.setAttribute("my-attribute", "my-attribute-value");
rootSpan.setStatus(StatusCode.ERROR, "Some error details...");
}
} finally {
childSpan.end();
}
}
}
스팬 추가하기
지원되는 프레임워크 계측을 사용하지 않거나 애플리케이션 트레이스에 더 깊이를 더하고 싶다면, 완전한 플레임 그래프를 만들거나 코드 조각의 실행 시간을 측정하기 위해 커스텀 계측을 코드에 추가하고 싶을 수 있어요.
애플리케이션 코드 수정이 불가능하다면 dd.trace.methods 환경 변수를 사용해 이러한 메서드를 지정해요.
기존의 @Trace 또는 유사한 어노테이션이 있거나, Datadog 내에서 불완전한 트레이스를 완성하기 위해 어노테이션을 선호한다면 Trace Annotations를 사용하세요.
Trace 어노테이션
OpenTelemetry와 dd-java-agent.jar로 실행할 때 메서드가 추적되도록 @WithSpan을 추가하세요. Agent가 연결되어 있지 않으면 이 어노테이션은 애플리케이션에 아무 영향도 주지 않아요.
OpenTelemetry의 @WithSpan 어노테이션은 opentelemetry-instrumentation-annotations 의존성에서 제공돼요.
import io.opentelemetry.instrumentation.annotations.WithSpan;
public class SessionManager {
@WithSpan
public static void saveSession() {
// your method implementation here
}
}
수동으로 새 스팬 만들기
현재 트레이스 컨텍스트 안에서 새 스팬을 수동으로 만들려면:
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Scope;
public class Example {
public void doSomething() {
Tracer tracer = GlobalOpenTelemetry.getTracer("my-scope", "0.1.0");
Span span = tracer.spanBuilder("my-resource").startSpan();
try (Scope scope = span.makeCurrent()) {
// do some work
} catch (Throwable t) {
span.recordException(t);
throw t;
} finally {
span.end();
}
}
}
스팬 이벤트 추가하기
참고: 스팬 이벤트를 추가하려면 SDK 1.40.0 이상 버전이 필요해요.
addEvent API를 사용해 스팬 이벤트를 추가할 수 있어요. 이 메서드는 name 파라미터가 필요하고 선택적으로 attributes와 timestamp 파라미터를 받아요. 이 메서드는 지정한 속성으로 새 스팬 이벤트를 만들고 해당 스팬과 연결해요.
- Name [필수]: 이벤트 이름을 나타내는 문자열.
- Attributes [선택]: 키가 빈 문자열이 아닌 문자열이고 값이 기본형 또는 기본형 값의 동질 배열인 키-값 쌍.
- Timestamp [선택]: 이벤트 발생 시간을 나타내는 UNIX 타임스탬프.
Instant객체를 기대해요.
Attributes eventAttributes = Attributes.builder()
.put(AttributeKey.longKey("int_val"), 1L)
.put(AttributeKey.stringKey("string_val"), "two")
.put(AttributeKey.longArrayKey("int_array"), Arrays.asList(3L, 4L))
.put(AttributeKey.stringArrayKey("string_array"), Arrays.asList("5", "6"))
.put(AttributeKey.booleanArrayKey("bool_array"), Arrays.asList(true, false))
.build();
span.addEvent("Event With No Attributes");
span.addEvent("Event With Some Attributes", eventAttributes);
이벤트 추가에 대한 OpenTelemetry 사양을 읽어보세요.
예외 기록하기
예외를 기록하려면 recordException API를 사용해요:
span.recordException(new Exception("Error Message"));
span.recordException(new Exception("Error Message"),
Attributes.builder().put(AttributeKey.stringKey("status"), "failed").build());
예외 기록에 대한 OpenTelemetry 사양을 읽어보세요.
트레이스 클라이언트 및 Agent 구성
트레이싱 클라이언트와 Datadog Agent 모두 컨텍스트 전파를 위한 추가 구성 옵션을 제공해요. 헬스 체크와 관련된 트레이스처럼 계산된 메트릭에 포함하고 싶지 않은 특정 리소스를 Datadog로 트레이스를 보내지 않도록 제외할 수도 있어요.
헤더 추출·주입으로 컨텍스트 전파하기
헤더를 주입·추출해 분산 트레이스의 컨텍스트 전파를 구성할 수 있어요. Trace Context Propagation 문서를 읽어보세요.
리소스 필터링
리소스 이름을 기준으로 트레이스를 제외해 헬스 체크 같은 합성 트래픽이 Datadog에 트레이스를 보고하지 않도록 할 수 있어요. 이 설정과 다른 보안·미세 조정 구성은 Security 페이지 또는 Ignoring Unwanted Resources에서 찾을 수 있어요.
Python
설정
OpenTelemetry가 Datadog 트레이스 프로바이더를 사용하도록 구성하려면:
- 아직 자동 계측 및 설정 지침을 읽지 않았다면 Python 설정 지침부터 시작하세요.
DD_TRACE_OTEL_ENABLED환경 변수를true로 설정하세요.
커스텀 스팬 만들기
기존 트레이스 컨텍스트 안에서 커스텀 스팬을 만들려면:
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
def do_work():
with tracer.start_as_current_span("operation_name") as span:
# Perform the work that you want to track with the span
print("Doing work...")
# When the 'with' block ends, the span is automatically closed
활성 스팬 접근하기
현재 활성 스팬에 접근하려면 get_current_span() 함수를 사용해요:
from opentelemetry import trace
current_span = trace.get_current_span()
# enrich 'current_span' with information
스팬 태그 추가하기
추가 컨텍스트나 메타데이터를 제공하려면 스팬에 속성을 추가해요:
from opentelemetry import trace
current_span = trace.get_current_span()
current_span.set_attribute("attribute_key1", 1)
스팬 이벤트 추가하기
참고: 스팬 이벤트를 추가하려면 SDK 2.9.0 이상 버전이 필요해요.
add_event API를 사용해 스팬 이벤트를 추가할 수 있어요. 이 메서드는 name 파라미터가 필요하고 선택적으로 attributes와 timestamp 파라미터를 받아요.
span.add_event("Event With No Attributes")
span.add_event("Event With Some Attributes", {"int_val": 1, "string_val": "two", "int_array": [3, 4], "string_array": ["5", "6"], "bool_array": [True, False]})
이벤트 추가에 대한 OpenTelemetry 사양을 읽어보세요.
예외 기록하기
예외를 기록하려면 record_exception API를 사용해요:
span.record_exception(Exception("Error Message"))
span.record_exception(Exception("Error Message"), {"status": "failed"})
예외 기록에 대한 OpenTelemetry 사양을 읽어보세요.
Node.js
설정
애플리케이션을 계측하려면 Datadog 트레이서(dd-trace)를 초기화하고 OpenTelemetry API에 그 TracerProvider를 명시적으로 등록해요. 그러면 모든 OpenTelemetry 호출이 Datadog를 통해 라우팅돼요.
-
의존성 추가:
npm install dd-trace @opentelemetry/api -
애플리케이션의 진입 파일(예:
index.js)에서 다른 import보다 먼저 트레이서를 초기화하고 등록해요.
완전한 예시
// 1. Import the dd-trace library (do not initialize it yet)
const ddtrace = require('dd-trace');
// 2. Initialize the Datadog tracer. This must be the first operation.
const tracer = ddtrace.init({
// service: 'my-nodejs-app'
// ... other Datadog configurations
});
// 3. Create and register Datadog's TracerProvider.
const provider = new tracer.TracerProvider();
provider.register(); // This wires the @opentelemetry/api to Datadog
// 4. Import and use the OpenTelemetry API
const otel = require('@opentelemetry/api');
const otelTracer = otel.trace.getTracer(
'my-custom-instrumentation' // A name for your specific instrumentation
);
// You can now use 'otelTracer' to create spans throughout your application.
Datadog는 이러한 OpenTelemetry 스팬을 다른 Datadog APM 스팬과 결합해 애플리케이션의 단일 트레이스로 만들어요. 통합 계측과 OpenTelemetry 자동 계측도 지원해요.
스팬 태그 추가하기
추가 컨텍스트를 제공하려면 스팬에 커스텀 속성을 추가해요:
function processData(i, param1, param2) {
return otelTracer.startActiveSpan(`processData:${i}`, (span) => {
const result = someOperation(param1, param2);
// Add an attribute to the span
span.setAttribute('app.processedData', result.toString());
span.end();
return result;
});
}
스팬 만들기
새 스팬을 만들고 제대로 닫으려면 startActiveSpan 메서드를 사용해요:
function performTask(iterations, param1, param2) {
// Create a span. A span must be closed.
return otelTracer.startActiveSpan('performTask', (span) => {
const results = [];
for (let i = 0; i < iterations; i++) {
results.push(processData(i, param1, param2));
}
// Be sure to end the span!
span.end();
return results;
});
}
스팬 이벤트 추가하기
참고: 스팬 이벤트를 추가하려면 SDK 5.17.0/4.41.0 이상 버전이 필요해요.
addEvent API를 사용해 스팬 이벤트를 추가할 수 있어요:
span.addEvent('Event With No Attributes')
span.addEvent('Event With Some Attributes', {"int_val": 1, "string_val": "two", "int_array": [3, 4], "string_array": ["5", "6"], "bool_array": [true, false]})
이벤트 추가에 대한 OpenTelemetry 사양을 읽어보세요.
예외 기록하기
예외를 기록하려면 recordException API를 사용해요:
span.recordException(new TestError())
예외 기록에 대한 OpenTelemetry 사양을 읽어보세요.
요청 필터링
경우에 따라 헬스 체크나 합성 트래픽 같은 특정 요청을 계측에서 제외하고 싶을 수 있어요. http 플러그인의 blocklist 또는 allowlist 옵션을 사용해 이 요청들을 무시할 수 있어요.
// at the top of the entry point right after tracer.init()
tracer.use('http', {
blocklist: ['/health', '/ping']
})
필요하다면 클라이언트와 서버 간에 구성을 분할할 수도 있어요:
tracer.use('http', {
server: {
blocklist: ['/ping']
}
})
추가로 리소스 이름을 기준으로 트레이스를 제외해 Agent가 이를 Datadog에 보내지 않게 할 수 있어요. 보안 및 미세 조정 Agent 구성에 대한 자세한 내용은 Security 또는 Ignoring Unwanted Resources 문서를 읽어보세요.
Go
임포트
Datadog 트레이스 프로바이더를 설정하려면 다음 패키지를 임포트해요:
import (
"context"
"log"
"os"
"github.com/DataDog/dd-trace-go/v2/ddtrace/ext"
"github.com/DataDog/dd-trace-go/v2/ddtrace/opentelemetry"
"github.com/DataDog/dd-trace-go/v2/ddtrace/tracer"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
)
설정
OpenTelemetry가 Datadog 트레이스 프로바이더를 사용하도록 구성하려면:
-
OpenTelemetry Go Manual Instrumentation 문서를 따라 Go 코드에 원하는 수동 OpenTelemetry 계측을 추가하세요. 중요! 이 지침이 코드에서 OpenTelemetry SDK를 호출하라고 하면, 대신 Datadog 트레이싱 라이브러리를 호출하세요.
-
OpenTelemetry 패키지를 설치해요:
go get go.opentelemetry.io/otel -
Datadog OpenTelemetry 래퍼 패키지를 설치해요:
go get github.com/DataDog/dd-trace-go/v2/ddtrace/opentelemetry -
패키지를 임포트해요:
import ( "go.opentelemetry.io/otel" ddotel "github.com/DataDog/dd-trace-go/v2/ddtrace/opentelemetry" ) -
TracerProvider를 만들고 Shutdown 메서드를 defer해요:
provider := ddotel.NewTracerProvider() defer provider.Shutdown() -
전역 TracerProvider를 설정해요:
otel.SetTracerProvider(provider) -
애플리케이션을 실행해요.
스팬 태그 추가하기
추가 메타데이터와 컨텍스트를 첨부하려면 스팬에 커스텀 태그를 추가해요:
// Start a span.
ctx, span := t.Start(ctx, "read.file")
// Set an attribute, or a tag in Datadog terminology, on a span.
span.SetAttributes(attribute.String(ext.ResourceName, "test.json"))
모든 스팬에 전역으로 태그 추가하기
WithGlobalTag 옵션으로 트레이서를 구성해 모든 스팬에 태그를 추가해요:
provider := ddotel.NewTracerProvider(
ddtracer.WithGlobalTag("datacenter", "us-1"),
ddtracer.WithGlobalTag("env", "dev"),
)
defer provider.Shutdown()
otel.SetTracerProvider(provider)
t := otel.Tracer("")
스팬에 오류 설정하기
스팬에 오류를 설정하려면:
// Start a span.
ctx, span := t.Start(context.Background(), "spanName")
// Set an error on a span with 'span.SetAttributes'.
span.SetAttributes(attribute.String(ext.ErrorMsg, "errorMsg"))
// Alternatively, set an error via end span options.
EndOptions(span, tracer.WithError(errors.New("myErr")))
span.End()
스팬 추가하기
다른 Datadog 트레이싱 라이브러리와 달리, Go 애플리케이션을 추적할 때는 스팬의 Go 컨텍스트를 명시적으로 관리하고 전달하는 것을 Datadog가 권장해요.
ctx, span := t.Start(
ddotel.ContextWithStartOptions(context.Background(), ddtracer.Measured()), "span_name")
span.End()
스팬 이벤트 추가하기
참고: 스팬 이벤트를 추가하려면 SDK 1.67.0 이상 버전이 필요해요.
AddEvent API를 사용해 스팬 이벤트를 추가할 수 있어요:
ctx, span := tracer.StartSpan(context.Background(), "span_name")
span.AddEvent("Event With No Attributes")
span.AddEvent("Event With Some Attributes", oteltrace.WithAttributes(attribute.Int("int_val", 1), attribute.String("string_val", "two")))
span.Finish()
이벤트 추가에 대한 OpenTelemetry 사양을 읽어보세요.
트레이스 클라이언트 및 Agent 구성
헤더 추출·주입으로 컨텍스트 전파하기
헤더를 주입·추출해 분산 트레이스의 컨텍스트 전파를 구성할 수 있어요. Trace Context Propagation 문서를 읽어보세요.
리소스 필터링
리소스 이름을 기준으로 트레이스를 제외해 헬스 체크 같은 합성 트래픽이 Datadog에 트레이스를 보고하지 않도록 할 수 있어요. 이 설정과 다른 보안·미세 조정 구성은 Security 페이지에서 찾을 수 있어요.
Ruby
요구 사항 및 제한 사항
- Datadog Ruby 트레이싱 라이브러리
dd-trace-rb1.9.0 이상. - Gem 버전 1.1.0 이상 지원.
Datadog 라이브러리에서 구현된 OpenTelemetry 기능:
| Feature | Support notes |
|---|---|
| OpenTelemetry Context propagation | Datadog와 W3C Trace Context 헤더 형식이 기본 활성화돼요. |
| Span processors | 지원 안 함 |
| Span Exporters | 지원 안 함 |
OpenTelemetry.logger |
OpenTelemetry.logger는 Datadog.logger와 같은 객체로 설정돼요. 커스텀 로깅으로 구성하세요. |
| Trace/span ID generators | ID 생성은 트레이싱 라이브러리가 수행하며, 128비트 trace ID를 지원해요. |
OpenTelemetry가 Datadog 트레이싱 라이브러리를 사용하도록 구성하기
-
OpenTelemetry Ruby Manual Instrumentation 문서를 따라 Ruby 코드에 원하는 수동 OpenTelemetry 계측을 추가하세요. 중요! 이 지침이 코드에서 OpenTelemetry SDK를 호출하라고 하면, 대신 Datadog 트레이싱 라이브러리를 호출하세요.
-
Gemfile에
datadoggem을 추가해요:source 'https://rubygems.org' gem 'datadog' # For dd-trace-rb v1.x, use the `ddtrace` gem. -
bundle install을 실행해 gem을 설치해요. -
OpenTelemetry 구성 파일에 다음 줄을 추가해요:
require 'opentelemetry/sdk' require 'datadog/opentelemetry' -
애플리케이션에 구성 블록을 추가해요:
Datadog.configure do |c| ... end
Datadog는 이러한 OpenTelemetry 스팬을 다른 Datadog APM 스팬과 결합해 애플리케이션의 단일 트레이스로 만들어요. 통합 계측과 OpenTelemetry 자동 계측도 지원해요.
스팬 이벤트 추가하기
참고: 스팬 이벤트를 추가하려면 SDK 2.3.0 이상 버전이 필요해요.
add_event API를 사용해 스팬 이벤트를 추가할 수 있어요:
span.add_event('Event With No Attributes')
span.add_event(
'Event With All Attributes',
attributes: { 'int_val' => 1, 'string_val' => 'two', 'int_array' => [3, 4], 'string_array' => ['5', '6'], 'bool_array' => [false, true]}
)
이벤트 추가에 대한 OpenTelemetry 사양을 읽어보세요.
예외 기록하기
예외를 기록하려면 record_exception API를 사용해요:
span.record_exception(
StandardError.new('Error Message')
)
span.record_exception(
StandardError.new('Error Message'),
attributes: { 'status' => 'failed' }
)
예외 기록에 대한 OpenTelemetry 사양을 읽어보세요.
.NET
설정
OpenTelemetry가 Datadog 트레이스 프로바이더를 사용하도록 구성하려면:
- OpenTelemetry .NET Manual Instrumentation 문서를 따라 .NET 코드에 원하는 수동 OpenTelemetry 계측을 추가하세요. 참고: 이 지침이 코드에서 OpenTelemetry SDK를 호출하라고 하면, 대신 Datadog 트레이싱 라이브러리를 호출하세요.
- Datadog .NET 트레이싱 라이브러리를 설치하고 .NET Framework 서비스 또는 .NET Core(및 .NET 5+) 서비스에 트레이서를 활성화해요. Single Step APM Instrumentation으로 선택적으로 이렇게 할 수 있어요.
DD_TRACE_OTEL_ENABLED환경 변수를true로 설정해요.- 애플리케이션을 실행해요.
Datadog는 이러한 OpenTelemetry 스팬을 다른 Datadog APM 스팬과 결합해 애플리케이션의 단일 트레이스로 만들어요. OpenTelemetry 계측 라이브러리도 지원해요.
커스텀 스팬 만들기
새롭고 독립적인 트레이스를 시작하는 스팬을 수동으로 만들려면:
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
// Start a new span
using (Activity? activity = Telemetry.ActivitySource.StartActivity("<RESOURCE NAME>"))
{
activity?.SetTag("operation.name", "custom-operation");
// Do something
}
스팬 만들기
기존 트레이스 컨텍스트 안에서 커스텀 스팬을 만들려면:
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using (Activity? parentScope = Telemetry.ActivitySource.StartActivity("<RESOURCE NAME>"))
{
parentScope?.SetTag("operation.name", "manual.sortorders");
using (Activity? childScope = Telemetry.ActivitySource.StartActivity("<RESOURCE NAME>"))
{
childScope?.SetTag("operation.name", "manual.sortorders.child");
SortOrders();
}
}
스팬 태그 추가하기
추가 컨텍스트를 제공하려면 스팬에 커스텀 태그를 추가해요:
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
public class ShoppingCartController : Controller
{
[HttpGet]
public IActionResult Index(int customerId)
{
Activity? activity = Telemetry.ActivitySource.StartActivity("<RESOURCE NAME>")
// Add a tag to the span for use in the Datadog web UI
activity?.SetTag("customer.id", customerId.ToString());
var cart = _shoppingCartRepository.Get(customerId);
return View(cart);
}
}
스팬에 오류 설정하기
스팬 실행 중 오류가 발생하면 스팬에 오류 정보를 설정해요:
try
{
// do work that can throw an exception
}
catch(Exception e)
{
activity?.SetTag("error", 1);
activity?.SetTag("error.message", exception.Message);
activity?.SetTag("error.stack", exception.ToString());
activity?.SetTag("error.type", exception.GetType().ToString());
}
스팬 이벤트 추가하기
참고: 스팬 이벤트를 추가하려면 SDK 2.53.0 이상 버전이 필요해요.
AddEvent API를 사용해 스팬 이벤트를 추가할 수 있어요:
var eventTags = new ActivityTagsCollection
{
{ "int_val", 1 },
{ "string_val", "two" },
{ "int_array", new int[] { 3, 4 } },
{ "string_array", new string[] { "5", "6" } },
{ "bool_array", new bool[] { true, false } }
};
activity.AddEvent(new ActivityEvent("Event With No Attributes"));
activity.AddEvent(new ActivityEvent("Event With Some Attributes", DateTimeOffset.Now, eventTags));
이벤트 추가에 대한 OpenTelemetry 사양을 읽어보세요.
헤더 추출·주입으로 컨텍스트 전파하기
헤더를 주입·추출해 분산 트레이스의 컨텍스트 전파를 구성할 수 있어요. Trace Context Propagation 문서를 읽어보세요.
PHP
설정
OpenTelemetry가 Datadog 트레이스 프로바이더를 사용하도록 구성하려면:
-
OpenTelemetry API 패키지를 설치해요:
composer require open-telemetry/sdk -
OpenTelemetry PHP Manual Instrumentation 문서를 따라 PHP 코드에 원하는 수동 OpenTelemetry 계측을 추가하세요.
-
Datadog PHP 트레이싱 라이브러리를 설치해요.
-
DD_TRACE_OTEL_ENABLED를true로 설정하세요.
Datadog는 이러한 OpenTelemetry 스팬을 다른 Datadog APM 스팬과 결합해 애플리케이션의 단일 트레이스로 만들어요.
스팬 태그 추가하기
정확히 스팬을 시작하는 순간에 속성을 추가할 수 있어요:
$span = $tracer->spanBuilder('mySpan')
->setAttribute('key', 'value')
->startSpan();
또는 스팬이 활성 상태인 동안:
$activeSpan = OpenTelemetry\API\Trace\Span::getCurrent();
$activeSpan->setAttribute('key', 'value');
스팬에 오류 설정하기
예외가 발생할 때 활성 스팬이 있으면 예외 정보가 포착되어 스팬에 첨부돼요:
// Create a span
$span = $tracer->spanBuilder('mySpan')->startSpan();
throw new \Exception('Oops!');
// 'mySpan' will be flagged as erroneous and have
// the stack trace and exception message attached as tags
트레이스를 오류로 표시하는 것도 수동으로 할 수 있어요:
use OpenTelemetry\API\Trace\Span;
use OpenTelemetry\Context\Context;
try {
throw new \Exception('Oops!');
} catch (\Exception $e) {
$rootSpan = Span::fromContext(Context::getRoot());
$rootSpan->recordException($e);
}
스팬 추가하기
스팬을 추가하려면:
// Get a tracer or use an existing one
$tracerProvider = \OpenTelemetry\API\Globals::tracerProvider();
$tracer = $tracerProvider->getTracer('datadog')
// Create a span
$span = $tracer->spanBuilder('mySpan')->startSpan();
// ... do stuff
// Close the span
$span->end();
스팬 이벤트 추가하기
참고: 스팬 이벤트를 추가하려면 SDK 1.3.0 이상 버전이 필요해요.
addEvent API를 사용해 스팬 이벤트를 추가할 수 있어요:
$span->addEvent("Event With No Attributes");
$span->addEvent(
"Event With Some Attributes",
[
'int_val' => 1,
'string_val' => "two",
'int_array' => [3, 4],
'string_array' => ["5", "6"],
'bool_array' => [true, false]
]
);
이벤트 추가에 대한 OpenTelemetry 사양을 읽어보세요.
예외 기록하기
예외를 기록하려면 recordException API를 사용해요:
$span->recordException(new \Exception("Error Message"));
$span->recordException(new \Exception("Error Message"), [ "status" => "failed" ]);
예외 기록에 대한 OpenTelemetry 사양을 읽어보세요.
활성 스팬 접근하기
현재 활성 스팬에 접근하려면:
$span = OpenTelemetry\API\Trace\Span::getCurrent();
Rust
참고: Datadog Rust SDK는 Preview 상태예요.
Datadog는 datadog-opentelemetry 크레이트를 통해 Rust 애플리케이션의 커스텀 계측을 지원해요. 이 라이브러리는 OpenTelemetry(OTel) API와 SDK 위에 구축되어 Datadog 특화 기능과 exporter를 포함한 트레이서를 제공해요.
이 라이브러리는 OpenTelemetry 위에 구축되어 있으므로 트레이스와 스팬을 만들 때 표준 OpenTelemetry API를 사용해요.
설정
Rust 애플리케이션이 OpenTelemetry 트레이스를 Datadog에 보내도록 구성하려면:
1. 의존성 추가
Cargo.toml에 datadog-opentelemetry와 코어 opentelemetry 크레이트를 추가해요:
cargo add datadog-opentelemetry opentelemetry
2. Tracer 초기화
애플리케이션의 main 함수에서 Datadog 트레이서 프로바이더를 초기화해요:
참고: 대기 중인 트레이스를 모두 플러시하려면 애플리케이션이 종료되기 전에 프로바이더를 셧다운해야 해요.
use datadog_opentelemetry;
use opentelemetry::{global, trace::Tracer};
use std::time::Duration;
fn main() {
// This picks up env var configuration (like DD_SERVICE)
// and initializes the global tracer provider
let tracer_provider = datadog_opentelemetry::tracing()
.init();
// --- Your application code starts here ---
let tracer = global::tracer("my-component");
tracer.in_span("my-operation", |_cx| {
// ... do work ...
});
println!("Doing work...");
// --- Your application code ends here ---
// Shut down the tracer provider to flush remaining spans
tracer_provider.shutdown_with_timeout(Duration::from_secs(5)).expect("tracer shutdown error");
}
3. Agent가 실행 중인지 확인
Datadog exporter는 Datadog Agent에 트레이스를 보내므로 Agent가 실행 중이고 접근 가능해야 해요.
구성
Datadog Rust SDK는 환경 변수로 구성돼요. 전체 옵션 목록은 Configuration 문서를 참고하세요.
예시
Tracer 가져오기
전역 프로바이더에서 Tracer 인스턴스를 가져와요:
use opentelemetry::global;
let tracer = global::tracer("my-component");
스팬 만들기
tracer.in_span을 사용해 새 스팬을 만들어요. 클로저가 끝나면 스팬이 자동으로 종료돼요:
use opentelemetry::{global, trace::Tracer};
fn do_work() {
let tracer = global::tracer("my-component");
tracer.in_span("operation_name", |_cx| {
// The span is active within this closure
println!("Doing work...");
});
}
하위 스팬 만들기
하위 스팬을 만들려면 in_span 호출을 중첩해요:
use opentelemetry::{global, trace::Tracer};
fn parent_operation() {
let tracer = global::tracer("my-component");
tracer.in_span("parent_operation", |_cx| {
tracer.in_span("child_operation", |_cx| {
// This span is automatically parented to "parent_operation"
println!("Doing child work...");
});
println!("Doing parent work...");
});
}
스팬 태그 추가하기
set_attribute 메서드를 사용해 스팬에 속성을 추가해요:
use opentelemetry::trace::{Tracer, TraceContextExt};
use opentelemetry::KeyValue;
fn add_tags_to_span() {
let tracer = opentelemetry::global::tracer("my-component");
tracer.in_span("operation.with.tags", |cx| {
let span = cx.span();
span.set_attribute(KeyValue::new("customer.id", "12345"));
span.set_attribute(KeyValue::new("http.method", "GET"));
});
}
스팬 이벤트 추가하기
add_event 메서드를 사용해 스팬에 타임스탬프가 찍힌 로그 메시지를 추가해요:
use opentelemetry::trace::{Tracer, TraceContextExt};
use opentelemetry::KeyValue;
fn add_events_to_span() {
let tracer = opentelemetry::global::tracer("my-component");
tracer.in_span("operation.with.events", |cx| {
let span = cx.span();
span.add_event("Data received", vec![]);
span.add_event(
"Processing data",
vec![
KeyValue::new("data.size_bytes", 1024),
KeyValue::new("data.format", "json"),
],
);
});
}
컨텍스트 전파
Rust에는 자동 계측이 없으므로, 서비스 간에 트레이스를 연결하려면 원격 호출을 만들거나 받을 때 트레이스 컨텍스트를 수동으로 전파해야 해요.
자세한 내용은 Trace Context Propagation을 참고하세요.
Datadog API를 사용한 커스텀 계측
개요
Datadog API를 사용해 Datadog로 보낼 트레이스를 프로그래밍 방식으로 생성·수정·삭제해요. 이는 자동 계측에 포착되지 않는 사내 코드를 추적하고, 트레이스에서 원하지 않는 스팬을 제거하며, 스팬 태그 추가를 포함해 스팬에 더 깊은 가시성과 컨텍스트를 제공하는 데 유용해요.
Java
참고: Datadog Java 트레이서는 커스텀 계측을 위해
opentracing-api라이브러리와 상호 운용돼요. 커스텀 계측에 OpenTelemetry API를 선호한다면 Java 커스텀 계측 - OpenTelemetry 사용을 대신 참고하세요.
사전 요구 사항
- 자동 계측 설정 지침을 읽지 않았다면 Java 설정 지침부터 시작하세요.
- 이 페이지의 예시를 컴파일하려면 프로젝트에 opentracing-api 의존성을 추가하세요.
태그 추가하기
Datadog 내 관측성을 커스터마이즈하려면 스팬에 커스텀 스팬 태그를 추가해요. 스팬 태그는 들어오는 트레이스에 적용되어, 가맹점 등급, 결제 금액, 사용자 ID 같은 코드 레벨 정보와 관측된 동작을 연관지을 수 있게 해줘요.
커스텀 스팬 태그 추가하기
customer.id 같은 애플리케이션 코드 내 동적 값에 해당하는 커스텀 태그를 스팬에 추가해요.
import org.apache.cxf.transport.servlet.AbstractHTTPServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import io.opentracing.Tracer;
import io.opentracing.util.GlobalTracer;
@WebServlet
class ShoppingCartServlet extends AbstractHttpServlet {
@Override
void doGet(HttpServletRequest req, HttpServletResponse resp) {
// Get the active span
final Span span = GlobalTracer.get().activeSpan();
if (span != null) {
// customer_id -> 254889
// customer_tier -> platinum
// cart_value -> 867
span.setTag("customer.id", customer_id);
span.setTag("customer.tier", customer_tier);
span.setTag("cart.value", cart_value);
}
// [...]
}
}
모든 스팬에 전역으로 태그 추가하기
dd.tags 속성은 애플리케이션의 모든 생성 스팬에 태그를 설정할 수 있게 해줘요. 이는 애플리케이션, 데이터센터 또는 Datadog UI 내에서 보고 싶은 다른 태그의 통계를 그룹화하는 데 유용할 수 있어요.
java -javaagent:<DD-JAVA-AGENT-PATH>.jar \
-Ddd.tags=datacenter:njc,<TAG_KEY>:<TAG_VALUE> \
-jar <YOUR_APPLICATION_PATH>.jar
스팬에 오류 설정하기
스팬 중 하나와 연결된 오류를 커스터마이즈하려면 스팬에 error 태그를 설정하고 Span.log()를 사용해 "error event"를 설정해요. error event는 Fields.ERROR_OBJECT->Throwable 항목, Fields.MESSAGE->String 항목, 또는 둘 다를 포함하는 Map<String,Object>예요.
import io.opentracing.Span;
import io.opentracing.tag.Tags;
import io.opentracing.util.GlobalTracer;
import io.opentracing.log.Fields;
...
// Get active span if not available in current method
final Span span = GlobalTracer.get().activeSpan();
if (span != null) {
span.setTag(Tags.ERROR, true);
span.log(Collections.singletonMap(Fields.ERROR_OBJECT, ex));
}
참고: Span.log()은 이벤트를 현재 타임스탬프와 연결하는 일반 OpenTracing 메커니즘이에요. Java Tracer는 오류 이벤트 로깅만 지원해요. 또는 log() 없이 스팬에 오류 태그를 직접 설정할 수 있어요:
import io.opentracing.Span;
import io.opentracing.tag.Tags;
import io.opentracing.util.GlobalTracer;
import datadog.trace.api.DDTags;
import java.io.PrintWriter;
import java.io.StringWriter;
...
final Span span = GlobalTracer.get().activeSpan();
if (span != null) {
span.setTag(Tags.ERROR, true);
span.setTag(DDTags.ERROR_MSG, ex.getMessage());
span.setTag(DDTags.ERROR_TYPE, ex.getClass().getName());
final StringWriter errorString = new StringWriter();
ex.printStackTrace(new PrintWriter(errorString));
span.setTag(DDTags.ERROR_STACK, errorString.toString());
}
참고: trace view 문서에 나열된 관련 오류 메타데이터를 추가할 수 있어요. 현재 스팬이 루트 스팬이 아니라면 dd-trace-api 라이브러리로 MutableSpan을 사용해 루트 스팬을 가져온 다음 setError(true)로 오류로 표시하세요. 자세한 내용은 루트 스팬에 태그·오류 설정하기 섹션을 참고하세요.
하위 스팬에서 루트 스팬에 태그·오류 설정하기
다운스트림에서 이벤트나 조건이 발생하면 해당 동작이나 값을 최상위 또는 루트 스팬의 태그로 반영하고 싶을 수 있어요. 이는 오류를 계산하거나 성능을 측정하거나 관측성을 위한 동적 태그를 설정하는 데 유용할 수 있어요.
import java.util.Collections;
import io.opentracing.Span;
import io.opentracing.Scope;
import datadog.trace.api.interceptor.MutableSpan;
import io.opentracing.log.Fields;
import io.opentracing.util.GlobalTracer;
import io.opentracing.util.Tracer;
Tracer tracer = GlobalTracer.get();
final Span span = tracer.buildSpan("<OPERATION_NAME>").start();
// Note: The scope in the try with resource block below
// will be automatically closed at the end of the code block.
// If you do not use a try with resource statement, you need
// to call scope.close().
try (final Scope scope = tracer.activateSpan(span)) {
// exception thrown here
} catch (final Exception e) {
// Set error tag on span as normal
span.log(Collections.singletonMap(Fields.ERROR_OBJECT, e));
// Set error on root span
if (span instanceof MutableSpan) {
MutableSpan localRootSpan = ((MutableSpan) span).getLocalRootSpan();
localRootSpan.setError(true);
localRootSpan.setTag("some.other.tag", "value");
}
} finally {
// Close span in a finally block
span.finish();
}
스팬을 수동으로 만들지 않아도 GlobalTracer를 통해 루트 스팬에 접근할 수 있어요:
import io.opentracing.Span;
import io.opentracing.util.GlobalTracer;
import datadog.trace.api.interceptor.MutableSpan;
...
final Span span = GlobalTracer.get().activeSpan();
if (span != null && (span instanceof MutableSpan)) {
MutableSpan localRootSpan = ((MutableSpan) span).getLocalRootSpan();
// do stuff with root span
}
참고: MutableSpan과 Span은 비슷한 메서드를 많이 공유하지만 서로 다른 타입이에요. MutableSpan은 Datadog 특화 타입이며 OpenTracing API의 일부가 아니에요.
스팬 추가하기
지원되는 프레임워크 계측을 사용하지 않거나 애플리케이션 트레이스에 더 깊이를 더하고 싶다면, 완전한 플레임 그래프를 만들거나 코드 조각의 실행 시간을 측정하기 위해 커스텀 계측을 코드에 추가하고 싶을 수 있어요.
애플리케이션 코드 수정이 불가능하다면 dd.trace.methods 환경 변수를 사용해 이러한 메서드를 지정해요.
기존의 @Trace 또는 유사한 어노테이션이 있거나, Datadog 내에서 불완전한 트레이스를 완성하기 위해 어노테이션을 선호한다면 Trace Annotations를 사용하세요.
Datadog trace methods
dd.trace.methods 시스템 속성을 사용하면 애플리케이션 코드를 변경하지 않고 지원되지 않는 프레임워크에 대한 가시성을 얻을 수 있어요.
java -javaagent:/path/to/dd-java-agent.jar -Ddd.env=prod -Ddd.service.name=db-app -Ddd.trace.methods=store.db.SessionManager[saveSession] -jar path/to/application.jar
같은 클래스 안에서 여러 함수를 추적하려면 다음 문법을 사용해요:
java -javaagent:/path/to/dd-java-agent.jar -Ddd.env=prod -Ddd.service.name=db-app -Ddd.trace.methods=store.db.SessionManager[saveSession,loadSession] -jar path/to/application.jar
이 접근 방식과 @Trace 어노테이션 사용의 유일한 차이는 operation 및 resource 이름의 커스터마이즈 옵션이에요. DD Trace Methods에서는 operationName이 trace.annotation이고 resourceName은 SessionManager.saveSession이에요.
Trace 어노테이션
dd-java-agent.jar로 실행할 때 메서드가 추적되도록 @Trace를 추가하세요. Agent가 연결되어 있지 않으면 이 어노테이션은 애플리케이션에 아무 영향도 주지 않아요.
Datadog의 Trace 어노테이션은 dd-trace-api 의존성에서 제공돼요.
@Trace 어노테이션의 사용 가능한 인자는:
operationName: 트레이스의 operation 이름을 설정해요(기본값: 메서드 이름).resourceName: 트레이스의 resource 이름을 설정해요(기본값:operationName과 같은 값).noParent: 그 메서드에서 항상 새 트레이스를 시작하려면true로 설정해요.dd-trace-javav1.22.0+에서 지원돼요(기본값:false).
import datadog.trace.api.Trace;
public class SessionManager {
@Trace(operationName = "database.persist", resourceName = "SessionManager.saveSession")
public static void saveSession() {
// your method implementation here
}
}
참고: dd.trace.annotations 시스템 속성을 통해 다른 추적 메서드 어노테이션도 Datadog에서 @Trace로 인식할 수 있어요. 이전에 코드를 장식했다면 TraceAnnotationsInstrumentation.java에서 목록을 찾을 수 있어요.
수동으로 새 스팬 만들기
자동 계측, @Trace 어노테이션, dd.trace.methods 구성 외에도 코드 블록 주위에 프로그래밍 방식으로 스팬을 만들어 관측성을 커스터마이즈할 수 있어요. 이 방식으로 만든 스팬은 다른 추적 메커니즘과 자동으로 통합돼요. 즉, 트레이스가 이미 시작되었다면 수동 스팬은 호출자를 부모 스팬으로 갖게 돼요. 마찬가지로 래핑된 코드 블록에서 호출되는 추적된 메서드들은 수동 스팬을 부모로 갖게 돼요.
import datadog.trace.api.DDTags;
import io.opentracing.Scope;
import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.util.GlobalTracer;
class SomeClass {
void someMethod() {
Tracer tracer = GlobalTracer.get();
// Service and resource name tags are required.
// You can set them when creating the span:
Span span = tracer.buildSpan("<OPERATION_NAME>")
.withTag(DDTags.SERVICE_NAME, "<SERVICE_NAME>")
.withTag(DDTags.RESOURCE_NAME, "<RESOURCE_NAME>")
.start();
// Note: The scope in the try with resource block below
// will be automatically closed at the end of the code block.
// If you do not use a try with resource statement, you need
// to call scope.close().
try (Scope scope = tracer.activateSpan(span)) {
// Alternatively, set tags after creation
span.setTag("my.tag", "value");
// The code you're tracing
} catch (Exception e) {
// Set error on span
} finally {
// Close span in a finally block
span.finish();
}
}
}
트레이서 확장하기
트레이싱 라이브러리는 확장 가능하도록 설계됐어요. TraceInterceptor라는 커스텀 후처리기를 작성해 스팬을 가로챈 다음 (예: 정규식 기반으로) 조정하거나 버릴 수 있어요. 다음 예시는 복잡한 후처리 로직을 달성하기 위해 두 개의 인터셉터를 구현해요.
import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import datadog.trace.api.interceptor.TraceInterceptor;
import datadog.trace.api.interceptor.MutableSpan;
class FilteringInterceptor implements TraceInterceptor {
@Override
public Collection<? extends MutableSpan> onTraceComplete(
Collection<? extends MutableSpan> trace) {
List<MutableSpan> filteredTrace = new ArrayList<>();
for (final MutableSpan span : trace) {
String orderId = (String) span.getTags().get("order.id");
// Drop spans when the order id starts with "TEST-"
if (orderId == null || !orderId.startsWith("TEST-")) {
filteredTrace.add(span);
}
}
return filteredTrace;
}
@Override
public int priority() {
// some high unique number so this interceptor is last
return 100;
}
}
class PricingInterceptor implements TraceInterceptor {
@Override
public Collection<? extends MutableSpan> onTraceComplete(
Collection<? extends MutableSpan> trace) {
for (final MutableSpan span : trace) {
Map<String, Object> tags = span.getTags();
Double originalPrice = (Double) tags.get("order.price");
Double discount = (Double) tags.get("order.discount");
// Set a tag from a calculation from other tags
if (originalPrice != null && discount != null) {
span.setTag("order.value", originalPrice - discount);
}
}
return trace;
}
@Override
public int priority() {
return 20; // some unique number
}
}
애플리케이션 시작 부분 근처에서 다음으로 인터셉터를 등록해요:
datadog.trace.api.GlobalTracer.get().addTraceInterceptor(new FilteringInterceptor());
datadog.trace.api.GlobalTracer.get().addTraceInterceptor(new PricingInterceptor());
트레이스 클라이언트 및 Agent 구성
트레이싱 클라이언트와 Datadog Agent 모두 컨텍스트 전파를 위한 추가 구성 옵션과, 계산된 메트릭에 포함하고 싶지 않은 특정 리소스(예: 헬스 체크)가 Datadog에 트레이스를 보내지 않도록 제외하는 구성 옵션을 제공해요.
헤더 추출·주입으로 컨텍스트 전파하기
헤더를 주입·추출해 분산 트레이스의 컨텍스트 전파를 구성할 수 있어요. Trace Context Propagation 문서를 읽어보세요.
리소스 필터링
리소스 이름을 기준으로 트레이스를 제외해 헬스 체크 같은 합성 트래픽이 Datadog에 트레이스를 보고하지 않도록 할 수 있어요. 이 설정과 다른 보안·미세 조정 구성은 Security 페이지 또는 Ignoring Unwanted Resources에서 찾을 수 있어요.
Python
자동 계측 설정 지침을 읽지 않았다면 Python 설정 지침부터 시작하세요.
지원되는 라이브러리 계측을 사용하지 않는다면(라이브러리 호환성 참고) 코드를 수동으로 계측하고 싶을 수 있어요.
ddtrace 라이브러리의 기능을 확장하거나 애플리케이션 계측을 더 세밀하게 제어하고 싶을 수도 있어요. 이를 위해 라이브러리는 몇 가지 기법을 제공해요.
스팬 만들기
ddtrace 라이브러리는 ddtrace-run으로 많은 라이브러리와 프레임워크에 대해 스팬을 자동으로 만들어요. 하지만 자신의 코드에 대한 가시성을 얻고 싶을 수 있으며, 이는 스팬을 사용해 달성해요.
웹 요청 안에서(예: make_sandwich_request) 측정하면 유용한 get_ingredients()와 assemble_sandwich() 같은 여러 연산을 수행할 수 있어요.
def make_sandwich_request(request):
ingredients = get_ingredients()
sandwich = assemble_sandwich(ingredients)
데코레이터 사용하기
ddtrace는 관심 있는 함수를 장식하는 데 사용할 수 있는 데코레이터 tracer.wrap()을 제공해요. 함수가 어디에서 호출되든 추적하고 싶을 때 유용해요.
from ddtrace import tracer
@tracer.wrap(service="my-sandwich-making-svc", resource="resource_name")
def get_ingredients():
# go to the pantry
# go to the fridge
# maybe go to the store
return
# You can provide more information to customize the span
@tracer.wrap("assemble_sandwich", service="my-sandwich-making-svc", resource="resource_name")
def assemble_sandwich(ingredients):
return
자세한 내용은 ddtrace.Tracer.wrap() 데코레이터의 API 상세를 읽어보세요.
컨텍스트 매니저 사용하기
임의의 코드 블록을 추적하려면 아래처럼 ddtrace.Span 컨텍스트 매니저를 사용하거나 고급 사용법 문서를 보세요.
from ddtrace import tracer
def make_sandwich_request(request):
# Capture both operations in a span
with tracer.trace("sandwich.make"):
ingredients = get_ingredients()
sandwich = assemble_sandwich(ingredients)
def make_sandwich_request(request):
# Capture both operations in a span
with tracer.trace("sandwich.create", resource="resource_name") as outer_span:
with tracer.trace("get_ingredients", resource="resource_name") as span:
ingredients = get_ingredients()
with tracer.trace("assemble_sandwich", resource="resource_name") as span:
sandwich = assemble_sandwich(ingredients)
자세한 내용은 ddtrace.Tracer()의 전체 API 상세를 읽어보세요.
수동 스팬 생성
데코레이터와 컨텍스트 매니저 방법이 여전히 추적 요구를 충족하지 못한다면, 스팬을 원하는 대로 시작·완료할 수 있는 수동 API가 제공돼요:
def make_sandwich_request(request):
span = tracer.trace("sandwich.create", resource="resource_name")
ingredients = get_ingredients()
sandwich = assemble_sandwich(ingredients)
span.finish() # remember to finish the span
데코레이터의 더 자세한 API 상세는 ddtrace.Tracer.trace 문서 또는 ddtrace.Span.finish 문서를 읽어보세요.
활성 스팬 접근하기
내장 계측과 사용자 커스텀 계측은 의미 있는 연산 주위에 스팬을 만들어요. 의미 있는 데이터를 포함하기 위해 활성 스팬에 접근할 수 있어요.
from ddtrace import tracer
def make_sandwich_request(request):
# Capture both operations in a span
with tracer.trace("sandwich.make") as my_span:
ingredients = get_ingredients()
sandwich = assemble_sandwich(ingredients)
현재 스팬
def get_ingredients():
# Get the active span
span = tracer.current_span()
# this span is my_span from make_sandwich_request above
루트 스팬
def assemble_sandwich(ingredients):
with tracer.trace("another.operation") as another_span:
# Get the active root span
span = tracer.current_root_span()
# this span is my_span from make_sandwich_request above
태그 추가하기
로컬로 태그 추가하기
스팬의 set_tag 메서드를 사용해 스팬에 태그를 추가할 수 있어요:
from ddtrace import tracer
def make_sandwich_request(request):
with tracer.trace("sandwich.make") as span:
ingredients = get_ingredients()
span.set_tag("num_ingredients", len(ingredients))
전역으로 태그 추가하기
트레이서에 태그를 전역으로 설정할 수 있어요. 이 태그들은 생성되는 모든 스팬에 적용돼요.
from ddtrace import tracer
from myapp import __version__
# This will be applied to every span
tracer.set_tags({"version": __version__, "<TAG_KEY_2>": "<TAG_VALUE_2>"})
스팬에 오류 설정하기
예외가 발생할 때 활성 스팬이 있으면 예외 정보가 포착되어 스팬에 첨부돼요.
from ddtrace import tracer
with tracer.trace("throws.an.error") as span:
raise Exception("Oops!")
# `span` will be flagged as erroneous and have
# the stack trace and exception message attached as tags
스팬을 오류로 표시하는 것도 수동으로 할 수 있어요:
from ddtrace import tracer
span = tracer.trace("operation")
span.error = 1
span.finish()
발생한 오류로 로컬 루트 스팬을 표시하고 싶다면:
import os
from ddtrace import tracer
try:
raise TypeError
except TypeError as e:
root_span = tracer.current_root_span()
(exc_type, exc_val, exc_tb) = sys.exc_info()
# this sets the error type, marks the span as an error, and adds the traceback
root_span.set_exc_info(exc_type, exc_val, exc_tb)
스팬 링크 추가하기
스팬 링크는 일반적인 부모-자식 관계가 없는 하나 이상의 스팬을 서로 연결해요. 같은 트레이스 안의 스팬이나 서로 다른 트레이스의 스팬을 연결할 수 있어요.
스팬 링크를 추가하려면 연결하려는 스팬의 컨텍스트로 link_span()을 호출해요. 속성은 선택 사항이에요.
from ddtrace import tracer
with tracer.trace("span_a") as span_a:
pass
with tracer.trace("span_b") as span_b:
# Link span_b to span_a
span_b.link_span(span_a.context, attributes={"link.name": "span_a"})
헤더 추출·주입으로 컨텍스트 전파하기
헤더를 주입·추출해 분산 트레이스의 컨텍스트 전파를 구성할 수 있어요. Trace Context Propagation 문서를 읽어보세요.
Baggage
스팬에서 Baggage를 조작하려면:
from ddtrace import tracer
# Start a new span and set baggage
with tracer.trace("example") as span:
# set_baggage_item
span.context.set_baggage_item("key1", "value1")
span.context.set_baggage_item("key2", "value2")
# get_all_baggage_items
all_baggage = span.context.get_all_baggage_items()
print(all_baggage) # {'key1': 'value1', 'key2': 'value2'}
# remove_baggage_item
span.context.remove_baggage_item("key1")
print(span.context.get_all_baggage_items()) # {'key2': 'value2'}
# get_baggage_item
print(span.context.get_baggage_item("key1")) # None
print(span.context.get_baggage_item("key2")) # value2
# remove_all_baggage_items
span.context.remove_all_baggage_items()
print(span.context.get_all_baggage_items()) # {}
실제 예시는 trace-examples의 flask-baggage를 참고하세요.
ddtrace-api
참고:
ddtrace-apiPython 패키지는 Preview 상태이며 필요한 모든 API 호출을 포함하지 않을 수 있어요. 더 완전한 기능이 필요하면 이전 섹션에서 설명한 API를 사용하세요.
ddtrace-api 패키지는 Datadog APM 커스텀 Python 계측을 위한 안정적인 공개 API를 제공해요. 이 패키지는 API 인터페이스만 구현하며, 스팬을 만들고 Datadog에 보내는 기본 기능은 구현하지 않아요.
인터페이스(ddtrace-api)와 구현(ddtrace)의 이러한 분리는 여러 이점을 제공해요:
- 커스텀 계측에 대해 덜 자주 더 예측 가능하게 변경되는 API에 의존할 수 있어요.
- 자동 계측만 사용한다면 API 변경을 완전히 무시할 수 있어요.
- 단일 단계와 커스텀 계측을 모두 구현한다면
ddtrace패키지의 여러 복사본에 의존하는 것을 피할 수 있어요.
ddtrace-api를 사용하려면:
-
ddtrace와ddtrace-api라이브러리를 모두 설치해요:pip install 'ddtrace>=3.1' ddtrace-api -
Python 진입점 명령에 접두어를 붙여
ddtrace-run으로 Python 애플리케이션을 계측해요:ddtrace-run python app.py -
이렇게 설정한 후에는 이전 섹션의 예시와 똑같이 커스텀 계측을 작성하되,
ddtrace대신ddtrace_api에서 import해요.
예를 들어:
from ddtrace_api import tracer
@tracer.wrap(service="my-sandwich-making-svc", resource="resource_name")
def get_ingredients():
# go to the pantry
# go to the fridge
# maybe go to the store
return
지원되는 API 호출 전체 목록은 해당 패키지의 API 정의를 참고하세요.
Node.js
참고: 아직 자동 계측 및 설정 지침을 읽지 않았다면 Node.js 설정 지침부터 시작하세요.
지원되는 라이브러리 계측을 사용하지 않는다면(라이브러리 호환성 참고) 코드를 수동으로 계측하고 싶을 수 있어요.
dd-trace 라이브러리의 기능을 확장하거나 애플리케이션 계측을 더 세밀하게 제어하고 싶을 수도 있어요. 이를 위해 라이브러리는 몇 가지 기법을 제공해요.
태그 추가하기
내장 계측과 사용자 커스텀 계측은 의미 있는 연산 주위에 스팬을 만들어요.
로컬로 태그 추가하기
태그를 추가해 의미 있는 데이터를 포함하도록 활성 스팬에 접근할 수 있어요.
const span = tracer.scope().active()
자세한 내용은 Scope의 API 상세를 읽어보세요.
스팬의 setTag 또는 addTags 메서드를 사용해 스팬에 태그를 추가할 수 있어요. 지원되는 값 타입은 문자열, 숫자, 객체예요.
// add a foo:bar tag
span.setTag('foo', 'bar')
// add a user_id:5 tag
span.setTag('user_id', 5)
// add a obj.first:foo and obj.second:bar tags
span.setTag('obj', { first: 'foo', second: 'bar' })
// add a foo:bar and baz:qux tags
span.addTags({
foo: 'bar',
baz: 'qux'
})
전역으로 태그 추가하기
쉼표로 구분된 DD_TAGS 환경 변수나 트레이서 초기화의 tags 옵션으로 트레이서에 직접 구성해 모든 스팬에 태그를 추가할 수 있어요:
// equivalent to DD_TAGS=foo:bar,baz:qux
tracer.init({
tags: {
foo: 'bar',
baz: 'qux'
}
})
// All spans will now have these tags
컴포넌트 훅으로 태그 추가하기
일부 Datadog 통합은 스팬이 끝나기 직전에 스팬을 업데이트하는 데 사용할 수 있는 스팬 훅을 지원해요. 이는 코드에서 달리 접근할 수 없는 스팬을 수정하거나 태그를 추가하는 데 유용해요.
// at the top of the entry point right after tracer.init()
tracer.use('express', {
// hook will be executed right before the request span is finished
hooks: {
request: (span, req, res) => {
span.setTag('customer.id', req.query.customer_id)
}
}
})
자세한 내용은 개별 플러그인의 API 상세를 읽어보세요.
스팬에 오류 설정하기
오류 객체를 지원하는 특별한 error 태그로 스팬에 오류를 추가할 수 있어요. 이는 오류를 error.type, error.message, error.stack의 세 가지 태그로 분리해요.
try {
getIngredients()
} catch (e) {
span.setTag('error', e)
}
tracer.trace() 또는 tracer.wrap()을 사용할 때는 오류가 발생하면 자동으로 처리돼요.
스팬 만들기
dd-trace 라이브러리는 많은 라이브러리와 프레임워크에 대해 tracer.init()으로 스팬을 자동으로 만들어요. 하지만 자신의 코드에 대한 가시성을 얻고 싶을 수 있으며, 이는 스팬을 사용해 달성해요.
웹 요청 안에서(예: /make-sandwich) 측정하면 유용한 getIngredients()와 assembleSandwich() 같은 여러 연산을 수행할 수 있어요.
동기 코드
동기 코드는 tracer.trace()로 추적할 수 있어요. 이는 콜백이 반환되면 자동으로 스팬을 완료하고 발생한 오류를 자동으로 포착해요.
app.get('/make-sandwich', (req, res) => {
const sandwich = tracer.trace('sandwich.make', { resource: 'resource_name' }, () => {
const ingredients = tracer.trace('get_ingredients', { resource: 'resource_name' }, () => {
return getIngredients()
})
return tracer.trace('assemble_sandwich', { resource: 'resource_name' }, () => {
assembleSandwich(ingredients)
})
})
res.end(sandwich)
})
자세한 내용은 tracer.trace()의 API 상세를 읽어보세요.
Promises
Promises는 tracer.trace()로 추적할 수 있어요. 이는 반환된 promise가 resolve되면 자동으로 스팬을 완료하고 거부 오류를 자동으로 포착해요.
const getIngredients = () => {
return new Promise((resolve, reject) => {
resolve('Salami');
});
};
app.get('/make-sandwich', (req, res) => {
return tracer.trace('sandwich.make', { resource: 'resource_name' }, () => {
return tracer.trace('get_ingredients', { resource: 'resource_name' }, () => getIngredients())
.then((ingredients) => {
return tracer.trace('assemble_sandwich', { resource: 'resource_name' }, () => {
return assembleSandwich(ingredients)
})
})
}).then(sandwich => res.end(sandwich))
})
Async/await
Async/await은 tracer.trace()로 추적할 수 있어요. 이는 반환된 promise가 resolve되면 자동으로 스팬을 완료하고 거부 오류를 자동으로 포착해요.
app.get('/make-sandwich', async (req, res) => {
const sandwich = await tracer.trace('sandwich.make', { resource: 'resource_name' }, async () => {
const ingredients = await tracer.trace('get_ingredients', { resource: 'resource_name' }, () => {
return getIngredients()
})
return tracer.trace('assemble_sandwich', { resource: 'resource_name' }, () => {
return assembleSandwich(ingredients)
})
})
res.end(sandwich)
})
Wrapper
코드를 변경하지 않고 기존 함수를 래핑할 수 있어요. 이는 코드를 제어할 수 없는 함수를 추적하는 데 유용해요. tracer.wrap()으로 이렇게 할 수 있으며, 콜백 대신 래핑할 함수를 마지막 인자로 받는 것 외에는 tracer.trace()와 같은 인자를 받아요.
// After the functions are defined
getIngredients = tracer.wrap('get_ingredients', { resource: 'resource_name' }, getIngredients)
assembleSandwich = tracer.wrap('assemble_sandwich', { resource: 'resource_name' }, assembleSandwich)
// Where routes are defined
app.get('/make-sandwich', (req, res) => {
const sandwich = tracer.trace('sandwich.make', { resource: 'resource_name' }, () => {
const ingredients = getIngredients()
return assembleSandwich(ingredients)
})
res.end(sandwich)
})
자세한 내용은 tracer.wrap()의 API 상세를 읽어보세요.
스팬 링크 추가하기
스팬 링크는 일반적인 부모-자식 관계가 없는 하나 이상의 스팬을 서로 연결해요. 같은 트레이스 안의 스팬이나 서로 다른 트레이스의 스팬을 연결할 수 있어요.
스팬을 만들 때 스팬 링크를 추가하려면 links 옵션에 전달해요. 각 링크는 연결하려는 스팬의 컨텍스트와 선택적 속성을 받아요.
const spanA = tracer.startSpan('span_a')
spanA.finish()
tracer.trace('span_b', {
// Link span_b to span_a
links: [{ context: spanA.context(), attributes: { 'link.name': 'span_a' } }]
}, () => {
// ...
})
기존 스팬에 스팬 링크를 추가하려면 addLink()를 사용해요:
const spanC = tracer.startSpan('span_c')
// Link span_c to span_a
spanC.addLink({ context: spanA.context() })
spanC.finish()
스팬 생성 후 추가된 링크는 스팬의 샘플링 결정에 영향을 주지 않아요. 가능하면 스팬을 만들 때 스팬 링크를 추가하세요.
요청 필터링
애플리케이션의 일부 요청을 계측하고 싶지 않을 수 있어요. 흔한 경우는 헬스 체크나 다른 합성 트래픽이에요. http 플러그인의 blocklist 또는 allowlist 옵션으로 이를 무시할 수 있어요.
// at the top of the entry point right after tracer.init()
tracer.use('http', {
blocklist: ['/health', '/ping']
})
필요하다면 클라이언트와 서버 간에 이 구성을 분할할 수 있어요. 예를 들어,
tracer.use('http', {
server: {
blocklist: ['/ping']
}
})
추가로 리소스 이름을 기준으로 트레이스를 제외해 Agent가 이를 Datadog에 보내지 않게 할 수 있어요. 이 설정과 다른 보안·미세 조정 Agent 구성은 Security 페이지 또는 Ignoring Unwanted Resources에서 찾을 수 있어요.
dd-trace-api
dd-trace-api 패키지는 Datadog APM 커스텀 Node.js 계측을 위한 안정적인 공개 API를 제공해요. 이 패키지는 API 인터페이스만 구현하며, 스팬을 만들고 Datadog에 보내는 기본 기능은 구현하지 않아요.
인터페이스(dd-trace-api)와 구현(dd-trace)의 이러한 분리는 여러 이점을 제공해요:
- 커스텀 계측에 대해 덜 자주 더 예측 가능하게 변경되는 API에 의존할 수 있어요.
- 자동 계측만 사용한다면 API 변경을 완전히 무시할 수 있어요.
- 단일 단계와 커스텀 계측을 모두 구현한다면
dd-trace패키지의 여러 복사본에 의존하는 것을 피할 수 있어요.
dd-trace-api를 사용하려면:
-
앱에
dd-trace와dd-trace-api라이브러리를 설치해요. 참고:dd-trace는 단일 단계 계측으로 설치되지만,dd-trace-api는 앱에 수동으로 설치해야 해요.npm install dd-trace dd-trace-api -
dd-trace로 Node.js 애플리케이션을 계측해요. 단일 단계 계측을 사용한다면 이 단계는 건너뛸 수 있어요.node --require dd-trace/init app.js -
이렇게 설정한 후에는 이전 섹션의 예시와 똑같이 커스텀 계측을 작성하되,
dd-trace대신dd-trace-api를 require해요.
예를 들어:
const tracer = require('dd-trace-api')
const express = require('express')
const app = express()
app.get('/make-sandwich', (req, res) => {
const sandwich = tracer.trace('sandwich.make', { resource: 'resource_name' }, () => {
const ingredients = tracer.trace('get_ingredients', { resource: 'resource_name' }, () => {
return getIngredients()
})
return tracer.trace('assemble_sandwich', { resource: 'resource_name' }, () => {
assembleSandwich(ingredients)
})
})
res.end(sandwich)
})
지원되는 API 호출 전체 목록은 해당 패키지의 API 정의를 참고하세요.
Go
참고: 아직 자동 계측 및 설정 지침을 읽지 않았다면 Go 설정 지침부터 시작하세요.
참고: 이 문서는 모든 사용자에게 Datadog가 권장하는 Go 트레이서 v2를 사용해요. v1을 사용한다면 마이그레이션 가이드를 참고해 v2로 업그레이드하세요.
이 페이지는 Datadog APM으로 관측성을 추가·커스터마이즈하는 일반적인 사용 사례를 다뤄요.
태그 추가하기
Datadog 내 관측성을 커스터마이즈하려면 스팬에 커스텀 스팬 태그를 추가해요. 스팬 태그는 들어오는 트레이스에 적용되어, 가맹점 등급, 결제 금액, 사용자 ID 같은 코드 레벨 정보와 관측된 동작을 연관지을 수 있게 해줘요.
커스텀 스팬 태그 추가하기
SetTag를 호출해 Span 인터페이스에 직접 태그를 추가해요:
package main
import (
"log"
"net/http"
"github.com/DataDog/dd-trace-go/v2/ddtrace/tracer"
)
func handler(w http.ResponseWriter, r *http.Request) {
// Create a span for a web request at the /posts URL.
span := tracer.StartSpan("web.request", tracer.ResourceName("/posts"))
defer span.Finish()
// Set tag
span.SetTag("http.url", r.URL.Path)
span.SetTag("<TAG_KEY>", "<TAG_VALUE>")
}
func main() {
tracer.Start(tracer.WithService("<SERVICE_NAME>"))
defer tracer.Stop()
http.HandleFunc("/posts", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
Datadog의 통합은 Context 타입을 사용해 현재 활성 스팬을 전파해요. Context에 첨부된 스팬 태그를 추가하려면 SpanFromContext 함수를 호출해요:
package main
import (
"net/http"
"github.com/DataDog/dd-trace-go/v2/ddtrace/tracer"
)
func handler(w http.ResponseWriter, r *http.Request) {
// Retrieve a span for a web request attached to a Go Context.
if span, ok := tracer.SpanFromContext(r.Context()); ok {
// Set tag
span.SetTag("http.url", r.URL.Path)
}
}
모든 스팬에 전역으로 태그 추가하기
WithGlobalTag 옵션으로 트레이서를 구성해 모든 스팬에 태그를 추가해요:
package main
import (
"github.com/DataDog/dd-trace-go/v2/ddtrace/tracer"
)
func main() {
tracer.Start(
tracer.WithGlobalTag("datacenter", "us-1"),
tracer.WithGlobalTag("env", "dev"),
)
defer tracer.Stop()
}
스팬에 오류 설정하기
스팬 중 하나에 오류를 설정하려면 아래처럼 tracer.WithError를 사용해요:
err := someOperation()
span.Finish(tracer.WithError(err))
스팬 추가하기
지원되는 라이브러리 계측을 사용하지 않는다면(라이브러리 호환성 참고) 코드를 수동으로 계측하고 싶을 수 있어요.
참고: 다른 Datadog 트레이싱 라이브러리와 달리, Go 애플리케이션을 추적할 때는 스팬의 Go 컨텍스트를 명시적으로 관리하고 전달하는 것이 권장돼요. 이 접근 방식은 정확한 스팬 관계와 의미 있는 트레이싱을 보장하는 데 도움이 돼요. 자세한 내용은 Go 컨텍스트 라이브러리 문서 또는 애플리케이션과 통합된 타사 라이브러리 문서를 참고하세요.
수동으로 스팬 만들기
스팬을 수동으로 만들려면 tracer 패키지를 사용해요(v2 API는 Datadog godoc에서, v1은 v1 godoc에서 확인하세요).
두 가지 방법으로 스팬을 만들 수 있어요:
- 기존 스팬에서 하위를 시작:
StartChild(v2) 또는StartSpan(v1) 사용. - 컨텍스트에서 스팬 시작:
StartSpanFromContext(API 상세는 v2 또는 v1 참고).
//v2: Create a span with a resource name, which is the child of parentSpan.
span := parentSpan.StartChild("mainOp", tracer.ResourceName("/user"))
//v1: Create a span with a resource name, which is the child of parentSpan.
span := tracer.StartSpan("mainOp", tracer.ResourceName("/user"), tracer.ChildOf(parentSpan))
// v1 and v2: Create a span which will be the child of the span in the Context ctx, if there is a span in the context.
// Returns the new span, and a new context containing the new span.
span, ctx := tracer.StartSpanFromContext(ctx, "mainOp", tracer.ResourceName("/user"))
비동기 트레이스
func main() {
span, ctx := tracer.StartSpanFromContext(context.Background(), "mainOp")
defer span.Finish()
go func() {
asyncSpan := tracer.StartSpanFromContext(ctx, "asyncOp")
defer asyncSpan.Finish()
performOp()
}()
}
분산 트레이싱
트레이싱 컨텍스트를 수동으로 전파해 분산 트레이스를 만들어요:
package main
import (
"net/http"
"github.com/DataDog/dd-trace-go/v2/ddtrace/tracer"
)
func handler(w http.ResponseWriter, r *http.Request) {
span, ctx := tracer.StartSpanFromContext(r.Context(), "post.process")
defer span.Finish()
req, err := http.NewRequest("GET", "http://example.com", nil)
req = req.WithContext(ctx)
// Inject the span Context in the Request headers
err = tracer.Inject(span.Context(), tracer.HTTPHeadersCarrier(req.Header))
if err != nil {
// Handle or log injection error
}
http.DefaultClient.Do(req)
}
그런 다음 서버 측에서 트레이스를 계속하려면 추출된 Context에서 새 Span을 시작해요:
package main
import (
"net/http"
"github.com/DataDog/dd-trace-go/v2/ddtrace/tracer"
)
func handler(w http.ResponseWriter, r *http.Request) {
// Extract the span Context and continue the trace in this service
sctx, err := tracer.Extract(tracer.HTTPHeadersCarrier(r.Header))
if err != nil {
// Handle or log extraction error
}
span := tracer.StartSpan("post.filter", tracer.ChildOf(sctx))
defer span.Finish()
}
스팬 링크 추가하기
스팬 링크는 일반적인 부모-자식 관계가 없는 하나 이상의 스팬을 서로 연결해요. 같은 트레이스 안의 스팬이나 서로 다른 트레이스의 스팬을 연결할 수 있어요.
tracer.SpanLink는 trace ID와 span ID로 연결하려는 스팬을 식별해요. 속성은 선택 사항이에요. 스팬을 만들 때 스팬 링크를 추가하려면 tracer.WithSpanLinks를 사용해요. 아직 실행 중인 스팬에 스팬 링크를 추가하려면 AddLink를 사용해요:
spanA := tracer.StartSpan("span_a")
spanA.Finish()
link := tracer.SpanLink{
TraceID: spanA.Context().TraceIDLower(),
TraceIDHigh: spanA.Context().TraceIDUpper(),
SpanID: spanA.Context().SpanID(),
Attributes: map[string]string{"link.name": "span_a"},
}
// Link span_b to span_a when you create it
spanB := tracer.StartSpan("span_b", tracer.WithSpanLinks([]tracer.SpanLink{link}))
defer spanB.Finish()
// Or link a running span to span_a
spanC := tracer.StartSpan("span_c")
spanC.AddLink(link)
defer spanC.Finish()
트레이스 클라이언트 및 Agent 구성
트레이싱 클라이언트와 Datadog Agent 모두 B3 헤더로 컨텍스트를 전파하는 추가 구성 옵션과, 헬스 체크처럼 계산된 메트릭에 포함하고 싶지 않은 특정 리소스가 Datadog에 트레이스를 보내지 않도록 제외하는 옵션을 제공해요.
헤더 추출·주입으로 컨텍스트 전파하기
헤더를 주입·추출해 분산 트레이스의 컨텍스트 전파를 구성할 수 있어요. Trace Context Propagation 문서를 읽어보세요.
리소스 필터링
리소스 이름을 기준으로 트레이스를 제외해 헬스 체크 같은 합성 트래픽이 Datadog에 트레이스를 보고하지 않도록 할 수 있어요. 이 설정과 다른 보안·미세 조정 구성은 Security 페이지에서 찾을 수 있어요.
Ruby
참고: 아직 자동 계측 및 설정 지침을 읽지 않았다면 Ruby 설정 지침을 읽어보세요.
이 페이지는 Datadog APM으로 관측성을 추가·커스터마이즈하는 사용 사례를 다뤄요.
요구 사항
Ruby 트레이서 버전에 맞는 적절한 gem을 require했는지 확인하세요:
-
v2.x를 사용한다면
datadoggem을 require해요:require 'datadog' -
v1.x를 사용한다면
ddtracegem을 require해요:require 'ddtrace'
태그 추가하기
Datadog 내 관측성을 커스터마이즈하려면 스팬에 커스텀 스팬 태그를 추가해요. 스팬 태그는 들어오는 트레이스에 적용되어, 가맹점 등급, 결제 금액, 사용자 ID 같은 코드 레벨 정보와 관측된 동작을 연관지을 수 있게 해줘요.
커스텀 스팬 태그 추가하기
customer.id 같은 애플리케이션 코드 내 동적 값에 해당하는 커스텀 태그를 스팬에 추가해요.
활성 스팬
코드의 어떤 메서드에서든 현재 활성 스팬에 접근할 수 있어요.
참고: 메서드가 호출될 때 활성 스팬이 없으면 active_span은 nil이에요.
# get '/shopping_cart/:customer_id', to: 'shopping_cart#index'
class ShoppingCartController < ApplicationController
# GET /shopping_cart
def index
# Get the active span and set customer_id -> 254889
Datadog::Tracing.active_span&.set_tag('customer.id', params.permit([:customer_id]))
# [...]
end
# POST /shopping_cart
def create
# [...]
end
end
수동으로 계측된 스팬
#set_tag를 호출해 Datadog::Span 객체에 태그를 직접 추가해요:
# An example of a Sinatra endpoint,
# with Datadog tracing around the request.
get '/posts' do
Datadog::Tracing.trace('web.request') do |span|
span.set_tag('http.url', request.path)
span.set_tag('<TAG_KEY>', '<TAG_VALUE>')
end
end
모든 스팬에 전역으로 태그 추가하기
tags 옵션으로 트레이서를 구성해 모든 스팬에 태그를 추가해요:
Datadog.configure do |c|
c.tags = { 'team' => 'qa' }
end
DD_TAGS 환경 변수를 사용해 애플리케이션의 모든 스팬에 태그를 설정할 수도 있어요. Ruby 환경 변수에 대한 자세한 내용은 설정 문서를 읽어보세요.
스팬에 오류 설정하기
스팬에 오류를 설정하는 방법은 두 가지가 있어요:
span.set_error를 호출하고 Exception 객체를 전달해요. 이렇게 하면 오류 타입, 메시지, 백트레이스가 자동으로 추출돼요.
require 'timeout'
def example_method
span = Datadog::Tracing.trace('example.trace')
puts 'some work'
sleep(1)
raise StandardError, "This is an exception"
rescue StandardError => error
Datadog::Tracing.active_span&.set_error(error)
raise
ensure
span.finish
end
example_method()
- 또는
tracer.trace를 사용해요. 기본적으로 오류 타입, 메시지, 백트레이스를 설정해요. 이 동작을 구성하려면on_error옵션을 사용할 수 있는데, 이는trace에 블록이 제공되고 블록이 오류를 발생시켰을 때 호출되는 Handler예요. Proc에는span과error가 인자로 제공돼요. 기본적으로on_error는 스팬에 오류를 설정해요.
on_error의 기본 동작:
require 'timeout'
def example_method
puts 'some work'
sleep(1)
raise StandardError, "This is an exception"
end
Datadog::Tracing.trace('example.trace') do |span|
example_method()
end
on_error의 커스텀 동작:
require 'timeout'
def example_method
puts 'some work'
sleep(1)
raise StandardError.new "This is a special exception"
end
custom_error_handler = proc do |span, error|
span.set_tag('custom_tag', 'custom_value')
span.set_error(error) unless error.message.include?("a special exception")
end
Datadog::Tracing.trace('example.trace', on_error: custom_error_handler) do |span|
example_method()
end
스팬 추가하기
지원되는 라이브러리 계측을 사용하지 않는다면(라이브러리 호환성 참고) 코드를 수동으로 계측할 수 있어요. Datadog::Tracing.trace 메서드를 사용해 코드에 추적을 추가하며, 이 메서드를 어떤 Ruby 코드에도 감쌀 수 있어요.
어떤 Ruby 코드든 추적하려면 Datadog::Tracing.trace 메서드를 사용할 수 있어요:
Datadog::Tracing.trace(name, resource: resource, **options) do |span|
# Wrap this block around the code you want to instrument
# Additionally, you can modify the span here.
# for example, change the resource name, or set tags
end
여기서 name은 수행되는 작업의 일반적인 종류를 설명하는 String이에요(예: 'web.request', 'request.parse').
resource는 작업 대상의 이름을 가진 String이에요. 같은 resource 값을 가진 트레이스는 메트릭 목적으로 함께 그룹화돼요. 리소스는 일반적으로 URL, 쿼리, 요청 등 도메인 특화적이에요(예: 'Article#submit', http://example.com/articles/list).
사용 가능한 모든 **options에 대해서는 참조 가이드를 참고하세요.
수동으로 새 스팬 만들기
코드 블록 주위에 프로그래밍 방식으로 스팬을 만들어요. 이 방식으로 만든 스팬은 다른 추적 메커니즘과 자동으로 통합돼요. 즉, 트레이스가 이미 시작되었다면 수동 스팬은 호출자를 부모 스팬으로 갖게 돼요. 마찬가지로 래핑된 코드 블록에서 호출되는 추적된 메서드들은 수동 스팬을 부모로 갖게 돼요.
# An example of a Sinatra endpoint,
# with Datadog tracing around the request,
# database query, and rendering steps.
get '/posts' do
Datadog::Tracing.trace('web.request', service: '<SERVICE_NAME>', resource: 'GET /posts') do |span|
# Trace the activerecord call
Datadog::Tracing.trace('posts.fetch') do
@posts = Posts.order(created_at: :desc).limit(10)
end
# Add some APM tags
span.set_tag('http.method', request.request_method)
span.set_tag('posts.count', @posts.length)
# Trace the template rendering
Datadog::Tracing.trace('template.render') do
erb :index
end
end
end
메서드 트레이싱 API로 메서드 호출 주위에 수동으로 스팬 만들기
DSL 같은 모듈로 메서드를 추적해요:
require 'datadog/kit/tracing/method_tracer'
class MyClass
extend Datadog::Kit::Tracing::MethodTracer
def foo; 'hello'; end
trace_method :foo, span_name: 'optional_span_name'
def self.bar; 'hi'; end
trace_singleton_class_method :bar, span_name: 'optional_span_name'
end
또는 더 직접적으로:
Datadog::Kit::Tracing::MethodTracer.trace_method(MyClass, :foo, span_name: 'optional_span_name')
Datadog::Kit::Tracing::MethodTracer.trace_method(MyClass.singleton_class, :bar, span_name: 'optional_span_name')
클래스 인자는 DSL 사용으로 암시되며, 그 외에는 필수이고 동적 클래스나 모듈을 받을 수 있어요.
스팬 이름은 선택 사항이며 기본값은 'Class#method'(싱글턴 클래스 메서드의 경우 Class.method)이지만, 클래스나 모듈 이름이 nil이면 필수예요.
추적된 메서드는 활성 트레이스 안에서만 스팬을 만들어요. 스스로 새 루트 스팬이나 트레이스를 만들지는 않아요.
일반 메서드는 trace_method를 호출하기 전에 정의되어야 해요. 동적 메서드(method_missing으로 처리되거나 호출 후 정의되는 메서드 포함)에는 dynamic: true를 사용해 메서드 존재 확인을 완화하되, 메서드 가시성은 보존하지 않아요.
참고: 메서드 트레이싱은 Module#prepend을 사용해요. 무한 재귀 충돌 위험을 줄이려면 alias method chained된 메서드에는 사용하지 마세요.
트레이스 후처리하기
일부 애플리케이션은 트레이스를 Datadog에 보내기 전에 변경하거나 필터링해야 할 수도 있어요. 처리 파이프라인을 사용하면 이러한 동작을 정의하는 프로세서를 만들 수 있어요.
필터링
Datadog::Tracing::Pipeline::SpanFilter 프로세서를 사용해 블록이 truthy로 평가되면 스팬을 제거할 수 있어요:
Datadog::Tracing.before_flush(
# Remove spans that match a particular resource
Datadog::Tracing::Pipeline::SpanFilter.new { |span| span.resource =~ /PingController/ },
# Remove spans that are trafficked to localhost
Datadog::Tracing::Pipeline::SpanFilter.new { |span| span.get_tag('host') == 'localhost' }
)
처리
Datadog::Tracing::Pipeline::SpanProcessor 프로세서를 사용해 스팬을 수정할 수 있어요:
Datadog::Tracing.before_flush(
# Strip matching text from the resource field
Datadog::Tracing::Pipeline::SpanProcessor.new { |span| span.resource.gsub!(/password=.*/, '') }
)
커스텀 프로세서
프로세서는 trace(Datadog::Span의 Array)를 인자로 받는 #call에 응답하는 모든 객체가 될 수 있어요.
예를 들어, 단축 블록 문법을 사용해:
Datadog::Tracing.before_flush do |trace|
# Processing logic...
trace
end
다음 예시는 복잡한 후처리 로직을 달성하는 프로세서를 구현해요:
Datadog::Tracing.before_flush do |trace|
trace.spans.each do |span|
originalPrice = span.get_tag('order.price'))
discount = span.get_tag('order.discount'))
# Set a tag from a calculation from other tags
if (originalPrice != nil && discount != nil)
span.set_tag('order.value', originalPrice - discount)
end
end
trace
end
커스텀 프로세서 클래스의 경우:
class MyCustomProcessor
def call(trace)
# Processing logic...
trace
end
end
Datadog::Tracing.before_flush(MyCustomProcessor.new)
두 경우 모두 프로세서 메서드는 trace 객체를 반환해야 해요. 이 반환 값이 파이프라인의 다음 프로세서로 전달돼요.
트레이스 클라이언트 및 Agent 구성
트레이싱 클라이언트와 Datadog Agent 모두 B3 헤더로 컨텍스트를 전파하는 추가 구성 옵션과, 헬스 체크처럼 계산된 메트릭에 포함하고 싶지 않은 특정 리소스가 Datadog에 트레이스를 보내지 않도록 제외하는 옵션을 제공해요.
헤더 추출·주입으로 컨텍스트 전파하기
헤더를 주입·추출해 분산 트레이스의 컨텍스트 전파를 구성할 수 있어요. Trace Context Propagation 문서를 읽어보세요.
Baggage
Baggage는 API를 통해 접근할 수 있고 기본적으로 전파되는 해시예요. 다음 예시를 보며 Baggage를 조작해보세요:
# set_baggage_item
Datadog::Tracing.baggage['key1'] = 'value1'
Datadog::Tracing.baggage['key2'] = 'value2'
# get_all_baggage_items
all_baggage = Datadog::Tracing.baggage
puts(all_baggage) # {"key1"=>"value1", "key2"=>"value2"}
# remove_baggage_item
Datadog::Tracing.baggage.delete('key1')
puts(Datadog::Tracing.baggage) # {"key2"=>"value2"}
# get_baggage_item
puts(Datadog::Tracing.baggage['key1']) # nil
puts(Datadog::Tracing.baggage['key2']) # "value2"
# remove_all_baggage_items
Datadog::Tracing.baggage.clear
puts(Datadog::Tracing.baggage) # {}
리소스 필터링
리소스 이름을 기준으로 트레이스를 제외해 헬스 체크 같은 합성 트래픽이 Datadog에 트레이스를 보고하지 않도록 할 수 있어요. 이 설정과 다른 보안·미세 조정 구성은 Security 페이지에서 찾을 수 있어요.
.NET
참고: 아직 자동 계측 및 설정 지침을 읽지 않았다면 .NET/.NET Core 또는 .NET Framework 설정 지침부터 시작하세요.
이 페이지는 Datadog APM으로 관측성을 추가·커스터마이즈하는 일반적인 사용 사례를 다뤄요. 지원되는 런타임 목록은 .NET Framework 호환성 요구 사항 또는 .NET Core 호환성 요구 사항을 참고하세요.
기본 자동 계측 이상을 얻는 방법은 여러 가지가 있어요:
- 구성 사용: 특정 태그를 추가할 수는 없어요.
- 속성 사용: operation과 resource 이름을 커스터마이즈할 수 있어요.
- 커스텀 코드 사용: 스팬을 가장 많이 제어할 수 있어요.
이 솔루션들을 서로 조합해 원하는 계측 세부 수준을 달성할 수 있어요. 하지만 자동 계측이 먼저 설정되어야 해요.
구성으로 메서드 계측하기
DD_TRACE_METHODS 환경 변수를 사용하면 애플리케이션 코드를 변경하지 않고 지원되지 않는 프레임워크에 대한 가시성을 얻을 수 있어요. DD_TRACE_METHODS 입력 형식의 전체 상세는 .NET Framework 구성 지침 또는 .NET Core 구성 지침을 참고하세요. 예를 들어 Store.Managers.SessionManager 타입에 정의된 SaveSession 메서드를 계측하려면 다음을 설정해요:
DD_TRACE_METHODS=Store.Managers.SessionManager[SaveSession]
결과 스팬은 trace.annotation 값을 가진 operationName 속성과 SaveSession 값을 가진 resourceName 속성을 가져요.
스팬의 속성을 커스터마이즈하고 소스 코드를 수정할 수 있다면, 대신 속성으로 메서드를 계측할 수 있어요.
속성으로 메서드 계측하기
자동 계측으로 실행할 때 Datadog가 추적하도록 메서드에 [Trace]를 추가해요. 자동 계측이 활성화되어 있지 않으면 이 속성은 애플리케이션에 아무 영향도 주지 않아요.
[Trace] 속성의 기본 operation 이름은 trace.annotation이고 resource 이름은 추적된 메서드예요. 계측 대상을 더 잘 반영하도록 [Trace] 속성의 명명된 인자로 operation name과 resource name을 설정할 수 있어요. operation name과 resource name은 [Trace] 속성에 설정할 수 있는 유일한 인자예요. 예를 들어:
using Datadog.Trace.Annotations;
namespace Store.Managers
{
public class SessionManager
{
[Trace(OperationName = "database.persist", ResourceName = "SessionManager.SaveSession")]
public static void SaveSession()
{
// your method implementation here
}
}
}
코드로 커스텀 계측하기
참고: 이 기능을 사용하려면 애플리케이션에
Datadog.TraceNuGet 패키지를 추가해야 해요. 이 패키지는 Tracer와 활성 스팬에 직접 접근할 수 있는 API를 제공해요.경고: v3.0.0부터 커스텀 계측에는 자동 계측도 함께 사용해야 해요. 자동 계측과 커스텀 계측 패키지 버전(예: MSI와 NuGet)을 동기화하고, 패키지의 메이저 버전을 혼합하지 않도록 해야 해요.
코드에서 Datadog 구성하기
애플리케이션을 구성하는 방법은 여러 가지가 있어요: 환경 변수, web.config 파일, 또는 datadog.json 파일을 사용할 수 있어요(문서에 설명된 대로). Datadog.Trace NuGet 패키지는 코드에서 설정을 구성할 수도 있게 해줘요.
구성 설정을 재정의하려면 TracerSettings 인스턴스를 만들고 정적 Tracer.Configure() 메서드에 전달해요:
using Datadog.Trace;
// Create a settings object using the existing
// environment variables and config sources
var settings = TracerSettings.FromDefaultSources();
// Override a value
settings.GlobalTags.Add("SomeKey", "SomeValue");
// Replace the tracer configuration
Tracer.Configure(settings);
Tracer.Configure()를 호출하면 커스텀 계측과 자동 계측 모두에 대해 이후 모든 트레이스의 설정을 대체해요.
경고: 구성 교체는 애플리케이션에서 한 번, 가능한 한 빨리 수행해야 해요.
커스텀 트레이스/스팬 만들기
자동 계측, [Trace] 속성, DD_TRACE_METHODS 구성 외에도 코드 블록 주위에 프로그래밍 방식으로 스팬을 만들어 관측성을 커스터마이즈할 수 있어요.
커스텀 스팬을 만들고 활성화하려면 Tracer.Instance.StartActive()를 사용해요. 트레이스가 이미 활성 상태라면(예: 자동 계측으로 생성된 경우) 스팬은 현재 트레이스의 일부가 돼요. 현재 트레이스가 없으면 새로 시작돼요.
경고:
StartActive가 반환한 scope를 dispose해야 해요. scope를 dispose하면 스팬이 닫히고, 모든 스팬이 닫히면 트레이스가 Datadog에 플러시되도록 보장해요.
using Datadog.Trace;
// Start a new span
using (var scope = Tracer.Instance.StartActive("custom-operation"))
{
// Do something
}
Datadog 내 관측성을 커스터마이즈하려면 스팬에 커스텀 스팬 태그를 추가해요. 스팬 태그는 들어오는 트레이스에 적용되어, 가맹점 등급, 결제 금액, 사용자 ID 같은 코드 레벨 정보와 관측된 동작을 연관지을 수 있게 해줘요.
수동으로 새 스팬 만들기
수동으로 만든 스팬은 다른 추적 메커니즘의 스팬과 자동으로 통합돼요. 즉, 트레이스가 이미 시작되었다면 수동 스팬은 호출자를 부모 스팬으로 갖게 돼요. 마찬가지로 래핑된 코드 블록에서 호출되는 추적된 메서드들은 수동 스팬을 부모로 갖게 돼요.
using (var parentScope =
Tracer.Instance.StartActive("manual.sortorders"))
{
parentScope.Span.ResourceName = "<RESOURCE NAME>";
using (var childScope =
Tracer.Instance.StartActive("manual.sortorders.child"))
{
// Nest using statements around the code to trace
childScope.Span.ResourceName = "<RESOURCE NAME>";
SortOrders();
}
}
커스텀 스팬 태그 추가하기
customer.id 같은 애플리케이션 코드 내 동적 값에 해당하는 커스텀 태그를 스팬에 추가해요.
using Datadog.Trace;
public class ShoppingCartController : Controller
{
private IShoppingCartRepository _shoppingCartRepository;
[HttpGet]
public IActionResult Index(int customerId)
{
// Access the active scope through the global tracer
// Note: This can return null if there is no active span
var scope = Tracer.Instance.ActiveScope;
if (scope != null)
{
// Add a tag to the span for use in the Datadog web UI
scope.Span.SetTag("customer.id", customerId.ToString());
}
var cart = _shoppingCartRepository.Get(customerId);
return View(cart);
}
}
ASP.NET IHttpModule과 함께 사용하기
커스텀 ASP.NET IHttpModule에서 현재 요청 스팬에 접근하려면 PreRequestHandlerExecute 이벤트(세션 상태가 필요하면 AcquireRequestState)에서 Tracer.Instance.ActiveScope를 읽는 것이 가장 좋아요.
Datadog는 ASP.NET 파이프라인의 시작에서 요청 스팬을 만들지만, IHttpModules의 실행 순서는 보장되지 않아요. 모듈이 Datadog보다 먼저 실행되면 BeginRequest 같은 초기 이벤트 동안 ActiveScope가 null일 수 있어요. PreRequestHandlerExecute 이벤트는 수명 주기에서 충분히 늦게 발생해 Datadog 모듈이 실행되고 스팬을 사용할 수 있도록 보장해요.
ActiveScope는 다른 이유(예: 계측이 비활성화된 경우)로도 null일 수 있으므로 항상 null 확인을 해야 해요.
using System;
using System.Web;
using Datadog.Trace;
public class MyCustomModule : IHttpModule
{
public void Init(HttpApplication context)
{
// Prefer reading ActiveScope late in the pipeline
context.PreRequestHandlerExecute += OnPreRequestHandlerExecute;
// If you need session state, you can also hook AcquireRequestState:
// context.AcquireRequestState += OnPreRequestHandlerExecute;
}
private void OnPreRequestHandlerExecute(object sender, EventArgs e)
{
// Earlier events (e.g., BeginRequest) may run before the Datadog module,
// so ActiveScope can be null there. Here it should be available.
var scope = Tracer.Instance.ActiveScope;
if (scope == null)
{
return; // there is no active scope, for example, if instrumentation is disabled
}
// Example: add a custom tag
scope.Span.SetTag("my.custom.tag", "some_value");
}
public void Dispose()
{
}
}
스팬에 오류 설정하기
코드에서 발생하는 오류를 표시하려면 Span.SetException(Exception) 메서드를 사용해요. 이 메서드는 스팬을 오류로 표시하고 예외에 대한 통찰력을 제공하는 관련 스팬 메타데이터를 추가해요.
try
{
// do work that can throw an exception
}
catch(Exception e)
{
span.SetException(e);
}
이렇게 하면 다음 태그가 스팬에 설정돼요:
"error.message":exception.Message"error.stack":exception.ToString()"error.type":exception.GetType().ToString()
헤더 추출·주입으로 컨텍스트 전파하기
헤더를 주입·추출해 분산 트레이스의 컨텍스트 전파를 구성할 수 있어요. Trace Context Propagation 문서를 읽어보세요.
모든 스팬에 전역으로 태그 추가하기
DD_TAGS 환경 변수를 사용해 애플리케이션의 모든 생성 스팬에 태그를 설정해요. 이는 애플리케이션, 데이터센터, 지역의 통계를 Datadog UI 내에서 그룹화하는 데 유용할 수 있어요. 예를 들어:
DD_TAGS=datacenter:njc,key2:value2
리소스 필터링
리소스 이름을 기준으로 트레이스를 제외해 헬스 체크 같은 Synthetics 트래픽을 제거할 수 있어요. 보안 및 추가 구성에 대한 자세한 내용은 데이터 보안을 위한 Datadog Agent 또는 Tracer 구성을 참고하세요.
PHP
참고: 아직 자동 계측 및 설정 지침을 읽지 않았다면 PHP 설정 지침부터 시작하세요. Datadog가 웹 프레임워크를 공식적으로 지원하지 않아도 수동 계측을 수행할 필요가 없을 수 있어요. 자세한 내용은 자동 계측을 참고하세요.
어노테이션
PHP 8을 사용한다면, 트레이서 v0.84부터 코드에 속성을 추가해 계측할 수 있어요. 코드로 작성된 커스텀 계측보다 가벼운 대안이에요. 예를 들어 메서드에 #[DDTrace\Trace] 속성을 추가하면 Datadog가 추적해요.
<?php
class Server {
#[\DDTrace\Trace(name: "spanName", resource: "resourceName", type: "Custom", service: "myService", tags: ["aTag" => "aValue"])]
static function process($arg) {}
#[\DDTrace\Trace]
function get() {
Foo::simple(1);
}
}
다음 인자를 제공할 수 있어요:
$name: 스팬에 할당할 operation 이름. 기본값은 함수 이름이에요.$resource: 스팬에 할당할 리소스.$type: 스팬에 할당할 타입.$service: 스팬에 할당할 서비스. 기본값은 default 또는 상속된 서비스 이름이에요.$tags: 스팬에 할당할 태그.$recurse: 재귀 호출을 추적할지 여부.$run_if_limited: 제한 모드에서 함수를 추적할지 여부(예: 스팬 한도 초과 시).
경고: 네임스페이스가 있으면 속성의 정규화된 이름
#[\\DDTrace\\Trace]을 반드시 사용해야 해요. 또는use DDTrace\Trace;로 네임스페이스를 import하고#[Trace]를 사용할 수 있어요.
커스텀 계측 작성하기
참고: 커스텀 계측을 작성하려면 추가 composer 패키지가 필요하지 않아요.
참고: Datadog APM PHP API는 stubs에 완전히 문서화되어 있어요. 이를 통해 PHPStorm에서 자동 문서화를 사용할 수 있어요.
계측할 샘플 애플리케이션
다음 디렉토리 구조를 가정해요:
.
|-- composer.json
|-- docker-compose.yml
|-- index.php
`-- src
|-- Exceptions
| `-- NotFound.php
|-- Services
| `-- SampleRegistry.php
`-- utils
`-- functions.php
이 중 두 파일에 계측할 가치가 있는 함수와 메서드가 있어요. 가장 관련 있는 파일은 src/utils/functions.php예요:
namespace App;
function some_utility_function($someArg)
{
return 'result';
}
그리고 src/Services/SampleRegistry.php:
namespace App\Services;
use App\Exceptions\NotFound;
use Exception;
class SampleRegistry
{
public function put($key, $value)
{
\App\some_utility_function('some argument');
// Return the id of the item inserted
return 456;
}
public function faultyMethod()
{
throw new Exception('Generated at runtime');
}
public function get($key)
{
// The service uses an exception to report a key not found.
throw new NotFound('The key was not found');
}
public function compact()
{
// This function executes some operations on the registry and
// returns nothing. In the middle of the function, we have an
// interesting value that is not returned but can be related
// to the slowness of the function
$numberOfItemsProcessed = 123;
// ...
}
}
샘플 애플리케이션 계측 단계
애플리케이션 또는 서비스 비즈니스 로직과 계측 코드를 섞지 않으려면 필요한 코드를 별도 파일에 작성해요:
-
datadog/instrumentation.php파일을 만들고 composer autoloader에 추가해요:{ ... "autoload": { ... "files": [ ... "datadog/instrumentation.php" ] }, ... } -
composer dump를 실행해 autoloader를 덤프해요.
참고: 커스텀 계측 코드를 포함하는 파일과 실제로 계측되는 클래스가 같은 코드베이스·패키지에 있어야 할 필요는 없어요. 분리하면 계측 코드만 포함한 오픈소스 composer 패키지를 게시할 수 있고, 다른 사람에게 유용할 수 있어요.
-
datadog/instrumentation.php파일에서 확장이 로드되었는지 확인해요:if (!extension_loaded('ddtrace')) { return; } -
함수를 계측해요.
\App\some_utility_function의 경우, 실행 시간 외의 특정 측면에 관심이 없다면:\DDTrace\trace_function('App\some_utility_function', function (\DDTrace\SpanData $span, $args, $ret, $exception) {}); -
SampleRegistry::put메서드의 경우 반환된 항목 식별자와 키가 있는 태그를 추가해요.put은 메서드이므로\DDTrace\trace_function대신\DDTrace\trace_method를 사용해요:\DDTrace\trace_method( 'App\Services\SampleRegistry', 'put', function (\DDTrace\SpanData $span, $args, $ret, $exception) { $span->meta['app.cache.key'] = $args[0]; // The first argument is the 'key' $span->meta['app.cache.item_id'] = $ret; // The returned value } ); -
예외를 생성하는
SampleRegistry::faultyMethod에는 추가로 할 일이 없어요. 메서드가 계측되면 기본 예외 보고 메커니즘이 예외 메시지와 스택 트레이스를 첨부해요. -
비즈니스 로직의 일부로
NotFound예외를 사용하는SampleRegistry::get의 경우, 예외를 unset해 스팬을 오류로 표시하는 것을 방지할 수 있어요:\DDTrace\trace_method( 'App\Services\SampleRegistry', 'get', function (\DDTrace\SpanData $span, $args, $ret, $exception) { if ($exception instanceof \App\Exceptions\NotFound) { unset($span->exception); $span->resource = 'cache.get.not_found'; } } ); -
SampleRegistry::compact의 경우 인자도 반환 값도 아닌 값으로 태그를 추가하려면 메서드 안에서 활성 스팬에 직접 접근할 수 있어요:public function compact() { $numberOfItemsProcessed = 123; // Add instrumenting code within your business logic. if (\function_exists('\DDTrace\active_span') && $span = \DDTrace\active_span()) { $span->meta['registry.compact.items_processed'] = $numberOfItemsProcessed; } // ... }
trace_function과 trace_method 상세
DDTrace\trace_function과 DDTrace\trace_method 함수는 특정 함수·메서드 호출을 계측(추적)해요. 이 함수들은 다음 작업을 자동으로 처리해요:
- 코드가 실행되기 전에 스팬을 열어요.
- 계측된 호출에서 발생한 오류를 스팬에 설정해요.
- 계측된 호출이 끝나면 스팬을 닫아요.
추가 태그는 클로저(트레이싱 클로저라고 함)에서 스팬에 설정돼요.
예를 들어 다음 스니펫은 CustomDriver::doWork 메서드를 추적하고 커스텀 태그를 추가해요:
<?php
\DDTrace\trace_method(
'CustomDriver',
'doWork',
function (\DDTrace\SpanData $span, array $args, $retval, $exception) {
// This closure runs after the instrumented call
$span->name = 'CustomDriver.doWork';
$span->resource = 'CustomDriver.doWork';
$span->service = 'php';
// If an exception was thrown from the instrumented call, return value is null
$span->meta['doWork.size'] = $exception ? 0 : count($retval),
// Access object members via $this
$span->meta['doWork.thing'] = $this->workToDo;
}
);
?>
활성 스팬 접근하기
내장 계측과 사용자 커스텀 계측은 의미 있는 연산 주위에 스팬을 만들어요. 의미 있는 데이터를 포함하기 위해 활성 스팬에 접근할 수 있어요.
현재 스팬
다음 메서드는 DDTrace\SpanData 객체를 반환해요. 추적이 비활성화되면 null이 반환돼요.
<?php
$span = \DDTrace\active_span();
if ($span) {
$span->meta['customer.id'] = get_customer_id();
}
?>
루트 스팬
다음 메서드는 DDTrace\SpanData 객체를 반환해요. 추적이 비활성화되면 null이 반환돼요. 루트 스팬에 추가할 메타데이터가 초기 스크립트 실행에 존재하지 않는 컨텍스트에서 유용해요.
<?php
$span = \DDTrace\root_span();
if ($span) {
$span->meta['customer.id'] = get_customer_id();
}
?>
태그 추가하기
경고: 태그를 설정할 때 Datadog 코어 계측이 자동으로 추가한 기존 태그를 덮어쓰지 않으려면
$span->meta['mytag'] = 'value'를 쓰세요.$span->meta = ['mytag' => 'value']는 쓰지 마세요.
로컬로 태그 추가하기
DDTrace\SpanData::$meta 배열을 사용해 스팬에 태그를 추가해요.
<?php
\DDTrace\trace_function(
'myRandFunc',
function(\DDTrace\SpanData $span, array $args, $retval) {
// ...
$span->meta['rand.range'] = $args[0] . ' - ' . $args[1];
$span->meta['rand.value'] = $retval;
}
);
전역으로 태그 추가하기
DD_TAGS 환경 변수(버전 0.47.0+)를 설정해 생성되는 모든 스팬에 자동으로 태그를 적용해요.
DD_TAGS=key1:value1,<TAG_KEY>:<TAG_VALUE>
스팬에 오류 설정하기
발생한 예외는 활성 스팬에 자동으로 첨부돼요. 단, 예외가 호출 스택의 더 깊은 레벨에서 발생하고 추적되는 함수에 도달하기 전에 catch된 경우는 제외해요.
<?php
function doRiskyThing() {
throw new Exception('Oops!');
}
\DDTrace\trace_function(
'doRiskyThing',
function() {
// Span will be flagged as erroneous and have
// the stack trace and exception message attached as tags
}
);
error.message 태그를 설정해 스팬을 수동으로 오류로 표시해요.
<?php
function doRiskyThing() {
return SOME_ERROR_CODE;
}
\DDTrace\trace_function(
'doRiskyThing',
function(\DDTrace\SpanData $span, $args, $retval) {
if ($retval === SOME_ERROR_CODE) {
$span->meta['error.message'] = 'Foo error';
// Optional:
$span->meta['error.type'] = 'CustomError';
$span->meta['error.stack'] = (new \Exception)->getTraceAsString();
}
}
);
스팬 링크 추가하기
스팬 링크는 일반적인 부모-자식 관계가 없는 하나 이상의 스팬을 서로 연결해요. 같은 트레이스 안의 스팬이나 서로 다른 트레이스의 스팬을 연결할 수 있어요.
기존 스팬에서 스팬 링크를 추가하려면:
$spanA = \DDTrace\start_trace_span();
$spanA->name = 'spanA';
\DDTrace\close_span();
$spanB = \DDTrace\start_trace_span();
$spanB->name = 'spanB';
// Link spanB to spanA
$spanB->links[] = $spanA->getLink();
\DDTrace\close_span();
분산 트레이스의 컨텍스트 전파
헤더를 주입·추출해 분산 트레이스의 컨텍스트 전파를 구성할 수 있어요. Trace Context Propagation 문서를 읽어보세요.
리소스 필터링
리소스 이름을 기준으로 트레이스를 제외해 헬스 체크 같은 합성 트래픽이 Datadog에 트레이스를 보고하지 않도록 할 수 있어요. 이 설정과 다른 보안·미세 조정 구성은 Security 페이지에서 찾을 수 있어요.
API 참조
참고: Datadog APM PHP API는 stubs에 완전히 문서화되어 있어요. 이를 통해 PHPStorm에서 자동 문서화를 사용할 수 있어요.
트레이싱 클로저의 파라미터
DDTrace\trace_method()와 DDTrace\trace_function()에 제공되는 트레이싱 클로저에는 네 가지 파라미터가 있어요:
function(
DDTrace\SpanData $span,
array $args,
mixed $retval,
Exception|null $exception
);
- $span: 스팬 속성에 쓸
DDTrace\SpanData인스턴스 - $args: 계측된 호출의 인자
array - $retval: 계측된 호출의 반환 값
- $exception: 계측된 호출에서 발생한 예외의 인스턴스 또는 예외가 없으면
null
고급 구성
내부 함수·메서드 추적하기
버전 0.76.0부터 모든 내부 함수를 무조건적으로 추적할 수 있어요.
이전 버전에서는 내부 함수·메서드를 추적하려면 DD_TRACE_TRACED_INTERNAL_FUNCTIONS 환경 변수를 설정해야 하는데, 이 변수는 계측할 함수·메서드의 CSV를 받아요. 예: DD_TRACE_TRACED_INTERNAL_FUNCTIONS=array_sum,mt_rand,DateTime::add. 함수나 메서드가 목록에 추가되면 각각 DDTrace\trace_function()과 DDTrace\trace_method()를 사용해 계측할 수 있어요. DD_TRACE_TRACED_INTERNAL_FUNCTIONS 환경 변수는 버전 0.76.0부터 obsolete예요.
계측된 호출 전에 트레이싱 클로저 실행하기
기본적으로 트레이싱 클로저는 posthook 클로저로 취급되어 계측된 호출 후에 실행돼요. 어떤 경우에는 트레이싱 클로저를 계측된 호출 전에 실행해야 해요. 이 경우 트레이싱 클로저를 연관 구성 배열을 사용해 prehook으로 표시해요.
\DDTrace\trace_function('foo', [
'prehook' => function (\DDTrace\SpanData $span, array $args) {
// This tracing closure will run before the instrumented call
}
]);
샌드박스 처리된 오류 디버깅
트레이싱 클로저는 "샌드박스" 처리되어, 클로저 안에서 발생한 예외와 오류가 계측된 호출에 영향을 주지 않아요.
<?php
function my_func() {
echo 'Hello!' . PHP_EOL;
}
\DDTrace\trace_function(
'my_func',
function() {
throw new \Exception('Oops!');
}
);
my_func();
echo 'Done.' . PHP_EOL;
/*
Hello!
Done.
*/
디버깅하려면 DD_TRACE_DEBUG=1 환경 변수를 설정해 트레이싱 클로저에서 발생할 수 있는 예외나 오류를 노출해요.
/*
Hello!
Exception thrown in tracing closure for my_func: Oops!
Done.
*/
Zend framework 1 수동 계측
Zend framework 1은 기본적으로 자동 계측되므로 ZF1 프로젝트를 수정할 필요가 없어요. 하지만 자동 계측이 비활성화되어 있다면 트레이서를 수동으로 활성화해요.
먼저 릴리스 페이지에서 최신 소스 코드를 다운로드해요. zip 파일을 추출하고 src/DDTrace 폴더를 애플리케이션의 /library 폴더에 복사해요. 그런 다음 application/configs/application.ini 파일에 다음을 추가해요:
autoloaderNamespaces[] = "DDTrace_"
pluginPaths.DDTrace = APPLICATION_PATH "/../library/DDTrace/Integrations/ZendFramework/V1"
resources.ddtrace = true
PHP 코드 최적화
PHP 7 이전에는 일부 프레임워크가 PHP 클래스를 컴파일하는 방법을 제공했어요(예: Laravel의 php artisan optimize 명령).
PHP 7.x를 사용한다면 이 기능은 더 이상 사용되지 않지만, 7.x 이전 버전에서는 앱에서 이 캐싱 메커니즘을 계속 사용할 수 있어요. 이 경우 Datadog는 Composer 파일에 datadog/dd-trace를 추가하는 대신 OpenTracing API를 사용할 것을 권장해요.
C++
참고: 아직 설정 지침을 읽지 않았다면 C++ 설정 지침부터 시작하세요.
스팬 만들기
메서드를 수동으로 계측하려면:
{
// Create a root span for the current request.
auto root_span = tracer.create_span();
root_span.set_name("get_ingredients");
// Set a resource name for the root span.
root_span.set_resource_name("bologna_sandwich");
// Create a child span with the root span as its parent.
auto child_span = root_span.create_child();
child_span.set_name("cache_lookup");
// Set a resource name for the child span.
child_span.set_resource_name("ingredients.bologna_sandwich");
// Spans can be finished at an explicit time ...
child_span.set_end_time(std::chrono::steady_clock::now());
} // ... or implicitly when the destructor is invoked.
// For example, root_span finishes here.
태그 추가하기
Datadog 내 관측성을 커스터마이즈하려면 스팬에 커스텀 스팬 태그를 추가해요. 스팬 태그는 들어오는 트레이스에 적용되어, 가맹점 등급, 결제 금액, 사용자 ID 같은 코드 레벨 정보와 관측된 동작을 연관지을 수 있게 해줘요.
일부 Datadog 태그는 통합 서비스 태깅에 필요하다는 점을 주목하세요.
로컬로 태그 추가하기
Span::set_tag를 호출해 스팬 객체에 직접 태그를 추가해요. 예를 들어:
// Add tags directly to a span by calling `Span::set_tag`
auto span = tracer.create_span();
span.set_tag("key must be string", "value must also be a string");
// Or, add tags by setting a `SpanConfig`
datadog::tracing::SpanConfig opts;
opts.tags.emplace("team", "apm-proxy");
auto span2 = tracer.create_span(opts);
전역으로 태그 추가하기
환경 변수
모든 스팬에 태그를 설정하려면 DD_TAGS 환경 변수를 쉼표로 구분된 key:value 쌍 목록으로 설정해요.
export DD_TAGS=team:apm-proxy,key:value
코드에서
datadog::tracing::TracerConfig tracer_config;
tracer_config.tags = {
{"team", "apm-proxy"},
{"apply", "on all spans"}
};
const auto validated_config = datadog::tracing::finalize_config(tracer_config);
auto tracer = datadog::tracing::Tracer(*validated_config);
// All new spans will have contains tags defined in `tracer_config.tags`
auto span = tracer.create_span();
스팬에 오류 설정하기
스팬을 오류와 연결하려면 스팬에 하나 이상의 오류 관련 태그를 설정해요. 예를 들어:
span.set_error(true);
error.message, error.stack, error.type의 조합을 각각 Span::set_error_message, Span::set_error_stack, Span::set_error_type를 사용해 설정하면 오류에 대한 더 구체적인 정보를 추가할 수 있어요. 오류 태그에 대한 자세한 내용은 Error Tracking을 참고하세요.
오류 태그 조합을 추가하는 예시:
// Associate this span with the "bad file descriptor" error from the standard
// library.
span.set_error_message("error");
span.set_error_stack("[EBADF] invalid file");
span.set_error_type("errno");
참고:
Span::set_error_*중 어느 것을 사용해도 내부적으로Span::set_error(true)를 호출하게 돼요.
스팬의 오류를 해제하려면 Span::set_error를 false로 설정해, Span::set_error_stack, Span::set_error_type, Span::set_error_message의 조합을 제거해요.
// Clear any error information associated with this span.
span.set_error(false);
헤더 추출·주입으로 컨텍스트 전파하기
헤더를 주입·추출해 분산 트레이스의 컨텍스트 전파를 구성할 수 있어요. Trace Context Propagation 문서를 읽어보세요.
리소스 필터링
리소스 이름을 기준으로 트레이스를 제외해 헬스 체크 같은 합성 트래픽이 트레이스를 보내고 트레이스 메트릭에 영향을 주지 않도록 할 수 있어요. 이 설정과 다른 보안·미세 조정 구성에 대한 정보는 Security 페이지에서 찾을 수 있어요.
더 알아보기 (Learn more)
추가로 도움이 되는 문서, 링크, 아티클: