[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6GYYR05MNXJ6FK300CQRPGX":3,"skill-same:01M6GYYR05MNXJ6FK300CQRPGX":77},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":16,"sourceHtmlUrl":17,"categories":18,"keywords":19,"publishedAt":35,"linkOnly":36,"markdownContent":37,"markdownBody":38,"frontMatter":39,"refName":40,"commitSha":41,"skillDirectory":42,"forksCount":43,"repositoryHtmlUrl":44,"repositoryHomepageUrl":6,"ownerHtmlUrl":45,"ownerBlogUrl":46,"ownerDescription":47,"updatedAt":48,"install":49,"resources":62},"01M6GYYR05MNXJ6FK300CQRPGX","instrument-a-service-with-otel-metrics",null,"Use when a service needs observable behaviour in production — adds RED and USE metrics via OpenTelemetry with bounded label cardinality and SLO-sized histogram buckets.","jiayaoqijia\u002Fcryptoskill","jiayaoqijia","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F1453879?v=4","01M6GMYTX7Q7S504VC6E756ENR","YQ","01M6GMYV1QKJ1CC75MTTGT9PR0",81,"MIT","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-instrument-a-service-with-otel-metrics\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-instrument-a-service-with-otel-metrics\u002FSKILL.md",[],[20,21,22,23,24,25,26,27,28,29,30,31,32,33,34],"otel","metrics","service","instrument","with","instrument a service with otel metrics","OpenTelemetry","Production","use","slo","red","histogram","via","bounded","when","2026-11-10 10:12:30",false,"---\nname: instrument-a-service-with-otel-metrics\ndescription: Use when a service needs observable behaviour in production — adds RED and USE metrics via OpenTelemetry with bounded label cardinality and SLO-sized histogram buckets.\n---\n\n# Instrument a service with OpenTelemetry metrics\n\nInstrument the request boundary for RED (Rate, Errors, Duration) and the host for USE (Utilisation, Saturation, Errors). Any series that is on neither a dashboard nor a paging alert is cost without benefit.\n\n## Procedure\n\n1. Pin the SDK version so instrument names are reproducible:\n       pip install 'opentelemetry-sdk==1.24.0' 'opentelemetry-exporter-otlp-proto-grpc==1.24.0'\n   Check `pip show opentelemetry-sdk` reports exactly that version before writing code.\n\n2. Define counters and histograms once at module import, not per request:\n       from opentelemetry import metrics\n       meter = metrics.get_meter(\"checkout\")\n       reqs = meter.create_counter(\"http.server.requests\")\n       dur = meter.create_histogram(\"http.server.duration.ms\", unit=\"ms\",\n           explicit_bucket_boundaries_advisory=[10,25,50,100,250,500,1000,2500])\n\n3. Time at the outermost middleware and label with bounded values — route template, method, status class:\n       route=\"\u002Forders\u002F{id}\"   # never \"\u002Forders\u002F8412\"\n\n4. Restrict label keys to `route`, `method`, `status_class`, `service`, `version`. Add a unit test asserting `set(metric.attributes) == ALLOWED` so a stray label is caught in CI.\n\n5. Set histogram buckets from the SLO, not from a tutorial default. If the SLO is p99 \u003C 500 ms, buckets must straddle 500 — `[10,25,50,100,250,500,1000,2500]` does, a seconds-scale default recording milliseconds does not.\n\n6. Export every 15 s over OTLP to the collector sidecar on `localhost:4317` using a batch reader; never export synchronously from the request path.\n\n7. Derive four alert rules from these series: error ratio > 1% for 5 min, p99 > SLO for 10 min, request rate drop > 50% vs 1 h ago, saturation (in-flight \u002F max concurrent) > 0.8.\n\n## Pitfalls\n\n- Labelling with the raw URL path: `\u002Forders\u002F8412` and `\u002Forders\u002F8413` become distinct series, cardinality explodes, and the TSDB OOMs.\n- Recording duration in seconds while the metric name and buckets are milliseconds — every observation lands in the last bucket and p99 reads as the bucket ceiling.\n- Timing inside the handler instead of around it, so time in deserialisation, TLS and queueing is invisible.\n- Using client-side summaries (quantiles computed in-process) instead of histograms; you cannot aggregate quantiles across pods or across time windows.\n\n## Verification\n\n    curl -s localhost:8889\u002Fmetrics | grep http_server_duration_ms_bucket | head\n    curl -s localhost:8889\u002Fmetrics | grep -c '^http_server_duration_ms_bucket'\n\nReport the boundary that was instrumented, that series count is unchanged after 10k requests (no per-request growth), and that the four alert rules load (`amtool check-config alerts.yml`).\n","# Instrument a service with OpenTelemetry metrics\n\nInstrument the request boundary for RED (Rate, Errors, Duration) and the host for USE (Utilisation, Saturation, Errors). Any series that is on neither a dashboard nor a paging alert is cost without benefit.\n\n## Procedure\n\n1. Pin the SDK version so instrument names are reproducible:\n       pip install 'opentelemetry-sdk==1.24.0' 'opentelemetry-exporter-otlp-proto-grpc==1.24.0'\n   Check `pip show opentelemetry-sdk` reports exactly that version before writing code.\n\n2. Define counters and histograms once at module import, not per request:\n       from opentelemetry import metrics\n       meter = metrics.get_meter(\"checkout\")\n       reqs = meter.create_counter(\"http.server.requests\")\n       dur = meter.create_histogram(\"http.server.duration.ms\", unit=\"ms\",\n           explicit_bucket_boundaries_advisory=[10,25,50,100,250,500,1000,2500])\n\n3. Time at the outermost middleware and label with bounded values — route template, method, status class:\n       route=\"\u002Forders\u002F{id}\"   # never \"\u002Forders\u002F8412\"\n\n4. Restrict label keys to `route`, `method`, `status_class`, `service`, `version`. Add a unit test asserting `set(metric.attributes) == ALLOWED` so a stray label is caught in CI.\n\n5. Set histogram buckets from the SLO, not from a tutorial default. If the SLO is p99 \u003C 500 ms, buckets must straddle 500 — `[10,25,50,100,250,500,1000,2500]` does, a seconds-scale default recording milliseconds does not.\n\n6. Export every 15 s over OTLP to the collector sidecar on `localhost:4317` using a batch reader; never export synchronously from the request path.\n\n7. Derive four alert rules from these series: error ratio > 1% for 5 min, p99 > SLO for 10 min, request rate drop > 50% vs 1 h ago, saturation (in-flight \u002F max concurrent) > 0.8.\n\n## Pitfalls\n\n- Labelling with the raw URL path: `\u002Forders\u002F8412` and `\u002Forders\u002F8413` become distinct series, cardinality explodes, and the TSDB OOMs.\n- Recording duration in seconds while the metric name and buckets are milliseconds — every observation lands in the last bucket and p99 reads as the bucket ceiling.\n- Timing inside the handler instead of around it, so time in deserialisation, TLS and queueing is invisible.\n- Using client-side summaries (quantiles computed in-process) instead of histograms; you cannot aggregate quantiles across pods or across time windows.\n\n## Verification\n\n    curl -s localhost:8889\u002Fmetrics | grep http_server_duration_ms_bucket | head\n    curl -s localhost:8889\u002Fmetrics | grep -c '^http_server_duration_ms_bucket'\n\nReport the boundary that was instrumented, that series count is unchanged after 10k requests (no per-request growth), and that the four alert rules load (`amtool check-config alerts.yml`).\n",{"name":5,"description":7},"main","3df1d0d67b30ff15236561f8c0f9f06d33f42dfd","skills\u002Fpayments\u002F0xklen-instrument-a-service-with-otel-metrics",17,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia","https:\u002F\u002Feth2030.com","Hardcore infra. Building @alt-research and applied cryptography.","2026-11-12 02:28:42",{"source":8,"skillName":5,"commands":50,"prompt":60,"zipAvailable":61},[51,54,57],{"tool":52,"command":53},"npx","npx skills add jiayaoqijia\u002Fcryptoskill --skill instrument-a-service-with-otel-metrics",{"tool":55,"command":56},"bunx","bunx skills add jiayaoqijia\u002Fcryptoskill --skill instrument-a-service-with-otel-metrics",{"tool":58,"command":59},"pnpm","pnpm dlx skills add jiayaoqijia\u002Fcryptoskill --skill instrument-a-service-with-otel-metrics","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-instrument-a-service-with-otel-metrics\u002FSKILL.md",true,[63,67,73],{"path":64,"resourceType":64,"resourceTypeDesc":65,"sizeBytes":66,"sourceHtmlUrl":16},"LICENSE","许可证",1063,{"path":68,"resourceType":69,"resourceTypeDesc":70,"sizeBytes":71,"sourceHtmlUrl":72},"SOURCE.md","REFERENCE","参考文档",364,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-instrument-a-service-with-otel-metrics\u002FSOURCE.md",{"path":74,"resourceType":69,"resourceTypeDesc":70,"sizeBytes":75,"sourceHtmlUrl":76},"TRUST.auto.yaml",2141,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-instrument-a-service-with-otel-metrics\u002FTRUST.auto.yaml",[78,106,129,147,160,170],{"skillNo":79,"name":80,"nameZh":6,"description":81,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":82,"sourceHtmlUrl":83,"categories":84,"keywords":85,"publishedAt":35},"01M712C436EQYE43342Q4E7GG1","recipe-performance","Diagnose a specific MetaMask user flow's real-app performance and Sentry critical-user-flow telemetry with deterministic mm-harness recipes. Use for CUF boundaries, cold\u002Fwarm\u002Fbackground-resume behavior, latency regressions, lifecycle tags, duplicate or blocking network requests, long tasks, layout\u002Fpaint cost, screen redraws, React rerenders, or browser trace analysis where tests alone cannot prove the real app.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fwallets\u002Fmetamask-official-recipe-performance\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fwallets\u002Fmetamask-official-recipe-performance\u002FSKILL.md",[],[86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105],"performance","recipe performance","recipe","mm","sentry","harness","app","deterministic","recipes","flow","cold","critical","analysis","tasks","react","browser","layout","screen","network","metamask",{"skillNo":107,"name":108,"nameZh":6,"description":109,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":110,"licenseFileUrl":111,"sourceHtmlUrl":112,"categories":113,"keywords":114,"publishedAt":35},"01M70XT2F8A5CQZ81JBP98KSW3","mexc-spot-websocket","MEXC Spot WebSocket workflows for public streams, protobuf handling, depth maintenance, listen keys, and private streams without exposing API keys.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-websocket\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-websocket\u002FSKILL.md",[],[115,116,117,118,119,120,121,122,123,124,125,126,127,128],"mexc spot websocket","spot","websocket","api","workflows","public","listen","streams","depth","keys","for","api keys","maintenance","protobuf",{"skillNo":130,"name":131,"nameZh":6,"description":132,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":110,"licenseFileUrl":133,"sourceHtmlUrl":134,"categories":135,"keywords":136,"publishedAt":35},"01M70XT0MBXN3WZY1BKN0CPNKR","mexc-spot-rest","MEXC Spot REST workflows for public data, signed account requests, orders, wallet\u002Fadmin actions, and secure signing without exposing API keys.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-rest\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-rest\u002FSKILL.md",[],[137,116,138,139,140,141,142,126,125,124,143,144,145,120,146,119,118],"mexc spot rest","REST","admin","signing","Wallet","requests","actions","secure","data","orders",{"skillNo":148,"name":149,"nameZh":6,"description":150,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":110,"licenseFileUrl":151,"sourceHtmlUrl":152,"categories":153,"keywords":154,"publishedAt":35},"01M70XSYSVZ2N0N91XCAR2CAK0","mexc-futures-websocket","MEXC Futures WebSocket workflows for public streams, private account\u002Forder\u002Fposition streams, ping\u002Fpong, subscriptions, and depth maintenance.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-futures-websocket\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-futures-websocket\u002FSKILL.md",[],[155,156,117,157,158,127,125,159,123,122,120,119],"mexc futures websocket","futures","position","ping","subscriptions",{"skillNo":161,"name":162,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":163,"sourceHtmlUrl":164,"categories":165,"keywords":166,"publishedAt":35},"01M6H0ZWHVE5W04WG2DKQE2SQC","0xklen-version-and-refresh-sanctions-lists","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-version-and-refresh-sanctions-lists\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-version-and-refresh-sanctions-lists\u002FSKILL.md",[],[167,168,169],"refresh","0xklen version and refresh sanctions lists","version",{"skillNo":171,"name":172,"nameZh":6,"description":173,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":174,"sourceHtmlUrl":175,"categories":176,"keywords":177,"publishedAt":35},"01M6H0Z28Q3R8J0S799GJQWXM3","verify-tests-cover-changed-lines","Use when a PR adds code that the existing suite may not exercise. Measures patch coverage — the share of newly changed lines hit by tests — before approving.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-verify-tests-cover-changed-lines\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-verify-tests-cover-changed-lines\u002FSKILL.md",[],[178,179,180,181,182,183,184,28,185,186,187],"tests","cover","verify tests cover changed lines","verify","coverage","pr","exercise","patch","code","share"]