Back to Beads

OpenTelemetry Data Model

docs/design/otel/otel-data-model.md

1.0.313.1 KB
Original Source

OpenTelemetry Data Model

Complete schema of all telemetry events emitted by Beads. Each event consists of:

  1. Span (→ any OTLP v1.x+ backend, stdout when BD_OTEL_STDOUT=true) with full structured attributes
  2. Metric counter/histogram (→ any OTLP v1.x+ backend, defaults to VictoriaMetrics) for aggregation

All command spans automatically carry bd.command, bd.version, bd.args from startup context; bd.actor is added after actor resolution.


Metric Naming Convention

OTel SDK names use dot notation internally. Prometheus-compatible backends (VictoriaMetrics, Prometheus) export these as underscore-separated names, appending type suffixes:

Code name (SDK)Exported name (Prometheus/VM)
bd.storage.operationsbd_storage_operations_total
bd.storage.operation.durationbd_storage_operation_duration_ms
bd.storage.errorsbd_storage_errors_total
bd.issue.countbd_issue_count
bd.db.retry_countbd_db_retry_count_total
bd.db.lock_wait_msbd_db_lock_wait_ms
bd.db.circuit_tripsbd_db_circuit_trips_total
bd.db.circuit_rejectedbd_db_circuit_rejected_total
bd.ai.input_tokensbd_ai_input_tokens_total
bd.ai.output_tokensbd_ai_output_tokens_total
bd.ai.request.durationbd_ai_request_duration_ms

Event Index

EventCategoryStatus
bd.commandCLI✅ Implemented
storage.*Storage✅ Implemented
dolt.*Dolt Backend✅ Implemented
doltserver.*Server Lifecycle🔲 Roadmap (Tier 1)
hook.execHooks✅ Implemented (span only)
anthropic.messages.newAI✅ Implemented

1. Identity Hierarchy

1.1 Instance

The outermost grouping. Derived at command startup time from the machine hostname and the working directory.

AttributeTypeDescription
hoststringSystem hostname
osstringSystem OS information

1.2 Command

Each bd command execution generates a span with full context.

AttributeTypeSource
bd.commandstringSubcommand name (create, list, show, etc.)
bd.versionstringbd version (e.g., "0.9.3")
bd.argsstringFull argument list
bd.actorstringActor identity — set after actor resolution (may lag span start)

2. CLI Command Events

bd.command.<name>

Emitted once per bd subcommand execution. Anchors all subsequent events for that command. The span name is bd.command. + command name (e.g. bd.command.create).

AttributeTypeDescription
bd.commandstringSubcommand name
bd.versionstringbd version
bd.argsstringFull arguments passed to command
bd.actorstringActor identity (set after actor resolution)

3. Storage Events

storage.CreateIssue

Emitted when an issue is created.

AttributeTypeDescription
db.operationstring"CreateIssue"
bd.issue.typestringIssue type (task, epic, merge-request, etc.)
bd.actorstringActor creating the issue

storage.UpdateIssue

Emitted when an issue is updated.

AttributeTypeDescription
db.operationstring"UpdateIssue"
bd.issue.idstringIssue ID being updated
bd.update.countintNumber of fields being updated
bd.actorstringActor updating the issue

storage.GetIssue

Emitted when an issue is retrieved.

AttributeTypeDescription
db.operationstring"GetIssue"
bd.issue.idstringIssue ID being retrieved

storage.SearchIssues

Emitted when searching for issues.

AttributeTypeDescription
db.operationstring"SearchIssues"
bd.querystringSearch query string
bd.result.countintNumber of results returned

storage.GetReadyWork

Emitted when querying for ready work.

AttributeTypeDescription
db.operationstring"GetReadyWork"
bd.result.countintNumber of ready issues returned

storage.GetBlockedIssues

Emitted when querying for blocked issues.

AttributeTypeDescription
db.operationstring"GetBlockedIssues"
bd.result.countintNumber of blocked issues returned

storage.RunInTransaction

Emitted when executing a transaction.

AttributeTypeDescription
db.operationstring"RunInTransaction"
db.commit_msgstringCommit message

4. Dolt Backend Events

dolt.query

Emitted for each SQL read query via queryContext().

AttributeTypeDescription
db.operationstring"query"
db.statementstringSQL statement (truncated to 300 chars)
db.systemstring"dolt"
db.readonlyboolWhether store is read-only

dolt.exec

Emitted for each SQL write statement via execContext().

AttributeTypeDescription
db.operationstring"exec"
db.statementstringSQL statement (truncated to 300 chars)
db.systemstring"dolt"

dolt.query_row

Emitted for single-row queries via queryRowContext().

AttributeTypeDescription
db.operationstring"query_row"
db.statementstringSQL statement (truncated to 300 chars)
db.systemstring"dolt"

dolt.commit

Emitted for DOLT_COMMIT operations.

AttributeTypeDescription
commit_msgstringCommit message

dolt.push

Emitted for DOLT_PUSH operations.

AttributeTypeDescription
dolt.branchstringBranch being pushed

dolt.pull

Emitted for DOLT_PULL operations.

AttributeTypeDescription
dolt.branchstringBranch being pulled

dolt.merge

Emitted for DOLT_MERGE operations.

AttributeTypeDescription
dolt.merge_branchstringBranch being merged

dolt.branch

Emitted for DOLT_BRANCH operations.

AttributeTypeDescription
dolt.branchstringBranch name

dolt.checkout

Emitted for DOLT_CHECKOUT operations.

AttributeTypeDescription
dolt.branchstringBranch being checked out

5. Dolt Server Events (Roadmap — not yet implemented)

internal/doltserver/ has no OTel imports. The events below are planned for Tier 1.

doltserver.start (planned)

AttributeTypeDescription
portintPort server is listening on
data_dirstringPath to Dolt data directory
pidintProcess ID of server

doltserver.stop (planned)

AttributeTypeDescription
pidintProcess ID of stopped server
reasonstringStop reason (graceful, forced, idle_timeout, crash)

6. Hooks Events

hook.exec

Emitted for hook execution. Span only — no metric counters or histograms exist for hooks. Duration aggregation is a Tier 3 roadmap item.

AttributeTypeDescription
hook.eventstringEvent type (create, update, close, delete, etc.)
hook.pathstringAbsolute path to hook script
bd.issue_idstringID of triggering issue

Stdout/stderr are added as span events (not attributes):

  • hook.stdout event: output (string, truncated), bytes (int, original size)
  • hook.stderr event: output (string, truncated), bytes (int, original size)

7. AI Events

Emitted by the compaction engine (bd compact) via internal/compact/haiku.go, and by duplicate detection (bd find-duplicates --method ai) via cmd/bd/find_duplicates.go. Both use the Anthropic SDK directly via ANTHROPIC_API_KEY.

Note: Only compact/haiku.go records to the bd.ai.* OTel metric instruments. find_duplicates.go records token counts as span attributes only.

anthropic.messages.new

One span per Anthropic API call. The bd.ai.operation attribute distinguishes the two callers.

AttributeTypeDescription
bd.ai.modelstringModel used (e.g. "claude-haiku-4-5")
bd.ai.operationstring"compact" or "find_duplicates"
bd.ai.input_tokensintInput tokens consumed
bd.ai.output_tokensintOutput tokens generated
bd.ai.attemptsintNumber of attempts (including retries)
bd.ai.batch_sizeintCandidate pairs evaluated (find_duplicates only)

Retry policy: exponential backoff, up to 3 attempts, on HTTP 429, 5xx, and network timeout errors.


8. Metrics Reference

Metric (code name)TypeLabelsStatus
bd.storage.operationsCounterdb.operation✅ Implemented
bd.storage.operation.durationHistogram (ms)db.operation✅ Implemented
bd.storage.errorsCounterdb.operation✅ Implemented
bd.issue.countGaugestatus✅ Implemented
bd.db.retry_countCounter✅ Implemented
bd.db.lock_wait_msHistogram🔲 Registered, not recorded
bd.db.circuit_tripsCounter✅ Implemented
bd.db.circuit_rejectedCounter✅ Implemented
bd.ai.input_tokensCounterbd.ai.model✅ Implemented (compact only)
bd.ai.output_tokensCounterbd.ai.model✅ Implemented (compact only)
bd.ai.request.durationHistogram (ms)bd.ai.model✅ Implemented (compact only)

host, os, bd.command, bd.version, bd.actor, db.operation, db.statement,
bd.issue.id, bd.issue.type, hook.event, hook.path, bd.ai.model, bd.ai.operation

10. Configuration and Backend

Environment variables, backend compatibility, Dolt system tables, and roadmap are documented in otel-architecture.md to avoid duplication.

Key variables: BD_OTEL_METRICS_URL, BD_OTEL_LOGS_URL, BD_OTEL_STDOUT.


Appendix: Source Reference Audit

Audited against main @ 371df32b. All line numbers below refer to that commit.

Every metric name, span name, and attribute listed in this document is backed by a specific source location. This table exists to prevent documentation drift and to make re-verification straightforward after code changes.

Metrics (internal/telemetry/storage.go, internal/storage/dolt/store.go, internal/compact/haiku.go)

Metric (SDK name)TypeSource
bd.storage.operationsCounterstorage.go:38m.Int64Counter("bd.storage.operations")
bd.storage.operation.durationHistogramstorage.go:41m.Float64Histogram("bd.storage.operation.duration")
bd.storage.errorsCounterstorage.go:45m.Int64Counter("bd.storage.errors")
bd.issue.countGaugestorage.go:48m.Int64Gauge("bd.issue.count")
bd.db.retry_countCounterstore.go:302m.Int64Counter("bd.db.retry_count")
bd.db.lock_wait_msHistogramstore.go:306 — registered; .Record() not called anywhere
bd.db.circuit_tripsCounterstore.go:310m.Int64Counter("bd.db.circuit_trips")
bd.db.circuit_rejectedCounterstore.go:314m.Int64Counter("bd.db.circuit_rejected")
bd.ai.input_tokensCounterhaiku.go:110m.Int64Counter("bd.ai.input_tokens")
bd.ai.output_tokensCounterhaiku.go:114m.Int64Counter("bd.ai.output_tokens")
bd.ai.request.durationHistogramhaiku.go:118m.Float64Histogram("bd.ai.request.duration")

Spans and attributes

Span nameAttributesSource
bd.command.<name>bd.command, bd.version, bd.argscmd/bd/main.go:262-266
bd.command.<name>bd.actor (added later)cmd/bd/main.go:474
storage.<op> (all methods)db.operation + method-specific attrsinternal/telemetry/storage.go:62-69
dolt.querydb.operation="query", db.statement, db.system="dolt"store.go:400-405
dolt.execdb.operation="exec", db.statement, db.system="dolt"store.go:363-368
dolt.query_rowdb.operation="query_row", db.statement, db.system="dolt"store.go:429-434
dolt.commitcommit_msgstore.go:1086
dolt.pushdolt.branchstore.go:1231, 1266
dolt.pulldolt.branchstore.go:1295
dolt.mergedolt.merge_branchstore.go:1389
dolt.branchdolt.branchstore.go:1357
dolt.checkoutdolt.branchstore.go:1372
hook.exechook.event, hook.path, bd.issue_idhooks_unix.go:31-36
hook.exec eventshook.stdout / hook.stderr with output, byteshooks_otel.go:14, 20
anthropic.messages.newbd.ai.model, bd.ai.operationhaiku.go:129-130
anthropic.messages.newbd.ai.input_tokens, bd.ai.output_tokens, bd.ai.attemptshaiku.go:165-167
anthropic.messages.newbd.ai.batch_size (find_duplicates only)find_duplicates.go:433