Skip to content

[Observability] TokenPilot 고유 Micrometer 지표 구현 #40

Description

@HuitaePark

문제와 현재 코드 근거

현재 MicroCostMetricsPublisher는 다음 metric을 기본 발행한다.

  • ai.token.usage.total
  • ai.token.usage.distribution
  • ai.token.cost.total

Spring AI 1.1.4에도 provider Usage 기반 gen_ai.client.token.usage가 있으므로 현재 token usage metric은 의미가 중복될 수 있다. cost description도 “estimated”로 고정되어 있고, TokenPilot의 차별점인 preflight decision, reservation, pricing miss와 actual reconciliation 지표는 없다.

또한 현재 MetricsOptions.DEFAULT_ALLOWED_TAG_KEYStenant_id다. whitelist는 key만 제한하며 tenant 값의 cardinality를 제한하지 않으므로 “모든 기본 tag가 bounded”라는 목표와 충돌한다.

DefaultLedgerManager는 listener를 순차 호출하며 첫 예외를 그대로 전파한다. optional metric sink의 실패가 성공한 accounting transition이나 provider 응답을 뒤집으면 안 된다. listener failure/state/event 순서는 #46과 #37이 소유하며, 이 이슈는 그 event와 정책을 Micrometer adapter에서 소비한다.

기본 metric 계약

Metric 타입 기본 bounded tag
tokenpilot.cost.total Counter currency
tokenpilot.preflight.requests Counter decision, reason
tokenpilot.budget.reservations Counter state
tokenpilot.reconciliation.error.tokens DistributionSummary direction
tokenpilot.reconciliation.outcomes Counter outcome, reason
tokenpilot.pricing.missing Counter policy
tokenpilot.listener.failures Counter listener, phase
tokenpilot.notification.events Counter outcome, threshold
  • reconciliation token 오차는 절대값을 기록하고 direction=underestimate|overestimate|exact으로 방향을 구분한다.
  • actual unavailable은 0 오차가 아니라 RECONCILIATION_REQUIRED outcome이다.
  • cost는 #37의 newly COMMITTED actual cost인 경우에만 증가한다.
  • missing pricing은 0원 cost로 기록하지 않고 tokenpilot.pricing.missing으로 구분한다.
  • notification metric은 [Budget/Notification] atomic accounting lifecycle에 threshold 알림 연결 #48 lifecycle event가 구현된 경우에만 발행하며 handler success/failure/deduplicated를 구분한다.
  • metric은 double 기반 운영 뷰이며 BigDecimal 회계 원장이 아니다.

기본 tag와 cardinality 정책

  • MetricsOptions.allowedTagKeys 기본값을 빈 집합으로 변경한다.
  • tenant_id, user_id, request_id, reservation/idempotency ID는 기본 tag가 아니다.
  • 사용자 tag는 명시적 whitelist opt-in일 때만 추가하며, whitelist가 value cardinality를 보장하지 않는다는 경고를 문서화한다.
  • model tag는 기본 생략하거나 설정으로 opt-in한다. 활성화 시 [Core] versioned ModelRegistry와 최소 모델 정책 등록 #32 ModelRegistry의 canonical model id만 허용하고 raw/unknown response model 문자열을 그대로 tag로 쓰지 않는다.
  • decision/reason/state/policy/direction/outcome/listener/phase는 제한된 enum 또는 등록된 bounded identifier만 사용한다.
  • prompt, completion, tool/media 원문과 오류 메시지를 tag, meter name 또는 description에 넣지 않는다.
  • 기존 tenant_id 기본 허용 변경은 migration note에 기록한다.

legacy ai.token.* 정책

  • ai.token.usage.total, ai.token.usage.distribution, ai.token.cost.total은 starter/autoconfigure 기본값에서 비활성화한다.
  • legacy metric이 필요한 사용자는 명시적인 token-pilot.metrics.legacy-ai-token-metrics-enabled=true와 같은 opt-in 설정을 사용한다.
  • legacy opt-in을 켜도 중복 가능성과 migration 종료 계획을 문서화한다.
  • tokenpilot.* metric은 Spring AI latency, trace와 provider input/output/total token metric을 복제하지 않는다.
  • 기존 public constructor의 호환 동작을 유지할지 새 기본값으로 전환할지는 [Build/Compatibility] 0.1.0 Java·Spring Boot·Spring AI 지원 기준 확정 #47 compatibility 결정과 migration note를 따른다. autoconfigure 기본은 legacy off로 고정한다.

domain event 연결

  1. [Core] TokenBudget.check()와 reserved output token 지원 #33 preflight decision, [Budget] atomic reservation store와 idempotency 구현 #36 reservation, [Budget] commit/release lifecycle와 actual reconciliation 구현 #37 accounting/reconciliation, [Pricing] missing pricing·explicit zero와 pricing snapshot 정책 구현 #28 pricing miss와 [Budget/Notification] atomic accounting lifecycle에 threshold 알림 연결 #48 notification lifecycle event를 Micrometer adapter가 소비한다.
  2. Advisor와 autoconfiguration이 직접 MeterRegistry를 조작하지 않는다.
  3. duplicate/REUSED/CONFLICT command가 같은 accounting event를 다시 만들지 않도록 #37의 newly applied result만 측정한다.
  4. event listener 인터페이스는 owning module의 framework-independent 계약으로 두고 Core/Budget/Notification에 Micrometer 타입을 노출하지 않는다.
  5. token-pilot-micrometer가 Budget/Notification event를 소비하는 module dependency 또는 조건부 publisher 구조를 명시하고 external consumer POM에서 검증한다.
  6. MeterRegistry가 있고 metrics enabled일 때만 autoconfigure하며 사용자 bean을 우선한다.
  7. tenant별 remaining gauge는 cardinality와 lifecycle 문제 때문에 기본 metric에서 제외한다.

Listener 실패 정책 소비

#46/#37이 정의한 정책을 다음처럼 검증한다.

  • accounting state transition과 event 생성은 listener 호출보다 먼저 완료된다.
  • optional Micrometer listener 실패가 provider 응답, COMMITTED/RELEASED/RECONCILIATION_REQUIRED 상태를 rollback하지 않는다.
  • 한 listener 실패 후에도 다른 listener가 각각 한 번 실행된다.
  • failure는 bounded tokenpilot.listener.failures와 sanitized error handler로 관측한다.
  • error handler 또는 failure metric 발행 실패가 재귀 event나 원래 accounting 예외 전파를 만들지 않는다.
  • listener 재전송과 exactly-once delivery는 durable outbox가 없는 MVP에서 보장하지 않는다. dispatch는 best-effort at-most-once다.

테스트

  • 각 domain event가 정확한 name/type/description/base unit/bounded tag로 발행된다.
  • newly COMMITTED actual cost만 tokenpilot.cost.total을 증가시킨다.
  • duplicate reconciliation/REUSED command가 cost와 outcome counter를 이중 증가시키지 않는다.
  • actual unavailable이 cost/error 0이 아니라 reconciliation-required outcome으로 기록된다.
  • missing pricing이 명시적 0원 cost와 구분된다.
  • 기본 allowedTagKeys가 empty이고 tenant/user/request ID가 노출되지 않는다.
  • whitelist opt-in 밖 user_id/request_id가 노출되지 않는다.
  • raw unknown model, prompt/response/error text가 meter ID와 tag에 포함되지 않는다.
  • metrics disabled 또는 registry 없음이면 관련 bean이 없다.
  • legacy ai.token.*은 autoconfigure 기본값에서 발행되지 않고 명시적 opt-in에서만 발행된다.
  • Spring sample에서 latency/input/output/total token 의미가 TokenPilot 기본 metric으로 중복 발행되지 않는다.
  • metric listener가 예외를 던져도 확정된 accounting 결과와 다른 listener는 보존된다.
  • listener error handler 실패가 재귀 실패나 provider 응답 변경을 만들지 않는다.
  • [Budget/Notification] atomic accounting lifecycle에 threshold 알림 연결 #48 notification success/failure/deduplicated event가 bounded tag로 발행된다.

Acceptance criteria

  • cost, preflight, reservation, pricing miss와 reconciliation metric이 제공된다.
  • [Budget/Notification] atomic accounting lifecycle에 threshold 알림 연결 #48 notification lifecycle metric 연결점이 제공된다.
  • metric은 ledger/control event의 운영 뷰이며 원장으로 사용되지 않는다.
  • 모든 기본 tag가 bounded이고 사용자/tenant/model tag는 명시적 opt-in이다.
  • 기본 user tag whitelist는 empty다.
  • legacy ai.token.*은 starter/autoconfigure 기본 off이며 migration 설정과 문서가 있다.
  • Spring AI telemetry와 TokenPilot 고유 metric 경계가 [Build/Compatibility] 0.1.0 Java·Spring Boot·Spring AI 지원 기준 확정 #47 compatibility 문서와 일치한다.
  • prompt/completion 원문 기록은 기본 비활성이다.
  • Core/Budget/Notification은 Micrometer 없이 동일하게 동작한다.
  • optional listener 실패가 provider 호출 결과와 accounting 상태를 뒤집지 않는다.
  • listener dispatch의 best-effort at-most-once 한계가 문서화된다.

제외 범위

의존관계와 순서

Source

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestmvpTokenPilot 0.1.0 MVP scope

    Type

    No type

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions