Home / Strands 관측성 / Strands 관측성
Module

Strands 관측성

StrandsTelemetry·OTEL 자동 계측·result.metrics — Strands 에이전트 관측성 구현

⏱ 45분 156 / 189

Strands 관측성

Telemetry · Tracing · Metrics · ADOT

에이전트의 동작을 투명하게 관찰한다

OpenTelemetry 기반 트레이싱·메트릭·로깅으로 에이전트 동작 가시성 확보

관측성 개요

StrandsTelemetry · OpenTelemetry · 3 Pillars

PART 1 · 관측성 개요

관측성 파이프라인 전체 흐름

SDK 계측부터 백엔드 시각화까지 — 데이터가 흐르는 경로

  1. 1
    SDK 계측

    StrandsTelemetry가 Agent Loop, Model Invoke, Tool Execute 각 단계에 자동으로 스팬과 메트릭을 생성. 코드 수정 없이 1줄 설정으로 활성화.

  2. 2
    Exporter 전송

    OTel SDK의 OTLP Exporter가 스팬·메트릭·로그를 gRPC 또는 HTTP/protobuf로 Collector에 전송 — StrandsTelemetry의 setup_otlp_exporter는 HTTP/protobuf(4318) 고정. 배치 처리로 네트워크 효율 확보.

  3. 3
    Collector 처리

    ADOT Collector가 수신된 텔레메트리를 배치·필터·샘플링 처리. 민감 정보 제거, 어트리뷰트 보강 등 전처리 수행.

  4. 4
    Backend 저장/시각화

    X-Ray에 트레이스, CloudWatch에 메트릭과 로그 저장. 서비스 맵, 대시보드, 알람으로 운영자에게 가시성 제공.

takeaway

네 단계 중 개발자가 만지는 것은 SDK 계측 1줄과 Collector 설정뿐 — 나머지는 파이프라인이 알아서 흘려보냅니다.

PART 1 · 관측성 개요

관측성 3 Pillars

세 축이 결합되어야 "어디서, 무엇이, 왜" 발생했는지 파악 가능

Traces (추적)

요청의 전체 실행 경로를 스팬 계층으로 기록 — "어디가 문제인가?"

Metrics (지표)

토큰 수, 지연, 에러율을 시계열로 집계 — "이상이 있는가?"

Logs (로그)

프롬프트 입출력, 도구 파라미터, 에러 상세를 이벤트로 기록 — "왜 발생했나?"

takeaway

Traces가 어디, Metrics가 이상 여부, Logs가 를 답합니다 — 하나만으로는 근본 원인에 도달하지 못합니다.

PART 1 · 관측성 개요

StrandsTelemetry 초기화

1줄 설정으로 에이전트 전체 자동 계측 활성화

핵심 포인트

StrandsTelemetry()
텔레메트리 진입점 — setup_* 메서드 체이닝으로 활성화
setup_otlp_exporter()
OTLP 전송 — HTTP/protobuf 전용(4318 포트), gRPC 아님
setup_console_exporter()
스팬 콘솔 출력 — Collector 없이 로컬 디버그
setup_meter()
OTel Meter 활성화 — 커스텀 메트릭의 기반
OTEL_TRACES_SAMPLER
SDK 측 샘플링(traceidratio) — 비율은 SAMPLER_ARG=0.5
gen_ai_span_attributes_only
gen_ai.* 어트리뷰트만 내보내는 환경 변수 옵션
자동 계측
invoke_agent · chat · execute_tool 스팬 + 토큰·지연 메트릭 자동 생성

코드

python
from strands import Agent
from strands.telemetry import StrandsTelemetry
from strands.models import BedrockModel

# Exporter + Meter 활성화 — 메서드 체이닝, HTTP/protobuf 전용
# 전송 대상: export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
StrandsTelemetry().setup_otlp_exporter() \
    .setup_meter(enable_otlp_exporter=True)

# 에이전트 조립·실행 — 이후 모든 호출이 자동 계측됨
agent = Agent(
    model=BedrockModel(model_id="us.anthropic.claude-sonnet-4-6"),
    tools=[search, calculate],
)
result = agent("최근 3개월 AWS 비용 추이를 분석해줘")
# → invoke_agent / execute_event_loop_cycle / chat / execute_tool
#   스팬 자동 생성 + 토큰·지연·도구 호출 횟수 메트릭 자동 발행

트레이싱

trace_attributes · Custom Spans · Span Hierarchy

PART 2 · 트레이싱

트레이싱

자동 계측이 만든 스팬 트리 위에 커스텀 스팬·속성을 얹는 확장

트레이싱

하나의 에이전트 호출이 스팬 트리로 분해되어 실행 경로 전체가 기록됩니다

  • 커스텀 스팬 — OTel tracer API로 도구 내부 계측
  • trace_attributes — 트레이스 공통 비즈니스 속성
  • Span 계층 — Agent → Cycle → Model Invoke · Tool Execute
  • gen_ai.* — GenAI Semantic Conventions 표준 속성
takeaway

자동 계측이 뼈대를 만들고, 커스텀 스팬과 어트리뷰트가 비즈니스 맥락을 입힙니다.

PART 2 · 트레이싱

커스텀 스팬과 어트리뷰트

OTel tracer API로 도구 내부에 커스텀 스팬과 속성을 추가

핵심 포인트

trace.get_tracer
OTel tracer 획득 — 커스텀 스팬 생성의 진입점
start_as_current_span
with 블록으로 자식 스팬 생성 — 도구 내부 구간을 독립 계측
set_attribute
질의 · top_k · 결과 수 같은 비즈니스 속성을 스팬에 기록
trace_attributes
Agent 트레이스 전체에 공통 속성 부여 — session.id 등

코드

python
from strands import Agent, tool
from opentelemetry import trace

tracer = trace.get_tracer("my-agent")  # 커스텀 스팬의 진입점

@tool
def knowledge_search(query: str, top_k: int = 5) -> list:
    """지식 베이스에서 관련 문서를 검색합니다."""
    with tracer.start_as_current_span("kb_retrieve") as span:
        span.set_attribute("search.query", query)
        span.set_attribute("search.top_k", top_k)
        results = bedrock_kb.retrieve(query=query, top_k=top_k)
        span.set_attribute("search.result_count", len(results))
    return results

# Agent에 트레이스 공통 속성 전달
agent = Agent(tools=[knowledge_search],
              trace_attributes={"session.id": "abc-123"})
PART 2 · 트레이싱

Span 계층 구조

하나의 에이전트 호출이 스팬 트리로 분해되는 구조 — 부모가 자식을 포함

takeaway

병목이 보이면 트리를 따라 내려갑니다 — 루트에서 External Call까지 어느 층에서 시간이 새는지 드러납니다.

PART 2 · 트레이싱

트레이스 워터폴 — 실물

요청 하나가 남긴 스팬 계단 — cost-analyzer 에이전트의 3사이클, 4,200ms




TRACE WATERFALL
gen_ai.agent.name = cost-analyzer · session.id = abc-123 · agent.loop.iterations = 3



Agent Loop Span
4,200ms



  ├ Model Invoke #1
1,420ms · in 1,234 tok



  ├ Tool Execute · knowledge_search
320ms



  │  └ External Call · POST → 200
210ms



  ├ Model Invoke #2
1,180ms



  ├ Tool Execute · knowledge_search
230ms



  └ Model Invoke #3 — 최종 응답
990ms · out 567 tok



막대 길이 = 소요 시간, 가로 위치 = 시작 시점 — 병목은 가장 긴 막대부터. 여기서는 모델 호출 3회(3,590ms)가 전체의 85%입니다. 사이클 스팬(execute_event_loop_cycle)은 지면상 생략했습니다.


PART 2 · 트레이싱

Trace Attributes 스키마

GenAI Semantic Conventions 표준(gen_ai.*) + 커스텀 비즈니스 속성 — 두 층이 합쳐져 검색 가능한 트레이스

스팬어트리뷰트설명예시 값
공통gen_ai.system기본 legacy 스키마 — OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental로 최신 semconv 전환strands-agents
Agent Loopgen_ai.agent.name에이전트 식별자cost-analyzer
Agent Loopagent.loop.iterations루프 반복 수 (커스텀 속성 예시)3
Model Invokegen_ai.request.model요청 모델 IDus.anthropic.claude-sonnet-4-6
Model Invokegen_ai.usage.input_tokens입력 토큰 수1,234
Model Invokegen_ai.usage.output_tokens출력 토큰 수567
Tool Executegen_ai.tool.name도구 이름knowledge_search
Tool Executetool.duration_ms실행 시간(ms) (커스텀 속성 예시)320
External Callhttp.request.methodHTTP 메서드POST
External Callhttp.response.status_code응답 코드200
PART 2 · 트레이싱

스팬 리댁션 — 민감 정보 마스킹

허용목록 밖 프롬프트·응답 원문을 SDK가 스팬 생성 시점에 차단 — python v1.47.0부터 지원

핵심 포인트

[REDACTED]
허용목록에 없으면 gen_ai.input.messages · gen_ai.output.messages · gen_ai.system_instructions 값이 이 문자열로 치환
허용목록(glob)
semconv 전환과 같은 환경 변수에 gen_ai_unredacted_attributes= 토큰 추가 — glob 패턴으로 원문 유지 대상 지정
SDK 원천 차단
스팬 생성 시점에 마스킹 — 원문이 Exporter · Collector · 백엔드 어디에도 도달하지 않음
Collector 필터와 대비
attributes · filter processor는 수집 후 파이프라인에서 제거 — 전송 구간에는 원문 노출. 리댁션은 SDK에서 먼저 자름

코드

bash
# 최신 semconv 모드 — 메시지 본문 어트리뷰트는 기본 리댁션
export OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental
# span: gen_ai.input.messages       = [REDACTED]
#       gen_ai.output.messages      = [REDACTED]
#       gen_ai.system_instructions  = [REDACTED]

# 허용목록(glob) 지정 — 출력 메시지만 원문 유지
export OTEL_SEMCONV_STABILITY_OPT_IN="gen_ai_latest_experimental,\
gen_ai_unredacted_attributes=gen_ai.output.*"
# span: gen_ai.input.messages       = [REDACTED]
#       gen_ai.output.messages      = [{"role": "assistant", ...}]

메트릭과 비용

result.metrics · Custom Meter · CloudWatch EMF

PART 3 · 메트릭과 비용

메트릭과 비용

호출 결과에서 바로 꺼내는 수치와, 그 위에 쌓는 운영 메트릭

result.metrics

에이전트 호출 결과에 토큰 · 지연 · 사이클 메트릭이 담겨 즉시 확인할 수 있습니다

  • accumulated_usage["inputTokens"] — 키는 camelCase
  • accumulated_metrics["latencyMs"] — 누적 지연
  • cycle_count · tool_metrics — 루프와 도구별 통계
  • get_summary() — 사람이 읽기 좋은 집계 dict
takeaway

별도 설정 없이 호출 즉시 확인 — 비용은 토큰 수 × 단가 한 줄 계산이고, 시계열 추적은 CloudWatch EMF로 얹습니다.

PART 3 · 메트릭과 비용

result.metrics 즉시 확인

에이전트 호출 결과에서 토큰·지연·비용 메트릭을 즉시 추출

python
from strands import Agent

# 에이전트 조립·실행 — 별도 설정 없이 메트릭 자동 수집
agent = Agent(model="us.anthropic.claude-sonnet-4-6", tools=[search])
result = agent("최근 보안 취약점 요약해줘")

# result.metrics — EventLoopMetrics 객체, 호출 즉시 확인 가능
usage = result.metrics.accumulated_usage       # 키는 camelCase
print(usage["inputTokens"])                    # 2340
print(usage["outputTokens"])                   # 891
print(usage["totalTokens"])                    # 3231
# accumulated_*는 에이전트 재사용 시 전 요청 누적 —
# 요청 단위는 latest_agent_invocation·agent_invocations로 추출

# 누적 지연·사이클 수·도구별 메트릭·요약 dict
print(result.metrics.accumulated_metrics["latencyMs"])  # 4520
print(result.metrics.cycle_count)                       # 2
print(result.metrics.tool_metrics)                      # 도구별 호출 통계
print(result.metrics.get_summary())                     # 사람이 읽기 좋은 집계

# 비용 계산 (Claude Sonnet 기준)
cost = (usage["inputTokens"] * 3 + usage["outputTokens"] * 15) / 1_000_000
print(f"이번 호출 비용: ${cost:.4f}")  # $0.0204
PART 3 · 메트릭과 비용

핵심 메트릭 지표

에이전트 운영에서 반드시 추적해야 하는 수치

Tokens 입력+출력 토큰 합산 — 비용의 직접 원인
Latency P50/P95/P99 응답 시간 — 사용자 체감 품질
Cost/req 요청당 비용 — 프로덕션 예산 관리 기준
Iterations 루프 반복 수 — 무한루프 조기 감지
Tool Calls 도구 호출 횟수 — 효율성 판단 지표
PART 3 · 메트릭과 비용

메트릭 수집 위치별 분류

SDK 자동 수집 vs CloudWatch 자동 발행 vs 커스텀 정의 구분

메트릭수집 위치타입용도
inputTokens / outputTokensSDK (metrics.accumulated_usage)Counter비용 산출, 프롬프트 최적화
latencyMsSDK (metrics.accumulated_metrics)HistogramP95 모니터링, SLA 준수
cycle_countSDK (result.metrics)Gauge무한루프 감지, 효율 측정
InvocationsCloudWatch (Bedrock)Counter트래픽 파악, 용량 계획
InvocationThrottlesCloudWatch (Bedrock)Counter쿼터 한계 감지
session_cost_usd커스텀 (EMF)Gauge세션별 비용 추적, 예산 알람
goal_completion_rate커스텀 (EMF)Gauge품질 모니터링, 프롬프트 개선
takeaway

SDK · CloudWatch · 커스텀 EMF 세 수집 위치를 구분하면, 이미 있는 메트릭을 다시 만드는 낭비를 막습니다.

ADOT 파이프라인

ADOT Collector · X-Ray · CloudWatch · 대시보드

PART 4 · ADOT 파이프라인

ADOT Collector 아키텍처

Agent에서 X-Ray·CloudWatch까지 텔레메트리가 흐르는 경로

  1. 1
    Strands Agent

    StrandsTelemetry가 계측한 스팬·메트릭을 OTel SDK가 수집. OTLP 프로토콜로 직렬화하여 Collector에 전송 준비.

  2. 2
    OTel SDK (Exporter)

    BatchSpanProcessor가 스팬을 배치로 모아 전송. StrandsTelemetry의 OTLPSpanExporter는 HTTP/protobuf(4318)로 Collector에 push — Collector 수신부는 gRPC 4317도 함께 열 수 있음.

  3. 3
    ADOT Collector

    Receiver(OTLP) → Processor(batch, filter, attributes) → Exporter(awsxray, awsemf) 3단 파이프라인. ECS Sidecar 또는 EC2 데몬으로 배포.

  4. 4
    X-Ray + CloudWatch

    X-Ray가 트레이스를 저장하고 서비스 맵을 생성. CloudWatch가 메트릭을 저장하고 대시보드·알람을 구동.

takeaway

Collector가 중간에 서 있어 백엔드 교체 · 필터링 · 배치를 애플리케이션 코드 수정 없이 처리합니다. 백엔드는 X-Ray 외에 Jaeger · Zipkin · Langfuse도 공식 문서에 등재되어 있습니다.

PART 4 · ADOT 파이프라인

ADOT Collector 설정

otel-collector-config.yaml — Receiver, Processor, Exporter 3단 구성

핵심 포인트

receivers.otlp
SDK가 보내는 텔레메트리 수신 — gRPC 4317 · HTTP 4318
processors.batch
5초 · 256개 배치 묶음 — filter를 추가하면 헬스체크 스팬 제외 같은 전처리 가능
exporters
awsxray는 트레이스를 X-Ray로, awsemf는 메트릭을 CloudWatch EMF로 발행
service.pipelines
traces · metrics 경로를 각각 Receiver → Processor → Exporter로 조립

코드

yaml
receivers:
  otlp:
    protocols:
      grpc: { endpoint: 0.0.0.0:4317 }
      http: { endpoint: 0.0.0.0:4318 }
processors:
  batch: { timeout: 5s, send_batch_size: 256 }
exporters:
  awsxray: { region: us-east-1 }
  awsemf:
    region: us-east-1
    namespace: StrandsAgent
    log_group_name: /strands/agent/metrics
service:
  pipelines:
    traces:
      {receivers: [otlp], processors: [batch], exporters: [awsxray]}
    metrics:
      {receivers: [otlp], processors: [batch], exporters: [awsemf]}
PART 4 · ADOT 파이프라인

대시보드 구성요소

운영팀이 에이전트 상태를 한눈에 파악하는 4패널 구성

Overview 패널

전체 요청 수, 성공률, P95 지연 — 현재 상태 한 줄 요약

Model 패널

모델별 토큰 사용량, 비용 추이, 스로틀링 횟수 추적

Tool 패널

도구별 호출 수, 실패율, 평균 지연 — 병목 도구 식별

Cost 패널

일간/주간 비용 추이, 에이전트별 비용 분배 — 예산 초과 조기 감지

takeaway

Overview → Model → Tool → Cost — 넓게 보다가 좁혀 들어가는 4패널이 운영 화면의 기본형입니다.

PART 4 · ADOT 파이프라인

메트릭 대시보드 — 실물

Strands가 내보낸 gen_ai.* · strands.* 데이터가 CloudWatch 4패널에서 읽히는 모습 (예시 수치)




CLOUDWATCH DASHBOARD
namespace = StrandsAgent · gen_ai.agent.name = cost-analyzer · 지난 3시간



토큰 사용량 추이

gen_ai.usage.input_tokens · output_tokens — Sum, 15m











input_tokens output_tokens



호출 레이턴시

invoke_agent 스팬 duration — p50 / p99







p50 4.1s p99 9.8s



도구 호출 성공률

strands.tool.* — gen_ai.tool.name 차원


98.2%


knowledge_search99.1

calculate98.8

web_fetch95.6





사이클 수 분포

strands.event_loop.* — 호출당 cycle_count


42%

31%

18%

9%


1234+ 사이클



네 패널 모두 Strands가 자동 발행한 gen_ai.* · strands.* 데이터만으로 구성됩니다 — 위젯·알람을 직접 구축하는 과정은 agent-observability 모듈의 CloudWatch 실습에서 다룹니다.


관측할 수 없으면 개선할 수 없습니다.

Telemetry · Tracing · Metrics · ADOT — 에이전트 가시성의 4요소