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.zip

Installs 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.
273 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Intermediate

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

You give it
Code to instrument, functions to trace, or errors to structure
You get back
Instrumented code with traces, structured errors, and accumulated request context

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.error for 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

TaskReference
Convert console.log to wide eventswide-events.md
Add structured errorsstructured-errors.md
Accumulate request contextrequest-logger.md
Review code for anti-patternscode-review.md
Add attribute redaction(use `init({ attributeRedactor: 'default'
Lock init from re-initialization(use lockLogger() in framework plugins)

Tracing API

import { trace, span } from 'autotel';

// Factory pattern (receives ctx for attributes)
export const createUser = trace((ctx) => async (data) => {
  ctx.setAttribute('user.id', data.id);
  return await db.users.create(data);
});

// Direct pattern (no ctx needed)
export const getUser = trace(async (id) => {
  return await db.users.findById(id);
});

// Nested span
span('db.insert', async () => {
  await db.insert(record);
});

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((ctx) => 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:

  1. Attach call-site context, then rethrow: getRequestLogger(ctx).error(err, { step }). Use when the rethrown error needs context only known at the catch site.
  2. Writing instrumentation/middleware that wraps user handlers: ctx.recordError(err) from inside a trace((ctx) => ...) callback. Sets ERROR status, structured error.* attributes, and (during the back-compat window) records the exception. Accepts unknown so no as Error cast is needed in catch blocks. For code that doesn't have a ctx handle, use the standalone form recordStructuredError(ctx, err).
// Inside a trace() callback — instrumentation wrapping a user handler:
return trace({ 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';

export const handleOrder = trace((ctx) => async (req) => {
  const log = getRequestLogger(ctx);
  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, getEventQueue } from 'autotel';

// Inside trace() — use ctx.track for ergonomic, ctx-bound emission:
export const signup = trace((ctx) => 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();

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-PatternFix
console.log('user created', userId)log.set({ user_id: userId }) inside trace()
catch (e) { throw e }Delete the catch: trace() records errors automatically. Or log.error(e, { step }); throw e to attach call-site context
catch (e) { res.json({ error: e.message }) }parseError(e) for consistent shape
throw new Error('Payment failed')createStructuredError({ message, why, fix, link })
ctx.recordException(err) / span.recordException(err)App code: throw createStructuredError(...). Instrumentation: ctx.recordError(err) (or recordStructuredError(ctx, err) if you don't have a ctx handle). Span Event API is deprecated (OTEP 4430) and type-gated out of TraceContext
ctx.addEvent('name', { ... }) / span.addEvent(...)Discrete event inside trace(): ctx.track('event.name', { ... }) (or standalone track('event.name', { ... }) when there's no ctx handle). Wide-event attribute: getRequestLogger(ctx).set({ ... })
(ctx as any).recordException(err) / as unknown as { recordException }Don't bypass the type gate: use recordStructuredError(ctx, err) instead
Manual console.log at start/end of functiontrace() wrapper handles lifecycle
Separate request ID generationctx.correlationId provides automatic correlation

init() Configuration

Signals: Traces, Metrics, Logs

When endpoint is set, traces and metrics are auto-configured by default. Logs are opt-in to avoid unexpected export and preserve OTel SDK OTEL_LOGS_EXPORTER handling:

in

---

*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.

SkillInstallsUpdatedSafetyDifficulty
autotel (this skill)01moReviewIntermediate
ai-debug-harness03moReviewAdvanced
gcloud-usage17moNo flagsIntermediate
devops-troubleshooter14moNo flagsAdvanced

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

Search skills

Search the agent skills registry