スキル一覧に戻る
mgd34msu

axiom

by mgd34msu

Plug in, Receive good vibes.

2🍴 0📅 2026年1月25日
GitHubで見るManusで実行

SKILL.md


name: axiom description: 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.

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:

  1. Go to Vercel Dashboard > Integrations
  2. Install Axiom integration
  3. Connect your Axiom organization
  4. Logs from console.log, console.error, etc. are automatically sent

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

  1. Flush before returning - Always call flush() in server components
  2. Use structured data - Pass objects, not strings
  3. Add request context - Include requestId, path, method
  4. Log at appropriate levels - debug, info, warn, error
  5. Proxy client logs - Don't expose tokens to browser
  6. Use Vercel integration - For automatic console.log capture
  7. Add timing - Track duration for performance monitoring

スコア

総合スコア

60/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です