Nhờ context propagation: trace context được truyền kèm request chứ không phải suy ra từ log.
Với HTTP: chuẩn W3C Trace Context dùng header traceparent chứa trace_id (chung cho cả trace) và span_id của span hiện tại (đóng vai trò parent cho chặng sau).
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
ver trace_id parent span_id flagsService nhận đọc header → tạo span con với cùng trace_id, parent_span_id là span vừa nhận → khi gọi tiếp thì inject context của span mới vào header đi ra. Backend ghép các span cùng trace_id thành cây theo quan hệ cha-con.
Qua message queue: không có header HTTP, nên phải đưa trace context vào message — thường là message header/attribute (Kafka headers, RabbitMQ headers, SQS message attributes), không nhét vào payload nghiệp vụ. Producer inject lúc publish, consumer extract lúc nhận rồi mở span mới.
// producer
const carrier = {}
propagation.inject(context.active(), carrier)
await channel.publish(ex, key, body, { headers: carrier })
// consumer
const parent = propagation.extract(context.active(), msg.properties.headers)
tracer.startActiveSpan('order.process', { kind: SpanKind.CONSUMER }, parent, span => { /* ... */ })Hai điểm hay sai:
- quên propagate ở worker nền khiến trace đứt tại hàng đợi, mỗi bên thành một trace rời;
- dùng quan hệ cha-con cho luồng bất đồng bộ chạy rất lâu — trường hợp đó nên dùng span link để nối mà không ràng buộc thời lượng