@luanpdd/kit-mcp 1.34.0 → 1.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/cli.js +2 -2
- package/bin/mcp.js +6 -6
- package/bin/ui.js +74 -74
- package/gates/ai-prompt-stability.md +120 -120
- package/gates/budget-description.md +68 -68
- package/gates/confidence.md +29 -29
- package/gates/dependency-check.md +33 -33
- package/gates/dept-cycle-prevention.md +179 -179
- package/gates/golden-signals-coverage.md +133 -133
- package/gates/legacy-refactor-safety.md +178 -178
- package/gates/multi-tenant-rls-coverage.md +102 -102
- package/gates/no-personal-uuid.md +72 -72
- package/gates/obs-agents-mcp-supabase.md +86 -86
- package/gates/obs-skills-frontmatter.md +76 -76
- package/gates/observability-coverage.md +151 -151
- package/gates/omm-no-regression.md +83 -83
- package/gates/postmortem-template-required.md +127 -127
- package/gates/prr-checklist-coverage.md +128 -128
- package/gates/regression.md +32 -32
- package/gates/release-pipeline-policy.md +132 -132
- package/gates/secrets-scan.md +33 -33
- package/gates/service-role-not-in-user-facing.md +113 -113
- package/gates/skill-must-include.md +71 -71
- package/gates/sync-idempotent.md +62 -62
- package/gates/verify-phase-goal.md +34 -34
- package/kit/agents/designer-ui.md +216 -216
- package/kit/agents/workflow-generator.md +537 -0
- package/kit/commands/adicionar-backlog.md +1 -1
- package/kit/commands/adicionar-fase.md +1 -1
- package/kit/commands/adicionar-tarefa.md +1 -1
- package/kit/commands/auditar-observabilidade.md +103 -103
- package/kit/commands/auditar-toil.md +129 -129
- package/kit/commands/caracterizar-prompt.md +195 -195
- package/kit/commands/criar-workflow.md +158 -0
- package/kit/commands/definir-perfil.md +1 -1
- package/kit/commands/definir-slo.md +108 -108
- package/kit/commands/fio.md +1 -1
- package/kit/commands/golden-signals.md +142 -142
- package/kit/commands/instrumentar-fase.md +200 -200
- package/kit/commands/investigar-producao.md +162 -162
- package/kit/commands/observabilidade.md +118 -118
- package/kit/commands/postmortem.md +179 -179
- package/kit/commands/prr.md +205 -205
- package/kit/commands/publicar-rapido.md +207 -207
- package/kit/commands/risk-budget.md +220 -220
- package/kit/commands/sre.md +230 -230
- package/kit/file-manifest.json +5 -2
- package/kit/framework/references/output-style.md +22 -22
- package/kit/hooks/post-apply-migration.js +199 -199
- package/kit/hooks/sidecar-tool-publisher.js +210 -210
- package/kit/skills/_shared-dados-distribuidos/glossary.md +224 -224
- package/kit/skills/_shared-legacy/glossary.md +389 -389
- package/kit/skills/_shared-multi-tenant/glossary.md +186 -186
- package/kit/skills/_shared-observability/glossary.md +396 -396
- package/kit/skills/_shared-sre/glossary.md +712 -712
- package/kit/skills/_shared-supabase/glossary.md +234 -234
- package/kit/skills/blameless-postmortems/SKILL.md +340 -340
- package/kit/skills/burn-rate-alerting/SKILL.md +258 -258
- package/kit/skills/cascading-failures/SKILL.md +311 -311
- package/kit/skills/core-analysis-loop/SKILL.md +352 -352
- package/kit/skills/distributed-tracing/SKILL.md +362 -362
- package/kit/skills/dynamic-workflow-authoring/SKILL.md +327 -0
- package/kit/skills/eliminating-toil/SKILL.md +243 -243
- package/kit/skills/event-based-slos/SKILL.md +296 -296
- package/kit/skills/four-golden-signals/SKILL.md +314 -314
- package/kit/skills/hermetic-builds/SKILL.md +323 -323
- package/kit/skills/legacy-monster-methods/SKILL.md +444 -444
- package/kit/skills/llm-as-dependency/SKILL.md +436 -436
- package/kit/skills/load-shedding-graceful-degradation/SKILL.md +396 -396
- package/kit/skills/observability-driven-development/SKILL.md +315 -315
- package/kit/skills/observability-maturity-model/SKILL.md +222 -222
- package/kit/skills/opentelemetry-standard/SKILL.md +351 -351
- package/kit/skills/production-readiness-review/SKILL.md +305 -305
- package/kit/skills/release-engineering/SKILL.md +367 -367
- package/kit/skills/retry-strategies/SKILL.md +372 -372
- package/kit/skills/sre-risk-management/SKILL.md +221 -221
- package/kit/skills/structured-events/SKILL.md +265 -265
- package/kit/skills/supabase-cron-queues/SKILL.md +275 -275
- package/kit/skills/supabase-database-functions/SKILL.md +332 -332
- package/kit/skills/supabase-declarative-schema/SKILL.md +183 -183
- package/kit/skills/supabase-pgvector-rag/SKILL.md +253 -253
- package/kit/skills/supabase-postgres-style/SKILL.md +138 -138
- package/kit/skills/supabase-storage/SKILL.md +234 -234
- package/kit/skills/telemetry-pipelines/SKILL.md +259 -259
- package/kit/skills/telemetry-sampling/SKILL.md +256 -256
- package/kit/skills/ui-anti-padroes-ia/SKILL.md +261 -261
- package/kit/skills/ui-contexto-produto/SKILL.md +248 -248
- package/kit/skills/ui-cor-estrategia/SKILL.md +213 -213
- package/kit/skills/ui-critica-auditoria/SKILL.md +260 -260
- package/kit/skills/ui-motion-funcional/SKILL.md +264 -264
- package/kit/skills/ui-ritmo-espacial/SKILL.md +259 -259
- package/kit/skills/ui-tipografia/SKILL.md +211 -211
- package/package.json +1 -1
- package/src/cli/index.js +1114 -1114
- package/src/cli/render.js +194 -194
- package/src/cli/upgrade-check.js +135 -135
- package/src/core/error-redaction.js +76 -76
- package/src/core/failures.js +153 -153
- package/src/core/gate-runner.js +205 -205
- package/src/core/gates.js +82 -82
- package/src/core/logger.js +170 -170
- package/src/core/manifest-verify.js +174 -174
- package/src/core/metrics.js +268 -268
- package/src/core/notify.js +60 -60
- package/src/core/path-safety.js +141 -141
- package/src/core/replays.js +120 -120
- package/src/core/ui.js +185 -185
- package/src/mcp-server/install.js +149 -149
- package/src/mcp-server/roots.js +124 -124
- package/src/ui/auto-spawn.js +113 -113
- package/src/ui/browser.js +78 -78
- package/src/ui/client.js +130 -130
- package/src/ui/events.js +65 -65
- package/src/ui/lockfile.js +191 -191
- package/src/ui/port.js +67 -67
- package/src/ui/server.js +547 -547
- package/src/ui/wrapper.js +129 -129
|
@@ -1,351 +1,351 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: opentelemetry-standard
|
|
3
|
-
description: Use ao adotar OTel — SDK + API + Tracer + Meter + Exporter + OTLP + Collector. Auto-instrumentation primeiro, custom attrs depois. Vendor-neutral por design.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Observabilidade — OpenTelemetry (OTel)
|
|
7
|
-
|
|
8
|
-
## Quando usar
|
|
9
|
-
|
|
10
|
-
LLM carrega esta skill ao instrumentar código com OpenTelemetry. Trigger phrases:
|
|
11
|
-
|
|
12
|
-
- "OpenTelemetry", "OTel"
|
|
13
|
-
- "instrumentação vendor-neutral"
|
|
14
|
-
- "OTel SDK Tracer Meter Exporter Collector"
|
|
15
|
-
- "OTLP exporter"
|
|
16
|
-
- "auto-instrumentation"
|
|
17
|
-
- "OTel para Edge Function Deno", "OTel Node.js"
|
|
18
|
-
|
|
19
|
-
## Regras absolutas
|
|
20
|
-
|
|
21
|
-
- **Use OTel sempre** — vendor-neutral por design. Não adote APM proprietário no código aplicacional. Trocar backend = trocar exporter, não código.
|
|
22
|
-
- **API ≠ SDK** — `@opentelemetry/api` é o que devs importam (especificação). `@opentelemetry/sdk-*` é a implementação. Use API em libs, SDK no entry-point do app.
|
|
23
|
-
- **Auto-instrumentation primeiro** — instale `@opentelemetry/auto-instrumentations-node` (ou Deno equivalente) e tenha tracing de HTTP/gRPC/DB grátis em minutos. Depois adicione custom attrs.
|
|
24
|
-
- **Configure SDK NO ENTRY-POINT** — antes de qualquer outro require/import. Caso contrário, instrumentation patches não pegam.
|
|
25
|
-
- **Use OTLP como wire format** — porta 4318 (HTTP) ou 4317 (gRPC). É o padrão; todos os backends modernos aceitam.
|
|
26
|
-
- **Collector como sidecar** — em produção, app envia OTLP para Collector local (porta 4318). Collector roteia para destino final. Permite trocar destino sem redeploy.
|
|
27
|
-
- **Tracer name = component name** — `trace.getTracer('orders-service')`, não `trace.getTracer('default')`.
|
|
28
|
-
- **Resource attributes obrigatórios** — `service.name`, `service.version`, `deployment.environment`. Setados 1× no SDK setup.
|
|
29
|
-
- **Não polua o tracer global** — em libs, exponha como parâmetro ou use named tracer. Não dependa de tracer global.
|
|
30
|
-
|
|
31
|
-
## Componentes OTel
|
|
32
|
-
|
|
33
|
-
| Componente | Responsabilidade | Exemplo de uso |
|
|
34
|
-
|---|---|---|
|
|
35
|
-
| **API** | Especificação (interface) | `import { trace } from '@opentelemetry/api'` |
|
|
36
|
-
| **SDK** | Implementação concreta | `import { NodeSDK } from '@opentelemetry/sdk-node'` |
|
|
37
|
-
| **Tracer** | Cria e gerencia spans | `trace.getTracer('my-service')` |
|
|
38
|
-
| **Meter** | Cria e gerencia métricas | `metrics.getMeter('my-service')` |
|
|
39
|
-
| **Context propagation** | Serializa/extrai contexto entre services | `propagation.inject()`, `propagation.extract()` |
|
|
40
|
-
| **Exporter** | Envia dados para backend | `OTLPTraceExporter`, `JaegerExporter`, etc. |
|
|
41
|
-
| **Collector** | Proxy/sidecar standalone | Binário `otelcol` |
|
|
42
|
-
| **OTLP** | Wire protocol default | HTTP 4318, gRPC 4317, Protobuf |
|
|
43
|
-
|
|
44
|
-
## Patterns canônicos
|
|
45
|
-
|
|
46
|
-
### Pattern: SDK setup Node.js (entry-point)
|
|
47
|
-
|
|
48
|
-
```ts
|
|
49
|
-
// PT-BR: arquivo `instrumentation.ts` — IMPORTAR ANTES de qualquer outra coisa
|
|
50
|
-
// Em package.json: "node --import ./instrumentation.ts ./src/index.ts"
|
|
51
|
-
import { NodeSDK } from '@opentelemetry/sdk-node'
|
|
52
|
-
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
|
|
53
|
-
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'
|
|
54
|
-
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'
|
|
55
|
-
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'
|
|
56
|
-
import { resourceFromAttributes } from '@opentelemetry/resources'
|
|
57
|
-
import {
|
|
58
|
-
ATTR_SERVICE_NAME,
|
|
59
|
-
ATTR_SERVICE_VERSION,
|
|
60
|
-
} from '@opentelemetry/semantic-conventions'
|
|
61
|
-
|
|
62
|
-
const sdk = new NodeSDK({
|
|
63
|
-
resource: resourceFromAttributes({
|
|
64
|
-
[ATTR_SERVICE_NAME]: 'orders-service',
|
|
65
|
-
[ATTR_SERVICE_VERSION]: process.env.BUILD_ID ?? 'dev',
|
|
66
|
-
'deployment.environment': process.env.NODE_ENV ?? 'development',
|
|
67
|
-
}),
|
|
68
|
-
traceExporter: new OTLPTraceExporter({
|
|
69
|
-
url: 'http://localhost:4318/v1/traces', // PT-BR: Collector local
|
|
70
|
-
}),
|
|
71
|
-
metricReader: new PeriodicExportingMetricReader({
|
|
72
|
-
exporter: new OTLPMetricExporter({
|
|
73
|
-
url: 'http://localhost:4318/v1/metrics',
|
|
74
|
-
}),
|
|
75
|
-
exportIntervalMillis: 10_000,
|
|
76
|
-
}),
|
|
77
|
-
instrumentations: [getNodeAutoInstrumentations()],
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
sdk.start()
|
|
81
|
-
|
|
82
|
-
// PT-BR: graceful shutdown — flush pending traces
|
|
83
|
-
process.on('SIGTERM', () => {
|
|
84
|
-
sdk.shutdown().finally(() => process.exit(0))
|
|
85
|
-
})
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### Pattern: SDK setup Deno (Edge Function)
|
|
89
|
-
|
|
90
|
-
```ts
|
|
91
|
-
// PT-BR: setup OTel em Edge Function — pode ser arquivo `_otel.ts` importado primeiro
|
|
92
|
-
import { NodeSDK } from 'npm:@opentelemetry/sdk-node@0.55.0'
|
|
93
|
-
import { OTLPTraceExporter } from 'npm:@opentelemetry/exporter-trace-otlp-http@0.55.0'
|
|
94
|
-
import { resourceFromAttributes } from 'npm:@opentelemetry/resources@1.27.0'
|
|
95
|
-
|
|
96
|
-
const sdk = new NodeSDK({
|
|
97
|
-
resource: resourceFromAttributes({
|
|
98
|
-
'service.name': 'edge-process-emails',
|
|
99
|
-
'service.version': Deno.env.get('SUPABASE_GIT_SHA') ?? 'local',
|
|
100
|
-
'deployment.environment': Deno.env.get('SUPABASE_ENV') ?? 'production',
|
|
101
|
-
}),
|
|
102
|
-
traceExporter: new OTLPTraceExporter({
|
|
103
|
-
// PT-BR: em Supabase, OTLP collector pode rodar como sidecar ou
|
|
104
|
-
// enviar direto para destino externo (Honeycomb, etc.)
|
|
105
|
-
url: Deno.env.get('OTLP_ENDPOINT') ?? 'http://localhost:4318/v1/traces',
|
|
106
|
-
headers: {
|
|
107
|
-
// PT-BR: backends comerciais usam header de auth aqui
|
|
108
|
-
authorization: `Bearer ${Deno.env.get('OTLP_TOKEN') ?? ''}`,
|
|
109
|
-
},
|
|
110
|
-
}),
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
sdk.start()
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### Pattern: usar Tracer em código
|
|
117
|
-
|
|
118
|
-
```ts
|
|
119
|
-
import { trace, SpanKind, SpanStatusCode } from '@opentelemetry/api'
|
|
120
|
-
|
|
121
|
-
// PT-BR: 1× por arquivo/módulo — nome do componente
|
|
122
|
-
const tracer = trace.getTracer('orders-service')
|
|
123
|
-
|
|
124
|
-
export async function placeOrder(req: Request) {
|
|
125
|
-
return tracer.startActiveSpan(
|
|
126
|
-
'place_order',
|
|
127
|
-
{ kind: SpanKind.SERVER },
|
|
128
|
-
async (span) => {
|
|
129
|
-
span.setAttribute('user.id', req.user.id)
|
|
130
|
-
try {
|
|
131
|
-
const order = await db.insertOrder(req.body)
|
|
132
|
-
span.setAttribute('order.id', order.id)
|
|
133
|
-
span.setStatus({ code: SpanStatusCode.OK })
|
|
134
|
-
return order
|
|
135
|
-
} catch (e) {
|
|
136
|
-
span.recordException(e as Error)
|
|
137
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: e.message })
|
|
138
|
-
throw e
|
|
139
|
-
} finally {
|
|
140
|
-
span.end()
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
)
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
### Pattern: usar Meter (métricas)
|
|
148
|
-
|
|
149
|
-
```ts
|
|
150
|
-
import { metrics } from '@opentelemetry/api'
|
|
151
|
-
|
|
152
|
-
const meter = metrics.getMeter('orders-service')
|
|
153
|
-
|
|
154
|
-
// PT-BR: counter para eventos contáveis
|
|
155
|
-
const ordersCreated = meter.createCounter('orders.created.total', {
|
|
156
|
-
description: 'Total orders created',
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
// PT-BR: histogram para distribuições (latency)
|
|
160
|
-
const orderDuration = meter.createHistogram('orders.duration_ms', {
|
|
161
|
-
description: 'Order placement duration in ms',
|
|
162
|
-
unit: 'ms',
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
export async function placeOrder(req: Request) {
|
|
166
|
-
const start = Date.now()
|
|
167
|
-
try {
|
|
168
|
-
const order = await db.insertOrder(req.body)
|
|
169
|
-
ordersCreated.add(1, {
|
|
170
|
-
'tenant_id': req.user.tenant,
|
|
171
|
-
'customer.tier': req.user.tier,
|
|
172
|
-
'result.success': true,
|
|
173
|
-
})
|
|
174
|
-
return order
|
|
175
|
-
} finally {
|
|
176
|
-
orderDuration.record(Date.now() - start, {
|
|
177
|
-
'tenant_id': req.user.tenant,
|
|
178
|
-
})
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
### Pattern: OTel Collector config (otelcol-config.yaml)
|
|
184
|
-
|
|
185
|
-
```yaml
|
|
186
|
-
# PT-BR: collector como sidecar — recebe OTLP, processa, exporta para múltiplos destinos
|
|
187
|
-
receivers:
|
|
188
|
-
otlp:
|
|
189
|
-
protocols:
|
|
190
|
-
http:
|
|
191
|
-
endpoint: 0.0.0.0:4318
|
|
192
|
-
grpc:
|
|
193
|
-
endpoint: 0.0.0.0:4317
|
|
194
|
-
|
|
195
|
-
processors:
|
|
196
|
-
batch:
|
|
197
|
-
timeout: 10s
|
|
198
|
-
send_batch_size: 1024
|
|
199
|
-
# PT-BR: tail-based sampling — 100% errors, 1% successes
|
|
200
|
-
tail_sampling:
|
|
201
|
-
decision_wait: 10s
|
|
202
|
-
policies:
|
|
203
|
-
- name: errors-policy
|
|
204
|
-
type: status_code
|
|
205
|
-
status_code: { status_codes: [ERROR] }
|
|
206
|
-
- name: probabilistic-policy
|
|
207
|
-
type: probabilistic
|
|
208
|
-
probabilistic: { sampling_percentage: 1 }
|
|
209
|
-
|
|
210
|
-
exporters:
|
|
211
|
-
# PT-BR: para Honeycomb (exemplo)
|
|
212
|
-
otlphttp/honeycomb:
|
|
213
|
-
endpoint: https://api.honeycomb.io
|
|
214
|
-
headers:
|
|
215
|
-
x-honeycomb-team: ${env:HONEYCOMB_API_KEY}
|
|
216
|
-
# PT-BR: para arquivo local — debug
|
|
217
|
-
file:
|
|
218
|
-
path: /var/log/otel-traces.json
|
|
219
|
-
# PT-BR: para Logflare (Supabase)
|
|
220
|
-
otlphttp/logflare:
|
|
221
|
-
endpoint: https://api.logflare.app/otel
|
|
222
|
-
headers:
|
|
223
|
-
x-api-key: ${env:LOGFLARE_API_KEY}
|
|
224
|
-
|
|
225
|
-
service:
|
|
226
|
-
pipelines:
|
|
227
|
-
traces:
|
|
228
|
-
receivers: [otlp]
|
|
229
|
-
processors: [tail_sampling, batch]
|
|
230
|
-
exporters: [otlphttp/honeycomb, file]
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
### Pattern: rodar Collector via Docker (dev)
|
|
234
|
-
|
|
235
|
-
```bash
|
|
236
|
-
# PT-BR: Collector local com config customizado
|
|
237
|
-
docker run -p 4317:4317 -p 4318:4318 \
|
|
238
|
-
-v "$(pwd)/otelcol-config.yaml":/etc/otelcol/config.yaml \
|
|
239
|
-
-e HONEYCOMB_API_KEY="$HONEYCOMB_API_KEY" \
|
|
240
|
-
otel/opentelemetry-collector:latest \
|
|
241
|
-
--config=/etc/otelcol/config.yaml
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
### Pattern: tracegen — testar pipeline
|
|
245
|
-
|
|
246
|
-
```bash
|
|
247
|
-
# PT-BR: gera 100 traces sintéticos, 10/segundo, valida que pipeline está vivo
|
|
248
|
-
go install github.com/open-telemetry/opentelemetry-collector-contrib/cmd/telemetrygen@latest
|
|
249
|
-
telemetrygen traces --otlp-insecure --otlp-endpoint=localhost:4317 --traces 100 --rate 10
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
## Anti-patterns
|
|
253
|
-
|
|
254
|
-
### ANTI: configurar SDK depois de imports
|
|
255
|
-
|
|
256
|
-
```ts
|
|
257
|
-
// PT-BR: BAD — instrumentation patches não pegam código já carregado
|
|
258
|
-
import express from 'express' // express já carregado, sem patches OTel
|
|
259
|
-
import { NodeSDK } from '@opentelemetry/sdk-node'
|
|
260
|
-
new NodeSDK({...}).start() // tarde demais
|
|
261
|
-
|
|
262
|
-
// PT-BR: GOOD — SDK no entry-point com `--import`
|
|
263
|
-
// node --import ./instrumentation.ts ./src/index.ts
|
|
264
|
-
// (instrumentation.ts inicializa SDK antes de qualquer outro código)
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
### ANTI: usar SDK em libs
|
|
268
|
-
|
|
269
|
-
```ts
|
|
270
|
-
// PT-BR: BAD — lib importa SDK, força app a usar mesma versão
|
|
271
|
-
import { NodeSDK } from '@opentelemetry/sdk-node' // em uma lib
|
|
272
|
-
|
|
273
|
-
// PT-BR: GOOD — lib só importa API, app traz SDK
|
|
274
|
-
import { trace } from '@opentelemetry/api' // lib usa só API
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
### ANTI: tracer global anônimo
|
|
278
|
-
|
|
279
|
-
```ts
|
|
280
|
-
// PT-BR: BAD — sem nome de componente, dificulta filtrar por service em queries
|
|
281
|
-
const tracer = trace.getTracer('default')
|
|
282
|
-
|
|
283
|
-
// PT-BR: GOOD — nome do component
|
|
284
|
-
const tracer = trace.getTracer('orders-service')
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
### ANTI: backend proprietary direto
|
|
288
|
-
|
|
289
|
-
```ts
|
|
290
|
-
// PT-BR: BAD — code aplicacional acoplado a vendor
|
|
291
|
-
import { Datadog } from 'dd-trace' // 6 meses depois quer trocar = refactor massivo
|
|
292
|
-
|
|
293
|
-
// PT-BR: GOOD — OTel + exporter trocável via config
|
|
294
|
-
import { trace } from '@opentelemetry/api'
|
|
295
|
-
// trocar backend = trocar exporter no SDK setup, não código
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
### ANTI: instrumentar sem resource attributes
|
|
299
|
-
|
|
300
|
-
```ts
|
|
301
|
-
// PT-BR: BAD — sem service.name, query SELECT WHERE service = ? não funciona
|
|
302
|
-
new NodeSDK({ traceExporter: ... })
|
|
303
|
-
|
|
304
|
-
// PT-BR: GOOD — resource sempre presente
|
|
305
|
-
new NodeSDK({
|
|
306
|
-
resource: resourceFromAttributes({
|
|
307
|
-
'service.name': 'orders-service',
|
|
308
|
-
'service.version': BUILD_ID,
|
|
309
|
-
'deployment.environment': ENV,
|
|
310
|
-
}),
|
|
311
|
-
traceExporter: ...
|
|
312
|
-
})
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
### ANTI: enviar OTLP direto para múltiplos backends
|
|
316
|
-
|
|
317
|
-
```ts
|
|
318
|
-
// PT-BR: BAD — app conhece todos os destinos (Honeycomb, Datadog, Logflare)
|
|
319
|
-
// redeploy obrigatório para mudar destino
|
|
320
|
-
new NodeSDK({
|
|
321
|
-
traceExporter: new OTLPTraceExporter({ url: 'https://honeycomb.io...' }),
|
|
322
|
-
})
|
|
323
|
-
|
|
324
|
-
// PT-BR: GOOD — app envia para Collector local; Collector roteia
|
|
325
|
-
new NodeSDK({
|
|
326
|
-
traceExporter: new OTLPTraceExporter({ url: 'http://localhost:4318/v1/traces' }),
|
|
327
|
-
})
|
|
328
|
-
// PT-BR: Collector decide para onde mandar (Honeycomb + Logflare + arquivo) via config
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
## Verificação
|
|
332
|
-
|
|
333
|
-
1. **SDK iniciou** — log no setup: "OTel SDK started for service=orders-service version=...". Sem isso, traces não saem.
|
|
334
|
-
2. **Auto-instrumentation ativa** — fazer 1 request HTTP via fetch ou axios → span aparece em `select * from spans` sem código manual.
|
|
335
|
-
3. **OTLP sendo enviado** — `tcpdump port 4318` durante request real → tráfego POST visível.
|
|
336
|
-
4. **Resource attributes corretos** — `select distinct service_name, service_version FROM spans` → resultado esperado.
|
|
337
|
-
5. **Tracer custom funciona** — adicionar `tracer.startSpan('custom')` → span aparece queryable.
|
|
338
|
-
6. **Collector roteando** — fazer request → trace aparece em DESTINO 1 (Honeycomb) e DESTINO 2 (arquivo local) simultaneamente.
|
|
339
|
-
7. **Graceful shutdown** — `kill -TERM` no app → SDK flush pendente; sem traces perdidos no shutdown.
|
|
340
|
-
|
|
341
|
-
---
|
|
342
|
-
|
|
343
|
-
## Ver também
|
|
344
|
-
|
|
345
|
-
- `kit/skills/_shared-observability/glossary.md` — termos OTel canônicos
|
|
346
|
-
- `kit/skills/structured-events/SKILL.md` — campos canônicos por span
|
|
347
|
-
- `kit/skills/distributed-tracing/SKILL.md` — context propagation cross-service
|
|
348
|
-
- `kit/skills/telemetry-pipelines/SKILL.md` *(Phase 34)* — Collector config avançada
|
|
349
|
-
- `kit/skills/telemetry-sampling/SKILL.md` *(Phase 34)* — sampling no Collector
|
|
350
|
-
|
|
351
|
-
*Material-fonte: Observability Engineering (O'Reilly, 2022) — Cap 7: "Instrumentation with OpenTelemetry".*
|
|
1
|
+
---
|
|
2
|
+
name: opentelemetry-standard
|
|
3
|
+
description: Use ao adotar OTel — SDK + API + Tracer + Meter + Exporter + OTLP + Collector. Auto-instrumentation primeiro, custom attrs depois. Vendor-neutral por design.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Observabilidade — OpenTelemetry (OTel)
|
|
7
|
+
|
|
8
|
+
## Quando usar
|
|
9
|
+
|
|
10
|
+
LLM carrega esta skill ao instrumentar código com OpenTelemetry. Trigger phrases:
|
|
11
|
+
|
|
12
|
+
- "OpenTelemetry", "OTel"
|
|
13
|
+
- "instrumentação vendor-neutral"
|
|
14
|
+
- "OTel SDK Tracer Meter Exporter Collector"
|
|
15
|
+
- "OTLP exporter"
|
|
16
|
+
- "auto-instrumentation"
|
|
17
|
+
- "OTel para Edge Function Deno", "OTel Node.js"
|
|
18
|
+
|
|
19
|
+
## Regras absolutas
|
|
20
|
+
|
|
21
|
+
- **Use OTel sempre** — vendor-neutral por design. Não adote APM proprietário no código aplicacional. Trocar backend = trocar exporter, não código.
|
|
22
|
+
- **API ≠ SDK** — `@opentelemetry/api` é o que devs importam (especificação). `@opentelemetry/sdk-*` é a implementação. Use API em libs, SDK no entry-point do app.
|
|
23
|
+
- **Auto-instrumentation primeiro** — instale `@opentelemetry/auto-instrumentations-node` (ou Deno equivalente) e tenha tracing de HTTP/gRPC/DB grátis em minutos. Depois adicione custom attrs.
|
|
24
|
+
- **Configure SDK NO ENTRY-POINT** — antes de qualquer outro require/import. Caso contrário, instrumentation patches não pegam.
|
|
25
|
+
- **Use OTLP como wire format** — porta 4318 (HTTP) ou 4317 (gRPC). É o padrão; todos os backends modernos aceitam.
|
|
26
|
+
- **Collector como sidecar** — em produção, app envia OTLP para Collector local (porta 4318). Collector roteia para destino final. Permite trocar destino sem redeploy.
|
|
27
|
+
- **Tracer name = component name** — `trace.getTracer('orders-service')`, não `trace.getTracer('default')`.
|
|
28
|
+
- **Resource attributes obrigatórios** — `service.name`, `service.version`, `deployment.environment`. Setados 1× no SDK setup.
|
|
29
|
+
- **Não polua o tracer global** — em libs, exponha como parâmetro ou use named tracer. Não dependa de tracer global.
|
|
30
|
+
|
|
31
|
+
## Componentes OTel
|
|
32
|
+
|
|
33
|
+
| Componente | Responsabilidade | Exemplo de uso |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| **API** | Especificação (interface) | `import { trace } from '@opentelemetry/api'` |
|
|
36
|
+
| **SDK** | Implementação concreta | `import { NodeSDK } from '@opentelemetry/sdk-node'` |
|
|
37
|
+
| **Tracer** | Cria e gerencia spans | `trace.getTracer('my-service')` |
|
|
38
|
+
| **Meter** | Cria e gerencia métricas | `metrics.getMeter('my-service')` |
|
|
39
|
+
| **Context propagation** | Serializa/extrai contexto entre services | `propagation.inject()`, `propagation.extract()` |
|
|
40
|
+
| **Exporter** | Envia dados para backend | `OTLPTraceExporter`, `JaegerExporter`, etc. |
|
|
41
|
+
| **Collector** | Proxy/sidecar standalone | Binário `otelcol` |
|
|
42
|
+
| **OTLP** | Wire protocol default | HTTP 4318, gRPC 4317, Protobuf |
|
|
43
|
+
|
|
44
|
+
## Patterns canônicos
|
|
45
|
+
|
|
46
|
+
### Pattern: SDK setup Node.js (entry-point)
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
// PT-BR: arquivo `instrumentation.ts` — IMPORTAR ANTES de qualquer outra coisa
|
|
50
|
+
// Em package.json: "node --import ./instrumentation.ts ./src/index.ts"
|
|
51
|
+
import { NodeSDK } from '@opentelemetry/sdk-node'
|
|
52
|
+
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
|
|
53
|
+
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'
|
|
54
|
+
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'
|
|
55
|
+
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'
|
|
56
|
+
import { resourceFromAttributes } from '@opentelemetry/resources'
|
|
57
|
+
import {
|
|
58
|
+
ATTR_SERVICE_NAME,
|
|
59
|
+
ATTR_SERVICE_VERSION,
|
|
60
|
+
} from '@opentelemetry/semantic-conventions'
|
|
61
|
+
|
|
62
|
+
const sdk = new NodeSDK({
|
|
63
|
+
resource: resourceFromAttributes({
|
|
64
|
+
[ATTR_SERVICE_NAME]: 'orders-service',
|
|
65
|
+
[ATTR_SERVICE_VERSION]: process.env.BUILD_ID ?? 'dev',
|
|
66
|
+
'deployment.environment': process.env.NODE_ENV ?? 'development',
|
|
67
|
+
}),
|
|
68
|
+
traceExporter: new OTLPTraceExporter({
|
|
69
|
+
url: 'http://localhost:4318/v1/traces', // PT-BR: Collector local
|
|
70
|
+
}),
|
|
71
|
+
metricReader: new PeriodicExportingMetricReader({
|
|
72
|
+
exporter: new OTLPMetricExporter({
|
|
73
|
+
url: 'http://localhost:4318/v1/metrics',
|
|
74
|
+
}),
|
|
75
|
+
exportIntervalMillis: 10_000,
|
|
76
|
+
}),
|
|
77
|
+
instrumentations: [getNodeAutoInstrumentations()],
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
sdk.start()
|
|
81
|
+
|
|
82
|
+
// PT-BR: graceful shutdown — flush pending traces
|
|
83
|
+
process.on('SIGTERM', () => {
|
|
84
|
+
sdk.shutdown().finally(() => process.exit(0))
|
|
85
|
+
})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Pattern: SDK setup Deno (Edge Function)
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
// PT-BR: setup OTel em Edge Function — pode ser arquivo `_otel.ts` importado primeiro
|
|
92
|
+
import { NodeSDK } from 'npm:@opentelemetry/sdk-node@0.55.0'
|
|
93
|
+
import { OTLPTraceExporter } from 'npm:@opentelemetry/exporter-trace-otlp-http@0.55.0'
|
|
94
|
+
import { resourceFromAttributes } from 'npm:@opentelemetry/resources@1.27.0'
|
|
95
|
+
|
|
96
|
+
const sdk = new NodeSDK({
|
|
97
|
+
resource: resourceFromAttributes({
|
|
98
|
+
'service.name': 'edge-process-emails',
|
|
99
|
+
'service.version': Deno.env.get('SUPABASE_GIT_SHA') ?? 'local',
|
|
100
|
+
'deployment.environment': Deno.env.get('SUPABASE_ENV') ?? 'production',
|
|
101
|
+
}),
|
|
102
|
+
traceExporter: new OTLPTraceExporter({
|
|
103
|
+
// PT-BR: em Supabase, OTLP collector pode rodar como sidecar ou
|
|
104
|
+
// enviar direto para destino externo (Honeycomb, etc.)
|
|
105
|
+
url: Deno.env.get('OTLP_ENDPOINT') ?? 'http://localhost:4318/v1/traces',
|
|
106
|
+
headers: {
|
|
107
|
+
// PT-BR: backends comerciais usam header de auth aqui
|
|
108
|
+
authorization: `Bearer ${Deno.env.get('OTLP_TOKEN') ?? ''}`,
|
|
109
|
+
},
|
|
110
|
+
}),
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
sdk.start()
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Pattern: usar Tracer em código
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
import { trace, SpanKind, SpanStatusCode } from '@opentelemetry/api'
|
|
120
|
+
|
|
121
|
+
// PT-BR: 1× por arquivo/módulo — nome do componente
|
|
122
|
+
const tracer = trace.getTracer('orders-service')
|
|
123
|
+
|
|
124
|
+
export async function placeOrder(req: Request) {
|
|
125
|
+
return tracer.startActiveSpan(
|
|
126
|
+
'place_order',
|
|
127
|
+
{ kind: SpanKind.SERVER },
|
|
128
|
+
async (span) => {
|
|
129
|
+
span.setAttribute('user.id', req.user.id)
|
|
130
|
+
try {
|
|
131
|
+
const order = await db.insertOrder(req.body)
|
|
132
|
+
span.setAttribute('order.id', order.id)
|
|
133
|
+
span.setStatus({ code: SpanStatusCode.OK })
|
|
134
|
+
return order
|
|
135
|
+
} catch (e) {
|
|
136
|
+
span.recordException(e as Error)
|
|
137
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: e.message })
|
|
138
|
+
throw e
|
|
139
|
+
} finally {
|
|
140
|
+
span.end()
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Pattern: usar Meter (métricas)
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
import { metrics } from '@opentelemetry/api'
|
|
151
|
+
|
|
152
|
+
const meter = metrics.getMeter('orders-service')
|
|
153
|
+
|
|
154
|
+
// PT-BR: counter para eventos contáveis
|
|
155
|
+
const ordersCreated = meter.createCounter('orders.created.total', {
|
|
156
|
+
description: 'Total orders created',
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
// PT-BR: histogram para distribuições (latency)
|
|
160
|
+
const orderDuration = meter.createHistogram('orders.duration_ms', {
|
|
161
|
+
description: 'Order placement duration in ms',
|
|
162
|
+
unit: 'ms',
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
export async function placeOrder(req: Request) {
|
|
166
|
+
const start = Date.now()
|
|
167
|
+
try {
|
|
168
|
+
const order = await db.insertOrder(req.body)
|
|
169
|
+
ordersCreated.add(1, {
|
|
170
|
+
'tenant_id': req.user.tenant,
|
|
171
|
+
'customer.tier': req.user.tier,
|
|
172
|
+
'result.success': true,
|
|
173
|
+
})
|
|
174
|
+
return order
|
|
175
|
+
} finally {
|
|
176
|
+
orderDuration.record(Date.now() - start, {
|
|
177
|
+
'tenant_id': req.user.tenant,
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Pattern: OTel Collector config (otelcol-config.yaml)
|
|
184
|
+
|
|
185
|
+
```yaml
|
|
186
|
+
# PT-BR: collector como sidecar — recebe OTLP, processa, exporta para múltiplos destinos
|
|
187
|
+
receivers:
|
|
188
|
+
otlp:
|
|
189
|
+
protocols:
|
|
190
|
+
http:
|
|
191
|
+
endpoint: 0.0.0.0:4318
|
|
192
|
+
grpc:
|
|
193
|
+
endpoint: 0.0.0.0:4317
|
|
194
|
+
|
|
195
|
+
processors:
|
|
196
|
+
batch:
|
|
197
|
+
timeout: 10s
|
|
198
|
+
send_batch_size: 1024
|
|
199
|
+
# PT-BR: tail-based sampling — 100% errors, 1% successes
|
|
200
|
+
tail_sampling:
|
|
201
|
+
decision_wait: 10s
|
|
202
|
+
policies:
|
|
203
|
+
- name: errors-policy
|
|
204
|
+
type: status_code
|
|
205
|
+
status_code: { status_codes: [ERROR] }
|
|
206
|
+
- name: probabilistic-policy
|
|
207
|
+
type: probabilistic
|
|
208
|
+
probabilistic: { sampling_percentage: 1 }
|
|
209
|
+
|
|
210
|
+
exporters:
|
|
211
|
+
# PT-BR: para Honeycomb (exemplo)
|
|
212
|
+
otlphttp/honeycomb:
|
|
213
|
+
endpoint: https://api.honeycomb.io
|
|
214
|
+
headers:
|
|
215
|
+
x-honeycomb-team: ${env:HONEYCOMB_API_KEY}
|
|
216
|
+
# PT-BR: para arquivo local — debug
|
|
217
|
+
file:
|
|
218
|
+
path: /var/log/otel-traces.json
|
|
219
|
+
# PT-BR: para Logflare (Supabase)
|
|
220
|
+
otlphttp/logflare:
|
|
221
|
+
endpoint: https://api.logflare.app/otel
|
|
222
|
+
headers:
|
|
223
|
+
x-api-key: ${env:LOGFLARE_API_KEY}
|
|
224
|
+
|
|
225
|
+
service:
|
|
226
|
+
pipelines:
|
|
227
|
+
traces:
|
|
228
|
+
receivers: [otlp]
|
|
229
|
+
processors: [tail_sampling, batch]
|
|
230
|
+
exporters: [otlphttp/honeycomb, file]
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Pattern: rodar Collector via Docker (dev)
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# PT-BR: Collector local com config customizado
|
|
237
|
+
docker run -p 4317:4317 -p 4318:4318 \
|
|
238
|
+
-v "$(pwd)/otelcol-config.yaml":/etc/otelcol/config.yaml \
|
|
239
|
+
-e HONEYCOMB_API_KEY="$HONEYCOMB_API_KEY" \
|
|
240
|
+
otel/opentelemetry-collector:latest \
|
|
241
|
+
--config=/etc/otelcol/config.yaml
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Pattern: tracegen — testar pipeline
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
# PT-BR: gera 100 traces sintéticos, 10/segundo, valida que pipeline está vivo
|
|
248
|
+
go install github.com/open-telemetry/opentelemetry-collector-contrib/cmd/telemetrygen@latest
|
|
249
|
+
telemetrygen traces --otlp-insecure --otlp-endpoint=localhost:4317 --traces 100 --rate 10
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Anti-patterns
|
|
253
|
+
|
|
254
|
+
### ANTI: configurar SDK depois de imports
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
// PT-BR: BAD — instrumentation patches não pegam código já carregado
|
|
258
|
+
import express from 'express' // express já carregado, sem patches OTel
|
|
259
|
+
import { NodeSDK } from '@opentelemetry/sdk-node'
|
|
260
|
+
new NodeSDK({...}).start() // tarde demais
|
|
261
|
+
|
|
262
|
+
// PT-BR: GOOD — SDK no entry-point com `--import`
|
|
263
|
+
// node --import ./instrumentation.ts ./src/index.ts
|
|
264
|
+
// (instrumentation.ts inicializa SDK antes de qualquer outro código)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### ANTI: usar SDK em libs
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
// PT-BR: BAD — lib importa SDK, força app a usar mesma versão
|
|
271
|
+
import { NodeSDK } from '@opentelemetry/sdk-node' // em uma lib
|
|
272
|
+
|
|
273
|
+
// PT-BR: GOOD — lib só importa API, app traz SDK
|
|
274
|
+
import { trace } from '@opentelemetry/api' // lib usa só API
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### ANTI: tracer global anônimo
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
// PT-BR: BAD — sem nome de componente, dificulta filtrar por service em queries
|
|
281
|
+
const tracer = trace.getTracer('default')
|
|
282
|
+
|
|
283
|
+
// PT-BR: GOOD — nome do component
|
|
284
|
+
const tracer = trace.getTracer('orders-service')
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### ANTI: backend proprietary direto
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
// PT-BR: BAD — code aplicacional acoplado a vendor
|
|
291
|
+
import { Datadog } from 'dd-trace' // 6 meses depois quer trocar = refactor massivo
|
|
292
|
+
|
|
293
|
+
// PT-BR: GOOD — OTel + exporter trocável via config
|
|
294
|
+
import { trace } from '@opentelemetry/api'
|
|
295
|
+
// trocar backend = trocar exporter no SDK setup, não código
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### ANTI: instrumentar sem resource attributes
|
|
299
|
+
|
|
300
|
+
```ts
|
|
301
|
+
// PT-BR: BAD — sem service.name, query SELECT WHERE service = ? não funciona
|
|
302
|
+
new NodeSDK({ traceExporter: ... })
|
|
303
|
+
|
|
304
|
+
// PT-BR: GOOD — resource sempre presente
|
|
305
|
+
new NodeSDK({
|
|
306
|
+
resource: resourceFromAttributes({
|
|
307
|
+
'service.name': 'orders-service',
|
|
308
|
+
'service.version': BUILD_ID,
|
|
309
|
+
'deployment.environment': ENV,
|
|
310
|
+
}),
|
|
311
|
+
traceExporter: ...
|
|
312
|
+
})
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### ANTI: enviar OTLP direto para múltiplos backends
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
// PT-BR: BAD — app conhece todos os destinos (Honeycomb, Datadog, Logflare)
|
|
319
|
+
// redeploy obrigatório para mudar destino
|
|
320
|
+
new NodeSDK({
|
|
321
|
+
traceExporter: new OTLPTraceExporter({ url: 'https://honeycomb.io...' }),
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
// PT-BR: GOOD — app envia para Collector local; Collector roteia
|
|
325
|
+
new NodeSDK({
|
|
326
|
+
traceExporter: new OTLPTraceExporter({ url: 'http://localhost:4318/v1/traces' }),
|
|
327
|
+
})
|
|
328
|
+
// PT-BR: Collector decide para onde mandar (Honeycomb + Logflare + arquivo) via config
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## Verificação
|
|
332
|
+
|
|
333
|
+
1. **SDK iniciou** — log no setup: "OTel SDK started for service=orders-service version=...". Sem isso, traces não saem.
|
|
334
|
+
2. **Auto-instrumentation ativa** — fazer 1 request HTTP via fetch ou axios → span aparece em `select * from spans` sem código manual.
|
|
335
|
+
3. **OTLP sendo enviado** — `tcpdump port 4318` durante request real → tráfego POST visível.
|
|
336
|
+
4. **Resource attributes corretos** — `select distinct service_name, service_version FROM spans` → resultado esperado.
|
|
337
|
+
5. **Tracer custom funciona** — adicionar `tracer.startSpan('custom')` → span aparece queryable.
|
|
338
|
+
6. **Collector roteando** — fazer request → trace aparece em DESTINO 1 (Honeycomb) e DESTINO 2 (arquivo local) simultaneamente.
|
|
339
|
+
7. **Graceful shutdown** — `kill -TERM` no app → SDK flush pendente; sem traces perdidos no shutdown.
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## Ver também
|
|
344
|
+
|
|
345
|
+
- `kit/skills/_shared-observability/glossary.md` — termos OTel canônicos
|
|
346
|
+
- `kit/skills/structured-events/SKILL.md` — campos canônicos por span
|
|
347
|
+
- `kit/skills/distributed-tracing/SKILL.md` — context propagation cross-service
|
|
348
|
+
- `kit/skills/telemetry-pipelines/SKILL.md` *(Phase 34)* — Collector config avançada
|
|
349
|
+
- `kit/skills/telemetry-sampling/SKILL.md` *(Phase 34)* — sampling no Collector
|
|
350
|
+
|
|
351
|
+
*Material-fonte: Observability Engineering (O'Reilly, 2022) — Cap 7: "Instrumentation with OpenTelemetry".*
|