autotel
Instruments applications with tracing and structured logging for comprehensive observability.
Install
mkdir -p .claude/skills/autotel && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/12000" && unzip -o skill.zip -d .claude/skills/autotel && rm skill.zipInstalls to .claude/skills/autotel
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Use when instrumenting with trace/span/track, reviewing code for logging and observability patterns, converting console.log to wide events, adding structured errors, setting up canonical log lines, configuring init(), adding subscribers, or working in the autotel monorepo.Key capabilities
- →Instrument functions with tracing using `trace()`
- →Add structured errors with `createStructuredError()`
- →Accumulate request context using `getRequestLogger()`
- →Track events using `ctx.track` or standalone `track()`
How it works
The skill provides APIs like `trace()` to wrap functions, `createStructuredError()` to add context to errors, and `getRequestLogger()` to accumulate request-specific attributes, all contributing to observability.
Inputs & outputs
When to use autotel
- →Adding tracing to functions
- →Converting console.log to wide events
- →Improving error observability
About this skill
Autotel
Philosophy: "Write once, observe everywhere" - instrument once, stream to any OTLP-compatible backend.
trace() wraps functions. getRequestLogger() accumulates context. createStructuredError() adds why/fix/link to errors. Canonical log lines emit one wide event per request automatically.
When to Use
- Instrumenting functions with tracing
- Code uses
console.log/console.errorfor observability - Error handling lacks structured context (no why, fix, or link)
- Adding tracing to any Node.js or edge runtime handler
- Reviewing code for observability anti-patterns
- Setting up observability in Cloudflare Workers, Hono, or Next.js
- Working in the autotel monorepo
Quick Reference
| Task | Reference |
|---|---|
| Convert console.log to wide events | wide-events.md |
| Add structured errors | structured-errors.md |
| Accumulate request context | request-logger.md |
| Review code for anti-patterns | code-review.md |
| Add attribute redaction | (use `init({ attributeRedactor: 'default' |
| Lock init from re-initialization | (use lockLogger() in framework plugins) |
Tracing API
import { trace, ctx, span } from 'autotel';
// trace(name, fn) wraps a reusable function under a stable span name
export const createUser = trace('user.create', async (data) => {
// The ambient ctx reads the active span from anywhere inside a traced body
ctx.setAttribute('user.id', data.id);
return await db.users.create(data);
});
// trace(fn) infers the name from the function or const
export const getUser = trace(async (id) => {
return await db.users.findById(id);
});
// Nested span
span('db.insert', async () => {
await db.insert(record);
});
ctx is a live view of the active span, not a value captured at import time.
Read it inside a traced body and it answers from that span. With nothing traced
- an uninstrumented test run, or a plain
node server.js-ctx.traceIdreadsundefinedand the methods no-op, so instrumentation is never what throws.
Attribute values can be as rich as the data: an object, Map, Set or Date
is flattened to dot-notation keys, so ctx.setAttribute('user', user) records
user.id, user.plan. Never flatten by hand before the call.
requestCtx is the same ambient view aimed at the request span. Framework
instrumentation opens a span per middleware and per route handler, so context
describing the whole request - the authenticated user, the tenant, the plan -
set from a shared middleware belongs there rather than on a layer span that ends
at next():
import { ctx, requestCtx } from 'autotel';
app.use((req, _res, next) => {
requestCtx.setAttributes({ user: req.user }); // on GET /users/:id
ctx.setAttribute('auth.cache_hit', cached); // on the middleware's own span
next();
});
withTracing({ name })((ctx) => fn) hands the context in as an argument
instead. Both forms are supported: prefer the ambient ctx in application
code, and the factory when a wrapper needs an explicit context handle.
Recording Errors
Default: throw, don't catch. trace() records status, exception, and structured attributes when the wrapped function rejects.
import { trace, createStructuredError } from 'autotel';
export const charge = trace('cart.charge', async (cart) => {
if (!cart.items.length) {
throw createStructuredError({
message: 'Cart is empty',
why: 'User submitted checkout with no items',
fix: 'Validate cart on the client before submit',
link: 'https://docs.example.com/errors/empty-cart',
});
}
return await processCart(cart);
});
Fallbacks, in order:
- Attach call-site context, then rethrow:
getRequestLogger(ctx).error(err, { step }). Use when the rethrown error needs context only known at the catch site. - Writing instrumentation/middleware that wraps user handlers:
ctx.recordError(err)from inside awithTracing({})((ctx) => ...)callback. Sets ERROR status, structurederror.*attributes, and (during the back-compat window) records the exception. Acceptsunknownso noas Errorcast is needed in catch blocks. For code that doesn't have actxhandle, use the standalone formrecordStructuredError(ctx, err).
// Instrumentation wrapping a user handler. trace.run() is the immediate form:
// it runs now and hands the callback the span's ctx. trace(name, fn) returns a
// wrapper instead, and passes fn the caller's arguments, never a ctx.
return trace.run(name, async (ctx) => {
try {
return await userHandler(args);
} catch (err) {
ctx.recordError(err); // ergonomic replacement for ctx.recordException
throw err;
}
});
ctx.recordException(...) and ctx.addEvent(...) are intentionally hidden from the TraceContext type per OTEP 4430 (March 2026. Span Event API deprecation). The runtime methods exist for back-compat only; new code MUST go through createStructuredError, ctx.recordError(err) / recordStructuredError(ctx, err), or the request logger.
Request Logger
import { trace, getRequestLogger } from 'autotel';
// getRequestLogger() with no args reads the active span
export const handleOrder = trace('order.handle', async (req) => {
const log = getRequestLogger();
log.set({ feature: 'checkout', tier: req.user.tier });
const cart = await loadCart(req.cartId);
log.set({ cart_items: cart.items.length, cart_total: cart.total });
try {
const payment = await processPayment(cart);
log.set({ payment_method: payment.method });
} catch (error) {
// Fallback pattern: attach call-site context, then rethrow.
// Default is to let the error propagate and let trace() record it.
log.error(error, { step: 'payment' });
throw error;
}
});
Event Tracking
import { trace, ctx, getEventQueue } from 'autotel';
// Inside a traced body — use ctx.track for ergonomic, ctx-bound emission:
export const signup = trace('user.signup', async (data) => {
ctx.track('user.signup', { userId: data.id, plan: data.plan });
return await db.users.create(data);
});
// Outside trace() — use the standalone track():
import { track } from 'autotel';
track('user.signup', { userId: '123', plan: 'pro' });
// MUST flush before assertions or shutdown
await getEventQueue()?.flush();
Experiments and Cohorts
import { experiment, getRequestLogger, trace } from 'autotel';
import { bucket } from 'autotel/analysis';
export const checkout = trace('checkout', async (order) => {
// Names the guess: stamps experiment.name / .variant / .expectation on the
// active span and puts the first two in baggage, so child spans and the
// services behind this one carry the same answer.
experiment({
name: 'checkout-cache',
variant: useCache ? 'cached' : 'direct',
expect: 'cached should cut p95 by 200ms',
});
// compareCohorts skips fields whose values never repeat, so bucket numbers
// at instrumentation time. Non-finite values give 'unknown'.
getRequestLogger().set({
'payload.size_bucket': bucket(order.bytes, [1024, 65_536]),
});
return submitOrder(order);
});
experiment() is ambient: call it at any depth inside a traced body, and it
no-ops when nothing is being traced. Bare baggage keys need
init({ baggage: '' }); baggage: true prefixes them. Devtools Compare then
offers the experiment's arms instead of asking the reader to know them.
Correlation ID
import { getOrCreateCorrelationId, runWithCorrelationId } from 'autotel';
const correlationId = getOrCreateCorrelationId();
runWithCorrelationId(incomingId, () => handleRequest());
Framework Adapters
// Cloudflare Workers
import { init, wrapModule, trace } from 'autotel-cloudflare';
const processOrder = trace(async (orderId: string, kv: KVNamespace) => {
return await kv.get(orderId);
});
export default wrapModule(
{ service: { name: 'my-worker' } },
{
async fetch(_req, env) {
return Response.json(await processOrder('123', env.ORDERS_KV));
},
},
);
// Next.js
import { withAutotel, useLogger } from 'autotel-adapters/next';
export const POST = withAutotel(async (request) => {
const log = useLogger(request);
log.set({ feature: 'checkout' });
return Response.json({ ok: true });
});
// Hono (with autotel-hono middleware already creating spans)
import { useLogger } from 'autotel-adapters/hono';
app.get('/orders/:id', (c) => {
const log = useLogger(c);
log.set({ route: c.req.path });
return c.json({ ok: true });
});
Anti-Patterns to Detect
| Anti-Pattern | Fix |
|---|---|
console.log('user created', userId) | log.set({ user_id: userId }) inside trace() |
Content truncated.
When not to use it
- →When the user wants to use `ctx.recordException` or `ctx.addEvent` for new code
- →When the user wants to hand-build log lines from string interpolation
- →When the user wants to use `console.log` for observability
Limitations
- →New code must use `createStructuredError`, `ctx.recordError(err)`, or the request logger
- →`ctx.recordException` and `ctx.addEvent` are hidden from `TraceContext` type
- →Requires flushing event queue before assertions or shutdown
How it compares
This skill implements a 'write once, observe everywhere' philosophy by providing a unified instrumentation framework for tracing, structured errors, and context accumulation, enabling streaming to any OTLP-compatible backend.
Compared to similar skills
autotel side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| autotel (this skill) | 0 | 3mo | Review | Intermediate |
| ai-debug-harness | 0 | 5mo | Review | Advanced |
| gcloud-usage | 1 | 9mo | No flags | Intermediate |
| devops-troubleshooter | 1 | 5mo | No flags | Advanced |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
ai-debug-harness
DeandreFu
Self-driving Electron + Node debug harness with NDJSON logs, Playwright E2E, doctor preflight, and a YAML-frontmatter cookbook of known causes. Use when a voice-chat E2E flow misbehaves locally, audio publish silently fails, the agent worker emits warnings, or any LiveKit/Electron/Fastify error appe
gcloud-usage
fcakyon
This skill should be used when user asks about "GCloud logs", "Cloud Logging queries", "Google Cloud metrics", "GCP observability", "trace analysis", or "debugging production issues on GCP".
devops-troubleshooter
sickn33
Expert DevOps troubleshooter specializing in rapid incident response, advanced debugging, and modern observability. Masters log analysis, distributed tracing, Kubernetes debugging, performance optimization, and root cause analysis. Handles production outages, system reliability, and preventive monitoring. Use PROACTIVELY for debugging, incident response, or system troubleshooting.
analyze-prod-issue
MaxPayne89
>-
service-mesh-observability
wshobson
Implement comprehensive observability for service meshes including distributed tracing, metrics, and visualization. Use when setting up mesh monitoring, debugging latency issues, or implementing SLOs for service communication.
observability-monitoring-monitor-setup
sickn33
You are a monitoring and observability expert specializing in implementing comprehensive monitoring solutions. Set up metrics collection, distributed tracing, log aggregation, and create insightful da