@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.
Files changed (118) hide show
  1. package/README.md +1 -1
  2. package/bin/cli.js +2 -2
  3. package/bin/mcp.js +6 -6
  4. package/bin/ui.js +74 -74
  5. package/gates/ai-prompt-stability.md +120 -120
  6. package/gates/budget-description.md +68 -68
  7. package/gates/confidence.md +29 -29
  8. package/gates/dependency-check.md +33 -33
  9. package/gates/dept-cycle-prevention.md +179 -179
  10. package/gates/golden-signals-coverage.md +133 -133
  11. package/gates/legacy-refactor-safety.md +178 -178
  12. package/gates/multi-tenant-rls-coverage.md +102 -102
  13. package/gates/no-personal-uuid.md +72 -72
  14. package/gates/obs-agents-mcp-supabase.md +86 -86
  15. package/gates/obs-skills-frontmatter.md +76 -76
  16. package/gates/observability-coverage.md +151 -151
  17. package/gates/omm-no-regression.md +83 -83
  18. package/gates/postmortem-template-required.md +127 -127
  19. package/gates/prr-checklist-coverage.md +128 -128
  20. package/gates/regression.md +32 -32
  21. package/gates/release-pipeline-policy.md +132 -132
  22. package/gates/secrets-scan.md +33 -33
  23. package/gates/service-role-not-in-user-facing.md +113 -113
  24. package/gates/skill-must-include.md +71 -71
  25. package/gates/sync-idempotent.md +62 -62
  26. package/gates/verify-phase-goal.md +34 -34
  27. package/kit/agents/designer-ui.md +216 -216
  28. package/kit/agents/workflow-generator.md +537 -0
  29. package/kit/commands/adicionar-backlog.md +1 -1
  30. package/kit/commands/adicionar-fase.md +1 -1
  31. package/kit/commands/adicionar-tarefa.md +1 -1
  32. package/kit/commands/auditar-observabilidade.md +103 -103
  33. package/kit/commands/auditar-toil.md +129 -129
  34. package/kit/commands/caracterizar-prompt.md +195 -195
  35. package/kit/commands/criar-workflow.md +158 -0
  36. package/kit/commands/definir-perfil.md +1 -1
  37. package/kit/commands/definir-slo.md +108 -108
  38. package/kit/commands/fio.md +1 -1
  39. package/kit/commands/golden-signals.md +142 -142
  40. package/kit/commands/instrumentar-fase.md +200 -200
  41. package/kit/commands/investigar-producao.md +162 -162
  42. package/kit/commands/observabilidade.md +118 -118
  43. package/kit/commands/postmortem.md +179 -179
  44. package/kit/commands/prr.md +205 -205
  45. package/kit/commands/publicar-rapido.md +207 -207
  46. package/kit/commands/risk-budget.md +220 -220
  47. package/kit/commands/sre.md +230 -230
  48. package/kit/file-manifest.json +5 -2
  49. package/kit/framework/references/output-style.md +22 -22
  50. package/kit/hooks/post-apply-migration.js +199 -199
  51. package/kit/hooks/sidecar-tool-publisher.js +210 -210
  52. package/kit/skills/_shared-dados-distribuidos/glossary.md +224 -224
  53. package/kit/skills/_shared-legacy/glossary.md +389 -389
  54. package/kit/skills/_shared-multi-tenant/glossary.md +186 -186
  55. package/kit/skills/_shared-observability/glossary.md +396 -396
  56. package/kit/skills/_shared-sre/glossary.md +712 -712
  57. package/kit/skills/_shared-supabase/glossary.md +234 -234
  58. package/kit/skills/blameless-postmortems/SKILL.md +340 -340
  59. package/kit/skills/burn-rate-alerting/SKILL.md +258 -258
  60. package/kit/skills/cascading-failures/SKILL.md +311 -311
  61. package/kit/skills/core-analysis-loop/SKILL.md +352 -352
  62. package/kit/skills/distributed-tracing/SKILL.md +362 -362
  63. package/kit/skills/dynamic-workflow-authoring/SKILL.md +327 -0
  64. package/kit/skills/eliminating-toil/SKILL.md +243 -243
  65. package/kit/skills/event-based-slos/SKILL.md +296 -296
  66. package/kit/skills/four-golden-signals/SKILL.md +314 -314
  67. package/kit/skills/hermetic-builds/SKILL.md +323 -323
  68. package/kit/skills/legacy-monster-methods/SKILL.md +444 -444
  69. package/kit/skills/llm-as-dependency/SKILL.md +436 -436
  70. package/kit/skills/load-shedding-graceful-degradation/SKILL.md +396 -396
  71. package/kit/skills/observability-driven-development/SKILL.md +315 -315
  72. package/kit/skills/observability-maturity-model/SKILL.md +222 -222
  73. package/kit/skills/opentelemetry-standard/SKILL.md +351 -351
  74. package/kit/skills/production-readiness-review/SKILL.md +305 -305
  75. package/kit/skills/release-engineering/SKILL.md +367 -367
  76. package/kit/skills/retry-strategies/SKILL.md +372 -372
  77. package/kit/skills/sre-risk-management/SKILL.md +221 -221
  78. package/kit/skills/structured-events/SKILL.md +265 -265
  79. package/kit/skills/supabase-cron-queues/SKILL.md +275 -275
  80. package/kit/skills/supabase-database-functions/SKILL.md +332 -332
  81. package/kit/skills/supabase-declarative-schema/SKILL.md +183 -183
  82. package/kit/skills/supabase-pgvector-rag/SKILL.md +253 -253
  83. package/kit/skills/supabase-postgres-style/SKILL.md +138 -138
  84. package/kit/skills/supabase-storage/SKILL.md +234 -234
  85. package/kit/skills/telemetry-pipelines/SKILL.md +259 -259
  86. package/kit/skills/telemetry-sampling/SKILL.md +256 -256
  87. package/kit/skills/ui-anti-padroes-ia/SKILL.md +261 -261
  88. package/kit/skills/ui-contexto-produto/SKILL.md +248 -248
  89. package/kit/skills/ui-cor-estrategia/SKILL.md +213 -213
  90. package/kit/skills/ui-critica-auditoria/SKILL.md +260 -260
  91. package/kit/skills/ui-motion-funcional/SKILL.md +264 -264
  92. package/kit/skills/ui-ritmo-espacial/SKILL.md +259 -259
  93. package/kit/skills/ui-tipografia/SKILL.md +211 -211
  94. package/package.json +1 -1
  95. package/src/cli/index.js +1114 -1114
  96. package/src/cli/render.js +194 -194
  97. package/src/cli/upgrade-check.js +135 -135
  98. package/src/core/error-redaction.js +76 -76
  99. package/src/core/failures.js +153 -153
  100. package/src/core/gate-runner.js +205 -205
  101. package/src/core/gates.js +82 -82
  102. package/src/core/logger.js +170 -170
  103. package/src/core/manifest-verify.js +174 -174
  104. package/src/core/metrics.js +268 -268
  105. package/src/core/notify.js +60 -60
  106. package/src/core/path-safety.js +141 -141
  107. package/src/core/replays.js +120 -120
  108. package/src/core/ui.js +185 -185
  109. package/src/mcp-server/install.js +149 -149
  110. package/src/mcp-server/roots.js +124 -124
  111. package/src/ui/auto-spawn.js +113 -113
  112. package/src/ui/browser.js +78 -78
  113. package/src/ui/client.js +130 -130
  114. package/src/ui/events.js +65 -65
  115. package/src/ui/lockfile.js +191 -191
  116. package/src/ui/port.js +67 -67
  117. package/src/ui/server.js +547 -547
  118. 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".*