@luanpdd/kit-mcp 1.8.1 → 1.10.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/CHANGELOG.md +86 -0
- package/README.md +97 -1
- package/gates/golden-signals-coverage.md +133 -0
- package/gates/obs-agents-mcp-supabase.md +86 -0
- package/gates/obs-skills-frontmatter.md +76 -0
- package/gates/omm-no-regression.md +83 -0
- package/gates/postmortem-template-required.md +127 -0
- package/gates/prr-checklist-coverage.md +128 -0
- package/gates/skill-must-include.md +21 -19
- package/kit/agents/burn-rate-forecaster.md +160 -0
- package/kit/agents/golden-signals-instrumenter.md +241 -0
- package/kit/agents/incident-investigator.md +245 -0
- package/kit/agents/observability-instrumenter.md +200 -0
- package/kit/agents/omm-auditor.md +251 -0
- package/kit/agents/postmortem-writer.md +282 -0
- package/kit/agents/prr-conductor.md +288 -0
- package/kit/agents/slo-engineer.md +224 -0
- package/kit/agents/supabase-architect.md +62 -0
- package/kit/agents/supabase-auth-bootstrapper.md +17 -0
- package/kit/agents/supabase-edge-fn-writer.md +124 -0
- package/kit/agents/supabase-migration-writer.md +98 -0
- package/kit/agents/supabase-realtime-implementer.md +23 -0
- package/kit/agents/supabase-rls-writer.md +17 -0
- package/kit/agents/supabase-storage-implementer.md +174 -0
- package/kit/agents/toil-auditor.md +277 -0
- package/kit/commands/auditar-marco.md +102 -1
- package/kit/commands/auditar-observabilidade.md +103 -0
- package/kit/commands/auditar-toil.md +129 -0
- package/kit/commands/burn-rate-status.md +140 -0
- package/kit/commands/concluir-marco.md +73 -1
- package/kit/commands/definir-slo.md +108 -0
- package/kit/commands/discutir-fase.md +26 -0
- package/kit/commands/forense.md +83 -1
- package/kit/commands/golden-signals.md +142 -0
- package/kit/commands/instrumentar-fase.md +200 -0
- package/kit/commands/investigar-producao.md +162 -0
- package/kit/commands/observabilidade.md +116 -0
- package/kit/commands/planejar-fase.md +20 -0
- package/kit/commands/postmortem.md +179 -0
- package/kit/commands/prr.md +205 -0
- package/kit/commands/risk-budget.md +220 -0
- package/kit/commands/sre.md +227 -0
- package/kit/commands/verificar-trabalho.md +26 -0
- package/kit/skills/_shared-observability/glossary.md +396 -0
- package/kit/skills/_shared-sre/glossary.md +573 -0
- package/kit/skills/blameless-postmortems/SKILL.md +340 -0
- package/kit/skills/burn-rate-alerting/SKILL.md +258 -0
- package/kit/skills/core-analysis-loop/SKILL.md +352 -0
- package/kit/skills/distributed-tracing/SKILL.md +362 -0
- package/kit/skills/eliminating-toil/SKILL.md +243 -0
- package/kit/skills/event-based-slos/SKILL.md +296 -0
- package/kit/skills/four-golden-signals/SKILL.md +297 -0
- package/kit/skills/observability-driven-development/SKILL.md +315 -0
- package/kit/skills/observability-maturity-model/SKILL.md +222 -0
- package/kit/skills/opentelemetry-standard/SKILL.md +351 -0
- package/kit/skills/production-readiness-review/SKILL.md +305 -0
- package/kit/skills/sre-risk-management/SKILL.md +221 -0
- package/kit/skills/structured-events/SKILL.md +265 -0
- package/kit/skills/telemetry-pipelines/SKILL.md +259 -0
- package/kit/skills/telemetry-sampling/SKILL.md +256 -0
- package/package.json +1 -1
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: telemetry-pipelines
|
|
3
|
+
description: Use ao gerenciar coleta/transporte de telemetria — OTel Collector, routing por destino, buffering, filtering, security. App envia para sidecar; sidecar roteia.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Observabilidade — Telemetry Pipelines
|
|
7
|
+
|
|
8
|
+
## Quando usar
|
|
9
|
+
|
|
10
|
+
LLM carrega esta skill ao desenhar pipeline de telemetria. Trigger phrases:
|
|
11
|
+
|
|
12
|
+
- "OTel Collector", "telemetry pipeline"
|
|
13
|
+
- "routing de telemetria"
|
|
14
|
+
- "buffering, filtering, transformation"
|
|
15
|
+
- "build vs buy de pipeline"
|
|
16
|
+
- "1 backend ou múltiplos"
|
|
17
|
+
|
|
18
|
+
## Atributos do pipeline (Cap 18)
|
|
19
|
+
|
|
20
|
+
| Atributo | Significado | Importância |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| Routing | Mandar dados a destinos diferentes baseado em conteúdo | Alta |
|
|
23
|
+
| Security | TLS + auth headers + audit trail | Alta |
|
|
24
|
+
| Workload isolation | Erros num destino não afetam outros | Alta |
|
|
25
|
+
| Buffering | Tolerar lentidão temporária | Alta |
|
|
26
|
+
| Capacity management | Backpressure quando upstream lento | Alta |
|
|
27
|
+
| Data filtering | Drop dados sensíveis antes de export | Média-Alta |
|
|
28
|
+
| Data augmentation | Adicionar resource attributes (region, env) | Média |
|
|
29
|
+
| Data transformation | Renomear campos, normalizar formatos | Média |
|
|
30
|
+
| Quality | Validação de schema | Média |
|
|
31
|
+
|
|
32
|
+
## Regras absolutas
|
|
33
|
+
|
|
34
|
+
- **App envia para sidecar/Collector local** — nunca direto para backend remoto. Trocar destino = config no Collector, não redeploy do app.
|
|
35
|
+
- **OTel Collector é o default** — vendor-neutral, plug-in arquitetura. Usar pipelines proprietários (vendor agent) cria lock-in.
|
|
36
|
+
- **Multi-destino é normal** — 1 mesmo trace pode ir para Honeycomb (debug), Logflare (compliance), arquivo local (dev) simultaneamente.
|
|
37
|
+
- **Buffering é obrigatório** — destinos remotos têm hiccups; sem buffer, perde dados.
|
|
38
|
+
- **Filtragem por security/compliance** — drop campos PII antes de export externo. PII em arquivo local = ok; em vendor remoto = problema legal.
|
|
39
|
+
- **Workload isolation** — erro/lentidão em 1 destino não bloqueia outros. Use exporters paralelos no Collector.
|
|
40
|
+
- **Capacity managemement** — Collector deve ter limites de buffer e graceful drop quando saturado (não OOM).
|
|
41
|
+
|
|
42
|
+
## Patterns canônicos
|
|
43
|
+
|
|
44
|
+
### Pattern: Collector config canônico (multi-destino)
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
# PT-BR: otel-collector-config.yaml — recebe OTLP, processa, roteia
|
|
48
|
+
receivers:
|
|
49
|
+
otlp:
|
|
50
|
+
protocols:
|
|
51
|
+
http: { endpoint: 0.0.0.0:4318 }
|
|
52
|
+
grpc: { endpoint: 0.0.0.0:4317 }
|
|
53
|
+
|
|
54
|
+
processors:
|
|
55
|
+
# PT-BR: batch para reduzir round-trips
|
|
56
|
+
batch:
|
|
57
|
+
timeout: 10s
|
|
58
|
+
send_batch_size: 1024
|
|
59
|
+
|
|
60
|
+
# PT-BR: tail sampling — 100% errors, 1% baseline
|
|
61
|
+
tail_sampling:
|
|
62
|
+
decision_wait: 10s
|
|
63
|
+
policies:
|
|
64
|
+
- name: errors
|
|
65
|
+
type: status_code
|
|
66
|
+
status_code: { status_codes: [ERROR] }
|
|
67
|
+
- name: baseline
|
|
68
|
+
type: probabilistic
|
|
69
|
+
probabilistic: { sampling_percentage: 1 }
|
|
70
|
+
|
|
71
|
+
# PT-BR: filter PII — drop campos sensíveis antes de export remoto
|
|
72
|
+
attributes/redact_pii:
|
|
73
|
+
actions:
|
|
74
|
+
- key: user.email
|
|
75
|
+
action: hash # hash em vez de drop — mantém cardinalidade
|
|
76
|
+
- key: user.cpf
|
|
77
|
+
action: delete
|
|
78
|
+
- key: credit_card.number
|
|
79
|
+
action: delete
|
|
80
|
+
|
|
81
|
+
# PT-BR: augment com resource attributes
|
|
82
|
+
resource:
|
|
83
|
+
attributes:
|
|
84
|
+
- key: deployment.environment
|
|
85
|
+
value: ${env:NODE_ENV}
|
|
86
|
+
action: insert
|
|
87
|
+
- key: cloud.region
|
|
88
|
+
value: ${env:AWS_REGION}
|
|
89
|
+
action: insert
|
|
90
|
+
|
|
91
|
+
exporters:
|
|
92
|
+
# PT-BR: para Honeycomb (debug)
|
|
93
|
+
otlphttp/honeycomb:
|
|
94
|
+
endpoint: https://api.honeycomb.io
|
|
95
|
+
headers:
|
|
96
|
+
x-honeycomb-team: ${env:HONEYCOMB_API_KEY}
|
|
97
|
+
|
|
98
|
+
# PT-BR: para Logflare (Supabase compliance)
|
|
99
|
+
otlphttp/logflare:
|
|
100
|
+
endpoint: https://api.logflare.app/otel
|
|
101
|
+
headers:
|
|
102
|
+
x-api-key: ${env:LOGFLARE_API_KEY}
|
|
103
|
+
|
|
104
|
+
# PT-BR: arquivo local — debug local, retain 7d
|
|
105
|
+
file:
|
|
106
|
+
path: /var/log/otel/traces.json
|
|
107
|
+
rotation:
|
|
108
|
+
max_megabytes: 100
|
|
109
|
+
max_days: 7
|
|
110
|
+
max_backups: 10
|
|
111
|
+
|
|
112
|
+
service:
|
|
113
|
+
pipelines:
|
|
114
|
+
traces:
|
|
115
|
+
receivers: [otlp]
|
|
116
|
+
processors: [tail_sampling, attributes/redact_pii, resource, batch]
|
|
117
|
+
exporters: [otlphttp/honeycomb, otlphttp/logflare, file]
|
|
118
|
+
metrics:
|
|
119
|
+
receivers: [otlp]
|
|
120
|
+
processors: [resource, batch]
|
|
121
|
+
exporters: [otlphttp/honeycomb]
|
|
122
|
+
logs:
|
|
123
|
+
receivers: [otlp]
|
|
124
|
+
processors: [attributes/redact_pii, batch]
|
|
125
|
+
exporters: [otlphttp/logflare, file]
|
|
126
|
+
|
|
127
|
+
# PT-BR: telemetria do collector próprio (meta-observability)
|
|
128
|
+
telemetry:
|
|
129
|
+
logs:
|
|
130
|
+
level: info
|
|
131
|
+
metrics:
|
|
132
|
+
level: detailed
|
|
133
|
+
address: 0.0.0.0:8888
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Pattern: routing por conteúdo
|
|
137
|
+
|
|
138
|
+
```yaml
|
|
139
|
+
# PT-BR: rotear traces para destinos diferentes baseado em service.name
|
|
140
|
+
processors:
|
|
141
|
+
routing/service:
|
|
142
|
+
from_attribute: service.name
|
|
143
|
+
table:
|
|
144
|
+
- value: orders-service
|
|
145
|
+
exporters: [otlphttp/honeycomb]
|
|
146
|
+
- value: payments-service
|
|
147
|
+
exporters: [otlphttp/honeycomb, otlphttp/datadog] # 2 destinos
|
|
148
|
+
default_exporters: [file]
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Pattern: backpressure
|
|
152
|
+
|
|
153
|
+
```yaml
|
|
154
|
+
# PT-BR: limit memory + drop oldest se saturar
|
|
155
|
+
processors:
|
|
156
|
+
memory_limiter:
|
|
157
|
+
check_interval: 1s
|
|
158
|
+
limit_mib: 1500 # PT-BR: drop quando passar de 1.5 GB
|
|
159
|
+
spike_limit_mib: 512 # PT-BR: tolerância a spikes de 512 MB
|
|
160
|
+
|
|
161
|
+
service:
|
|
162
|
+
pipelines:
|
|
163
|
+
traces:
|
|
164
|
+
processors: [memory_limiter, ...] # PT-BR: PRIMEIRO no pipeline
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Pattern: build vs buy
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
PT-BR: critérios para construir vs comprar pipeline (Cap 18 p239):
|
|
171
|
+
|
|
172
|
+
CONSTRUIR (próprio Collector custom) se:
|
|
173
|
+
- Volume > 10M spans/segundo (vendors caros nesse range)
|
|
174
|
+
- Compliance específico que vendor não cobre
|
|
175
|
+
- 5+ engineers full-time disponíveis para ops
|
|
176
|
+
|
|
177
|
+
COMPRAR (vendor managed: Honeycomb / Datadog / etc.) se:
|
|
178
|
+
- Volume < 1M spans/segundo
|
|
179
|
+
- Time pequeno (≤ 3 engineers)
|
|
180
|
+
- Compliance geral (SOC2, GDPR — vendors já cobrem)
|
|
181
|
+
|
|
182
|
+
HÍBRIDO (default recomendado):
|
|
183
|
+
- OTel Collector (open source) como sidecar local
|
|
184
|
+
- Backend SaaS como destino primary
|
|
185
|
+
- File local como secondary (compliance/debug)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Anti-patterns
|
|
189
|
+
|
|
190
|
+
### ANTI: app envia direto para backend remoto
|
|
191
|
+
|
|
192
|
+
```text
|
|
193
|
+
ANTI: SDK exporta direto para api.honeycomb.io
|
|
194
|
+
Trocar para Datadog = redeploy de TODOS os services
|
|
195
|
+
Pipeline vai abaixo se backend tem hiccup → app trava
|
|
196
|
+
|
|
197
|
+
CERTO: app → localhost:4318 (Collector) → roteamento múltiplo
|
|
198
|
+
Trocar destino = editar Collector config; sem redeploy
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### ANTI: 1 destino monolítico
|
|
202
|
+
|
|
203
|
+
```text
|
|
204
|
+
ANTI: Honeycomb único destino para tudo
|
|
205
|
+
Vendor outage = visibilidade total perdida
|
|
206
|
+
Compliance pode exigir cópia em region específica
|
|
207
|
+
|
|
208
|
+
CERTO: Honeycomb (debug) + Logflare (compliance) + file (local)
|
|
209
|
+
Cada destino independente; falha em 1 não afeta outros
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### ANTI: sem PII filter antes de export remoto
|
|
213
|
+
|
|
214
|
+
```text
|
|
215
|
+
ANTI: spans com `user.email`, `user.cpf` enviados literalmente para vendor SaaS
|
|
216
|
+
GDPR / LGPD violado; vendor outage = leak
|
|
217
|
+
|
|
218
|
+
CERTO: processor `attributes/redact_pii` — hash emails, drop docs.
|
|
219
|
+
Cópia local pode reter para debug interno; remoto vê só hash.
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### ANTI: sem buffering
|
|
223
|
+
|
|
224
|
+
```text
|
|
225
|
+
ANTI: sync export — cada span é POST imediato
|
|
226
|
+
Backend latência = app latência sobe
|
|
227
|
+
Backend down = spans perdidos
|
|
228
|
+
|
|
229
|
+
CERTO: batch processor (10s ou 1024 spans) + retry
|
|
230
|
+
Buffer absorve hiccups de até segundos sem afetar app
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### ANTI: vendor agent proprietary
|
|
234
|
+
|
|
235
|
+
```text
|
|
236
|
+
ANTI: instalar dd-agent / new-relic-agent / etc. em todos os hosts
|
|
237
|
+
Vendor lock-in; trocar = reinstrumentar tudo
|
|
238
|
+
|
|
239
|
+
CERTO: OTel SDK + OTel Collector
|
|
240
|
+
Vendor é apenas o destino do exporter; trocar = mudar 1 linha de config
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Verificação
|
|
244
|
+
|
|
245
|
+
1. **App configurado para localhost:4318** — `select * from connections` deve mostrar app→Collector apenas
|
|
246
|
+
2. **Multi-destino funciona** — fazer 1 request → trace aparece em Honeycomb + Logflare + file simultaneamente
|
|
247
|
+
3. **Filter PII testado** — span com user.email=foo@x.com → no destino remoto, atributo é hash, não literal
|
|
248
|
+
4. **Backpressure** — gerar carga sintética acima do limit → Collector dropa, não OOM
|
|
249
|
+
5. **Buffer recovery** — desligar destino remoto temporariamente → spans bufferados → ligar → flush
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Ver também
|
|
254
|
+
|
|
255
|
+
- `kit/skills/_shared-observability/glossary.md` — telemetry pipeline, routing, buffering
|
|
256
|
+
- `kit/skills/opentelemetry-standard/SKILL.md` — OTel Collector basics
|
|
257
|
+
- `kit/skills/telemetry-sampling/SKILL.md` — tail_sampling processor
|
|
258
|
+
|
|
259
|
+
*Material-fonte: Observability Engineering (O'Reilly, 2022) — Cap 18: "Telemetry Management with Pipelines".*
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: telemetry-sampling
|
|
3
|
+
description: Use ao reduzir custo de telemetria — head/tail sampling, by-key, dynamic. 100% errors, by-tier para customers, head-based propaga via traceparent.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Observabilidade — Telemetry Sampling
|
|
7
|
+
|
|
8
|
+
## Quando usar
|
|
9
|
+
|
|
10
|
+
LLM carrega esta skill ao reduzir custo de telemetria sem perder sinal. Trigger phrases:
|
|
11
|
+
|
|
12
|
+
- "sampling", "reduzir custo de telemetria"
|
|
13
|
+
- "head-based vs tail-based"
|
|
14
|
+
- "by-key sampling", "dynamic sampling"
|
|
15
|
+
- "100% errors mas só 1% sucessos"
|
|
16
|
+
- "trace fica incompleto após sampling"
|
|
17
|
+
|
|
18
|
+
## Regras absolutas
|
|
19
|
+
|
|
20
|
+
- **100% dos erros sempre** — sample 100% de eventos com `result.success = false`. Erros são raros e críticos. Nunca sample.
|
|
21
|
+
- **100% de paying/enterprise customers** — high-value, baixo volume relativo, debug crucial.
|
|
22
|
+
- **Head-based propaga via `traceparent` flag** — decisão tomada no service de entrada, propagada downstream para garantir trace completo.
|
|
23
|
+
- **Tail-based requer collector buffer** — decisão pós-trace; impossível de implementar inline em código.
|
|
24
|
+
- **Constant probability falha em low volume** — 1/1000 de 100 req/min = 0.1 evento/min, perde tudo.
|
|
25
|
+
- **Sample rate gravado no evento** — sem isso, agregações reconstroem totais errados.
|
|
26
|
+
- **Errors > success** — categorize: paying customers > free, enterprise > pro > free.
|
|
27
|
+
- **Não sample antes de aggregate** — pre-aggregation perde alta cardinalidade. Sample evento bruto, aggregate no read.
|
|
28
|
+
|
|
29
|
+
## Estratégias canônicas
|
|
30
|
+
|
|
31
|
+
### Head-based sampling (decisão no início do trace)
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
// PT-BR: decisão tomada no service de entrada, propagada via traceparent flag
|
|
35
|
+
import { trace, context } from '@opentelemetry/api'
|
|
36
|
+
import { TraceFlags } from '@opentelemetry/api'
|
|
37
|
+
|
|
38
|
+
function shouldSample(event: SpanContext): boolean {
|
|
39
|
+
// PT-BR: 100% errors (head-based: erros raramente são conhecidos no head;
|
|
40
|
+
// verificar HTTP status no início via header)
|
|
41
|
+
if (event.attributes['result.success'] === false) return true
|
|
42
|
+
|
|
43
|
+
// PT-BR: 100% enterprise — alto valor
|
|
44
|
+
if (event.attributes['customer.tier'] === 'enterprise') return true
|
|
45
|
+
|
|
46
|
+
// PT-BR: 10% pro
|
|
47
|
+
if (event.attributes['customer.tier'] === 'pro') return Math.random() < 0.1
|
|
48
|
+
|
|
49
|
+
// PT-BR: 1% free baseline
|
|
50
|
+
return Math.random() < 0.01
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// PT-BR: marcar flag sampled no traceparent — propaga para downstream
|
|
54
|
+
const flags = shouldSample(event) ? TraceFlags.SAMPLED : TraceFlags.NONE
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Tail-based sampling (decisão após trace completar)
|
|
58
|
+
|
|
59
|
+
```yaml
|
|
60
|
+
# PT-BR: OTel Collector config — sampling pós-trace
|
|
61
|
+
# 100% errors + outliers de latência + 1% success
|
|
62
|
+
processors:
|
|
63
|
+
tail_sampling:
|
|
64
|
+
decision_wait: 10s # PT-BR: buffer 10s para esperar todos os spans do trace
|
|
65
|
+
policies:
|
|
66
|
+
- name: errors-policy
|
|
67
|
+
type: status_code
|
|
68
|
+
status_code: { status_codes: [ERROR] }
|
|
69
|
+
- name: latency-outliers
|
|
70
|
+
type: latency
|
|
71
|
+
latency: { threshold_ms: 1000 } # PT-BR: > 1s é outlier
|
|
72
|
+
- name: probabilistic-baseline
|
|
73
|
+
type: probabilistic
|
|
74
|
+
probabilistic: { sampling_percentage: 1 }
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### By-key sampling
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
// PT-BR: taxas diferentes por chave — mais preciso que constant
|
|
81
|
+
const SAMPLE_RATES: Record<string, number> = {
|
|
82
|
+
// chave: [error.type | endpoint | tenant_id, etc.]
|
|
83
|
+
'error_rate_limit': 0.5, // PT-BR: 50% (já frequente, mas importante)
|
|
84
|
+
'error_validation': 1.0, // PT-BR: 100% (raro, debug crítico)
|
|
85
|
+
'tenant_acme-corp': 1.0, // PT-BR: 100% (big customer)
|
|
86
|
+
'endpoint_/health': 0.001, // PT-BR: 0.1% (muito frequente, baixo valor)
|
|
87
|
+
'default': 0.05 // PT-BR: 5% baseline
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function sampleByKey(event: SpanLike): boolean {
|
|
91
|
+
const errorKey = `error_${event.attributes['error.type']}`
|
|
92
|
+
const tenantKey = `tenant_${event.attributes['tenant_id']}`
|
|
93
|
+
const endpointKey = `endpoint_${event.attributes['endpoint']}`
|
|
94
|
+
|
|
95
|
+
const rate = SAMPLE_RATES[errorKey]
|
|
96
|
+
?? SAMPLE_RATES[tenantKey]
|
|
97
|
+
?? SAMPLE_RATES[endpointKey]
|
|
98
|
+
?? SAMPLE_RATES['default']
|
|
99
|
+
|
|
100
|
+
return Math.random() < rate
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Dynamic sampling (taxa adapta com volume)
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
// PT-BR: lookback 30s — quanto traffic veio recentemente?
|
|
108
|
+
let recentVolume = 0
|
|
109
|
+
setInterval(() => { recentVolume = 0 }, 30_000)
|
|
110
|
+
|
|
111
|
+
function sampleDynamic(event: SpanLike): boolean {
|
|
112
|
+
recentVolume++
|
|
113
|
+
|
|
114
|
+
// PT-BR: tráfego baixo → sample mais; tráfego alto → sample menos
|
|
115
|
+
if (recentVolume < 100) return true // até 100 spans em 30s, mantém todos
|
|
116
|
+
if (recentVolume < 1000) return Math.random() < 0.1 // até 1k, 10%
|
|
117
|
+
return Math.random() < 0.01 // > 1k, 1%
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Combinando: by-key + dynamic + head
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
function shouldSample(event: SpanLike): boolean {
|
|
125
|
+
// PT-BR: 1. Errors sempre 100%
|
|
126
|
+
if (event.attributes['result.success'] === false) return true
|
|
127
|
+
|
|
128
|
+
// PT-BR: 2. Enterprise sempre 100%
|
|
129
|
+
if (event.attributes['customer.tier'] === 'enterprise') return true
|
|
130
|
+
|
|
131
|
+
// PT-BR: 3. Outras chaves de alto valor
|
|
132
|
+
if (event.attributes['feature_flag.experiment_a'] === true) return true // experimento ativo
|
|
133
|
+
|
|
134
|
+
// PT-BR: 4. Dynamic baseline
|
|
135
|
+
return sampleDynamic(event)
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Patterns canônicos
|
|
140
|
+
|
|
141
|
+
### Pattern: gravar sample_rate no evento
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
// PT-BR: sem sample_rate, agregações no read time não conseguem reconstruir totais
|
|
145
|
+
const sampleRate = computeSampleRate(event)
|
|
146
|
+
if (Math.random() < sampleRate) {
|
|
147
|
+
span.setAttribute('_sample_rate', sampleRate) // PT-BR: 0.01 = 1% sampled
|
|
148
|
+
span.setAttribute('_sampled', true)
|
|
149
|
+
// PT-BR: agora o backend pode multiplicar contagens por 1/sample_rate
|
|
150
|
+
exportSpan(span)
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Pattern: query reconstruindo totais com sample_rate
|
|
155
|
+
|
|
156
|
+
```sql
|
|
157
|
+
-- PT-BR: sem sample_rate, count(*) está errado
|
|
158
|
+
-- COM sample_rate, sum(1/_sample_rate) reconstrói total estimado
|
|
159
|
+
select
|
|
160
|
+
endpoint,
|
|
161
|
+
sum(1.0 / _sample_rate) as estimated_total,
|
|
162
|
+
count(*) as samples_collected,
|
|
163
|
+
sum(1.0 / _sample_rate) filter (where result_success = false) as estimated_errors
|
|
164
|
+
from observability.events
|
|
165
|
+
where timestamp > now() - interval '1 hour'
|
|
166
|
+
group by endpoint
|
|
167
|
+
order by estimated_total desc;
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Pattern: sampling para alta cardinalidade
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
// PT-BR: cardinalidade alta (millions of users) — não pode sample por user.id
|
|
174
|
+
// mas pode sample por (customer.tier, error.type) — combinação cardin. baixa
|
|
175
|
+
function sampleByDimensions(event: SpanLike): number {
|
|
176
|
+
const key = `${event.attributes['customer.tier']}-${event.attributes['error.type'] ?? 'success'}`
|
|
177
|
+
|
|
178
|
+
const rates: Record<string, number> = {
|
|
179
|
+
'enterprise-success': 0.5,
|
|
180
|
+
'enterprise-error': 1.0,
|
|
181
|
+
'pro-success': 0.1,
|
|
182
|
+
'pro-error': 1.0,
|
|
183
|
+
'free-success': 0.01,
|
|
184
|
+
'free-error': 1.0,
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return rates[key] ?? 0.01
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Anti-patterns
|
|
192
|
+
|
|
193
|
+
### ANTI: constant probability em low volume
|
|
194
|
+
|
|
195
|
+
```text
|
|
196
|
+
ANTI: app com 100 req/min, sample rate fixo 1/1000 → 0.1 evento/min retidos
|
|
197
|
+
Você verá 1 erro a cada 10 minutos. Sinal perdido.
|
|
198
|
+
|
|
199
|
+
CERTO: dynamic sampling — alta taxa quando volume baixo, baixa quando alto.
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### ANTI: sample errors
|
|
203
|
+
|
|
204
|
+
```text
|
|
205
|
+
ANTI: sample 1% de errors junto com 1% de success — erros são 0.5% do tráfego;
|
|
206
|
+
seu sample retém 0.005% de errors total. Praticamente nunca aparecem.
|
|
207
|
+
|
|
208
|
+
CERTO: 100% errors. SEMPRE. Erros são raros e críticos.
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### ANTI: sample sem gravar rate
|
|
212
|
+
|
|
213
|
+
```text
|
|
214
|
+
ANTI: sample 1/100 mas evento não tem _sample_rate
|
|
215
|
+
Backend conta literais → count = 1% do real → métricas erradas
|
|
216
|
+
|
|
217
|
+
CERTO: gravar _sample_rate no evento; agregar com sum(1/rate) no read.
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### ANTI: tail-based sem collector
|
|
221
|
+
|
|
222
|
+
```text
|
|
223
|
+
ANTI: tentar implementar tail-based em SDK do app — precisa bufferizar todos os spans
|
|
224
|
+
de cada trace, esperar conclusão, decidir, exportar. Memória e latência altas.
|
|
225
|
+
|
|
226
|
+
CERTO: tail-based requer OTel Collector como sidecar/proxy. App envia 100% para
|
|
227
|
+
Collector; Collector decide via processor `tail_sampling`.
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### ANTI: head-based sem propagação
|
|
231
|
+
|
|
232
|
+
```text
|
|
233
|
+
ANTI: decisão de sample tomada no service A → não propagada para B → B decide sozinho
|
|
234
|
+
→ trace fica incompleto (alguns spans em A, outros em B, sem correlação)
|
|
235
|
+
|
|
236
|
+
CERTO: marcar TraceFlags.SAMPLED no traceparent; B respeita decisão upstream.
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Verificação
|
|
240
|
+
|
|
241
|
+
1. **Errors 100%** — `select count(*) where result_success=false` × `1/sample_rate` ≈ count real
|
|
242
|
+
2. **Enterprise 100%** — verificar via query que enterprise tier tem _sample_rate=1 sempre
|
|
243
|
+
3. **Sample rate gravado** — `select count(*) filter (where _sample_rate is null)` = 0
|
|
244
|
+
4. **Trace integridade** — head-based: trace tem todos os spans (não 50% missing)
|
|
245
|
+
5. **Custo redução real** — bytes/segundo enviado para backend caiu sem perder sinal de error/p99
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Ver também
|
|
250
|
+
|
|
251
|
+
- `kit/skills/_shared-observability/glossary.md` — termos sampling
|
|
252
|
+
- `kit/skills/distributed-tracing/SKILL.md` — head vs tail decision timing
|
|
253
|
+
- `kit/skills/opentelemetry-standard/SKILL.md` — Collector tail_sampling processor
|
|
254
|
+
- `kit/skills/event-based-slos/SKILL.md` — SLO precisa de sample_rate para reconstruir totais
|
|
255
|
+
|
|
256
|
+
*Material-fonte: Observability Engineering (O'Reilly, 2022) — Cap 17: "Cheap and Accurate Enough: Sampling".*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@luanpdd/kit-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "Generic infrastructure to ship YOUR personal kit of agents/commands/skills as an MCP server, with cross-IDE sync (Claude Code, Cursor, Codex, Gemini, Windsurf, Antigravity, Copilot, Trae).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|