{"id":"1774779a-ce8a-4ce6-a255-b716ffafbcbe","shortId":"FY3CU6","kind":"skill","title":"sentry-instrumentation","tagline":"Rules and examples for adding Sentry metrics the right way. Covers how to name a counter, gauge, or duration metric; which tags are safe versus which will blow up your Sentry bill; how to track failures with a small fixed list of error types instead of raw exception strings; and ","description":"# Sentry Instrumentation\n\nSentry **system metrics** only (counter / gauge / distribution, duration, failure, resource). Product-analytics events (clicks, funnels, flag exposure) belong in your product-analytics tool — never in Sentry. Python under `examples/python/` is the canonical reference; other languages port the same shapes under idiomatic names.\n\nDo not invoke for product-analytics changes. Stop and use the right tool.\n\n## Decision rules\n\n1. **New metric?** Read `references/signal-model.md` and pick a classmethod constructor (`MetricDef.counter|latency|gauge|resource|failure_counter`). Register in the project's metric registry. **Never** call an emission helper with a raw string or a dynamically-assembled name.\n2. **Tag values?** Either enumerate them in `MetricDef.tag_constraints` or route through a bucket function from `references/tagging-and-cardinality.md`.\n3. **Inside a loop?** Use `AggregatingCounter` or `DurationAccumulator` (see `references/cost-model.md`). If the metric's `loop_policy` is `\"forbidden\"` the CI gate refuses any emission inside a `for`/`while` body for that metric.\n4. **New surface (HTTP route / external API / workflow step / retry / fallback)?** Use the matching reusable pattern from `references/surface-patterns.md`. Don't hand-roll the emissions.\n5. **Changing a metric's meaning, unit, or tag shape?** It's a new versioned metric. See `references/naming-and-lifecycle.md`.\n6. **Failure counter?** Build with `MetricDef.failure_counter(...)` and emit with `emit_failure(metric, failure=classify(exc), tags=...)`. Never pass `str(exc)` as a tag. See `references/failure-taxonomy.md`.\n\n## Language detection\n\nDetect the project language from manifest files, then extend any existing observability layer you find (`observability.py` / `observability.ts` / `metrics/` package). If none exists, scaffold from the matching example directory.\n\n```\npyproject.toml / setup.py  → Python. Use examples/python/.\npackage.json               → TypeScript/JavaScript. Port from examples/python/ shapes.\ngo.mod                     → Go. Port from examples/python/ shapes.\nGemfile                    → Ruby. Port from examples/python/ shapes.\npom.xml / build.gradle     → Java/Kotlin. Port from examples/python/ shapes.\n```\n\nFor ports: preserve the five constructors, the `FailureClass` taxonomy values, the 13 CI gate checks, and the emission-boundary rules. Names become idiomatic (`emit_counter` → `emitCounter`, `@instrumented_step` → `instrumentedStep(fn)`, etc.).\n\n## Python project paths (canonical reference)\n\nReplace `yourapp` with the project's package root on first use.\n\n```\nEmission module:    yourapp/observability.py\nRegistry:           yourapp/shared/metrics.py\nTag buckets:        yourapp/shared/metric_tags.py\nFailure taxonomy:   yourapp/shared/failure_taxonomy.py\nHTTP middleware:    yourapp/middleware/observability.py\nWorkflow decorator: yourapp/services/<workflow>/instrumentation.py\nExternal API base:  yourapp/services/providers/instrumented_http_client.py\nRetry helper:       yourapp/services/retry.py\nFallback helper:    yourapp/observability.py (or yourapp/shared/fallback.py)\nCI gate:            scripts/check_metrics.py\n```\n\n## References (load on demand)\n\n| Topic | Reference | Example |\n|---|---|---|\n| Charter & scope | `references/charter.md` | — |\n| `MetricDef` schema + constructors | `references/signal-model.md` | `examples/python/metric_def.py` |\n| Five metric classes by purpose | `references/metric-classes.md` | — |\n| Kind semantic rules (counter/gauge/distribution) | `references/semantic-rules.md` | — |\n| Naming + lifecycle (version suffix, retired_at) | `references/naming-and-lifecycle.md` | — |\n| Tagging + cardinality policy + bucket fns | `references/tagging-and-cardinality.md` | `examples/python/metric_tags.py` |\n| Cost model (sampling, rate limit, aggregation) | `references/cost-model.md` | `examples/python/emission_module.py` |\n| Emission boundaries (where to emit) | `references/emission-boundaries.md` | — |\n| Failure taxonomy (`FailureClass` + `classify`) | `references/failure-taxonomy.md` | `examples/python/failure_taxonomy.py` |\n| Reusable surface patterns | `references/surface-patterns.md` | `examples/python/http_middleware.py`, `examples/python/external_api_client.py`, `examples/python/workflow_decorator.py`, `examples/python/retry_loop.py`, `examples/python/fallback_path.py` |\n| Emission helpers + validators | — | `examples/python/emission_module.py` |\n| CI enforcement gate (13 AST checks) | `references/enforcement.md` | `examples/python/ci_gate.py` |\n| Test gates | `references/enforcement.md` | `examples/python/test_gates.py` |\n| PR review rubric | `references/review-rubric.md` | — |","tags":["sentry","instrumentation","tortastudios","agent-skills","claude-skills","codex-skill","monitoring","observability","telemetry"],"capabilities":["skill","source-tortastudios","skill-sentry-instrumentation","topic-agent-skills","topic-claude-skills","topic-codex-skill","topic-instrumentation","topic-monitoring","topic-observability","topic-sentry","topic-telemetry"],"categories":["sentry-instrumentation"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/tortastudios/sentry-instrumentation","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add tortastudios/sentry-instrumentation","source_repo":"https://github.com/tortastudios/sentry-instrumentation","install_from":"skills.sh"}},"qualityScore":"0.456","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 13 github stars · SKILL.md body (4,695 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:06:50.213Z","embedding":null,"createdAt":"2026-04-19T00:40:49.261Z","updatedAt":"2026-05-18T19:06:50.213Z","lastSeenAt":"2026-05-18T19:06:50.213Z","tsv":"'/instrumentation.py':397 '1':116 '13':343,489 '2':154 '3':171 '4':203 '5':228 '6':246 'ad':8 'aggreg':458 'aggregatingcount':176 'analyt':68,79,106 'api':209,399 'assembl':152 'ast':490 'base':400 'becom':354 'belong':74 'bill':35 'blow':31 'bodi':199 'boundari':351,462 'bucket':167,386,449 'build':249 'build.gradle':326 'call':140 'canon':89,367 'cardin':447 'chang':107,229 'charter':420 'check':346,491 'ci':190,344,410,486 'class':430 'classifi':260,470 'classmethod':124 'click':70 'constraint':162 'constructor':125,337,425 'cost':453 'counter':19,60,131,248,252,357 'counter/gauge/distribution':437 'cover':14 'decis':114 'decor':395 'demand':416 'detect':273,274 'directori':301 'distribut':62 'durat':22,63 'durationaccumul':178 'dynam':151 'dynamically-assembl':150 'either':157 'emiss':142,194,227,350,380,461,482 'emission-boundari':349 'emit':254,256,356,465 'emitcount':358 'enforc':487 'enumer':158 'error':46 'etc':363 'event':69 'exampl':6,300,419 'examples/python':86,306,311,317,323,330 'examples/python/ci_gate.py':493 'examples/python/emission_module.py':460,485 'examples/python/external_api_client.py':478 'examples/python/failure_taxonomy.py':472 'examples/python/fallback_path.py':481 'examples/python/http_middleware.py':477 'examples/python/metric_def.py':427 'examples/python/metric_tags.py':452 'examples/python/retry_loop.py':480 'examples/python/test_gates.py':497 'examples/python/workflow_decorator.py':479 'exc':261,266 'except':51 'exist':284,295 'exposur':73 'extend':282 'extern':208,398 'failur':39,64,130,247,257,259,388,467 'failureclass':339,469 'fallback':213,405 'file':280 'find':288 'first':378 'five':336,428 'fix':43 'flag':72 'fn':362 'fns':450 'forbidden':188 'function':168 'funnel':71 'gate':191,345,411,488,495 'gaug':20,61,128 'gemfil':319 'go':314 'go.mod':313 'hand':224 'hand-rol':223 'helper':143,403,406,483 'http':206,391 'idiomat':98,355 'insid':172,195 'instead':48 'instrument':3,55,359 'instrumentedstep':361 'invok':102 'java/kotlin':327 'kind':434 'languag':92,272,277 'latenc':127 'layer':286 'lifecycl':440 'limit':457 'list':44 'load':414 'loop':174,185 'manifest':279 'match':216,299 'mean':233 'metric':10,23,58,118,137,183,202,231,243,258,291,429 'metricdef':423 'metricdef.counter':126 'metricdef.failure':251 'metricdef.tag':161 'middlewar':392 'model':454 'modul':381 'name':17,99,153,353,439 'never':81,139,263 'new':117,204,241 'none':294 'observ':285 'observability.py':289 'observability.ts':290 'packag':292,375 'package.json':307 'pass':264 'path':366 'pattern':218,475 'pick':122 'polici':186,448 'pom.xml':325 'port':93,309,315,321,328,333 'pr':498 'preserv':334 'product':67,78,105 'product-analyt':66,77,104 'project':135,276,365,373 'purpos':432 'pyproject.toml':302 'python':84,304,364 'rate':456 'raw':50,146 'read':119 'refer':90,368,413,418 'references/charter.md':422 'references/cost-model.md':180,459 'references/emission-boundaries.md':466 'references/enforcement.md':492,496 'references/failure-taxonomy.md':271,471 'references/metric-classes.md':433 'references/naming-and-lifecycle.md':245,445 'references/review-rubric.md':501 'references/semantic-rules.md':438 'references/signal-model.md':120,426 'references/surface-patterns.md':220,476 'references/tagging-and-cardinality.md':170,451 'refus':192 'regist':132 'registri':138,383 'replac':369 'resourc':65,129 'retir':443 'retri':212,402 'reusabl':217,473 'review':499 'right':12,112 'roll':225 'root':376 'rout':164,207 'rubi':320 'rubric':500 'rule':4,115,352,436 'safe':27 'sampl':455 'scaffold':296 'schema':424 'scope':421 'scripts/check_metrics.py':412 'see':179,244,270 'semant':435 'sentri':2,9,34,54,56,83 'sentry-instrument':1 'setup.py':303 'shape':96,237,312,318,324,331 'skill' 'skill-sentry-instrumentation' 'small':42 'source-tortastudios' 'step':211,360 'stop':108 'str':265 'string':52,147 'suffix':442 'surfac':205,474 'system':57 'tag':25,155,236,262,269,385,446 'taxonomi':340,389,468 'test':494 'tool':80,113 'topic':417 'topic-agent-skills' 'topic-claude-skills' 'topic-codex-skill' 'topic-instrumentation' 'topic-monitoring' 'topic-observability' 'topic-sentry' 'topic-telemetry' 'track':38 'type':47 'typescript/javascript':308 'unit':234 'use':110,175,214,305,379 'valid':484 'valu':156,341 'version':242,441 'versus':28 'way':13 'workflow':210,394 'yourapp':370 'yourapp/middleware/observability.py':393 'yourapp/observability.py':382,407 'yourapp/services':396 'yourapp/services/providers/instrumented_http_client.py':401 'yourapp/services/retry.py':404 'yourapp/shared/failure_taxonomy.py':390 'yourapp/shared/fallback.py':409 'yourapp/shared/metric_tags.py':387 'yourapp/shared/metrics.py':384","prices":[{"id":"b4ef9f60-563f-4c5e-8997-e10be28c962d","listingId":"1774779a-ce8a-4ce6-a255-b716ffafbcbe","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"tortastudios","category":"sentry-instrumentation","install_from":"skills.sh"},"createdAt":"2026-04-19T00:40:49.261Z"}],"sources":[{"listingId":"1774779a-ce8a-4ce6-a255-b716ffafbcbe","source":"github","sourceId":"tortastudios/sentry-instrumentation","sourceUrl":"https://github.com/tortastudios/sentry-instrumentation","isPrimary":false,"firstSeenAt":"2026-04-19T00:40:49.261Z","lastSeenAt":"2026-05-18T19:06:50.213Z"}],"details":{"listingId":"1774779a-ce8a-4ce6-a255-b716ffafbcbe","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"tortastudios","slug":"sentry-instrumentation","github":{"repo":"tortastudios/sentry-instrumentation","stars":13,"topics":["agent-skills","claude-skills","codex-skill","instrumentation","monitoring","observability","sentry","telemetry"],"license":"mit","html_url":"https://github.com/tortastudios/sentry-instrumentation","pushed_at":"2026-04-24T23:47:09Z","description":"Sentry instrumentation skill for system-behavior tracking","skill_md_sha":"2f20c499b80189f082a8413d63d7846c4d9fa5d6","skill_md_path":"SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/tortastudios/sentry-instrumentation"},"layout":"root","source":"github","category":"sentry-instrumentation","frontmatter":{"name":"sentry-instrumentation","description":"Rules and examples for adding Sentry metrics the right way. Covers how to name a counter, gauge, or duration metric; which tags are safe versus which will blow up your Sentry bill; how to track failures with a small fixed list of error types instead of raw exception strings; and how to add metrics around HTTP routes, external API calls, workflow steps, retry loops, and fallback paths without copy-pasting emit calls everywhere. Ships a CI check that blocks bad metrics before merge. Use this when someone asks to \"instrument\" code, \"add a metric\", \"track duration\", \"count failures\", \"emit a counter/gauge/distribution\", \"add a span\", \"observe\" a workflow step, or add a route, external API client, retry loop, or fallback path. Python reference examples included; the same shapes work in any language."},"skills_sh_url":"https://skills.sh/tortastudios/sentry-instrumentation"},"updatedAt":"2026-05-18T19:06:50.213Z"}}