Markdown Editor

Distributed Tracing and Logging System Design Template (Reference Design)

45-minute path, W3C trace context and baggage, async propagation, head, tail and hybrid sampling, span metrics, log correlation, retention tiers, failure modes

系统设计完整W3C Trace Context (Rec 2021); W3C Baggage (CR 2024); OpenTelemetry 1.62.0designdistributedtracingloggingmath

使用方法: Use it when designing or replacing a tracing and log pipeline for many services. Fill the volume assumptions and the sampling strategy first, then retention per data class and redaction. The main pitfall is head sampling alone, which keeps traces for only a small share of failed requests.

预览

System Design: [Tracing and logging platform name]

Reference design for a distributed tracing and log pipeline: how trace context crosses service and queue boundaries, how spans and logs are collected, which traces are kept (head, tail and hybrid sampling), how logs are correlated with traces, and how long each kind of data is retained. It uses W3C Trace Context (Recommendation, Level 1, 23 November 2021), W3C Baggage (Candidate Recommendation Snapshot, 30 May 2024) and OpenTelemetry (specification 1.62.0 as of October 2026, with the OTLP protocol and the Collector). It follows the structure of the System Design Document template, adds a 45-minute interview path, access-pattern and failure-mode tables and a cited "How real systems do it" box, and is pre-filled with a worked design to adapt. Replace every [bracketed] value and every row marked Example; values marked Example are assumptions, not benchmarks.

Document control

FieldValue
Document ID[SDD-OBS-002]
System / feature[Distributed tracing and centralised logging]
Version[0.1]
Status[Draft / In review / Approved / Implemented / Superseded]
Owner[@owner]
Author(s)[@author]
Reviewers[@reviewer-1], [@reviewer-2]
Last updatedYYYY-MM-DD
Classification[Internal]
DifficultyAdvanced
Specifications implemented[W3C Trace Context Level 1; W3C Baggage (CR); OpenTelemetry specification 1.62.0; OTLP]
Related[Observability specification], [Metrics platform design], [Data retention standard]

Approvals

RoleNameDecisionDate
Tech lead[@name][Approved / Changes requested]YYYY-MM-DD
Staff / principal engineer[@name][Decision]YYYY-MM-DD
SRE / platform[@name][Decision]YYYY-MM-DD
Security and privacy[@name][Decision]YYYY-MM-DD
FinOps (telemetry budget)[@name][Decision]YYYY-MM-DD

Revision history

VersionDateAuthorChange summary
0.1YYYY-MM-DD[@name]First draft for design review
0.2YYYY-MM-DD[@name]Example: Replaced 1% head sampling with hybrid head and tail sampling
0.3YYYY-MM-DD[@name]Example: Added request metrics recorded in the SDK for every request, independent of sampling
1.0YYYY-MM-DD[@name]Example: Approved

Contents

1. Overview

1.1 Problem statement

[Example: About 2 000 services emit logs in four formats and three tracing libraries that do not share context. During last month's checkout outage it took 70 minutes to connect a customer's failed payment to the service that timed out, because trace IDs stopped at the message queue and logs carried no trace ID at all. The logging bill grew 60% in a year, mostly from debug logs nobody reads.]

1.2 Proposed solution

[Example: Every service uses the OpenTelemetry SDK and propagates W3C traceparent, tracestate and baggage headers over HTTP, gRPC and message headers. SDKs head-sample 25% of traces with a parent-based, trace-ID-ratio sampler and attach the trace and span ID to every log record. The SDK instrumentation also records request, error and duration metrics for every request, sampled or not, and exports them as OTLP metrics. A Collector agent on each node forwards the metrics and sends sampled spans with a load-balancing exporter keyed by trace ID to a tail-sampling gateway tier. The gateway keeps every error and slow trace plus 5% of the rest and writes them to a trace store on object storage with a trace-ID index. Logs flow through the same agents to Kafka, then to a hot search index for 7 days and compressed object storage for 30 days.]

1.3 Decisions requested from reviewers

IDQuestionRecommended optionSection
Q-01Example: Head, tail or hybrid sampling?Hybrid: 25% head, then tail rules7.2
Q-02Example: How do error rates stay exact if traces are sampled?Request metrics recorded in the SDK for every request, independent of the sampling decision7.3
Q-03Example: How is context carried through Kafka and batch jobs?Trace headers in message headers; span links for fan-in7.1
Q-04Example: Retention per data class?Traces 14 days; logs 7 days hot, 30 days cold; audit logs 365 days7.5
[Q-nn][Question][Option][Section]

1.4 45-minute interview path

Use this order when the document serves an interview or a short design review. The written sections below are the long form of each step.

MinutesCoverOutput on the whiteboard
0 to 5Scope: traces and logs, the incident questions they answer; below-the-line items (2.3)Three queries: trace by ID, search traces, logs for a trace
5 to 10Estimates: spans per second, bytes per day unsampled, tail buffer (section 3)"About 0.41 PB a day unsampled, so we must sample"
10 to 15Interface: traceparent header, OTLP export, query API (section 4)Header format and two calls
15 to 25High-level design: SDK, agent, gateway, stores, query (section 6)One diagram, trace and log paths
25 to 40One deep dive: sampling (default, 7.2 and 7.3), or context propagation across async boundaries (7.1), or log retention and cost (7.5)Options, choice, reason
40 to 45Failures (gateway overload, broken propagation), the 10x row in section 10Two failure rows

Start the default deep dive with the naive answer, keep 1% of traces chosen at random at the first service, and show what it misses: 99% of failed requests have no trace. Then add tail sampling, show that it needs every span of a trace on one machine, and size the buffer that requires.

2. Requirements

2.1 Core functional requirements

IDRequirementPriority
FR-01Example: Propagate trace context across HTTP, gRPC, Kafka and scheduled jobsMust
FR-02Example: Retrieve a complete trace by trace IDMust
FR-03Example: Search traces by service, operation, status, duration and selected attributesMust
FR-04Example: Keep every trace that contains an error or exceeds the latency threshold of its entry operation, subject to head sampling (7.2)Must
FR-05Example: Attach trace ID and span ID to every log record emitted inside a spanMust
FR-06Example: Search logs by service, severity, time and full text, and jump from a log line to its traceMust
FR-07Example: Request rate, error rate and duration per service and operation computed from every request, not from sampled tracesMust
FR-08Example: Redact secrets and personal data before storageMust
FR-09Example: Change sampling rules without redeploying servicesShould
[FR-nn][Requirement][Must / Should / Could]

2.2 Non-functional requirements

IDQualityTargetMeasured as
NFR-01Overhead on servicesExample: Under 2% CPU and under 1 ms added p99 latencyBenchmarks with SDK on and off
NFR-02Ingest freshnessExample: Trace searchable within 60 s of its last span (p95); logs within 30 sSynthetic canary traces
NFR-03Query latencyExample: Trace by ID under 2 s p95; log search over 1 h under 5 s p95Query logs
NFR-04CompletenessExample: At least 99% of stored traces have no missing spansOrphan span rate
NFR-05IsolationExample: Telemetry backpressure never blocks application requestsChaos test with the gateway down
NFR-06CostExample: Telemetry spend at or below [x]% of infrastructure spendMonthly FinOps report
[NFR-nn][Quality][Target][Measurement]

2.3 Below the line (out of scope)

Name these explicitly so reviewers and interviewers do not pull the design toward them.

  • [Example: the metrics platform itself (time series storage and alerting; see system-design/design-metrics-monitoring)]
  • [Example: continuous profiling (the OpenTelemetry profiles signal is still in development as of October 2026)]
  • [Example: real-user monitoring in browsers and mobile apps]
  • [Example: security event management (SIEM) correlation rules]
  • [Item deferred, with the release that will take it]

3. Capacity estimation

3.1 Assumptions

InputSymbolValueSource
Peak requests per second at the edgeRRExample: 400 000Edge metrics
Average spans per tracekkExample: 30Pilot services
Bytes per span (OTLP protobuf, uncompressed)bbExample: 800 BPilot export sizes
Average to peak ratioaaExample: 0.5Daily traffic curve
Head sampling ratiophp_hExample: 0.257.2
Tail decision waitTwT_wExample: 30 sLongest common trace duration plus margin
Share of traces with error or slowqqExample: 3%Pilot data
Baseline keep ratio for normal tracespbp_bExample: 5%7.2
Peak log lines per secondLLExample: 2.5 millionCurrent log platform
Bytes per log linellExample: 350 BCurrent log platform

3.2 Unsampled volume

S=R×k=4×105×30=1.2×107 spans/s,S×b=9.6 GB/s at peakS = R \times k = 4 \times 10^{5} \times 30 = 1.2 \times 10^{7} \ \text{spans/s}, \qquad S \times b = 9.6 \ \text{GB/s at peak}

At the average rate that is about 0.41 PB per day. Consequence: storing every span is not an option; sampling is the core of the design.

3.3 Tail-sampling buffer

The tail sampler must hold all spans of a trace until it decides. After 25% head sampling the gateway tier receives 3×1063 \times 10^{6} spans/s (2.4 GB/s):

B=S×ph×b×Tw=1.2×107×0.25×800×30 B=72 GBB = S \times p_h \times b \times T_w = 1.2 \times 10^{7} \times 0.25 \times 800 \times 30 \ \text{B} = 72 \ \text{GB}

Spread over 24 gateway instances that is 3 GB each, or 6 GB with 2x headroom. Without head sampling the same buffer would be 288 GB. Consequence: hybrid sampling keeps the tail tier at a modest, fixed size.

3.4 Stored traces

The tail sampler keeps all error and slow traces and 5% of the rest:

pkeep=q+(1−q)×pb=0.03+0.97×0.05=0.0785,pstored=ph×pkeep=0.25×0.0785≈1.96%p_{keep} = q + (1 - q) \times p_b = 0.03 + 0.97 \times 0.05 = 0.0785, \qquad p_{stored} = p_h \times p_{keep} = 0.25 \times 0.0785 \approx 1.96\%

At the average rate that is 117 750 spans/s, 8.1 TB per day raw, about 1.0 TB per day after 8x columnar compression and about 14.2 TB for 14 days of retention. The trace-ID index holds about 339 million traces per day at 40 B each, 13.6 GB per day or 190 GB for 14 days. Consequence: the trace store fits on object storage with a small index, not a large search cluster.

3.5 Logs

StepFormulaResult
Peak ingestL×lL \times l0.875 GB/s
Raw per day (average)L×a×l×86 400L \times a \times l \times 86\,40037.8 TB
Compressed per day (10x)3.78 TB
Hot index, 7 days, 1.5x index overhead3.78×7×1.53.78 \times 7 \times 1.539.7 TB
Object storage, 30 days3.78×303.78 \times 30113.4 TB
Audit class (10% of volume), 365 days3.78×0.1×3653.78 \times 0.1 \times 365138 TB

Consequence: logs, not traces, dominate storage; the cheapest saving is dropping debug logs at the source and indexing only 7 days.

3.6 Summary

QuantityEstimateDesign consequence
Spans unsampled12 million/s, 9.6 GB/s at peakMust sample
Tail buffer72 GB over 24 gatewaysHybrid sampling, trace-ID routing
Stored tracesAbout 2% of traces, 14.2 TB for 14 daysObject storage plus trace-ID index
Logs3.78 TB/day compressed7-day hot index, cold tier, source filtering
Export calls from SDKsAbout 5 860/s at 512 spans per batchBatching processor defaults are adequate

4. API design

4.1 Interfaces

InterfaceOperationPurpose
Propagationtraceparent, tracestate, baggage headersCarry context between processes (7.1)
IngestOTLP over gRPC or HTTP to the local agentExport spans, logs and metrics
Query APIGET /v1/traces/{trace_id}Full trace for the waterfall view
Query APIGET /v1/traces?service=&operation=&status=error&min_duration_ms=&from=&to=Trace search
Query APIGET /v1/logs?query=&service=&severity=&trace_id=&from=&to=Log search and logs for one trace
Admin APIPUT /v1/sampling-policies/{id}Change tail-sampling rules (versioned)

4.2 Trace context on the wire

W3C Trace Context Level 1 defines traceparent as four dash-separated fields: version (00), a 16-byte trace ID as 32 lowercase hex characters, an 8-byte parent span ID as 16 hex characters, and 8 bits of trace flags where the lowest bit means sampled. tracestate carries vendor-specific data as a list of at most 32 members. Trace Context Level 2 (Candidate Recommendation Draft, 28 March 2024) adds a random-trace-ID flag (bit value 2); check its status before relying on it.

GET /v1/orders/8812 HTTP/1.1
Host: orders.internal.example
traceparent: 00-7d3e1f9a5c2b4e8f9a0b1c2d3e4f5a6b-3c4d5e6f7a8b9c0d-01
tracestate: acme=q2v8n4kx
baggage: tenant.tier=gold,checkout.flow=express

Baggage carries application context (here a tenant tier) to downstream services; the W3C Baggage format sets minimum limits of 64 members and 8 192 bytes. Never put personal data or secrets in baggage: it is sent to every downstream service, including third parties.

4.3 Span as stored

The trace store keeps spans in the OTLP shape, flattened for columnar storage; times are Unix nanoseconds.

{"trace_id": "7d3e1f9a5c2b4e8f9a0b1c2d3e4f5a6b", "span_id": "9f8e7d6c5b4a3921", "parent_span_id": "3c4d5e6f7a8b9c0d", "name": "SELECT orders", "kind": "CLIENT", "start_unix_nano": 1793353447412000000, "end_unix_nano": 1793353447431000000, "status": "OK", "resource": {"service.name": "orders-api", "deployment.environment.name": "prod"}, "attributes": {"db.system.name": "postgresql"}, "links": []}

5. Data model

5.1 Entities

A trace is not stored as a row; it is the set of spans that share a trace ID. Log records point at spans by ID, and request metrics are series recorded for the same operations.

5.2 Storage choices

DataStoreKeyMain queriesWhy
SpansExample: Columnar blocks on object storage, one block per tenant per few minutesBlock sorted by trace_idTrace by ID, searchCheap, scales with object storage
Trace-ID indexPer-block Bloom filter plus a compact ID indextrace_idWhich blocks hold this traceAvoids a large search cluster
Trace search indexSmall columnar table of trace summaries(root_service, start_time)Search by service, status, durationSearches touch summaries, not spans
Logs (hot)Example: Log search cluster, 7 daysIndex per day, sharded by serviceFull-text and field searchInteractive search during incidents
Logs (cold)Compressed files on object storage, 30 days; audit class 365 daysdt, serviceRare investigations, auditsTen times cheaper per TB
Request metricsMetrics platformSeries labelsRates, errors, durationsExact, cheap, alertable

5.3 Access patterns

Access patternFrequencyKey or index that serves itPartition key rationale
Fetch full trace by IDEvery trace view, about 50/sTrace-ID Bloom filters then block readBlocks sorted by trace ID make one trace a contiguous read
Search traces by service and statusAbout 20/sTrace summary table by (root_service, start_time)Time-bounded scans over small rows
Logs for one traceEvery trace viewLog index field trace_idField index on the hot tier; cold tier reads only the trace's time range
Full-text log searchAbout 100/sInverted index per dayDaily indices drop cleanly at retention
Error rate per operationContinuous (alerting)Request metric seriesRecorded for every request, independent of sampling, so exact
Route spans to tail samplerEvery sampled span (3 million/s)Hash of trace_id in the load-balancing exporterAll spans of one trace reach the same gateway instance

6. High-level design

Spans and logs share the node agent; they split into a trace path and a log path after it.

ComponentResponsibilityScales by
OpenTelemetry SDKCreate spans, propagate context, record request metrics, head-sample, batch and exportWith each service
Collector agentReceive OTLP, add host metadata, forward metrics, route spans by trace IDOne per node
Tail-sampling gatewayBuffer spans per trace for 30 s, apply policies, forward kept tracesInstances, routed by trace ID
RedactionRemove secrets and personal data by attribute rulesWith gateway and log parsers
Trace storeWrite columnar blocks, maintain trace-ID index, compactObject storage and compactor count
Kafka logs topicBuffer logs so a slow index never blocks agentsPartitions
Log search clusterIndex 7 days of logsShards per day
Query UI and APITrace view, search, log-to-trace linksStateless instances

7. Detailed design

The deep dives in this section, each with options, choice and reason:

Deep diveOptions consideredChoiceReasonSection
Async propagationLose context at queues; carry headers in messages; span linksHeaders in message metadata plus links for fan-inKeeps one trace per request and honest batch traces7.1
SamplingHead only; tail only; hybridHybrid: 25% head, tail rulesBounded tail buffer, errors and slow traces kept7.2
Exact service metricsFrom stored traces; from spans in the agent; from SDK request metricsSDK request metrics for every requestSpans dropped by head sampling never leave the SDK, so only metrics recorded in the process see every request7.3
RetentionOne retention for everything; per data classPer data class and tierCost follows usefulness7.5

7.1 Context propagation

  • Synchronous calls: SDK instrumentation for HTTP and gRPC injects and extracts traceparent, tracestate and baggage on every call. Edge proxies keep incoming context only from trusted internal callers and start a new trace for public traffic, so outside clients cannot choose trace IDs or force sampling.
  • Messages: producers write the same fields into message headers (Kafka record headers, AMQP properties); consumers start a CONSUMER span whose parent is the producer span.
  • Fan-in and batches: a job that processes 500 messages in one batch starts its own trace and adds a span link to each message's context, instead of choosing one parent arbitrarily.
  • Threads and async code: use the SDK's context API to pass the active context into executors and callbacks; lost context is the main source of orphan spans (NFR-04).

7.2 Sampling

StrategyHow it decidesKeeps errors?CostVerdict
Head onlyAt the root, from the trace ID and a ratioOnly in proportion to the ratioLowestMisses most failures
Tail onlyAfter the trace completes, on all spansAllBuffer of 288 GB and full span traffic to the gatewayExpensive at this volume
Hybrid (chosen)25% head at the root, then tail rules on the head-sampled tracesAll errors among the 25%72 GB bufferBalanced

Head sampling uses ParentBased(root=TraceIdRatioBased(0.25)), so a child service never re-decides and traces stay complete. The OpenTelemetry specification marks TraceIdRatioBased stable but deprecated in favour of a ProbabilitySampler that is still in development as of version 1.62.0; it uses 56 bits of trace-ID randomness and records its threshold under the th key of the ot entry in tracestate. Plan to migrate when that sampler is stable in your SDKs.

Tail sampling needs every span of a trace on the same gateway instance. The agent uses the Collector's load-balancing exporter with the trace ID as the routing key, and the gateway runs the tail sampling processor with these policies:

Policy IDRuleKeep
SMP-01 (Example)Any span with status error100%
SMP-02 (Example)Root span duration above the operation's latency threshold (from the SLO)100%
SMP-03 (Example)Attribute tenant.tier=gold20%
SMP-04 (Example)Everything else5%

The consequence to state openly: only 25% of failed requests have a stored trace. Every failure still appears exactly in the request metrics (7.3) and in logs with its trace ID, which is usually enough to find a representative stored trace.

7.3 Request metrics independent of sampling

With parent-based head sampling in the SDK, a span that is not sampled is not recorded or exported, so the agent sees only 25% of traces and cannot count errors from spans. The SDK instrumentation therefore records request count, error count and a duration histogram per service, operation and status class for every request (the HTTP, RPC and messaging duration metrics of the OpenTelemetry semantic conventions), whatever the sampling decision, and exports them as OTLP metrics through the agent. If you later move head sampling from the SDK to the agent, a span-to-metrics step in the agent can do the same job, at the cost of exporting every span to the node. With about 2 000 services, 50 operations each, 3 status classes and 15 histogram buckets that is up to 4.5 million series. Cap operation names at the source (route templates, not raw URLs), or cardinality, not spans, becomes the cost problem.

7.4 Log pipeline and correlation

Services log through the OpenTelemetry logs bridge for their logging library, so each record follows the stable OpenTelemetry log data model and carries TraceId, SpanId and TraceFlags when emitted inside a span. The agent batches logs to Kafka; parsers normalise severity to SeverityNumber, redact (7.6) and write to the hot index and object storage in parallel. Debug logs are off in production by default and can be enabled for one service for 30 minutes through a dynamic configuration flag.

7.5 Retention

Data classHot (searchable)ColdDeleted afterReason
Traces14 daysNone14 daysIncident and performance work happen within two weeks
Application logs7 days30 days on object storage30 daysMost searches cover the last 48 hours
Audit and security logs7 days365 days, write-once storage365 days or the period your policy setsInvestigations and audits
Request metricsPer metrics platform policyDownsampledPer metrics platform policyLong-term trends

Retention for logs that can identify a person must follow your data retention standard. For example, the storage-limitation principle in EU GDPR and UK GDPR Article 5(1)(e) requires that identifiable data is kept no longer than needed. This is a design note, not legal advice; check the current official text and a qualified professional.

7.6 Redaction and access

Redaction runs twice: SDK attribute filters stop known sensitive attributes (authorization headers, cookies, card numbers) at the source, and the gateway and log parsers apply pattern rules as a second line. Access to traces and logs is by team and environment; production payload attributes are visible only to on-call roles, and every query is logged.

7.7 How real systems do it

How real systems do it (paraphrased, not copied). Google's technical report "Dapper, a Large-Scale Distributed Systems Tracing Infrastructure" (Sigelman and colleagues, dapper-2010-1, April 2010) describes tracing added to a small set of shared libraries so application developers did not have to instrument code by hand. Spans were written to local log files, collected by per-host daemons and stored with one wide-table row per trace and one column per span; median collection delay was under 15 seconds. The authors report that a uniform sampling rate as low as 1 in 1 024 still gave enough data for high-volume services, describe work towards adaptive sampling driven by a target number of traces, and add a second sampling stage in the collectors that hashes the trace ID so whole traces, not single spans, are kept or dropped. That trace-ID-based decision is the same idea behind TraceIdRatioBased and the trace-ID routing in 7.2. Read the original in 12.3.

8. Scalability and performance

ConcernApproachLimit before redesign
Span export from servicesBatching processor (OpenTelemetry defaults: queue 2 048, batch 512, 5 s delay)Queue drops show in SDK metrics; raise batch size before queue size
Tail buffer24 gateways, 6 GB each with headroomExample: about 2x current traffic before adding instances
Gateway rebalancingConsistent hashing on trace IDScaling the tier splits traces in flight for one decision window
Trace store writesColumnar blocks, compactionObject storage request rate per prefix
Log indexDaily indices, 7-day hot tierShard count per day

Overhead budget per service request (NFR-01, under 1 ms p99):

StepBudget
Extract and inject context0.02 ms
Create and end spans (about 3 per service hop)0.05 ms
Log enrichment with trace ID0.01 ms
Export (asynchronous, off the request path)0 ms on the request path
Headroom0.92 ms

9. Reliability, security and operations

9.1 Failure modes

ComponentFailureDetectionBlast radiusMitigationRTO
SDK exporterAgent unreachableSDK dropped-span counterTelemetry from that node onlyBounded queue, drop oldest; never block requests (NFR-05)Example: recovers with the agent
Gateway instanceCrashLoad-balancer health checksTraces in its 30 s buffer, about 1/24 of traces in flightExporter re-routes new traces; lost traces still appear in request metricsExample: 1 min
Gateway tierOverloadedMemory and refused spansAll new tracesShed by lowering the baseline policy (SMP-04) first, then head ratio via remote configExample: 5 min
PropagationA library strips headersOrphan span rate per serviceBroken traces through that serviceContract test per framework; alert on orphan rate above 1%Example: 1 day (code fix)
Kafka logs topicBroker lossUnder-replicated partitionsNone with replication factor 3Leader election; agents buffer on diskExample: 30 s
Log search clusterIndex slow or downIngest lagHot search onlyKafka buffers; cold tier still queryableExample: 30 min
Redaction rulesSecret leaks into storagePattern scanner on stored samplesAll data since the leakPurge affected blocks, rotate the secret, add the ruleExample: 4 h
[Component][Failure][Signal][Scope][Mitigation][Time]

9.2 Security and privacy

ThreatControl
Outside client forces sampling or injects trace IDsEdge restarts traces for untrusted callers (7.1)
Sensitive data in attributes, baggage or log bodiesTwo-stage redaction; baggage never carries personal data
Over-broad access to production payloadsRole-based access by team and environment; query audit log
Telemetry as an exfiltration pathEgress from collectors only to approved endpoints over TLS
Tampering with audit logsWrite-once storage for the audit class; integrity checks
[Threat][Control]

9.3 Observability of the pipeline

SignalMetric or logAlert threshold
Dropped spansSDK and Collector refused or dropped countersAbove 0.1% for 10 min
Tail bufferGateway memory and traces in flightAbove 70% of limit
Orphan spansSpans whose parent never arrives, per serviceAbove 1%
Ingest freshnessCanary trace end-to-end delayAbove 60 s p95
Log ingest lagKafka consumer lagAbove 120 s
CostStored GB per day by teamAbove budget by 20%

9.4 Cost estimate

ItemUnit costQuantityMonthly cost
Collector agents[$/vCPU-month]Example: 0.25 vCPU per node[$]
Tail-sampling gateways[$/instance-month]24[$]
Trace object storage[$/TB-month]About 14.2 TB[$]
Log search cluster[$/node-month]Example: sized for 39.7 TB[$]
Log object storage[$/TB-month]About 113 TB plus 138 TB audit[$]
Total[$]

10. Trade-offs and alternatives

DecisionOptionsChosenWhyWhat we give up
InstrumentationVendor agents; OpenTelemetry SDKs and CollectorOpenTelemetryOpen specification, one pipeline for all signals, vendor choice stays openSome SDK features still in development
SamplingHead; tail; hybridHybridErrors kept, buffer bounded75% of failures have no stored trace
Trace storageSearch cluster; object storage with ID indexObject storage with ID indexCost per TB, simple retentionAttribute search limited to summaries
Logs storageAll in search cluster; hot plus cold tiersHot 7 days, cold 30 daysCostSlower search beyond 7 days
Log transportAgents write directly to index; via KafkaVia KafkaIndex slowness never blocks agentsOne more system to run
What changes at 10x / 0.1x10x (120 million spans/s): at 25% head sampling the tail buffer grows to 720 GB, so lower head sampling to 5% (144 GB), shard the gateway tier by tenant and move log indexing to per-team retention budgets. 0.1x (1.2 million spans/s): skip head sampling and tail-sample everything with a 28.8 GB buffer on two or three gateways, or use head sampling alone with a managed backendReview at each doubling of spans per secondTail buffer and log storage grow first[Note]
[Decision][Options][Chosen][Why][Cost]

11. Delivery plan and risks

11.1 Milestones

MilestoneScopeExit criterionTarget date
M1Agents on all nodes, request metrics, head sampling for tier-1 servicesOrphan rate below 1% on tier-1 pathsYYYY-MM-DD
M2Tail-sampling gateway and trace storeAll error traces among head-sampled traces stored for 14 daysYYYY-MM-DD
M3Log pipeline via Kafka, trace ID on all logsLog-to-trace link works for 95% of error logsYYYY-MM-DD
M4Legacy tracing and log agents removedCost at or below budget for one monthYYYY-MM-DD

11.2 Rollout and rollback

[Example: Roll out the SDK service by service behind a configuration flag, starting with the checkout path. The old log shipper runs in parallel for 30 days; rollback is turning the flag off, which stops export without a redeploy.]

11.3 Risks

IDRiskLikelihoodImpactMitigationOwner
R-01Example: Teams keep custom log formats without trace IDsHighMediumLogging library wrapper with the bridge built in; lint rule[@name]
R-02Example: Attribute cardinality explodes request metricsMediumHighAllow-list of metric dimensions; route templates only[@name]
R-03Example: Sampler API changes as the specification evolvesMediumLowPin SDK versions, track the specification changelog[@name]
R-04Example: Personal data stored before redaction rules are completeMediumHighStart with deny-by-default attribute filters[@name]
[R-nn][Risk][L / M / H][L / M / H][Mitigation][@name]

12. Appendices

12.1 Open questions

IDQuestionOwnerDue
OQ-01Example: Do regulated tenants need traces kept longer than 14 days?[@name]YYYY-MM-DD
OQ-02Example: Adopt Trace Context Level 2 random flag once it is a Recommendation?[@name]YYYY-MM-DD
[OQ-nn][Question][@name]YYYY-MM-DD

12.2 Glossary

TermMeaning
TraceAll spans that share one trace ID, describing one request end to end
SpanOne timed operation with a parent, attributes and status
Context propagationPassing trace ID, parent span ID and flags across process boundaries
BaggageApplication key-value pairs propagated alongside trace context
Head samplingKeep-or-drop decision at the start of a trace
Tail samplingKeep-or-drop decision after the trace's spans have been seen
Span linkReference from one span to another trace's span, used for batches
Orphan spanA span whose parent never arrives in storage
OTLPThe OpenTelemetry protocol for exporting telemetry
[Term][Meaning]

12.3 References

ReferenceUse
W3C Trace Context, Recommendation (Level 1), 23 November 2021traceparent and tracestate in 4.2 and 7.1
W3C Trace Context Level 2, Candidate Recommendation Draft, 28 March 2024Random trace-ID flag in 4.2
W3C Propagation format for distributed context: Baggage, Candidate Recommendation Snapshot, 30 May 2024baggage header and limits in 4.2
OpenTelemetry Specification 1.62.0, tracing SDK (samplers, batching processor) and logs data model7.2, 7.4, 8
OpenTelemetry sampling concepts and Collector gateway deploymentHead and tail sampling, trace-ID routing in 7.2
Sigelman B. H. et al., "Dapper, a Large-Scale Distributed Systems Tracing Infrastructure", Google Technical Report dapper-2010-1, April 20107.7
ICO guide to UK GDPR: storage limitationRetention note in 7.5
Observability Specification (ops/observability-spec)Signals, SLOs and dashboards per service
SLO Document (dev/slo-doc)Latency thresholds used by SMP-02
Data Retention and Deletion Standard (data/data-retention-deletion-standard)Retention periods in 7.5
Stream Processing Engine System Design (system-design/design-stream-processing-engine)Log parsing and enrichment jobs
Metrics and Monitoring System Design (system-design/design-metrics-monitoring)Platform that stores the request metrics in 7.3
Back-of-Envelope Estimation and Capacity Model (system-design/back-of-envelope-estimation)Method for section 3

Standard and licence note

Based on W3C Trace Context (Recommendation, 23 November 2021), W3C Baggage (Candidate Recommendation Snapshot, 30 May 2024) and the OpenTelemetry specification 1.62.0 as published in October 2026. Baggage and Trace Context Level 2 are not yet Recommendations, and several OpenTelemetry samplers are still in development, so check the current status pages before implementing. The Dapper report is paraphrased in 7.7 only; no text, figures or code were copied, and every number in this template is an illustrative example computed for this design. The retention note is not legal advice. Original text written for this collection. Template licence: MIT.

相关模板