Investigate and root-cause production issues from live OpenTelemetry telemetry (traces, logs, metrics) with the Kopai SDK in TypeScript code mode. Use this skill to debug errors and error-rate spikes, investigate latency/slowness and timeouts, trace requests across services, find failing or cascading services, and correlate logs to a trace — including vague symptom reports like 'why is my API slow', 'getting 500 errors', 'service is down', 'requests are timing out', or 'something is failing in prod', even when the user never says 'traces' or 'observability'. This analyzes existing telemetry to find a cause. Do NOT use it to add instrumentation (use otel-instrumentation), to build dashboards or visualizations (use create-dashboard), or to fix non-telemetry problems like failing CI, lint errors, unit tests, or SQL query tuning.
77
97%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
| title | impact | tags |
|---|---|---|
| Pattern: HTTP 500 Errors | HIGH | pattern, http, 500, errors |
Impact: HIGH
Diagnose HTTP 500 / internal server errors. Lead with an SDK script that ranks failing endpoints by error rate, then drill into one trace and correlate its error logs.
Run: npx tsx http-errors.mts. Assumes the SKILL.md bootstrap
(const client = clientFromConfig(), import { kq, KopaiQueryBuildError } from "@kopai/sdk").
1. Rank failing endpoints — errorRate counts "Error" spans server-side:
try {
const q = kq.traces
.aggregate()
.measure((m) => m.errorRate("error_rate"))
.measure((m) => m.count("n"))
.dimension("http.route")
.dimension("service.name")
.where((f) => f.eq("StatusCode", "Error")) // "Unset" | "Ok" | "Error"
.timeRelative("1h")
.summary()
.orderByMeasure("error_rate", "desc")
.build();
const { data } = await client.query(q); // typed rows
console.log(JSON.stringify(data, null, 2));
} catch (e) {
if (e instanceof KopaiQueryBuildError) console.error(e.issues);
else throw e;
}2. Narrow to a specific status code — http.response.status_code is the semconv
attribute (a number, not "http.status_code"):
.where((f) => f.eq("http.response.status_code", 500))Add .measure((m) => m.max("Duration", "max_ns")) to spot slow-and-failing routes
(Duration is nanoseconds: 1ms = 1e6, 1s = 1e9). Swap .summary() for
.timeSeries("5m") to see when the spike started.
3. Pull a failing trace — grab a TraceId from a failing route, then:
const spans = await client.getTrace(traceId); // inspect StatusMessage, Duration, ParentSpanId4. Correlate error logs to that trace (SeverityNumber >= 17, not SeverityText):
const logs = kq.logs
.raw()
.where((f) => f.eq("TraceId", traceId))
.where((f) => f.gte("SeverityNumber", 17))
.timeRelative("1h")
.build();
const { data } = await client.query(logs); // raw query → { data, nextCursor }For a known signature, body-substring instead: .where((f) => f.contains("Body", "connection refused")).
| Attribute | Purpose |
|---|---|
http.response.status_code | HTTP response code (number) |
http.route | Endpoint that failed |
exception.message | Error description |
exception.type | Exception class |
error.type | Error category / classification |
For a single lookup. Note the status value is the literal Error, and HTTP status is
the semconv attribute http.response.status_code:
npx @kopai/cli traces search --status-code Error --span-attr "http.response.status_code=500" --json
npx @kopai/cli traces get <traceId> --json
npx @kopai/cli logs search --trace-id <traceId> --severity-min 17 --json