技能创建器
skill-creator
创建、改进和评估自定义技能,把专业流程转化为可重复使用的 AI 能力。
devops-opentelemetry【数据与研究】OpenTelemetry observability framework for distributed systems. Covers: OTel concepts (traces, metrics, logs, SDK, API, Collector, OTLP), Collector pipeline (receiver, processor, exporter, batch, sampling, tail sampling, attributes), SDK instrumentation (automatic and manual for Java, Python, Node.js, Go, .NET), trace sampling strategies (head-based, …
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Implement OpenTelemetry for vendor-neutral observability across distributed systems, covering traces, metrics, and logs collection, processing, and export to multiple backends.
Exact user phrases: "OpenTelemetry", "OTel", "OTLP", "tracing", "distributed tracing", "OpenTelemetry Collector", "OTel SDK", "auto-instrumentation", "tail sampling", "OTel exporter", "Jaeger", "Zipkin", "context propagation", "span", "trace".
Before activating, verify:
Writes to OTel Collector YAML configuration, SDK initialization code, and deployment manifests.
Configuration files and code snippets with OTel SDK imports, no extraneous explanation.
This skill is complete when:
Direct file write. No response text.
Deploy OTel Collector → Configure receiver (OTLP) → Add batch processor → Configure exporters → Instrument application with SDK → Set sampling → Verify traces flowing.
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
max_recv_msg_size_mib: 4
http:
endpoint: 0.0.0.0:4318
cors:
allowed_origins:
- http://localhost:3000
filelog:
include: [/var/log/app/*.log]
start_at: beginning
operators:
- type: regex_parser
regex: '^(?P<time>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d+Z)\s+(?P<level>\w+)\s+(?P<message>.*)#x27;
timestamp:
parse_from: attributes.time
layout: '%Y-%m-%dT%H:%M:%S.%LZ'
severity:
parse_from: attributes.level
processors:
batch:
timeout: 1s
send_batch_size: 1024
send_batch_max_size: 2048
memory_limiter:
check_interval: 1s
limit_mib: 512
spike_limit_mib: 128
attributes:
actions:
- key: environment
value: production
action: upsert
- key: datacenter
value: us-east-1
action: upsert
- key: db.connection_string
action: delete
- key: user.email
action: hash
filter:
error_mode: ignore
traces:
span:
- 'attributes["http.method"] == "OPTIONS"'
- 'attributes["healthcheck"] == true'
k8sattributes:
extract:
metadata:
- k8s.pod.name
- k8s.namespace.name
- k8s.deployment.name
- k8s.node.name
pod_association:
- sources:
- from: resource_attribute
name: k8s.pod.uid
exporters:
otlp/jaeger:
endpoint: jaeger:4317
tls:
insecure: true
otlp/grafana:
endpoint: grafana-tempo:4317
tls:
insecure: true
prometheus:
endpoint: 0.0.0.0:8889
resource_to_telemetry_conversion:
enabled: true
debug:
verbosity: detailed
sampling_initial: 2
sampling_thereafter: 500
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, k8sattributes, attributes, filter, batch]
exporters: [otlp/jaeger, otlp/grafana, debug]
metrics:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [prometheus, debug]
logs:
receivers: [otlp, filelog]
processors: [memory_limiter, batch]
exporters: [otlp/grafana]
processors:
tail_sampling:
decision_wait: 30s
num_traces: 50000
expected_new_rates_per_second: 1000
policies:
- name: always-sample-errors
type: status_code
config:
status_code_source: OC
status_codes:
- ERROR
- UNSET
- name: always-sample-slow
type: latency
config:
threshold_ms: 500
- name: sample-probabilistic
type: probabilistic
config:
sampling_percentage: 20
- name: sample-by-attribute
type: string_attribute
config:
key: priority
values:
- high
- critical
java -javaagent:opentelemetry-javaagent.jar \
-Dotel.service.name=payment-service \
-Dotel.traces.exporter=otlp \
-Dotel.metrics.exporter=otlp \
-Dotel.logs.exporter=otlp \
-Dotel.exporter.otlp.endpoint=http://otel-collector:4317 \
-Dotel.propagators=tracecontext,baggage \
-Dotel.resource.attributes=deployment.environment=production \
-jar app.jar
from opentelemetry import trace, metrics
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.resources import Resource
from opentelemetry.instrumentation.flask import FlaskInstrumentor
resource = Resource.create({
"service.name": "payment-service",
"service.version": "1.2.3",
"deployment.environment": "production"
})
provider = TracerProvider(resource=resource)
processor = BatchSpanProcessor(
OTLPSpanExporter(endpoint="http://otel-collector:4317")
)
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)
# Manual span creation
with tracer.start_as_current_span("process_payment") as span:
span.set_attribute("payment.amount", 99.99)
span.set_attribute("payment.currency", "USD")
span.add_event("payment.processed", {"provider": "stripe"})
result = process()
if result.error:
span.set_status(trace.Status(trace.StatusCode.ERROR, result.error))
# Flask auto-instrumentation
app = Flask(__name__)
FlaskInstrumentor().instrument_app(app)
import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
)
func initTracer() *sdktrace.TracerProvider {
exporter, _ := otlptrace.New(ctx, otlptracehttp.NewClient(
otlptracehttp.WithEndpoint("otel-collector:4318"),
otlptracehttp.WithInsecure(),
))
tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String("payment-service"),
semconv.DeploymentEnvironmentKey.String("production"),
)),
)
otel.SetTracerProvider(tp)
return tp
}
// Manual span
ctx, span := otel.Tracer("payment").Start(ctx, "process_payment")
span.SetAttributes(
attribute.Float64("payment.amount", 99.99),
attribute.String("payment.currency", "USD"),
)
defer span.End()
processors:
batch:
timeout: 1s
send_batch_size: 1024
# Propagation headers:
# traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
# tracestate: congo=t61rcWkgMzE
# baggage: user_id=12345, session_id=abc
import (
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/sdk/metric"
)
meter := otel.Meter("payment")
requestCounter, _ := meter.Int64Counter("payment.requests.total",
metric.WithDescription("Total payment requests"))
// Metric views for aggregation customization
provider := metric.NewMeterProvider(
metric.WithView(metric.NewView(
metric.Instrument{Name: "payment.duration"},
metric.Stream{Aggregation: metric.AggregationExplicitBucketHistogram{
Boundaries: []float64{10, 50, 100, 200, 500, 1000, 2000},
}},
)),
)
| Pattern | Description | Use Case |
|---|---|---|
| Agent | Sidecar or DaemonSet per node | Lightweight, low latency, simple routing |
| Gateway | Centralized deployment, separate from apps | Multi-backend, routing logic, sampling decisions |
| Sidecar | One collector per pod | Isolated configs, per-app filtering |
| Agent + Gateway | Agent per node + Gateway fan-out | High volume, central sampling + routing |
apiVersion: apps/v1
kind: Deployment
metadata:
name: otel-collector
spec:
replicas: 3
selector:
matchLabels:
app: otel-collector
template:
metadata:
labels:
app: otel-collector
spec:
serviceAccountName: otel-collector
containers:
- name: collector
image: otel/opentelemetry-collector-contrib:0.102.0
args: ["--config=/conf/otel-config.yaml"]
ports:
- containerPort: 4317 # OTLP gRPC
- containerPort: 4318 # OTLP HTTP
- containerPort: 8889 # Prometheus metrics
env:
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 2Gi
volumeMounts:
- name: config
mountPath: /conf
volumes:
- name: config
configMap:
name: otel-collector-config
exporters:
otlp/prod:
endpoint: tempo-prod:4317
tls:
insecure: true
headers:
x-auth-token: "${PROD_TOKEN}"
sending_queue:
enabled: true
queue_size: 5000
retry_on_failure:
enabled: true
initial_interval: 1s
max_interval: 30s
max_elapsed_time: 300s
otlp/dev:
endpoint: tempo-dev:4317
tls:
insecure: true
sending_queue:
enabled: false
retry_on_failure:
enabled: false
Best for Kubernetes environments where logs are written to stdout/stderr. The collector reads container logs from /var/log/pods/*/*/*.log or /var/log/containers/*.log.
receivers:
filelog:
include:
- /var/log/pods/*/*/*.log
include_file_name: false
include_file_path_resolved: true
operators:
- type: container
id: container-parser
- type: recombine
id: multi-line-recombine
combine_field: body
is_first_entry: 'body matches "^\\{"'
- type: json_parser
id: json-parse
parse_to: body
memory_limiter processor before batch processor.k8sattributes processor to enrich traces with Kubernetes metadata.send_batch_max_size to prevent large batches from causing OOM.sampling_initial and sampling_thereafter on debug exporter to avoid log flooding.| Strategy | Pros | Cons | Best For |
|---|---|---|---|
| Head-based probabilistic | Simple, low resource | Misses errors if rate low | Dev, low-traffic prod |
| Tail-based | Keeps errors + slow traces | Higher memory, latency | High-traffic prod |
| Consistent probability | Correlated across services | Complex setup | SLO monitoring |
| Rate limiting | Predictable volume | No intelligent selection | Budget-constrained |
memory_limiter.limit_mib, increase send_batch_size.sampling_percentage in tail_sampling.num_traces in tail_sampling.decision_wait in tail_sampling.resource_to_telemetry_conversion is enabled.otelcol --validate --config otel-config.yaml.traceparent header is passed in all HTTP/gRPC calls.After completing this skill:
| Decision | Agent-only | Collector (Gateway) |
|---|---|---|
| Deployment | Sidecar per pod | Separate deployment/DaemonSet |
| Scalability | Grows with app replicas | Independent scaling |
| Processing | Per-pod batching | Global aggregation |
| Filtering | Per-pod config | Central rules |
| Resilience | Lost if pod dies | Buffered, retries |
| Resource usage | Per-pod overhead | Shared, tunable |
| Best for | Simple setups, single service | Multi-service, filtering, enrichment |
| Aspect | Head Sampling | Tail Sampling |
|---|---|---|
| Decision point | At span creation | After full trace collected |
| Performance | Low overhead | Higher (buffers traces) |
| Completeness | Partial traces | Complete or none |
| Use case | High-volume, acceptable loss | Error analysis, critical tracing |
| Implementation | SDK sampling | Collector tailsampling processor |
| Memory | Minimal | Proportional to throughput |
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
prometheus:
config:
scrape_configs:
- job_name: 'otel-collector'
scrape_interval: 10s
static_configs:
- targets: ['0.0.0.0:8888']
processors:
batch:
timeout: 1s
send_batch_size: 1024
memory_limiter:
check_interval: 1s
limit_mib: 512
spike_limit_mib: 128
attributes:
actions:
- key: environment
value: production
action: upsert
- key: datacenter
value: us-east-1
action: upsert
tailsampling:
policies:
- name: errors-only
type: status_code
config:
status_code_source: status
rules:
- status_code: ERROR
- name: slow-traces
type: latency
config:
threshold_ms: 1000
exporters:
otlp:
endpoint: "https://api.honeycomb.io:443"
headers:
"x-honeycomb-team": "${HONEYCOMB_KEY}"
prometheus:
endpoint: "0.0.0.0:8889"
namespace: otel
logging:
verbosity: normal
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, attributes, batch, tailsampling]
exporters: [otlp, logging]
metrics:
receivers: [otlp, prometheus]
processors: [memory_limiter, batch]
exporters: [prometheus]
#!/usr/bin/env bash
set -euo pipefail
instrument_service() {
local service=$1
local lang=$2
case "$lang" in
node)
npm install @opentelemetry/api @opentelemetry/sdk-node \
@opentelemetry/auto-instrumentations-node
cat > instrumentation.ts << EOF
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
import { NodeSDK } from '@opentelemetry/sdk-node';
const sdk = new NodeSDK({
traceExporter: new OTLPTraceExporter({
url: '${OTEL_COLLECTOR_ENDPOINT:-http://localhost:4317}',
}),
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
EOF
;;
python)
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
export OTEL_TRACES_EXPORTER=otlp
export OTEL_METRICS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_ENDPOINT="${OTEL_COLLECTOR_ENDPOINT:-http://localhost:4317}"
;;
java)
curl -Lo opentelemetry-javaagent.jar \
"https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar"
export JAVA_OPTS="$JAVA_OPTS -javaagent:./opentelemetry-javaagent.jar"
;;
esac
}
keepalive: maxConnectionAge: 30s) for connection rebalancingcompression: gzip) to reduce egress bandwidth/metrics) and alert on dropped spansalways_on sampler in production — generates massive volume; use probability samplinguser_id, request_id) explode storagetimeout: 1s and send_batch_size: 1024 for optimal throughputsampling.priority) at the SDK level before exporting to Collectorcompression: gzip) in both exporter and receivermemory_limiter to 80% of Collector's memory limit, with 20% spike allowancetailsampling, metrics through batch onlybalancer_name: round_robin) for multi-collector deployment` interface EventObserver { onEvent(event: T): Promise; }
class EventBus { private observers: Set<EventObserver> = new Set(); subscribe(observer: EventObserver): void { this.observers.add(observer); } unsubscribe(observer: EventObserver): void { this.observers.delete(observer); } async emit(event: T): Promise { const results = Array.from(this.observers).map(o => o.onEvent(event)); await Promise.allSettled(results); } } `
config: defaults: timeout: 30s retryCount: 3 overrides: production: timeout: 60s retryCount: 5 development: timeout: 300s retryCount: 1
| Metric | Threshold | Severity | Action |
|---|---|---|---|
| Error rate | > 1% over 5min | Critical | Page on-call |
| p99 latency | > 2s over 5min | Warning | Investigate |
| Throughput drop | > 50% over 1min | Critical | Check upstream |
| Queue depth | > 1000 over 1min | Warning | Scale consumers |
| Disk usage | > 85% | Warning | Clean or expand |
| Memory usage | > 90% heap | Critical | Restart or scale |
| Anti-Pattern | Symptom | Root Cause | Solution |
|---|---|---|---|
| Premature optimization | Complex code for no measured benefit | Guessing instead of profiling | Measure first, optimize based on data |
| Copy-paste reuse | Duplicate code across codebase | Lack of abstraction | Extract shared logic into libraries |
| Gold-plating | Features with no current requirement | Over-engineering | YAGNI — build what's needed now |
| Magical thinking | Assumptions without validation | Skipping error handling | Handle all failure modes explicitly |
Cache hierarchy: L1 (in-memory local) → L2 (distributed Redis/Memcached) → L3 (CDN/Edge). Cache invalidation: TTL-based (simple, stale), event-based (complex, fresh), write-through (consistent, higher write latency), write-behind (fast writes, eventual consistency).