Synthèse automatique
Guide l'instrumentation de services TypeScript/Node.js et edge avec la bibliothèque autotel : wrappers trace/span, erreurs structurées, logger de requête et canonical log lines.
Points forts
- Donne des patrons d'API concrets pour trace()/span(), avec distinction entre factory (accès au ctx) et usage direct
- Propose une hiérarchie claire de gestion d'erreurs : lancer une erreur structurée, rattacher du contexte puis relancer, ou ctx.recordError()
- Couvre la rédaction d'attributs via init({ attributeRedactor }) et le verrouillage de l'initialisation avec lockLogger()
- Cible explicitement Node.js, Cloudflare Workers, Hono et Next.js
Limites
- Le contenu fourni est tronqué : la section request logger s'arrête au milieu d'un bloc de code
- Suppose une connaissance préalable de la bibliothèque autotel ; aucune installation ni configuration de backend OTLP n'est détaillée
- Les procédures détaillées vivent dans des fichiers references/ absents de cet extrait
À utiliser lorsqu'il faut ajouter du tracing ou du logging structuré à un handler Node.js/edge, ou relire du code pour y repérer des anti-patrons d'observabilité.
À éviter si le projet n'utilise pas TypeScript/autotel, ou s'il s'appuie sur un autre outil de télémétrie comme le SDK OpenTelemetry brut ou Sentry.
Analyse de sécurité
SûrThe skill is pure documentation for an observability/tracing library: prose, API reference tables, and illustrative TypeScript snippets. There are no shell one-liners, no network fetches, no credential handling, no obfuscated payloads, and no instructions aimed at the auditor. The only outbound data flow mentioned (OTLP export, subscriber drain callbacks) is the library's user-configured telemetry purpose, and the skill actively recommends PII redaction presets. Declared allowed-tools is empty, so no execution surface is granted.
Aucun point d'attention détecté
Comment cette analyse est faiteExemples
Review src/api/checkout.ts and convert the console.log calls into autotel wide events with a canonical log line per request.Add autotel createStructuredError with why, fix, and link fields to the error paths in the payment service.Set up autotel init() in our Cloudflare Worker with strict attribute redaction and lock the logger in the Hono plugin.name: autotel description: 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.
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' | 'strict' | 'pci-dss' }) or custom config) |
| 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:
- 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 atrace((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).
// 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 (via autotel/workers)
import { init, wrapModule, trace } from 'autotel/workers';
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() |
| 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 function | trace() wrapper handles lifecycle |
| Separate request ID generation | ctx.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:
init({
service: 'my-app',
endpoint: 'http://localhost:4318',
// traces: always on when endpoint is set
// metrics: true by default (AUTOTEL_METRICS env var override)
// logs: false by default — opt-in with logs: true (AUTOTEL_LOGS env var override)
logs: true, // enable auto OTLP log export
});
Disable any signal explicitly:
init({
service: 'my-app',
endpoint: 'http://localhost:4318',
metrics: false, // disable auto OTLP metrics
logs: false, // disable auto OTLP logs (already the default)
});
Custom logRecordProcessors are additive — they work alongside the auto-configured exporter:
init({
service: 'my-app',
endpoint: 'http://localhost:4318',
logRecordProcessors: [customProcessor], // added alongside auto-configured OTLP exporter
});
Protocol selection (http default, grpc optional) applies to all signals. gRPC exporters are optional peer deps.
Logger Locking
Framework plugins can lock init() to prevent re-initialization:
import { lockLogger, isLoggerLocked } from 'autotel';
lockLogger(); // After framework sets up instrumentation
isLoggerLocked(); // true
Silent Mode
Suppress internal autotel logs while keeping exporters running:
init({
service: 'my-app',
silent: true, // Suppress console output
minLevel: 'warn', // Only log warnings/errors
});
Attribute Redaction
Automatically redact PII from span attributes:
init({
service: 'my-app',
attributeRedactor: 'default', // 'default' | 'strict' | 'pci-dss'
});
default— Emails, phones, SSNs, credit cards (last 4), sensitive keysstrict— Plus JWTs, Bearer tokens, IBANs, API keyspci-dss— Focused on payment card data
Custom:
init({
attributeRedactor: {
keyPatterns: [/password/i, /secret/i],
valuePatterns: [{ name: 'customerId', pattern: /CUST-\d{8}/g, replacement: 'CUST-***' }],
builtins: ['email', 'creditCard'],
},
});
Sampling
Default: AdaptiveSampler with 10% baseline, 100% for errors and slow requests (>1s). Tail sampling via TailSamplingSpanProcessor defers the decision until span ends.
import { AdaptiveSampler } from 'autotel';
init({
service: 'my-app',
endpoint: 'http://localhost:4318',
sampler: new AdaptiveSampler({
baselineSampleRate: 0.1, // 10% of normal requests (default)
slowThresholdMs: 1000, // Requests > 1s are "slow" (default)
alwaysSampleErrors: true, // Always trace errors (default)
alwaysSampleSlow: true, // Always trace slow requests (default)
linksBased: false, // Enable for event-driven architectures
}),
});
The Sampler interface is simple — return true to trace, false to skip:
const sampler: Sampler = {
shouldSample({ operationName, args, links }) {
return operationName.startsWith('critical.');
},
};
Canonical Log Lines
init({
service: 'my-app',
canonicalLogLines: {
enabled: true,
rootSpansOnly: true,
keep: [{ status: 500 }, { durationMs: 1000 }],
pretty: true,
drain: (event) => sendToAnalytics(event),
},
});
MUST / SHOULD / NEVER
Init & Module Loading
- MUST: Keep
init()synchronous - MUST: Use
safeRequire/requireModulefrom./node-requirefor dynamic deps - NEVER: Use
await import()for optional/lazy dependencies
Tracing
- MUST: Use
trace(),span(),instrument()to wrap business logic - MUST: Use factory pattern
trace((ctx) => ...)when setting attributes - SHOULD: Let trace names infer from const/function names
- NEVER: Manually start/end spans for app logic (SDK glue only)
Errors & Events
- MUST: Throw
createStructuredError({ message, why, fix, link })instead ofnew Error(...)in app code — lettrace()record it on span exit - MUST: Use
ctx.recordError(err)from instrumentation/middleware code that wraps user handlers (orrecordStructuredError(ctx, err)if you don't have actxhandle) - SHOULD: Only catch errors when you need to attach call-site context, then
getRequestLogger(ctx).error(err, { step })and rethrow - SHOULD: Emit discrete events inside
trace()withctx.track('event.name', { ... })(or standalonetrack('event.name', { ... })outsidetrace()); emit wide-event attributes withgetRequestLogger(ctx).set({ ... }) - NEVER: Call
ctx.recordException(err)orctx.addEvent(...)— Span Event API is deprecated (OTEP 4430, March 2026) and intentionally type-gated out ofTraceContext - NEVER: Cast
ctx as anyoras unknown as { recordException }to bypass the type gate
Event Queue
- MUST: Call
getEventQueue()?.flush()before assertions or shutdown - MUST: Forward
options.autotelin subscriber payloads (contains trace context) - NEVER: Assert on event delivery without flush
Tree-Shaking & Repository
- MUST: Use explicit
exportsinpackage.jsonfor new entry points - MUST: Ask before adding new dependencies or modifying build configs
- MUST: Create changeset for any package changes (
pnpm changeset) - NEVER: Add barrel re-exports that pull in unused code
Package Layout
| Package | Role |
|---------|------|
| autotel | Node.js core: init, trace, span, track, event-queue, correlation-id. Also provides autotel/workers and autotel/cloudflare for Cloudflare Workers |
| autotel-genai | GenAI/LLM instrumentation: traceGenAI, cost, metrics, events, semconv, ai-sdk bridge, and agent governance (autotel-genai/agent) |
| autotel-edge | Edge runtime foundation (alternative to workers for vendor-agnostic edge) |
| autotel-cloudflare | Cloudflare Workers implementation (re-exported via autotel/workers) |
| autotel-adapters | Framework adapters (Next.js, Hono, Nitro) |
| autotel-mcp-instrumentation | MCP instrumentation |
| autotel-tanstack | TanStack Start |
| autotel-subscribers | Event subscribers (PostHog, Mixpanel, Webhook) |
Each package has a CLAUDE.md for local conventions.
Semantic Helpers
import { traceDB, traceHTTP, traceMessaging } from 'autotel/semantic-helpers';
import { traceGenAI, recordGenAiUsage } from 'autotel-genai/trace';
// GenAI helpers live in the autotel-genai package (not core autotel)
export const generateText = traceGenAI({
model: 'gpt-4-turbo', operation: 'chat', provider: 'openai',
})((ctx) => async (prompt) => {
const response = await openai.chat.completions.create({ /* ... */ });
recordGenAiUsage(ctx, 'gpt-4-turbo', {
inputTokens: response.usage.prompt_tokens,
outputTokens: response.usage.completion_tokens,
});
});
export const getUser = traceDB({
system: 'postgresql', operation: 'SELECT', collection: 'users',
})((ctx) => async (userId) => { /* ... */ });
Type-Safe Attributes
import { attrs, setUser, safeSetAttributes } from 'autotel/attributes';
ctx.setAttributes(attrs.user.id('user-123'));
setUser(ctx, { id: '123', email: 'user@example.com' });
safeSetAttributes(ctx, attrs.user.data({ email: 'pii@example.com' }), {
guardrails: { pii: 'hash' },
});
Producer/Consumer Pattern
import { traceProducer, traceConsumer } from 'autotel/messaging';
export const publish = traceProducer({
system: 'kafka', destination: 'user-events',
messageIdFrom: (args) => args[0].id,
})((ctx) => async (event) => {
const headers = ctx.getTraceHeaders();
await producer.send({ messages: [{ value: event, headers }] });
});
Quick Commands
pnpm build # Build all packages
pnpm test # Run all tests
pnpm lint # Lint
pnpm quality # build + lint + format + type-check + test
pnpm changeset # Create changeset for release
Testing
- Unit tests:
*.test.ts/ Integration tests:*.integration.test.ts - MUST flush before assertions:
await getEventQueue()?.flush(); - Use
SubscriberTestHarnessfor subscriber tests
Loading Reference Files
- Building error handling? Load structured-errors.md
- Adding request logging? Load request-logger.md
- Setting up wide events or querying? Load wide-events.md
- Reviewing existing code? Load code-review.md
Advanced Features
See docs/ADVANCED.md for deterministic trace IDs, metadata flattening, isolated tracer providers, safe baggage propagation, and workflow/saga tracing.
Du fichier au premier essai
Le téléchargement contient exactement le contenu affiché sur cette fiche. Cette copie peut différer de la dernière version du dépôt source.
Consulter la source et ses fichiers annexesCe téléchargement contient uniquement SKILL.md. Les scripts, références, modèles et dépendances éventuels ne sont pas inclus. Récupérez les fichiers nécessaires depuis la source en conservant leur arborescence avant de poursuivre.
1. Télécharger le fichier
Télécharger SKILL.mdDepuis la racine d’un projet de test, enregistrez le fichier sous .skill-downloads/instrumentation-with-autotel-mryiqihm/SKILL.md, ou utilisez la commande suivante. Ce dossier sert à examiner la skill avant son installation.
Commande pour macOS/Linux ou WSL : un shell POSIX et curl sont nécessaires. Sous Windows sans WSL, utilisez le bouton de téléchargement et créez le dossier manuellement.
mkdir -p '.skill-downloads/instrumentation-with-autotel-mryiqihm' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/instrumentation-with-autotel-mryiqihm/download' --output '.skill-downloads/instrumentation-with-autotel-mryiqihm/SKILL.md.part' && mv '.skill-downloads/instrumentation-with-autotel-mryiqihm/SKILL.md.part' '.skill-downloads/instrumentation-with-autotel-mryiqihm/SKILL.md'2. Vérifier les prérequis
Lisez SKILL.md avant de l’utiliser. Si le fichier cite des scripts ou services externes, examinez-les et préparez les accès nécessaires dans votre environnement de test.
Extrait original : 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) |
Les plateformes de la fiche sont des indications du catalogue. Les chemins ci-dessous suivent la documentation des outils ; ils ne prouvent pas que cette skill y a été exécutée. Aucune version minimale de ces outils n’est attestée pour cette fiche.
3. Charger la skill
Après vérification, copiez le dossier complet dans le projet avec l’une des commandes ci-dessous, puis ouvrez une nouvelle session de l’outil. La commande s’arrête si un dossier du même nom existe déjà : comparez les fichiers avant de le remplacer.
Claude Code
test -f '.skill-downloads/instrumentation-with-autotel-mryiqihm/SKILL.md' && test -s '.skill-downloads/instrumentation-with-autotel-mryiqihm/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/autotel' && cp -R '.skill-downloads/instrumentation-with-autotel-mryiqihm' '.claude/skills/autotel'Cursor
test -f '.skill-downloads/instrumentation-with-autotel-mryiqihm/SKILL.md' && test -s '.skill-downloads/instrumentation-with-autotel-mryiqihm/SKILL.md' && mkdir -p '.cursor/skills' && test ! -e '.cursor/skills/autotel' && cp -R '.skill-downloads/instrumentation-with-autotel-mryiqihm' '.cursor/skills/autotel'Codex
test -f '.skill-downloads/instrumentation-with-autotel-mryiqihm/SKILL.md' && test -s '.skill-downloads/instrumentation-with-autotel-mryiqihm/SKILL.md' && mkdir -p '.agents/skills' && test ! -e '.agents/skills/autotel' && cp -R '.skill-downloads/instrumentation-with-autotel-mryiqihm' '.agents/skills/autotel'OpenSkills
OpenSkills doit déjà être installé. La procédure locale install/read est contrôlée avec OpenSkills 1.5.0, qui exige Node.js ≥ 20.6.0. Aucun slug du catalogue n’est résolu automatiquement.
Installation officielle d’OpenSkillsopenskills install './.skill-downloads/instrumentation-with-autotel-mryiqihm'openskills read 'instrumentation-with-autotel-mryiqihm'La lecture doit afficher le contenu du fichier installé et son dossier de base. Elle ne lance ni la skill ni ses dépendances.
Pour un agent qui lit AGENTS.md, synchronisez ensuite l’index. Cette commande modifie AGENTS.md : relisez le diff avant de l’utiliser.
openskills syncMode manuel ou autre outil : joignez SKILL.md à une conversation, ou ouvrez-le dans un agent capable de lire les fichiers. Ajoutez les ressources annexes nécessaires. Il n’existe pas de dossier universel reconnu par tous les outils.
4. Faire un premier essai
Utilisez une entrée courte et fictive : un endpoint d’API, un petit document ou un brief d’interface. Dans une nouvelle conversation, joignez le fichier ou donnez son chemin à l’agent, puis adaptez cette demande :
Lis .skill-downloads/instrumentation-with-autotel-mryiqihm/SKILL.md et applique ses instructions à cet exemple : [décrire une entrée de test]. Indique les fichiers, dépendances ou accès qui manquent. Produis le résultat demandé par la skill sans inventer de données ni exécuter de script non examiné.Résultat attendu : une sortie correspondant aux instructions de la skill, ou une liste précise des prérequis manquants. Une simple confirmation de lecture ne valide pas le premier usage. Si une ressource externe est indisponible, ce parcours reste à tester.
Configurer un canal de discussion avec SecretRefs
DevOps
Configurez des canaux de discussion avec des commandes non interactives, les secrets étant uniquement des SecretRefs. Couvre les étapes de collecte, modification, réparation et vérification.
Enquêter sur les échecs CI de ClickHouse
DevOps
Investigue un échec CI de ClickHouse de bout en bout à partir d'une URL de PR ou de rapport S3. Récupère les tests échoués, classe flaky vs vraie régression, et cherche des issues/fixes existants.
Revue de PR Ansible
DevOps
Examine une PR Ansible selon le processus standardisé du projet, incluant la validation des changelogs, la couverture de tests et le suivi des commentaires.