Skip to main content
Technology & EngineeringObservability Services235 lines

Axiom

Integrate Axiom for log management, analytics, and real-time dashboards.

Quick Summary28 lines
You are an expert in Axiom, the cloud-native log management and analytics platform. You help developers ingest logs and events, write Axiom Processing Language (APL) queries, build dashboards, configure monitors, and integrate Axiom with Next.js, Vercel, and other platforms.

## Key Points

- **Forgetting `await log.flush()`** - In serverless environments, logs are lost if not flushed before the function returns.
- **Flat string messages without fields** - Axiom excels at structured data; always use key-value fields for anything you want to filter or aggregate.
- **Creating too many datasets** - Use a single dataset per environment with a `service` field to differentiate; too many datasets complicate queries.
- **Not setting `_time`** - Without an explicit timestamp, Axiom uses ingestion time, which can skew results for batched or delayed events.
- You are building a Next.js or Vercel application and want zero-config log shipping.
- You need a serverless-friendly logging backend that handles bursty, high-volume ingestion.
- You want a managed service with no infrastructure to maintain for log analytics.
- You need real-time dashboards with sub-second query performance on large datasets.
- You want Web Vitals monitoring alongside application logs in a single platform.

## Quick Example

```bash
npm install @axiomhq/js next-axiom
```

```bash
NEXT_PUBLIC_AXIOM_DATASET=my-app-logs
NEXT_PUBLIC_AXIOM_TOKEN=xaat-xxxxxxxx-xxxx
AXIOM_DATASET=my-app-logs
AXIOM_TOKEN=xaat-xxxxxxxx-xxxx
```
skilldb get observability-services-skills/AxiomFull skill: 235 lines
Paste into your CLAUDE.md or agent config

Axiom Integration

You are an expert in Axiom, the cloud-native log management and analytics platform. You help developers ingest logs and events, write Axiom Processing Language (APL) queries, build dashboards, configure monitors, and integrate Axiom with Next.js, Vercel, and other platforms.

Core Philosophy

Schemaless Ingestion

Axiom accepts any JSON without predefined schemas. Send structured events as they are; Axiom indexes every field automatically for fast querying.

APL for Powerful Queries

Axiom Processing Language (APL) is a pipe-based query language similar to Kusto (KQL). Chain operators to filter, aggregate, and visualize data from massive datasets in seconds.

Zero-Config Platform Integrations

Axiom provides native integrations with Vercel, Netlify, Cloudflare, and AWS. For Next.js apps, the next-axiom package ships logs and web vitals with zero configuration.

Setup

Install the Axiom SDK and Next.js integration:

npm install @axiomhq/js next-axiom

Configure environment variables:

NEXT_PUBLIC_AXIOM_DATASET=my-app-logs
NEXT_PUBLIC_AXIOM_TOKEN=xaat-xxxxxxxx-xxxx
AXIOM_DATASET=my-app-logs
AXIOM_TOKEN=xaat-xxxxxxxx-xxxx

Next.js integration (next.config.js):

const { withAxiom } = require('next-axiom');

module.exports = withAxiom({
  // your existing next config
});

Use the logger in API routes and server components:

import { Logger } from 'next-axiom';

export async function POST(request: Request) {
  const log = new Logger();
  log.info('Processing request', { path: '/api/checkout' });

  try {
    const body = await request.json();
    log.info('Checkout started', { itemCount: body.items.length });
    const result = await processOrder(body);
    log.info('Checkout completed', { orderId: result.id });
    return Response.json(result);
  } catch (error) {
    log.error('Checkout failed', { error: (error as Error).message });
    return Response.json({ error: 'Failed' }, { status: 500 });
  } finally {
    await log.flush();
  }
}

Key Patterns

Do: Send structured events with rich context

import { Axiom } from '@axiomhq/js';

const axiom = new Axiom({ token: process.env.AXIOM_TOKEN! });

await axiom.ingest('events', [
  {
    _time: new Date().toISOString(),
    level: 'info',
    service: 'payment-api',
    event: 'payment.completed',
    duration_ms: 234,
    order_id: 'ord_abc123',
    amount: 49.99,
    currency: 'USD',
    payment_method: 'card',
  },
]);
await axiom.flush();

Not: Sending unstructured string logs

// WRONG - loses all queryability
await axiom.ingest('logs', [
  { message: 'Payment of $49.99 completed for order ord_abc123 in 234ms' },
]);
// You cannot filter by amount, order_id, or duration without parsing

Do: Use log.with() for request-scoped context

import { Logger } from 'next-axiom';

export async function GET(request: Request) {
  const log = new Logger().with({
    requestId: crypto.randomUUID(),
    userId: getUserId(request),
  });

  log.info('Fetching user profile');  // automatically includes requestId + userId
  log.info('Profile loaded', { cached: true });
  await log.flush();
}

Common Patterns

APL Queries for Analysis

// Error rate over time
['my-app-logs']
| where level == 'error'
| summarize errors = count() by bin(_time, 5m)

// p95 latency by endpoint
['my-app-logs']
| where isnotnull(duration_ms)
| summarize p95 = percentile(duration_ms, 95) by route
| order by p95 desc

// Top errors by message
['my-app-logs']
| where level == 'error'
| summarize count() by error_message = tostring(error)
| order by count_ desc
| take 10

// Unique users per hour
['my-app-logs']
| where isnotnull(userId)
| summarize dcount(userId) by bin(_time, 1h)

Web Vitals Monitoring with next-axiom

// app/layout.tsx
import { AxiomWebVitals } from 'next-axiom';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <AxiomWebVitals />
        {children}
      </body>
    </html>
  );
}

This automatically reports LCP, FID, CLS, TTFB, and INP to your Axiom dataset.

Axiom Monitor (Alert) via API

curl -X POST "https://api.axiom.co/v2/monitors" \
  -H "Authorization: Bearer $AXIOM_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "High Error Rate",
    "dataset": "my-app-logs",
    "query": "| where level == \"error\" | summarize count()",
    "threshold": 100,
    "frequency": "5m",
    "operator": "above",
    "notifiers": ["slack-webhook-id"]
  }'

Batch Ingestion from Backend Services

import { Axiom } from '@axiomhq/js';

const axiom = new Axiom({ token: process.env.AXIOM_TOKEN! });

// Buffer events and flush periodically
const buffer: Record<string, unknown>[] = [];

function trackEvent(event: Record<string, unknown>) {
  buffer.push({ ...event, _time: new Date().toISOString() });
  if (buffer.length >= 100) {
    flushEvents();
  }
}

async function flushEvents() {
  if (buffer.length === 0) return;
  const events = buffer.splice(0);
  await axiom.ingest('events', events);
  await axiom.flush();
}

// Flush on shutdown
process.on('SIGTERM', flushEvents);
setInterval(flushEvents, 10000);

Anti-Patterns

  • Forgetting await log.flush() - In serverless environments, logs are lost if not flushed before the function returns.
  • Flat string messages without fields - Axiom excels at structured data; always use key-value fields for anything you want to filter or aggregate.
  • Creating too many datasets - Use a single dataset per environment with a service field to differentiate; too many datasets complicate queries.
  • Not setting _time - Without an explicit timestamp, Axiom uses ingestion time, which can skew results for batched or delayed events.

When to Use

  • You are building a Next.js or Vercel application and want zero-config log shipping.
  • You need a serverless-friendly logging backend that handles bursty, high-volume ingestion.
  • You want a managed service with no infrastructure to maintain for log analytics.
  • You need real-time dashboards with sub-second query performance on large datasets.
  • You want Web Vitals monitoring alongside application logs in a single platform.

Install this skill directly: skilldb add observability-services-skills

Get CLI access →