Axiom
Integrate Axiom for log management, analytics, and real-time dashboards.
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 linesAxiom 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
servicefield 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
Related Skills
Elastic Apm
Instrument applications with Elastic APM and the ELK Stack for traces, logs, and metrics.
Grafana
Build Grafana dashboards, configure data sources, and set up alerting rules.
Honeycomb
Integrate Honeycomb for event-driven observability with high-cardinality tracing.
Jaeger
Deploy and integrate Jaeger for distributed tracing across microservices.
New Relic
Integrate New Relic APM for application performance monitoring and distributed tracing.
Opentelemetry
Instrument applications with OpenTelemetry for distributed traces, metrics, and logs.