Files
tech-log-backend/docs/registries/metrics.yaml
T

541 lines
20 KiB
YAML

# Registry: Metrics
# SSOT: wiki/projects/ca-tmpl/registries/metrics.yaml
# Schema owner: feature-contract-registry-governance
# Owner branch: feature-metrics-alerting-contract
# Last updated: 2026-05-22
#
# Notes
# - Naming: Micrometer dot.case + unit suffix (.seconds | .bytes | .total).
# - Tag cardinality bounds are SSOT of feature-metrics-alerting-contract "Cardinality Bounds" table.
# - High-cardinality tags forbidden globally: user_id, request_id, raw_url, raw_query,
# raw_header_value, ip_address. These MUST NOT appear in any row.
# - tenant_id label is bounded mapping table id OR cohort bucket only (ULID raw forbidden).
# - error_code tag cardinality_limit follows error-codes.yaml row count (max 100).
metrics:
# === HTTP server (inbound) ===
# source: feature-metrics-alerting-contract — Metric/Alert Defaults
# "HTTP metric | http.server.requests with method/status/uri-template | raw URL or user id tag"
- name: http.server.requests
type: timer
unit: seconds
tags:
- name: method
cardinality_limit: 8
allowed_values: [GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, OTHER]
- name: status
cardinality_limit: 7
allowed_values: [1xx, 2xx, 3xx, 4xx, 5xx, ok, other]
- name: uri_template
cardinality_limit: 200
validation: must_be_template_not_raw_uri
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p1: "error_rate > 5% for 5m OR > 10% for 1m"
p2: "error_rate > 1% for 10m"
p3: "error_rate > 0.1% for 1h"
owner_branch: feature-metrics-alerting-contract
log_field_mapping: [method, status, uri_template]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-metrics-alerting-contract — P1/P2/P3 정량 기준 (HTTP latency p99)
# "P1: p99 > 5s 5분 / P2: p99 > 1s 10분 / P3: p99 > 500ms 30분"
- name: http.server.requests.latency
type: timer
unit: seconds
tags:
- name: method
cardinality_limit: 8
allowed_values: [GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, OTHER]
- name: uri_template
cardinality_limit: 200
validation: must_be_template_not_raw_uri
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p1: "p99 > 5s for 5m"
p2: "p99 > 1s for 10m"
p3: "p99 > 500ms for 30m"
owner_branch: feature-metrics-alerting-contract
log_field_mapping: [method, uri_template, duration_ms]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === HTTP client (outbound dependency) ===
# source: feature-metrics-alerting-contract — Metric/Alert Defaults
# "dependency metric | dependency.client.requests with dependency.name/type/outcome | endpoint with secret tag"
# source: feature-outbound-http-client-baseline — "circuit breaker metric은 dependency.name, dependency.type, outcome까지만 tag로 허용"
- name: dependency.client.requests
type: timer
unit: seconds
tags:
- name: dependency_name
cardinality_limit: 50
- name: dependency_type
cardinality_limit: 10
allowed_values: [http, grpc, db, cache, queue, broker, other]
- name: outcome
cardinality_limit: 5
allowed_values: [SUCCESS, FAILURE, CIRCUIT_OPEN, TIMEOUT, REJECTED]
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p1: "required dep unavailable for 2m"
p2: "optional dep degraded for 5m"
p3: "spike alert (10x baseline)"
owner_branch: feature-metrics-alerting-contract
log_field_mapping: [dependency_name, dependency_type, outcome, duration_ms]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-outbound-http-client-baseline — decisions
# "retry/circuit breaker 기본 라이브러리는 Resilience4j"
# source: feature-metrics-alerting-contract — "retry/CB minimum: resilience4j.retry.calls{outcome}"
- name: resilience4j.retry.calls
type: counter
unit: total
tags:
- name: name
cardinality_limit: 50
- name: outcome
cardinality_limit: 5
allowed_values: [SUCCESS, FAILURE, CIRCUIT_OPEN, TIMEOUT, REJECTED]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "retry exhaustion rate > 1% for 10m"
owner_branch: feature-outbound-http-client-baseline
log_field_mapping: [dependency_name, outcome, retry_attempt]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-metrics-alerting-contract — "resilience4j.circuitbreaker.state"
- name: resilience4j.circuitbreaker.state
type: gauge
unit: total
tags:
- name: name
cardinality_limit: 50
- name: state
cardinality_limit: 6
allowed_values: [CLOSED, OPEN, HALF_OPEN, DISABLED, FORCED_OPEN, METRICS_ONLY]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p1: "state == OPEN for required dependency for 2m"
p2: "state == OPEN for optional dependency for 5m"
owner_branch: feature-outbound-http-client-baseline
log_field_mapping: [dependency_name]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-metrics-alerting-contract — "resilience4j.circuitbreaker.calls{outcome}"
- name: resilience4j.circuitbreaker.calls
type: timer
unit: seconds
tags:
- name: name
cardinality_limit: 50
- name: outcome
cardinality_limit: 5
allowed_values: [SUCCESS, FAILURE, CIRCUIT_OPEN, TIMEOUT, REJECTED]
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p2: "CIRCUIT_OPEN rate > 1% for 10m"
owner_branch: feature-outbound-http-client-baseline
log_field_mapping: [dependency_name, outcome, duration_ms]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === DB connection pool ===
# source: feature-persistence-failure-baseline — Hikari Alert Threshold
# "pool wait p99 > 100ms 5분 지속 → P2 / pool exhaustion (active = max) > 1분 → P1"
# source: feature-metrics-alerting-contract — "hikaricp.connections.acquire{outcome='timeout'} p99 > 100ms"
- name: hikaricp.connections.acquire
type: timer
unit: seconds
tags:
- name: pool
cardinality_limit: 5
- name: outcome
cardinality_limit: 3
allowed_values: [SUCCESS, TIMEOUT, FAILURE]
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p1: "pool exhaustion (active == max) for 1m"
p2: "acquire p99 > 100ms for 5m"
owner_branch: feature-persistence-failure-baseline
log_field_mapping: [pool, outcome]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-persistence-failure-baseline — In scope "Hikari metric 노출 기준" + Hikari Alert Threshold
- name: hikaricp.connections.usage
type: timer
unit: seconds
tags:
- name: pool
cardinality_limit: 5
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p2: "usage p99 elevated > 10m"
owner_branch: feature-persistence-failure-baseline
log_field_mapping: [pool]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-persistence-failure-baseline — In scope "Hikari metric 노출 기준"
- name: hikaricp.connections.active
type: gauge
unit: total
tags:
- name: pool
cardinality_limit: 5
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p1: "active == max for 1m"
owner_branch: feature-persistence-failure-baseline
log_field_mapping: [pool]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-metrics-alerting-contract — Histogram Buckets/Percentile "DB query: same"
- name: db.query.duration
type: timer
unit: seconds
tags:
- name: operation
cardinality_limit: 20
allowed_values: [select, insert, update, delete, batch, ddl, other]
- name: outcome
cardinality_limit: 3
allowed_values: [SUCCESS, FAILURE, TIMEOUT]
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p2: "p99 > 1s for 10m"
owner_branch: feature-metrics-alerting-contract
log_field_mapping: [operation, outcome, duration_ms]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === Background job / async executor ===
# source: feature-background-job-async-contract — Decisionized Work Items "saturation policy"
# "AbortPolicy default (core=10, max=50, queue=200)"
- name: executor.saturation
type: gauge
unit: total
tags:
- name: executor_name
cardinality_limit: 10
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "queue size > 80% capacity for 5m"
p1: "rejection rate > 0 for 1m"
owner_branch: feature-background-job-async-contract
log_field_mapping: [executor_name]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-background-job-async-contract — Decisionized Work Items "saturation | bounded executor + rejection log"
- name: executor.rejected.total
type: counter
unit: total
tags:
- name: executor_name
cardinality_limit: 10
- name: policy
cardinality_limit: 3
allowed_values: [AbortPolicy, CallerRunsPolicy, DiscardPolicy]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p1: "rejection_count > 0 for 1m"
owner_branch: feature-background-job-async-contract
log_field_mapping: [executor_name, policy]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-background-job-async-contract — Decisionized Work Items "retry/DLQ | exp backoff jitter, max 3, DLQ exhausted"
- name: job.retry.total
type: counter
unit: total
tags:
- name: job_name
cardinality_limit: 50
- name: outcome
cardinality_limit: 4
allowed_values: [SUCCESS, RETRY, EXHAUSTED, DLQ]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "EXHAUSTED rate > 1% for 10m"
owner_branch: feature-background-job-async-contract
log_field_mapping: [job_name, outcome, retry_attempt]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-background-job-async-contract — "DLQ after exhausted attempts"
- name: job.dlq.total
type: counter
unit: total
tags:
- name: job_name
cardinality_limit: 50
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p1: "DLQ rate sustained > 0 for 5m"
owner_branch: feature-background-job-async-contract
log_field_mapping: [job_name]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === Distributed lock ===
# source: feature-distributed-lock-contract D7 — "metric lock.acquisition (tag: outcome =
# acquired/timeout/error) — 신규 제안" / D5 — try-lock + 유한 waitTime + lease(TTL). 분산
# 상호배제(distributedLockProvider) 획득 시도 결과를 센다. key 는 tag 로 넣지 않는다
# (무한 cardinality — 위 전역 금지 규칙). timeout outcome 은 LOCK_ACQUISITION_TIMEOUT 발생과 1:1.
- name: lock.acquisition
type: counter
unit: total
tags:
- name: outcome
cardinality_limit: 3
allowed_values: [acquired, timeout, error]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "timeout rate > 5% for 10m"
owner_branch: feature-distributed-lock-contract
log_field_mapping: [outcome]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-distributed-lock-contract §Edge / D5 (SI-LOCK-C5) — "lease 만료 후 unlock →
# ConcurrentModificationException — 삼킴 금지, 로그+metric 후 정상 흐름 복귀". Counts releases that
# found the lease already expired (the JdbcLock row was reclaimed by another instance before
# the holder called close()). A sustained nonzero rate means lease TTL is shorter than real
# critical-section duration — raise APP/lease TTL or shorten the protected work. Not an
# acquisition outcome, hence a separate counter from lock.acquisition.
- name: lock.lease.expired
type: counter
unit: total
tags: []
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "lease-expired rate sustained > 0 for 10m"
owner_branch: feature-distributed-lock-contract
log_field_mapping: []
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === Outbox publisher ===
# source: feature-domain-event-outbox-contract — Outbox Defaults
# "DB outbox table with eventId, aggregateId, eventType, payload, occurredAt, status, attemptCount, nextAttemptAt"
- name: outbox.publisher.published.total
type: counter
unit: total
tags:
- name: event_type
cardinality_limit: 50
- name: outcome
cardinality_limit: 4
allowed_values: [PUBLISHED, FAILED, DEAD, IN_FLIGHT]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "FAILED rate > 1% for 10m"
owner_branch: feature-domain-event-outbox-contract
log_field_mapping: [event_type, outcome, event_id]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-domain-event-outbox-contract — row status enum PENDING/IN_FLIGHT/PUBLISHED/FAILED/DEAD
- name: outbox.publisher.lag
type: gauge
unit: seconds
tags:
- name: event_type
cardinality_limit: 50
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "lag > 60s for 10m"
p1: "lag > 300s for 5m"
owner_branch: feature-domain-event-outbox-contract
log_field_mapping: [event_type]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-domain-event-outbox-contract — row status enum + Outbox Defaults attemptCount
- name: outbox.pending.size
type: gauge
unit: total
tags:
- name: status
cardinality_limit: 5
allowed_values: [PENDING, IN_FLIGHT, PUBLISHED, FAILED, DEAD]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "PENDING size growing for 10m"
owner_branch: feature-domain-event-outbox-contract
log_field_mapping: [status]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === Cache ===
# source: feature-cache-consistency-contract — Decisionized Work Items "cache pattern | cache-aside default"
- name: cache.gets.total
type: counter
unit: total
tags:
- name: cache_name
cardinality_limit: 50
- name: result
cardinality_limit: 3
allowed_values: [hit, miss, error]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p3: "hit_ratio < baseline 0.5x for 1h"
owner_branch: feature-cache-consistency-contract
log_field_mapping: [cache_name, result]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-cache-consistency-contract — "invalidation = after-commit only", "invalidation 실패가 조용히 무시되면 실패"
- name: cache.invalidations.total
type: counter
unit: total
tags:
- name: cache_name
cardinality_limit: 50
- name: outcome
cardinality_limit: 3
allowed_values: [SUCCESS, FAILURE, SKIPPED]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "FAILURE rate > 0 for 5m"
owner_branch: feature-cache-consistency-contract
log_field_mapping: [cache_name, outcome]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === Log appender ===
# source: feature-log-management-contract — Sampling Policy (final)
# "async appender overflow default: drop oldest INFO/DEBUG with counter metric (log.appender.dropped.total)"
- name: log.appender.dropped.total
type: counter
unit: total
tags:
- name: appender
cardinality_limit: 5
- name: level
cardinality_limit: 2
allowed_values: [INFO, DEBUG]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "dropped > 0 sustained for 10m"
owner_branch: feature-log-management-contract
log_field_mapping: [appender, level]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === Distributed tracing ===
# source: feature-distributed-tracing-contract — decisions
# "trace sampling rate default = prod 1%, staging 10%, dev/local 100%"
- name: tracing.sampling.rate
type: gauge
unit: total
tags:
- name: profile
cardinality_limit: 4
allowed_values: [prod, staging, dev, local]
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p3: "effective rate deviates from configured for 1h"
owner_branch: feature-distributed-tracing-contract
log_field_mapping: [profile]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# === JVM baseline ===
# source: feature-metrics-alerting-contract — In scope "JVM/process metric"
- name: jvm.memory.used
type: gauge
unit: bytes
tags:
- name: area
cardinality_limit: 2
allowed_values: [heap, nonheap]
- name: id
cardinality_limit: 10
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p2: "heap used / max > 0.85 for 10m"
owner_branch: feature-metrics-alerting-contract
log_field_mapping: [area, id]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-metrics-alerting-contract — In scope "JVM/process metric"
- name: jvm.gc.pause
type: timer
unit: seconds
tags:
- name: action
cardinality_limit: 10
- name: cause
cardinality_limit: 10
percentiles: [0.5, 0.9, 0.95, 0.99]
histogram_buckets: slo_driven
alert_severity_thresholds:
p2: "p99 pause > 500ms for 10m"
owner_branch: feature-metrics-alerting-contract
log_field_mapping: [action, cause]
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-metrics-alerting-contract — In scope "JVM/process metric"
- name: jvm.threads.live
type: gauge
unit: total
tags: []
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p3: "thread count > 2x baseline for 30m"
owner_branch: feature-metrics-alerting-contract
log_field_mapping: []
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality
# source: feature-metrics-alerting-contract — In scope "JVM/process metric" (process uptime)
- name: process.uptime
type: gauge
unit: seconds
tags: []
percentiles: null
histogram_buckets: null
alert_severity_thresholds:
p1: "uptime reset unexpectedly < 60s (crash loop signal)"
owner_branch: feature-metrics-alerting-contract
log_field_mapping: []
compatibility_impact: additive
required_test: contract-verification:metrics-cardinality