Claude-skill-registry axiom
Implements structured logging and observability with Axiom for serverless applications. Use when adding logging, tracing, and Web Vitals monitoring to Next.js and Vercel applications.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/axiom" ~/.claude/skills/majiayu000-claude-skill-registry-axiom && rm -rf "$T"
manifest:
skills/data/axiom/SKILL.mdsource content
Axiom
Observability platform for logs, metrics, and traces. Native Vercel integration with structured logging for Next.js applications.
Quick Start
npm install @axiomhq/js @axiomhq/logging @axiomhq/nextjs @axiomhq/react
Next.js Setup (2025 API)
Create Axiom Client
// lib/axiom/client.ts import { Axiom } from '@axiomhq/js'; export const axiom = new Axiom({ token: process.env.AXIOM_TOKEN!, orgId: process.env.AXIOM_ORG_ID, });
Create Logger
// lib/axiom/logger.ts import { Logger, ConsoleTransport, AxiomJSTransport } from '@axiomhq/logging'; import { nextJsFormatters } from '@axiomhq/nextjs'; import { axiom } from './client'; export const logger = new Logger({ transports: [ new AxiomJSTransport({ axiom, dataset: process.env.AXIOM_DATASET!, }), new ConsoleTransport(), ], formatters: nextJsFormatters, });
Create Route Handler
// lib/axiom/route.ts import { createAxiomRouteHandler } from '@axiomhq/nextjs'; import { axiom } from './client'; import { logger } from './logger'; export const axiomRouteHandler = createAxiomRouteHandler({ axiom, logger, dataset: process.env.AXIOM_DATASET!, });
API Route Handler
// app/api/axiom/route.ts import { axiomRouteHandler } from '@/lib/axiom/route'; export const POST = axiomRouteHandler;
Logging
Server Components
// app/page.tsx import { logger } from '@/lib/axiom/logger'; export default async function Page() { logger.info('Page rendered', { page: 'home' }); try { const data = await fetchData(); logger.debug('Data fetched', { count: data.length }); return <div>{/* render */}</div>; } catch (error) { logger.error('Failed to fetch data', { error }); throw error; } finally { await logger.flush(); } }
API Routes
// app/api/users/route.ts import { NextRequest, NextResponse } from 'next/server'; import { logger } from '@/lib/axiom/logger'; export async function POST(request: NextRequest) { const body = await request.json(); logger.info('Creating user', { email: body.email, source: request.headers.get('referer'), }); try { const user = await createUser(body); logger.info('User created', { userId: user.id }); return NextResponse.json(user); } catch (error) { logger.error('User creation failed', { error: error instanceof Error ? error.message : 'Unknown error', email: body.email, }); return NextResponse.json({ error: 'Failed' }, { status: 500 }); } finally { await logger.flush(); } }
Middleware
// middleware.ts import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; import { logger } from '@/lib/axiom/logger'; export async function middleware(request: NextRequest) { const start = Date.now(); logger.info('Request started', { path: request.nextUrl.pathname, method: request.method, }); const response = NextResponse.next(); logger.info('Request completed', { path: request.nextUrl.pathname, duration: Date.now() - start, }); await logger.flush(); return response; }
Client-Side Logging
// app/providers.tsx 'use client'; import { AxiomWebVitals } from '@axiomhq/react'; export function Providers({ children }: { children: React.ReactNode }) { return ( <> <AxiomWebVitals /> {children} </> ); }
Client Logger (Proxy Method)
Send logs through your API to avoid exposing tokens:
// lib/axiom/client-logger.ts class ClientLogger { private queue: Array<{ level: string; message: string; data?: object }> = []; log(level: string, message: string, data?: object) { this.queue.push({ level, message, data }); } info(message: string, data?: object) { this.log('info', message, data); } error(message: string, data?: object) { this.log('error', message, data); } async flush() { if (this.queue.length === 0) return; const logs = [...this.queue]; this.queue = []; await fetch('/api/axiom', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ logs }), }); } } export const clientLogger = new ClientLogger();
Client Component Usage
'use client'; import { useEffect } from 'react'; import { clientLogger } from '@/lib/axiom/client-logger'; export function TrackableButton() { const handleClick = () => { clientLogger.info('Button clicked', { buttonId: 'cta' }); clientLogger.flush(); }; useEffect(() => { clientLogger.info('Component mounted'); return () => { clientLogger.info('Component unmounted'); clientLogger.flush(); }; }, []); return <button onClick={handleClick}>Click me</button>; }
Web Vitals
Automatic Core Web Vitals tracking:
// app/layout.tsx import { AxiomWebVitals } from '@axiomhq/react'; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body> <AxiomWebVitals /> {children} </body> </html> ); }
Legacy API (next-axiom)
The older
next-axiom package is still supported:
npm install next-axiom
Setup
// next.config.js const { withAxiom } = require('next-axiom'); module.exports = withAxiom({ // your next config });
Server Component Logging
import { Logger } from 'next-axiom'; export default async function Page() { const log = new Logger(); log.info('Page rendered'); await log.flush(); return <div>Content</div>; }
Client Component Logging
'use client'; import { useLogger } from 'next-axiom'; export function ClientComponent() { const log = useLogger(); const handleClick = () => { log.info('Button clicked'); }; return <button onClick={handleClick}>Click</button>; }
Structured Logging Patterns
Request Context
function createRequestLogger(request: NextRequest) { return { info: (message: string, data?: object) => { logger.info(message, { ...data, requestId: request.headers.get('x-request-id'), path: request.nextUrl.pathname, method: request.method, userAgent: request.headers.get('user-agent'), }); }, error: (message: string, data?: object) => { logger.error(message, { ...data, requestId: request.headers.get('x-request-id'), path: request.nextUrl.pathname, }); }, }; }
Timing
async function withTiming<T>( name: string, fn: () => Promise<T> ): Promise<T> { const start = Date.now(); try { const result = await fn(); logger.info(`${name} completed`, { duration: Date.now() - start, success: true, }); return result; } catch (error) { logger.error(`${name} failed`, { duration: Date.now() - start, error: error instanceof Error ? error.message : 'Unknown', }); throw error; } } // Usage const users = await withTiming('fetchUsers', () => db.user.findMany());
Error Logging
function logError(error: unknown, context?: object) { if (error instanceof Error) { logger.error(error.message, { ...context, name: error.name, stack: error.stack, cause: error.cause, }); } else { logger.error('Unknown error', { ...context, error: String(error), }); } }
Vercel Integration
Enable the Axiom integration in Vercel for automatic log drains:
- Go to Vercel Dashboard > Integrations
- Install Axiom integration
- Connect your Axiom organization
- Logs from
,console.log
, etc. are automatically sentconsole.error
Environment Variables
AXIOM_TOKEN=xaat-xxxxxxxx AXIOM_ORG_ID=your-org-id AXIOM_DATASET=your-dataset # For next-axiom NEXT_PUBLIC_AXIOM_INGEST_ENDPOINT=https://api.axiom.co/v1/datasets/your-dataset/ingest
Query Examples (APL)
// Recent errors dataset | where level == "error" | order by _time desc | limit 100 // Request latency by path dataset | where message == "Request completed" | summarize avg(duration), p95(duration), count() by path | order by count_ desc // Errors by type dataset | where level == "error" | summarize count() by ['error.name'] | order by count_ desc
Best Practices
- Flush before returning - Always call flush() in server components
- Use structured data - Pass objects, not strings
- Add request context - Include requestId, path, method
- Log at appropriate levels - debug, info, warn, error
- Proxy client logs - Don't expose tokens to browser
- Use Vercel integration - For automatic console.log capture
- Add timing - Track duration for performance monitoring