目录
[1. Specification(规范)](#1. Specification(规范))
[2. 语言 API & SDK(应用侧主力)](#2. 语言 API & SDK(应用侧主力))
[2.1 Instrumentation Libraries(插桩库)](#2.1 Instrumentation Libraries(插桩库))
[2.2 Exporters(导出器)](#2.2 Exporters(导出器))
[2.3 Zero-code(零代码插桩)](#2.3 Zero-code(零代码插桩))
[2.4 Resource Detectors](#2.4 Resource Detectors)
[2.5 Propagators(跨服务传播)](#2.5 Propagators(跨服务传播))
[2.6 Samplers(采样器)](#2.6 Samplers(采样器))
[3. Collector(采集/中转侧主力)](#3. Collector(采集/中转侧主力))
[4. 平台周边](#4. 平台周边)
[① Kubernetes Operator](#① Kubernetes Operator)
[② FaaS 资产(函数计算)](#② FaaS 资产(函数计算))
官方把主体拆成下面几块(见 编辑Components)。
总览
规范 Specification
├─ API 怎么打点
├─ SDK 要求 怎么实现、采样、导出
└─ Data 语义约定 + OTLP
语言实现 API & SDK
├─ 插桩库 Instrumentation Libraries
├─ 导出器 Exporters(首选 OTLP)
├─ 零代码插桩 Zero-code
├─ Resource Detectors
├─ Propagators(跨服务传 Context)
└─ Samplers
Collector 接收 → 处理 → 导出(厂商无关代理)
周边
├─ Kubernetes Operator
├─ Helm Charts
└─ FaaS 资产(如 Lambda Layer)
1. Specification(规范)
跨语言的契约,所有实现都要对齐:
| 部分 | 作用 |
|---|---|
| API | 生成、关联 Traces / Metrics / Logs 的接口 |
| SDK | 语言实现必须满足的行为:配置、处理、导出 |
| Data | OTLP(怎么编码传输)+ 语义约定(字段叫什么) |
规范本身不是进程,但后面所有组件都按它来。
Specification 是 OTel 的契约,不是进程。各语言 SDK、Collector、OpenObserve 能互通,是因为大家都按这份规范实现。当前文档版本大约是 OTel Spec 1.60.0、OTLP 1.11.0、SemConv 1.44.0。入口:docs/specs/otel。
(1)规范解决什么问题
没有规范时:Java 一套字段、Go 一套字段、A 厂商一个协议、B 厂商另一个协议。换后端就要改代码。
规范规定三件事:
API 应用 / 库怎么打点(插座形状)
SDK 怎么采样、批处理、导出(插头怎么做)
Data 字段叫什么(语义约定)+ 网上怎么运(OTLP)
对应排障:
| 规范块 | 失败时的现象 |
|---|---|
| API | 根本没有 span(没调用或库没插桩) |
| SDK | 有调用但没数据:采样、队列、exporter、OTEL_SDK_DISABLED |
| 语义约定 | 有数据但查不到:字段名不标准 |
| OTLP | SDK 有导出日志,后端没有:端口、路径、Content-Type、413、鉴权 |
(2)规范怎么读(否则会误读)
规范用 RFC 2119:
- MUST / MUST NOT:不合规实现
- SHOULD:强烈建议,实现可以有差异
- MAY:可选
组件生命周期:Draft → Experimental → Stable → Deprecated。
Stable 的 API/OTLP 有长期兼容承诺;Experimental 的语义约定可能改名,生产查询不要绑死实验字段。
规范还规定:环境变量若某语言支持,名字和解析规则必须统一(例如布尔值只有大小写不敏感的 "true" 才是真)。这就是为什么 Java 和 Python 都能认 OTEL_SERVICE_NAME。
(3)三块分别管什么
3.1 API:打点接口,默认是空操作
API 给库作者 和应用 用。设计要点:没装 SDK 时,API 调用必须几乎零开销、不发数据。这样中间件可以先写上 tracer.span(),用户没接 SDK 也不会崩、也不会变慢。
API 主要包括:
- Context / Propagators / Baggage
- Tracing:Tracer、Span、SpanContext
- Metrics:Meter、各种 Instrument
- Logs:主要是 Bridge API(给日志框架作者,不是让业务直接调)
3.2 SDK:把 API 变成真数据
SDK 是 API 的实现:Resource、Sampler、Batch Processor、Exporter、属性条数限制等。
规范要求:凡是环境变量能配的,代码里必须有等价配置 。所以 OTEL_TRACES_SAMPLER=always_off 和代码里装一个 AlwaysOff sampler 是同一件事。
3.3 Data:语义约定 + OTLP
- 语义约定:
service.name、http.request.method、http.response.status_code等,保证 Java/Go 打出来能用同一套查询。 - OTLP:
Export请求怎么编码、4317/4318、成功/部分成功/重试。
(4)操作示例
下面示例用 Python,只为对照规范;换 Java/Go 概念相同。先装:
python
pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp
示例 1:只有 API、没有 SDK ------ 规范要求的「空操作」
这是理解规范最重要的一个实验。
python
# api_only.py
from opentelemetry import trace
tracer = trace.get_tracer("demo")
with tracer.start_as_current_span("checkout") as span:
span.set_attribute("order.id", "A1001")
print("span recording?", span.is_recording())
print("trace_id", format(span.get_span_context().trace_id, "032x"))
python
python api_only.py
执行后会看到:is_recording() 为 False,trace_id 全 0。
调用了 API,但没有 TracerProvider(SDK),规范规定这是 No-Op Span:不记录、不导出。
现象:代码「打了点」,产品里什么都没有。 原因在规范的 API/SDK 分离,不是 OpenObserve 坏了。
示例 2:接上 SDK ------ 规范里的 TracerProvider / Resource / Processor / Exporter
python
# sdk_console.py
from opentelemetry import trace
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
resource = Resource.create({
"service.name": "checkout-service", # 语义约定:Resource
"service.version": "1.0.0",
"deployment.environment": "dev",
})
provider = TracerProvider(resource=resource)
provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))
trace.set_tracer_provider(provider)
tracer = trace.get_tracer("demo", "1.0.0") # InstrumentationScope
with tracer.start_as_current_span("POST /checkout") as span:
span.set_attribute("http.request.method", "POST")
span.set_attribute("http.route", "/checkout")
span.set_attribute("http.response.status_code", 200)
span.set_attribute("order.id", "A1001") # 业务属性,不是 SemConv 强制字段
provider.force_flush()
python
python sdk_console.py
终端会打出 SDK 导出的 Span(name、trace_id、属性、Resource)。
对照规范的三层标签:
| 层 | 示例里是谁 |
|---|---|
| Resource | service.name=checkout-service |
| Scope | tracer 名 demo |
| Span | POST /checkout 和那些 attribute |
force_flush() 对应规范:进程退出前必须把 Batch Processor 队列刷出去,否则数据还在内存里,后端永远没有。
示例 3:用规范规定的环境变量配置 SDK(不改代码)
规范把常用开关做成统一环境变量。把示例 2 的 Resource 改成从环境读也可以,更常见的是 零代码/自动配置 读这些变量。
PowerShell:
bash
$env:OTEL_SERVICE_NAME = "checkout-service"
$env:OTEL_RESOURCE_ATTRIBUTES = "service.version=1.0.0,deployment.environment=dev"
$env:OTEL_TRACES_EXPORTER = "console"
$env:OTEL_TRACES_SAMPLER = "always_on"
$env:OTEL_PROPAGATORS = "tracecontext,baggage"
python sdk_console.py
规范里最常用的一批:
| 变量 | 规范含义 | 默认 |
|---|---|---|
OTEL_SERVICE_NAME |
Resource 的 service.name |
unknown_service |
OTEL_RESOURCE_ATTRIBUTES |
其它 Resource 键值 | 空 |
OTEL_SDK_DISABLED |
true 则全信号 No-Op |
false |
OTEL_PROPAGATORS |
传播器 | tracecontext,baggage |
OTEL_TRACES_SAMPLER |
采样器 | parentbased_always_on |
OTEL_TRACES_SAMPLER_ARG |
如 0.1 表示 10% |
视采样器 |
OTEL_TRACES_EXPORTER |
默认 otlp |
otlp |
OTEL_EXPORTER_OTLP_ENDPOINT |
基址;HTTP 会自动拼 /v1/traces 等 |
http://localhost:4318 |
OTEL_EXPORTER_OTLP_PROTOCOL |
grpc / http/protobuf / http/json |
视 SDK |
OTEL_BSP_SCHEDULE_DELAY |
批量导出间隔 ms | 5000 |
OTEL_BSP_MAX_QUEUE_SIZE |
队列满就丢 | 2048 |
操作对照:
bash
# 规范行为:全部关掉 → 又变回 No-Op,和示例 1 一样
$env:OTEL_SDK_DISABLED = "true"
# 规范行为:一律不采样 → API 仍 recording 为 false(或采了但不导出)
$env:OTEL_TRACES_SAMPLER = "always_off"
# 没设服务名 → 后端常见 unknown_service(规范默认值)
Remove-Item Env:OTEL_SERVICE_NAME
OTEL_SERVICE_NAME 与 OTEL_RESOURCE_ATTRIBUTES 里同时有 service.name 时,规范规定前者优先。
示例 4:语义约定 ------ 同样的 HTTP,字段必须同名
规范不要求你用 HTTP,但一旦是 HTTP 操作,键名应对齐 SemConv,查询才能跨语言复用。
python
from opentelemetry.semconv.trace import SpanAttributes # 或新包 semconv
span.set_attribute("http.request.method", "GET")
span.set_attribute("http.route", "/product/{id}")
span.set_attribute("http.response.status_code", 500)
span.set_status(Status(StatusCode.ERROR)) # Span Status ≠ HTTP 码,规范里是两套
错误示范(能导出,但换库/换语言就查不着):
python
span.set_attribute("httpCode", 500)
span.set_attribute("method", "GET")
操作: 在 OpenObserve 里对规范字段写 http.response.status_code>=500;若你们库还在用旧名 http.status_code,那是 SemConv 版本迁移,不是产品 bug。查 SemConv 当前 HTTP 约定。
示例 5:OTLP(规范 Data 的传输部分)------ 不写 SDK,直接按协议 POST
OTLP/HTTP JSON 默认路径 POST /v1/traces,Content-Type: application/json。
规范要求:traceId/spanId 用十六进制,kind 用数字(2 = SERVER),字段 lowerCamelCase。
先自己算一对 ID(32/16 位 hex),再发:
bash
$json = @'
{
"resourceSpans": [{
"resource": {
"attributes": [
{ "key": "service.name", "value": { "stringValue": "checkout-service" } }
]
},
"scopeSpans": [{
"scope": { "name": "manual-otlp-demo", "version": "1.0.0" },
"spans": [{
"traceId": "a0892f3577b34da6a3ce929d0e0e4736",
"spanId": "f03067aa0ba902b7",
"name": "POST /checkout",
"kind": 2,
"startTimeUnixNano": "1730000000000000000",
"endTimeUnixNano": "1730000000500000000",
"status": { "code": 1 },
"attributes": [
{ "key": "http.request.method", "value": { "stringValue": "POST" } },
{ "key": "http.response.status_code", "value": { "intValue": "200" } }
]
}]
}]
}]
}
'@
# 本地 Collector 默认 4318
Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:4318/v1/traces" `
-ContentType "application/json" -Body $json
成功时 HTTP 200,body 里不应带 rejected_spans(Full Success)。
若打 OpenObserve,路径往往是规范路径加组织前缀,body 仍是这份 OTLP:
POST https://<o2>/api/default/v1/traces (鉴权按环境加 Header。)
故意违反规范看现象:
| 做法 | 规范后果 |
|---|---|
traceId 用 base64 |
400 / 无法解码 |
"kind": "SPAN_KIND_SERVER" |
JSON 枚举必须是数字,对端拒收或忽略 |
dropped_attributes_count 蛇形命名 |
必须 droppedAttributesCount |
| gRPC 打到 4318,或 HTTP 打到 4317 | 连上了也不是同一种 OTLP 运输 |
只设 OTEL_EXPORTER_OTLP_ENDPOINT=http://host:4318 却用 gRPC |
端口和 protocol 必须一致 |
SDK 版导出(规范环境变量,等价于示例 5):
bash
$env:OTEL_SERVICE_NAME = "checkout-service"
$env:OTEL_EXPORTER_OTLP_PROTOCOL = "http/protobuf"
$env:OTEL_EXPORTER_OTLP_ENDPOINT = "http://127.0.0.1:4318"
# HTTP 时 SDK 会拼出 http://127.0.0.1:4318/v1/traces
python sdk_otlp.py
sdk_otlp.py 只需把示例 2 的 ConsoleSpanExporter 换成 OTLPSpanExporter()(opentelemetry-exporter-otlp)。
示例 6:Context 在规范里的位置
传播 不是 OTLP,但在 API 规范里(Context + Propagators)。默认 OTEL_PROPAGATORS=tracecontext,baggage。
python
from opentelemetry.propagate import inject, extract
from opentelemetry import context
headers = {}
inject(headers) # 发送方:写入 traceparent
print(headers)
# 典型:{'traceparent': '00-a0892f35...-f03067aa0ba902b7-01'}
ctx = extract(headers) # 接收方:读出,后续 span 共用 trace_id
token = context.attach(ctx)
# ... 在此创建的 span,parent 就是对端 span
context.detach(token)
01 是规范/W3C 里的 sampled 标志。OTLP 只负责把已经采了的 Span 运走;采不采是 SDK 规范。
(5)三块如何对应到一次真实请求
业务代码 / 插桩库
│ 调的是 API 规范
▼
SDK(采样、Batch、Resource)
│ 行为由 SDK 规范 + 环境变量规定
▼
OTLP Export (Data 规范)
│ ResourceSpans → ScopeSpans → Span
▼
Collector / OpenObserve
在产品里看到的每一条 Span,都可以反问:
- 哪个 API 调用产生的?
- SDK 有没有采样、有没有 flush?
- 字段是否符合 SemConv?
- OTLP 这一跳是 200 全成功,还是 partial / 4xx / 超时丢掉?
规范正文按需查:API/SDK · 环境变量 · OTLP · SemConv。
2. 语言 API & SDK(应用侧主力)
各语言一套实现(Java、Go、Python、JS...),让你在进程里造出信号并送出去。SDK 里通常还包括:
| 子组件 | 做什么 |
|---|---|
| Instrumentation Libraries | 给 HTTP、gRPC、DB、消息队列等自动打点 |
| Exporters | 把数据发给 Collector 或后端;生产优先 OTLP |
| Zero-code | 不改业务代码(Java Agent、Operator 注入、eBPF 等) |
| Resource Detectors | 自动填 service.name、主机、K8s Pod 等 |
| Propagators | Inject/Extract Context(默认 W3C traceparent) |
| Samplers | 头采样等,决定哪些 Trace 真正导出 |
是什么: 跑在服务进程里的库。API 是打点接口;SDK 是实现(Provider、Processor、Exporter)。
职责: 生成 Span/Metric/Log → 采样 → 批量 → OTLP 发出。没它(也没零代码),进程不会自己产生 OTel 数据。
下面 6 个子组件都属于「语言实现」这一主组件。
2.1 Instrumentation Libraries(插桩库)
给 HTTP、gRPC、DB、消息队列等自动打点,业务少写 span。
经典操作(Python + Flask + requests):
pip install flask requests \
opentelemetry-api opentelemetry-sdk \
opentelemetry-instrumentation-flask \
opentelemetry-instrumentation-requests \
opentelemetry-exporter-otlp
# app.py ------ 业务代码几乎不写 span
from flask import Flask
import requests
app = Flask(__name__)
@app.get("/checkout")
def checkout():
requests.get("https://httpbin.org/delay/1") # 出站 HTTP,由 requests 插桩打 Client span
return {"ok": True}
# 启动时挂上插桩(或见 2.3 零代码,一行都不改)
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.instrumentation.requests import RequestsInstrumentor
from opentelemetry import trace
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
trace.set_tracer_provider(TracerProvider(resource=Resource.create({"service.name": "shop-api"})))
trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))
FlaskInstrumentor().instrument_app(app)
RequestsInstrumentor().instrument()
app.run(port=5000)
访问 http://127.0.0.1:5000/checkout,控制台应出现:
- Server span:
GET /checkout - Client span:对 httpbin 的出站请求
父子靠插桩库做的 Context 传播,不是你手写的。
2.2 Exporters(导出器)
把 SDK 里的数据送给下一跳。生产优先 OTLP;调试用 console。
经典操作: 同一套打点,只换 exporter。
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, BatchSpanProcessor
# 调试:看本地是否真正生成了 Span
processor = BatchSpanProcessor(ConsoleSpanExporter())
# 生产:发给 Collector(默认会拼 /v1/traces)
processor = BatchSpanProcessor(OTLPSpanExporter(
endpoint="http://127.0.0.1:4318/v1/traces"
))
或只改环境变量(规范行为,不改代码):
$env:OTEL_TRACES_EXPORTER = "otlp" # 或 console、none
$env:OTEL_EXPORTER_OTLP_PROTOCOL = "http/protobuf"
$env:OTEL_EXPORTER_OTLP_ENDPOINT = "http://127.0.0.1:4318"
排障口诀: console 有、OTLP 没有 → 生成没问题,问题在传输/后端;console 也没有 → 还在 SDK/采样/插桩。
2.3 Zero-code(零代码插桩)
不改业务源码:Java -javaagent、Python opentelemetry-instrument、K8s Operator 注入。
经典操作(Python):
pip install flask requests opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
# 业务就是普通 flask,不必 import otel
opentelemetry-instrument python app.py
$env:OTEL_SERVICE_NAME = "shop-api"
$env:OTEL_TRACES_EXPORTER = "console"
$env:OTEL_PROPAGATORS = "tracecontext,baggage"
opentelemetry-instrument python app.py
Java 经典等价:
java -javaagent:opentelemetry-javaagent.jar \
-Dotel.service.name=shop-api \
-Dotel.exporter.otlp.endpoint=http://otel-collector:4318 \
-jar app.jar
覆盖 HTTP/DB 等框架调用;订单号等业务属性仍要手动补 span。
2.4 Resource Detectors
给每条信号贴「谁在发」:service.name、主机、容器、K8s Pod。没有它,后端常显示 unknown_service。
经典操作:
$env:OTEL_SERVICE_NAME = "checkout-service"
$env:OTEL_RESOURCE_ATTRIBUTES = "service.version=1.2.0,deployment.environment=dev"
代码等价:
from opentelemetry.sdk.resources import Resource, SERVICE_NAME
Resource.create({
SERVICE_NAME: "checkout-service",
"service.version": "1.2.0",
"k8s.pod.name": "checkout-7f8d9", # 集群里多由 detector / Collector 的 k8sattributes 补
})
Resource 是进程级,不要把 order.id 放这里(那是 Span 属性)。
2.5 Propagators(跨服务传播)
Inject/Extract Context。默认 W3C:traceparent + baggage。断链第一原因在这里,不在 Collector。
经典操作: 两个进程,只靠 HTTP 头串成一条 Trace。
服务 A(客户端):
import requests
from opentelemetry.propagate import inject
headers = {}
inject(headers) # 写入 traceparent
print("发出的头", headers)
requests.get("http://127.0.0.1:5001/product", headers=headers)
服务 B(服务端,Flask 插桩会自动 Extract;手工则):
from opentelemetry.propagate import extract
from opentelemetry import context, trace
ctx = extract(dict(request.headers))
token = context.attach(ctx)
try:
with tracer.start_as_current_span("GET /product"):
...
finally:
context.detach(token)
看打印应类似:traceparent: 00-<32位trace_id>-<16位span_id>-01。
B 的 span 必须沿用这个 trace_id,并把对端 span_id 当 parent。
若 A 用 tracecontext、B 只用 b3,就会裂成两条 Trace。
$env:OTEL_PROPAGATORS = "tracecontext,baggage" # 全链路保持一致
2.6 Samplers(采样器)
决定哪些 Trace 真正导出。头采看 trace-flags;always_off 时日志仍可能有 trace_id,界面没有 Span。
经典操作:
# 全采(开发)
$env:OTEL_TRACES_SAMPLER = "always_on"
# 全丢(对照:产品里突然没 Trace)
$env:OTEL_TRACES_SAMPLER = "always_off"
# 生产常用:尊重父采样,根按 10%
$env:OTEL_TRACES_SAMPLER = "parentbased_traceidratio"
$env:OTEL_TRACES_SAMPLER_ARG = "0.1"
默认是 parentbased_always_on:有父且父 sampled 则采,根默认全采。流量一大才改成 ratio。
3. Collector(采集/中转侧主力)
独立进程:接收、处理、再导出。应用不必直连后端。
管道由五类插件组成:Receiver、Processor、Exporter、Connector、Extension。
生产上常见:应用 SDK → Collector → OpenObserve。Collector 是 OTel 的组件;OpenObserve 是后端产品,不是 OTel 组件。
为什么要它: 应用快速卸数据;重试、批处理、脱敏、加 K8s 属性、一扇出多后端,都放在 Collector,而不是每个服务里写。
两种部署:Agent(每机/每 Pod sidecar) + Gateway(集群统一入口)。
经典操作 1 ------ 官方 Quick Start(先证明 Collector 活着):
docker pull otel/opentelemetry-collector:0.158.0
docker run --rm -p 4317:4317 -p 4318:4318 -p 55679:55679 \
otel/opentelemetry-collector:0.158.0
另开终端(需 Go):
go install github.com/open-telemetry/opentelemetry-collector-contrib/cmd/telemetrygen@latest
telemetrygen traces --otlp-insecure --traces 3
Collector 日志里应出现 Span;浏览器打开 http://localhost:55679/debug/tracez。
这只验证 OTLP 收进 Collector,还没到 OpenObserve。
经典操作 2 ------ 接到后端(含 OpenObserve)的最小 config:
otel-config.yaml:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
memory_limiter:
check_interval: 1s
limit_percentage: 75
spike_limit_percentage: 15
exporters:
debug:
verbosity: basic
otlphttp:
endpoint: https://<你的O2>/api/default # 会再拼 /v1/traces
headers:
Authorization: Basic <token>
tls:
insecure: false
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [debug, otlphttp]
docker run --rm -p 4317:4317 -p 4318:4318 \
-v ${PWD}/otel-config.yaml:/etc/otelcol/config.yaml \
otel/opentelemetry-collector-contrib:0.158.0 \
--config /etc/otelcol/config.yaml
应用只需:
$env:OTEL_EXPORTER_OTLP_ENDPOINT = "http://127.0.0.1:4318"
$env:OTEL_EXPORTER_OTLP_PROTOCOL = "http/protobuf"
排障: debug 有、O2 没有 → exporter 地址/鉴权/路径;debug 也没有 → 应用没打到 4317/4318,或 grpc/http 混用。
4. 平台周边
| 组件 | 做什么 |
|---|---|
| Kubernetes Operator | 管 Collector 资源、给工作负载注入自动插桩 |
| Helm Charts | 在集群里安装 Collector / Operator |
| FaaS 资产 | 如 AWS Lambda 自动插桩 Layer、独立 Collector Layer |
① Kubernetes Operator
是什么: 集群里的 Operator,管两件事:
OpenTelemetryCollectorCR:帮你跑 CollectorInstrumentationCR + Pod 注解:往工作负载注入零代码 Agent
经典操作:
bash
# 需先有 cert-manager
kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/latest/download/opentelemetry-operator.yaml
Collector(Operator 会建 Service demo-collector):
bash
apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
name: demo
spec:
config:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
memory_limiter:
check_interval: 1s
limit_percentage: 75
spike_limit_percentage: 15
exporters:
debug: {}
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter]
exporters: [debug]
注入策略:
bash
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: demo-instrumentation
spec:
exporter:
endpoint: http://demo-collector:4318
propagators: [tracecontext, baggage]
sampler:
type: parentbased_traceidratio
argument: "1"
业务 Deployment 只加注解(Java 示例):
spec:
template:
metadata:
annotations:
instrumentation.opentelemetry.io/inject-java: "true"
其它语言:inject-python / inject-nodejs / inject-dotnet / inject-go。
滚动发布后,Pod 里会被注入 Agent,流量会出 HTTP/DB span,代码可以零改动。
② FaaS 资产(函数计算)
是什么: 针对 Lambda 等短生命周期环境的现成 Layer:自动插桩 Layer,以及可选的 Collector Layer(函数里不便常驻进程时,用 Layer 做导出)。
和普通 SDK 的差别: 冷启动、执行完进程被冻/杀,必须在返回前 flush;传播要穿过网关事件(API Gateway header → Lambda)。
经典操作(AWS Lambda 自动插桩思路):
- 给函数挂上官方 OTel Lambda Layer(按语言选)。
- 配置例如:
bash
AWS_LAMBDA_EXEC_WRAPPER = /opt/otel-handler
OTEL_SERVICE_NAME = order-fn
OTEL_EXPORTER_OTLP_ENDPOINT = http://localhost:4318
- 需要在函数旁收数据时,再挂 Collector Layer,把 OTLP 转到 OpenObserve。
- 手工插桩时,handler 结束前调用
force_flush(),否则 Span 还在 Batch 队列里函数就结束了。
细则:FaaS · Lambda Auto-Instrumentation。
对照:谁负责什么(排障时用)
| 现象 | 先查哪个组件 |
|---|---|
| 完全没 span | SDK / 零代码没挂上,或 OTEL_SDK_DISABLED |
| 有 HTTP span,没有订单号 | 插桩库正常;缺手动业务 span |
| console 有、后端没有 | Exporter / Collector 地址、协议、鉴权 |
| 两个服务两条 Trace | Propagator 不一致或网关剥了 traceparent |
| 日志有 ID、界面无 Trace | Sampler always_off / 比例采样 |
| 服务名 unknown_service | Resource / OTEL_SERVICE_NAME |
| 应用正常、集群里部分 Pod 没数据 | Operator 注解没打上或 Instrumentation CR 的 endpoint 错 |
| Lambda 偶发丢 Trace | 没 flush,不是 OTLP「丢包」那么简单 |
和「信号」的关系(避免再混)
每个信号(Trace / Metric / Log)在规范里都对应:API → SDK → OTLP → Collector。
Baggage 只有 API/SDK,没有 OTLP 和 Collector------它沿请求传播,不「导出到后端」。