OpenTelemetry Learning
Telemetry signals

Signal correlation

Thiết kế và kiểm chứng correlation giữa metrics, traces và logs bằng trace context, exemplars, resource và semantic conventions.

Mục tiêu của correlation

Correlation biến một alert tổng hợp thành đường đi có thể kiểm chứng tới request, span và log liên quan. Đường nối chính là trace_id/span_id, exemplar và Resource nhất quán; timestamp chỉ hỗ trợ thu hẹp khi đường nối trực tiếp không có.

Mục lục

Correlation là gì

Correlation là khả năng chứng minh nhiều telemetry record nói về cùng một execution, operation hoặc thực thể. Ví dụ, một exemplar trong histogram trỏ tới trace 4bf92f...; một log mang cùng trace ID và span ID nên có thể được đặt cạnh span đã phát sinh log đó.

Correlation không có nghĩa là gom mọi signal vào một bảng. Metrics vẫn tối ưu cho tổng hợp. Traces vẫn giữ quan hệ nhân quả. Logs vẫn giữ chi tiết sự kiện. Correlation chỉ tạo các đường nối đáng tin cậy giữa ba góc nhìn.

Câu hỏiSignal bắt đầuĐường nối tốt nhất
Request chậm nào đại diện cho bucket trên 2 giây?Metric histogramExemplar có trace_idspan_id
Log lỗi này thuộc request nào?Logtrace_id, rồi thu hẹp bằng span_id
Deployment nào tạo ra nhóm lỗi?Metric, trace hoặc logResource như service.name, service.version, deployment.environment.name
Hai record gần nhau có cùng request không?Bất kỳID trực tiếp; timestamp chỉ là bằng chứng phụ

Correlation không phải context propagation

Hai khái niệm liên quan nhưng giải quyết hai thời điểm khác nhau:

Khái niệmXảy ra khi nào?Làm gì?Ví dụ
Context propagationKhi request/message đang đi qua boundaryInject và extract context để downstream tạo quan hệ đúngTruyền W3C traceparent từ checkout sang payment
CorrelationKhi sinh, lưu hoặc truy vấn telemetryGắn và dùng các khóa chung để chuyển giữa signalDùng trace_id trên log để mở trace

Propagation tạo ra nguyên liệu cho correlation. Nếu payment không extract traceparent, nó có thể tạo trace ID mới. Backend không thể sửa quan hệ nhân quả đã mất chỉ bằng cách so timestamp.

Ngược lại, propagation đúng chưa bảo đảm trải nghiệm correlation hoàn chỉnh. Log bridge có thể không chép active SpanContext vào LogRecord. Metric pipeline cũng có thể tắt exemplars. Khi đó trace vẫn liền mạch nhưng nút nhảy giữa signal bị thiếu.

Takeaway

Propagation giữ context đúng trong lúc chạy. Correlation dùng context và metadata đã ghi để điều tra sau đó. Phải kiểm thử cả hai lớp.

Các khóa nối và vai trò của chúng

Không có một khóa duy nhất giải quyết mọi loại correlation. Hãy dùng ID trực tiếp cho execution, Resource cho phạm vi nguồn phát và timestamp cho cửa sổ tìm kiếm.

Khóa hoặc metadataNối gì?Độ tin cậyKhông nên dùng để làm gì?
trace_idCác span và logs của cùng trace; exemplar tới traceCao khi ID được giữ nguyên và dữ liệu còn retentionNhận diện order lâu dài hoặc xác thực caller
span_idLog/exemplar tới operation cụ thể trong traceCao khi đi cùng trace_idTruy vấn toàn cục mà không có trace ID
trace_flagsGiải thích trạng thái context, đặc biệt sampledMetadata hỗ trợLàm join key
ExemplarMetric measurement đại diện tới trace/spanCao nếu có ID và trace còn lưuĐại diện thống kê cho mọi request
Resource attributesLọc đúng service, version, instance, environmentCao nếu cấu hình nhất quánChứng minh hai record thuộc cùng request
Semantic attributesGiữ tên, kiểu và ý nghĩa field thống nhấtCao khi cùng convention versionTự tạo quan hệ nhân quả
TimestampThu hẹp dữ liệu theo thời gianThấp hơn ID do clock skew và ingest delayKhẳng định hai record thuộc cùng execution
Business correlation IDNối các bước của giao dịch dài hạnTùy thiết kế nghiệp vụThay parent-child graph của trace

Logs sang trace bằng trace ID span ID và trace flags

Trong OpenTelemetry Logs Data Model, TraceId, SpanIdTraceFlags là các top-level fields tùy chọn. Chúng không phải Resource attributes. Logs SDK phải lấy các field này từ Context được resolve khi emit LogRecord.

Nhiều backend chuẩn hóa tên thành trace_id, span_idtrace_flags; OTLP JSON hoặc storage schema khác có thể dùng casing khác. Vì vậy, hãy phân biệt:

  • nghĩa chuẩn: TraceId, SpanId, TraceFlags trong data model;
  • tên truy vấn chuẩn hóa của tổ chức: ví dụ trace_id, span_id, trace_flags;
  • tên vật lý của backend: được ánh xạ tại adapter ingest hoặc query.

trace_id dạng hex có 32 ký tự thường nhận diện cả trace. span_id dạng hex có 16 ký tự nhận diện operation cụ thể. Hãy giữ chúng dưới dạng chuỗi lowercase hex; đừng parse thành số vì có thể mất số 0 ở đầu.

trace_flags giúp giải thích sampling. Ví dụ, sampled bit được đặt cho biết trace được chọn để export theo quyết định truyền trong context. Field này không bảo đảm trace vẫn còn trong backend: exporter có thể lỗi, Collector có thể drop hoặc retention có thể hết.

{
  "timestamp": "2026-03-15T10:05:12.482Z",
  "severity_text": "ERROR",
  "body": "payment gateway timeout",
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "span_id": "2222222222222222",
  "trace_flags": "01",
  "resource": {
    "service.name": "payment",
    "deployment.environment.name": "production"
  }
}

Đây là normalized query view minh họa, không phải khẳng định về casing của OTLP JSON. Khi validate pipeline, hãy xem payload thực tế và schema sau ingest.

Metrics sang trace bằng exemplar

Metric data point là dữ liệu tổng hợp. Nó không mang một trace ID đại diện cho toàn bộ bucket. Exemplar là một measurement mẫu được giữ cạnh data point để cung cấp context cụ thể.

Một exemplar có thể chứa:

  • giá trị measurement;
  • thời điểm measurement được record;
  • filtered attributes không còn trên metric point sau aggregation/View;
  • trace_idspan_id tùy chọn của active span với synchronous instrument.

Ví dụ, histogram có bucket latency cao và exemplar sau:

{
  "metric": "http.server.request.duration",
  "data_point_attributes": {
    "http.request.method": "POST",
    "http.route": "/checkout",
    "http.response.status_code": 504
  },
  "exemplar": {
    "value": 3.8,
    "time_unix_nano": "1773569112482000000",
    "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
    "span_id": "00f067aa0ba902b7"
  }
}

Exemplar sampling không giữ mọi measurement. Theo Metrics SDK specification, filter mặc định được khuyến nghị là TraceBased: measurement chỉ đủ điều kiện khi được record trong context của sampled parent span. Reservoir vẫn có thể chọn một tập con nhỏ hơn.

Do đó, link metric → trace có thể thiếu khi:

  • measurement được record ngoài active span;
  • trace không sampled;
  • exemplar filter là AlwaysOff;
  • reservoir không chọn measurement đó;
  • exporter hoặc backend không giữ/hiển thị exemplar;
  • trace đã hết retention dù exemplar còn tồn tại.

Filtered attributes vẫn có thể rời process

Attribute bị loại khỏi metric stream bằng View vẫn có thể xuất hiện trong filtered_attributes của exemplar. Nếu mục tiêu là loại PII hoặc secret, chỉ cấu hình View là chưa đủ; phải loại dữ liệu trước khi record hoặc cấu hình exemplar filter/reservoir phù hợp.

Resource attributes để giữ đúng phạm vi

Resource mô tả entity tạo telemetry. Cùng một process nên gắn cùng Resource logic vào TracerProvider, MeterProviderLoggerProvider.

Bộ tối thiểu hữu ích cho correlation thường gồm:

AttributeVai tròQuy tắc thực dụng
service.nameTên logic của serviceGiữ giống nhau cho mọi instance horizontally scaled của cùng service
service.namespaceNhóm các service thuộc cùng hệ thốngDùng khi tên service có thể trùng giữa các hệ thống
service.instance.idPhân biệt instance chạy đồng thờiCùng process không nên sinh ba ID khác nhau cho ba signal provider
service.versionPhân biệt artifact/deployment versionDùng đúng giá trị build hoặc release
deployment.environment.nameTên deployment environmentDùng key hiện hành; ưu tiên development, test, staging, production khi phù hợp
Hạ tầng như k8s.*, cloud.*Khoanh vùng pod, cluster, regionDùng detector và semantic conventions tương ứng

deployment.environment.name là schema hiện hành. Key cũ deployment.environment không nên được thêm vào instrumentation mới. Lưu ý, environment không tham gia bộ nhận dạng duy nhất của service theo semantic conventions. Trong query vận hành, bạn vẫn nên lọc environment để tránh trộn production với staging.

“Resource nhất quán” không có nghĩa mọi service dùng cùng service.name. checkoutpayment phải có tên khác nhau. Nó có nghĩa metrics, traces và logs do cùng một service instance phát ra phải đồng ý về tên, namespace, version, instance và environment.

Semantic conventions để các field có cùng nghĩa

Semantic conventions là vocabulary chung cho tên, kiểu và ý nghĩa của telemetry. Ví dụ, dùng http.route=/checkout thay vì service A ghi route, service B ghi httpRoute và dashboard phải đoán cả ba.

Correlation phụ thuộc conventions theo hai cách:

  1. Query từ metric sang trace cần các chiều tương đương như route, method và status có cùng nghĩa.
  2. Resource filters cần các field như service.namedeployment.environment.name không bị đổi tên giữa signal.

Pin phiên bản SDK, instrumentation và semantic conventions. Khi nâng version, kiểm tra migration notes, Schema URL và chạy song song query cũ/mới nếu backend cần giai đoạn chuyển tiếp.

Với field nghiệp vụ chưa có convention, dùng namespace của tổ chức hoặc ứng dụng, ví dụ com.acme.checkout.order_id. Không tự chiếm namespace otel.* vì namespace này được dành cho OpenTelemetry.

Timestamps là khóa nối dự phòng

Timestamp trả lời “xảy ra khi nào”, không trả lời chắc chắn “thuộc request nào”. Hai request cùng route có thể chạy trong cùng millisecond.

Các timestamp quan trọng gồm:

  • span start/end time;
  • exemplar time_unix_nano, là thời điểm measurement được record;
  • log Timestamp, là lúc event xảy ra theo clock tại nguồn;
  • log ObservedTimestamp, là lúc OpenTelemetry quan sát event.

Clock skew là độ lệch đồng hồ giữa các máy. Nó có thể làm child span trông như bắt đầu trước parent hoặc log trông như xảy ra ngoài span. Queueing, batching và network retry còn tạo ingest delay, tức dữ liệu đến backend muộn hơn lúc phát sinh.

Biện pháp thực dụng:

  • đồng bộ clock bằng hạ tầng time synchronization của môi trường;
  • lưu cả TimestampObservedTimestamp cho log khi có thể;
  • ưu tiên parent-child IDs để đọc thứ tự nhân quả;
  • mở rộng time window có chủ đích khi ID không đủ;
  • theo dõi chênh lệch ObservedTimestamp - Timestamp, nhưng không xem nó là phép đo clock skew thuần túy vì còn chứa collection delay.

Takeaway

Dùng timestamp để tìm ứng viên. Dùng ID và causal relationship để xác nhận.

Correlation ID nghiệp vụ

Correlation ID nghiệp vụ là định danh do domain sở hữu, chẳng hạn order ID, workflow ID hoặc batch ID. Nó tồn tại theo vòng đời nghiệp vụ, không theo vòng đời của một trace.

Khi nào cần

Business ID hữu ích khi một giao dịch:

  • kéo dài lâu hơn retention của trace;
  • qua nhiều job bất đồng bộ và chủ động bắt đầu trace mới;
  • có retry hoặc callback tạo nhiều trace;
  • cần được support team tìm từ dữ liệu nghiệp vụ đã biết;
  • phải đối chiếu telemetry với audit record theo policy cho phép.

Ví dụ, order ord_7F3A có thể có trace tạo order, trace xử lý payment webhook và trace gửi email sau đó. Attribute com.acme.checkout.order_id=ord_7F3A trên các span/log được phép giúp tìm ba trace đó.

Vì sao không thay thế trace ID

Business ID không mã hóa parent-child relationship. Nó cũng có thể được tái sử dụng qua nhiều attempt. Nếu chỉ query bằng order ID, bạn nhận một tập record liên quan nhưng chưa biết operation nào gọi operation nào.

Thuộc tínhTrace IDBusiness correlation ID
Chủ sở hữuTracing systemDomain/application
Vòng đờiMột distributed traceMột giao dịch hoặc workflow
Quan hệ parent-childCó, qua span IDsKhông
Bị ảnh hưởng bởi trace sampling/retentionGiá trị vẫn tồn tại ở hệ thống nghiệp vụ; telemetry chứa nó vẫn có retention riêng
Dùng làm idempotency/database keyKhôngCó thể, nếu domain thiết kế như vậy

Không trả business ID trực tiếp thành metric attribute. Order ID có cardinality cao và có thể tạo một time series cho mỗi order. Hãy đặt nó có chọn lọc trên traces/logs, với retention, access control và redaction rõ ràng.

Thiết kế correlation từ nơi sinh telemetry

Correlation bền vững bắt đầu ở SDK và pipeline, không bắt đầu bằng một dashboard đẹp. Cấu hình đúng Resource, active context và conventions trước khi xây link.

Resource detection và merge nhất quán

Resource detectors đọc metadata từ process, host, container, Kubernetes hoặc cloud. Kết quả từ nhiều detector phải được merge theo thứ tự rõ ràng.

Theo Resource SDK specification, khi merge old với updating:

  • kết quả chứa attributes từ cả hai Resource;
  • nếu trùng key, giá trị từ updating thắng, kể cả giá trị rỗng;
  • hai Schema URL khác nhau và đều không rỗng tạo merge error với kết quả không được chuẩn hóa bởi spec.

Một mental model cấu hình là:

default Resource
  → merge Resource do detectors phát hiện
  → merge Resource từ environment
  → merge Resource ứng dụng cấu hình rõ ràng
  = final Resource dùng lại cho traces, metrics và logs

Thứ tự tự động cụ thể phụ thuộc SDK. Specification yêu cầu Resource do user cung cấp có ưu tiên cao hơn OTEL_RESOURCE_ATTRIBUTES. Riêng OTEL_SERVICE_NAME có ưu tiên hơn service.name đặt trong OTEL_RESOURCE_ATTRIBUTES.

Ví dụ cấu hình portable:

export OTEL_SERVICE_NAME=checkout
export OTEL_RESOURCE_ATTRIBUTES='service.namespace=shop,service.version=2.4.1,deployment.environment.name=production'

Sau detection và merge, nên tạo hoặc lấy một final Resource rồi dùng lại cho các provider nếu SDK cho phép:

resource = build_and_merge_resource_once()
tracer_provider = create_tracer_provider(resource)
meter_provider  = create_meter_provider(resource)
logger_provider = create_logger_provider(resource)

Nếu mỗi provider chạy detector riêng, một detector sinh ID ngẫu nhiên có thể tạo ba service.instance.id khác nhau trong cùng process. Backend khi đó chia telemetry thành ba nguồn giả.

Baggage không tự trở thành attributes

Baggage là key-value nằm cạnh distributed Context và có thể được propagate qua boundary. Baggage không tự động trở thành span, metric hoặc log attributes. Instrumentation phải đọc từng key được phép và chép có chủ đích.

baggage["tenant.tier"] = "premium"

# Chưa tạo ra telemetry attribute nào.
# Instrumentation phải allowlist rồi mới ghi:
span.set_attribute("com.acme.tenant.tier", "premium")

Không chép toàn bộ baggage vào mọi signal. Baggage có thể đến từ caller không tin cậy và có thể bị forward tới third-party. Nó không có integrity guarantee. Không đặt credential, token, secret hoặc PII vào baggage.

Nếu cần business ID ở downstream, ưu tiên truyền qua contract nghiệp vụ đã có khi phù hợp. Chỉ dùng baggage khi cần context xuyên boundary, đã có allowlist, giới hạn kích thước và policy xóa tại trust boundary.

Giữ cardinality và dữ liệu nhạy cảm trong kiểm soát

Cardinality là số tổ hợp giá trị phân biệt. Correlation IDs gần như luôn có cardinality cao.

Vị tríBusiness/request ID có phù hợp không?Lý do
Metric attributesThường khôngTạo nhiều time series và tăng chi phí aggregation/index
Exemplar filtered attributesChỉ khi đã đánh giáCó thể lộ field đã bị View loại khỏi metric point
Span attributesCó chọn lọcHữu ích cho tìm kiếm nhưng tăng index/storage
Log attributesCó chọn lọcHữu ích cho support; cần access control và retention
BaggageRất hạn chếĐược propagate rộng và có thể vượt trust boundary

PII là dữ liệu định danh cá nhân. Một order ID có thể trở thành PII nếu có thể liên kết lại với khách hàng. Hãy phân loại dữ liệu theo ngữ cảnh thực tế, không chỉ theo tên field.

Ví dụ checkout end-to-end

Bối cảnh và quan hệ nhân quả

Lúc 10:05:08.682Z, checkout phiên bản 2.4.1 nhận POST /checkout. Nó gọi payment; gateway thanh toán timeout sau khoảng 3,2 giây. Histogram checkout ghi measurement 3.8 s trong active server span.

Bốn record cần nối

Ví dụ dưới đây dùng dạng normalized, rút gọn để làm rõ correlation. Đây không phải OTLP JSON hoàn chỉnh.

Một: metric point và exemplar từ checkout

{
  "metric": "http.server.request.duration",
  "unit": "s",
  "resource": {
    "service.namespace": "shop",
    "service.name": "checkout",
    "service.instance.id": "checkout-pod-7d9f",
    "service.version": "2.4.1",
    "deployment.environment.name": "production"
  },
  "attributes": {
    "http.request.method": "POST",
    "http.route": "/checkout",
    "http.response.status_code": 504
  },
  "exemplar": {
    "value": 3.8,
    "time_unix_nano": "1773569112482000000",
    "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
    "span_id": "00f067aa0ba902b7"
  }
}

Hai: checkout server span mà exemplar trỏ tới

{
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "span_id": "00f067aa0ba902b7",
  "parent_span_id": null,
  "name": "POST /checkout",
  "start_time": "2026-03-15T10:05:08.682Z",
  "end_time": "2026-03-15T10:05:12.482Z",
  "status": "ERROR",
  "attributes": {
    "http.request.method": "POST",
    "http.route": "/checkout",
    "com.acme.checkout.order_id": "ord_7F3A"
  },
  "resource": {
    "service.namespace": "shop",
    "service.name": "checkout",
    "service.version": "2.4.1",
    "deployment.environment.name": "production"
  }
}

Ba: payment server span trên critical path

{
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "span_id": "2222222222222222",
  "parent_span_id": "1111111111111111",
  "name": "POST /charge",
  "start_time": "2026-03-15T10:05:09.101Z",
  "end_time": "2026-03-15T10:05:12.301Z",
  "status": "ERROR",
  "attributes": {
    "http.route": "/charge",
    "error.type": "gateway_timeout",
    "com.acme.checkout.order_id": "ord_7F3A"
  },
  "resource": {
    "service.namespace": "shop",
    "service.name": "payment",
    "service.instance.id": "payment-pod-84bc",
    "service.version": "2.4.1",
    "deployment.environment.name": "production"
  }
}

Bốn: log phát sinh trong payment server span

{
  "timestamp": "2026-03-15T10:05:12.280Z",
  "observed_timestamp": "2026-03-15T10:05:12.286Z",
  "severity_text": "ERROR",
  "body": "payment gateway timeout",
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "span_id": "2222222222222222",
  "trace_flags": "01",
  "attributes": {
    "error.type": "gateway_timeout",
    "retry.count": 2,
    "com.acme.checkout.order_id": "ord_7F3A"
  },
  "resource": {
    "service.namespace": "shop",
    "service.name": "payment",
    "service.instance.id": "payment-pod-84bc",
    "service.version": "2.4.1",
    "deployment.environment.name": "production"
  }
}

Cách đọc chuỗi liên kết

  1. Exemplar trỏ chính xác tới trace 4bf92f... và checkout span 00f067....
  2. Trace tree dẫn từ checkout span tới payment client span 111111..., rồi payment server span 222222....
  3. Log có cùng trace ID và payment span ID nên thuộc operation POST /charge.
  4. Resource của payment span và log khớp nhau, nên có thể tin chúng đến từ cùng service version, instance và environment.
  5. Business order ID giúp tìm các trace khác của ord_7F3A; nó không được dùng làm metric attribute.
  6. Timestamp log nằm gần cuối payment span, nhưng IDs mới là bằng chứng chính.

Một trace chỉ là một trường hợp. Sau khi tìm thấy nguyên nhân khả dĩ, phải quay lại metrics để đo phạm vi ảnh hưởng.

Workflow điều tra incident

Bước một xác nhận alert metric

Giữ nguyên metric name, aggregation, time range và filters của alert. Kiểm tra unit, temporality và route template. Với ví dụ checkout, xác nhận:

metric: http.server.request.duration
resource: service.name=checkout
filter: deployment.environment.name=production
attributes: http.request.method=POST, http.route=/checkout
window: 10:00Z..10:10Z

Nếu dashboard dùng field đã deprecated hoặc trộn checkout với unknown_service, sửa phạm vi trước khi điều tra tiếp.

Bước hai mở exemplar và trace

Chọn exemplar trong bucket hoặc vùng latency bất thường. Xác nhận exemplar có value, timestamp và valid trace ID/span ID. Sau đó mở trace bằng exact trace ID.

Nếu trace không tồn tại, kiểm tra theo thứ tự:

  1. trace ID có bị đổi casing, cắt số 0 đầu hoặc parse sai kiểu không;
  2. trace có bị sampling loại hoặc exporter drop không;
  3. metric và trace retention có khác nhau không;
  4. exemplar và trace có đi tới hai tenant/project khác nhau không.

Không có exemplar thì tìm trace bằng resource, route, status, duration và time window. Đây là fallback có thể trả nhiều ứng viên, không phải correlation chắc chắn.

Bước ba tìm span gây chậm hoặc lỗi

Trong trace, đọc parent-child graph và waterfall. Tìm span trên critical path, tức chuỗi operation quyết định latency end-to-end.

Với checkout, payment server span dài 3,2 giây và có error.type=gateway_timeout. Kiểm tra cả client/server spans để phân biệt xử lý server, network, proxy và queueing. Không cộng hai duration chồng lấp.

Bước bốn mở logs trong đúng context

Query logs bằng trace_id. Sau đó thêm span_id của operation cần xem. Giữ Resource filter để tránh field collision hoặc dữ liệu từ tenant khác.

find logs where
  trace_id = "4bf92f3577b34da6a3ce929d0e0e4736"
  and span_id = "2222222222222222"
  and service.name = "payment"

Nếu không có log, bỏ span_id tạm thời để phát hiện log chỉ có trace ID. Sau đó kiểm tra logging bridge, active context lúc emit, parser và log filtering.

Bước năm kiểm chứng phạm vi ảnh hưởng

Dùng giả thuyết từ trace/log quay lại dữ liệu tổng hợp. Ví dụ, nhóm error rate và latency theo service.version hoặc region có cardinality kiểm soát. Không group metric theo order ID.

Kết luận tốt có dạng: “Từ 10:02Z đến 10:14Z, payment 2.4.1 ở production có tỷ lệ gateway_timeout tăng; trace đại diện cho thấy POST /charge chiếm 3,2 giây trên critical path; correlated log xác nhận hai retry.”

Kết luận yếu có dạng: “Một trace chậm nên toàn bộ deployment chắc chắn lỗi.”

OpenTelemetry chuẩn hóa telemetry data model và OTLP. OpenTelemetry không chuẩn hóa query language hoặc URL deep-link của backend. Vì vậy, tính portable đến từ correlation contract và adapter, không đến từ một URL dùng được ở mọi nơi.

Định nghĩa correlation contract

Tạo một contract logic độc lập với storage:

correlation_contract:
  trace_id:
    type: lowercase_hex_string
    length: 32
    physical_fields: [TraceId, trace_id, traceId]
  span_id:
    type: lowercase_hex_string
    length: 16
    physical_fields: [SpanId, span_id, spanId]
  trace_flags:
    type: bitset
    physical_fields: [TraceFlags, trace_flags, flags]
  resource_filters:
    - service.namespace
    - service.name
    - service.instance.id
    - service.version
    - deployment.environment.name
  time:
    canonical_zone: UTC
    precision: nanoseconds_when_available

Danh sách physical_fields minh họa các schema có thể gặp; không phải yêu cầu backend phải lưu tất cả alias. Tại ingest hoặc query adapter, ánh xạ một field vật lý về một field logic. Test mapping bằng payload thật.

Các operation backend-neutral nên có dạng:

get_trace(trace_id)
find_logs(trace_id, span_id?, resource_filters?, start_time, end_time)
find_traces(resource_filters, operation_filters, start_time, end_time)
find_related_telemetry(business_id, start_time, end_time)

Instrumentation chỉ phát OTLP và field chuẩn. Nó không cần biết backend đang dùng query language nào.

Đặt link templates trong cấu hình UI, dashboard-as-code hoặc một correlation gateway:

jump_links:
  exemplar_to_trace: "/observe/trace?trace_id={trace_id}"
  span_to_logs: "/observe/logs?trace_id={trace_id}&span_id={span_id}&from={from}&to={to}"
  log_to_trace: "/observe/trace?trace_id={trace_id}&span_id={span_id}"

Correlation gateway có thể đổi route tới backend A hoặc B mà không sửa instrumentation. Nó cũng là nơi:

  • validate trace/span ID trước khi tạo query;
  • URL-encode parameter;
  • enforce tenant và access control;
  • thêm Resource filters mặc định;
  • chọn time window và backend theo signal retention;
  • ngăn open redirect hoặc query injection.

Không ghi URL của vendor vào span/log attributes. Làm vậy vừa tăng payload vừa khóa telemetry vào giao diện hiện tại.

Thiết kế time window có chủ đích

Khi đi từ span sang logs, cửa sổ cơ sở là span start/end. Thêm buffer cho clock skew và collection delay, ví dụ:

from = span.start_time - 30s
to   = span.end_time   + 30s

30s chỉ là giá trị khởi đầu. Hãy đo phân phối ingest delay và clock offset để đặt giá trị thực tế. Với async queue hoặc batch job, window có thể cần dài hơn và business ID có thể hữu ích hơn một span window ngắn.

Khi exact trace_id hoạt động, time filter chủ yếu tối ưu query và chọn đúng retention partition. Khi thiếu ID, time window trở thành điều kiện tìm ứng viên; lúc đó phải kết hợp thêm service, route, status và business ID.

Failure modes thường gặp

Triệu chứngNguyên nhân thường gặpCách xác minhCách xử lý
Metrics ở checkout, traces ở checkout-apiservice.name không khớp giữa providers hoặc deploymentXem Resource của cả ba signal tại Collector/backendXây final Resource một lần; chuẩn hóa OTEL_SERVICE_NAME
Production và staging bị trộnDùng key cũ, thiếu hoặc sai deployment.environment.nameGroup theo cả key cũ/mới và kiểm tra payloadChuyển sang key hiện hành; dùng giá trị canonical khi phù hợp
Downstream tạo trace mớiLost context tại HTTP/RPC/message boundaryCapture traceparent trước/sau boundaryInject trước send, extract trước tạo server/consumer span
Log không có trace ID/span IDEmit ngoài active context, logging bridge không hỗ trợ hoặc parser làm mất fieldSo log tại source, Collector và backendCấu hình bridge; truyền Context đúng; sửa parser mapping
Log có trace ID nhưng không có traceUnsampled trace, export failure, khác tenant hoặc trace hết retentionXem trace_flags, sampler, exporter errors và retentionĐiều chỉnh sampling/retention; giữ đường fallback; không hứa link luôn tồn tại
Exemplar không có linkMeasurement ngoài sampled span, filter/reservoir hoặc backend không hỗ trợKiểm tra OTEL_METRICS_EXEMPLAR_FILTER và OTLP exemplarRecord trong active context; bật hỗ trợ phù hợp; test exporter/backend
Exemplar trỏ trace không tồn tạiRetention lệch hoặc trace bị drop sau SDKSo thời điểm, pipeline route và backend tenantCăn retention; theo dõi export/drop; hiển thị lỗi link rõ ràng
Exact ID query trả rỗngField parsing/casing sai, ID bị parse thành số hoặc cắt leading zeroSo raw OTLP với indexed fieldLưu ID dạng bytes/hex chuẩn; normalize lowercase; test parser
Log nằm ngoài span trên UIClock skew, source timestamp sai hoặc async loggingSo Timestamp, ObservedTimestamp, span times và host clocksĐồng bộ clock; nới window; ưu tiên causal IDs
Query time window bỏ lỡ dữ liệuWindow quá hẹp hoặc ingest delay lớnĐo lateness theo signalTính buffer từ dữ liệu, không hard-code tùy tiện
Metric cardinality tăng đột biếnĐưa request/order/trace ID vào metric attributesKiểm tra số series theo instrument và recent schema changeLoại high-cardinality dimensions bằng View; giữ ID ở trace/log
PII xuất hiện trong exemplarView bỏ attribute khỏi series nhưng exemplar giữ filtered attributeInspect OTLP exemplar filtered_attributesKhông record PII; hoặc tắt/tùy biến exemplar sampling
Cùng process có ba instance IDsProviders chạy detector sinh ID riêngSo service.instance.id của metric/span/logTạo Resource một lần và dùng lại
Merge cho kết quả bất địnhHai Resource có Schema URL khác nhau và đều không rỗngLog merge errors và inspect Schema URLĐồng bộ convention/schema version trước khi merge

Correlation không khôi phục dữ liệu đã mất

Backend không thể dựng lại span bị sampling/drop, log chưa ingest hoặc context chưa từng được propagate. Jump link tốt phải báo “không tìm thấy dữ liệu” thay vì ngụ ý rằng target chắc chắn tồn tại.

Xác minh end-to-end

Đừng chỉ kiểm tra từng pipeline riêng. Bài test phải đi qua cùng đường mà on-call sẽ dùng trong incident.

Bài test dương và âm

Tạo một checkout request có latency/error dự đoán được trong môi trường kiểm soát. Ghi lại business ID và thời gian gửi.

Positive test:

  1. Xác nhận metric point có đúng Resource, route, unit và bucket.
  2. Xác nhận ít nhất một exemplar test có value, timestamp và IDs hợp lệ.
  3. Mở trace bằng exemplar trace_id.
  4. Xác nhận exemplar span_id tồn tại trong trace.
  5. Xác nhận payment spans giữ cùng trace ID và parent relationship đúng.
  6. Query log bằng trace ID + payment span ID.
  7. Xác nhận Resource của payment span và log khớp.
  8. Quay lại metric để kiểm tra filter theo version/environment.

Negative tests có kiểm soát:

Thay đổi testKỳ vọngĐiều được chứng minh
Emit một log ngoài active spanLog thiếu trace fields hoặc không trỏ span testBridge không bịa context
Tạo trace unsampledTrace có thể không có trong backend; link phải fail rõUI xử lý sampling gap đúng
Tắt exemplar filterMetric vẫn có, exemplar biến mấtMetric không phụ thuộc exemplar để tồn tại
Làm mất propagation tại lab boundaryDownstream có trace ID mớiTest phát hiện lost context
Đổi service.name ở một signal trong labResource-based query bỏ lỡ recordData-quality check bắt mismatch
Dịch source clock trong môi trường giả lậpID query vẫn nối được dù timeline lệchCorrelation không phụ thuộc timestamp tuyệt đối

Không thực hiện negative test phá propagation hoặc clock trên production traffic.

Checklist sẵn sàng vận hành

  • trace_id được giữ dạng 32 ký tự lowercase hex; span_id là 16 ký tự lowercase hex.
  • Logs emit trong active span có TraceId, SpanIdTraceFlags đúng.
  • span_id trên log resolve tới một span thuộc cùng trace_id khi trace được giữ.
  • Metric measurements cần correlation được record trong active Context.
  • Exemplar pipeline bảo toàn value, timestamp, optional trace/span IDs và filtered attributes theo policy.
  • Jump metric → exemplar → trace hoạt động với trace sampled còn retention.
  • Jump span → logs dùng exact IDs, Resource filters và time buffer hợp lý.
  • service.name, namespace, version, instance ID và environment khớp giữa ba signal của cùng process.
  • Instrumentation mới dùng deployment.environment.name, không dùng key cũ.
  • Resource merge order được ghi lại; merge errors và Schema URL conflicts được quan sát.
  • Semantic convention versions được pin và có migration test.
  • Business correlation ID chỉ xuất hiện ở nơi đã được phê duyệt; không làm metric dimension.
  • Baggage có allowlist, size limit và trust-boundary policy; không chứa PII/secret.
  • View loại attribute nhạy cảm đã được kiểm tra cả exemplar filtered attributes.
  • Sampling và retention gaps hiển thị rõ, không tạo dead link im lặng.
  • Timestamp/ObservedTimestamp, clock sync và ingest lateness có dashboard hoặc test phù hợp.
  • Parser mapping được test từ raw OTLP tới indexed/query fields.
  • Query/deep-link adapter có validation, URL encoding, tenant và access control.
  • Cardinality của metrics và indexed trace/log fields nằm trong ngân sách.

Takeaway

Correlation tốt có thứ tự ưu tiên rõ ràng:

  1. Dùng trace_id để nhận diện execution và span_id để chỉ đúng operation.
  2. Dùng exemplar để đi từ metric tổng hợp tới measurement và trace đại diện.
  3. Dùng Resource nhất quán để giữ đúng service, instance, version và environment.
  4. Dùng semantic conventions để query cùng một nghĩa trên mọi signal.
  5. Dùng timestamp làm phạm vi tìm kiếm, không làm bằng chứng nhân quả.
  6. Dùng business ID cho workflow dài hạn, nhưng không thay trace ID và không đưa vào metric dimensions.
  7. Kiểm thử toàn bộ đường alert → exemplar → trace → span → log trước incident.

Câu hỏi tự kiểm cuối cùng

Từ một alert thật, on-call có thể đến một log thuộc đúng span bằng các khóa đã ghi hay vẫn phải đoán bằng thời gian và text search? Nếu còn phải đoán, đường correlation chưa hoàn chỉnh.

Nguồn tham khảo chính thức

Bài liên quan

On this page