Oleqlog

Adapters

Express, NestJS, and Next.js / React integrations for @oleq-ai/logs

Optional subpath exports wrap OleqLog for common frameworks. Peer dependencies are optional — install only what you use.

ImportPeerPurpose
@oleq-ai/logs/expressexpressHTTP middleware — req / res access logs
@oleq-ai/logs/nestjs@nestjs/commonLoggerService, module, HTTP middleware
@oleq-ai/logs/next/serverLazy server logger for Route Handlers
@oleq-ai/logs/next/routeProxy handler for browser batches
@oleq-ai/logs/reactreactuseOleqLog hook for client components

Never expose API keys in the browser

Client components must use useOleqLog with ingestUrl pointing at a server route you control. The route forwards batches with your real OLEQLOG_API_KEY.


Express

Install express alongside the SDK, then attach middleware:

bun add express @oleq-ai/logs
server.ts
import express from "express";
import OleqLog from "@oleq-ai/logs";
import { oleqExpressMiddleware } from "@oleq-ai/logs/express";

const app = express();
const log = new OleqLog({ appName: "api" });

app.use(
  oleqExpressMiddleware(log, {
    skip: (req) => req.url === "/health",
  }),
);

app.get("/users", async (req, res) => {
  await req.oleqLog!.info({ message: "listed users" });
  res.json([]);
});

process.on("SIGTERM", async () => {
  await log.close();
  process.exit(0);
});

oleqExpressMiddleware logs a kind: "req" event on entry and kind: "res" on finish. The shared logger is available as req.oleqLog.


NestJS

bun add @nestjs/common express @oleq-ai/logs

Register the global module and apply HTTP middleware:

app.module.ts
import { MiddlewareConsumer, Module, NestModule } from "@nestjs/common";
import {
  OleqLogModule,
  OleqLogMiddleware,
  OleqLogger,
} from "@oleq-ai/logs/nestjs";

@Module({
  imports: [
    OleqLogModule.forRoot({
      appName: "api",
      environment: process.env.NODE_ENV,
      middleware: { skip: (req) => req.url === "/health" },
    }),
  ],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(OleqLogMiddleware).forRoutes("*");
  }
}

Inject OleqLogger anywhere you would use Nest's built-in logger:

users.service.ts
import { Injectable } from "@nestjs/common";
import { OleqLogger } from "@oleq-ai/logs/nestjs";

@Injectable()
export class UsersService {
  constructor(private readonly logger: OleqLogger) {}

  async list() {
    this.logger.log("listing users", UsersService.name);
  }
}

OleqLogModule.forRoot() accepts the same options as new OleqLog(...), plus optional middleware (passed to the Express middleware under the hood).


Next.js — server

Use a lazy singleton so Next.js build does not require OLEQLOG_API_KEY at compile time:

lib/oleq-log.ts
import { createServerLogger } from "@oleq-ai/logs/next/server";

export const getLogger = createServerLogger({
  appName: "web",
  environment: process.env.NODE_ENV,
});
app/api/health/route.ts
import { getLogger } from "@/lib/oleq-log";

export async function GET() {
  const log = getLogger();
  await log.info({ message: "health check" });
  await log.flush();
  return Response.json({ ok: true });
}

Call flush() before returning in serverless / edge handlers so batched events are sent.


Next.js — client

Two pieces: a proxy route on the server and the React hook in the browser.

1. Proxy route

app/api/oleqlog/route.ts
import { createIngestHandler } from "@oleq-ai/logs/next/route";

export const POST = createIngestHandler({ appName: "web" });

createIngestHandler accepts the same options as new OleqLog(...) and forwards { logs: [...] } batches to Oleq with your API key.

Rate limiting is on by default60 requests per minute per client IP, max 50 logs per request. This is a safety net for dev and single-node apps. On serverless (Vercel, Lambda) limits are per instance, not global — see middleware for production.

Override or disable on the handler:

app/api/oleqlog/route.ts
import { createIngestHandler } from "@oleq-ai/logs/next/route";

export const POST = createIngestHandler({
  appName: "web",
  rateLimit: {
    maxRequests: 120,
    windowMs: 60_000,
    maxLogsPerRequest: 25,
    // key: (req) => req.headers.get("x-session-id") ?? "anon",
  },
});

// When using edge middleware with a shared store, disable handler limiting:
// rateLimit: false,

Returns 429 Too Many Requests with Retry-After when limited, 413 when a batch exceeds maxLogsPerRequest.

Next.js middleware (production)

For serverless production, rate-limit before the route handler hits your function — ideally with a shared store (Redis / Upstash) so limits apply across all instances.

1. Route handler — keep maxLogsPerRequest (always useful), turn off request counting if middleware handles it:

app/api/oleqlog/route.ts
export const POST = createIngestHandler({
  appName: "web",
  rateLimit: { maxLogsPerRequest: 50, maxRequests: 999_999, windowMs: 60_000 },
  // or rateLimit: false if middleware is your only gate
});

2. Middleware — block abusive traffic at the edge:

middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { ingestClientKey } from "@oleq-ai/logs/next/route";
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(60, "1 m"),
});

export async function middleware(request: NextRequest) {
  if (request.nextUrl.pathname !== "/api/oleqlog") {
    return NextResponse.next();
  }

  if (request.method !== "POST") {
    return NextResponse.next();
  }

  const ip = ingestClientKey(request);
  const { success, reset } = await ratelimit.limit(ip);

  if (!success) {
    return NextResponse.json(
      { error: "Too many requests" },
      {
        status: 429,
        headers: {
          "Retry-After": String(Math.max(1, Math.ceil((reset - Date.now()) / 1000))),
        },
      },
    );
  }

  return NextResponse.next();
}

export const config = {
  matcher: "/api/oleqlog",
};

Install Upstash separately (@upstash/ratelimit, @upstash/redis) and set UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN. Any Redis-backed limiter works — the important part is edge + shared store, not the specific library.

ApproachGood for
Handler default (rateLimit on)Dev, single Node server, quick start
Handler maxLogsPerRequest onlyAlways — caps batch size cheaply
Edge middleware + RedisProduction serverless — global limits, fewer wasted invocations

2. Client hook

bun add react @oleq-ai/logs
components/checkout-button.tsx
"use client";

import { useOleqLog } from "@oleq-ai/logs/react";

export function CheckoutButton() {
  const log = useOleqLog({
    appName: "web",
    ingestUrl: "/api/oleqlog",
  });

  return (
    <button
      type="button"
      onClick={() => void log.info({ message: "checkout clicked" })}
    >
      Checkout
    </button>
  );
}

Under the hood, useOleqLog constructs an OleqLog with ingestUrl set — no x-api-key header leaves the browser.


ingestUrl (proxy mode)

When ingestUrl is set on OleqLog, batches POST to that URL instead of the Oleq ingest API, and no API key is sent. Pair with createIngestHandler on your server.

ContextapiKeyingestUrl
Server (Node, Nest, Route Handler)required*
Browser (useOleqLog)neverrequired

*Or OLEQLOG_API_KEY env var.


  • Pino transport — if you already log through Pino
  • Usage — levels, options, batching
  • Examples — raw OleqLog recipes without adapters

On this page