DeepTracer
SDK Reference

Advanced Usage

Event filtering, child loggers, lifecycle management, serverless, and testing.

beforeSend hook

Filter, modify, or drop events before they're sent. Return the event to send it, or null to drop it:

const logger = init({
  beforeSend: (event) => {
    // Drop health-check logs
    if (event.type === "log" && event.data.message.includes("/health")) {
      return null
    }

    // Scrub PII from error context
    if (event.type === "error" && event.data.context?.password) {
      delete event.data.context.password
    }

    return event
  },
})

The event is a discriminated union with four shapes:

event.typeevent.dataDescription
"log"LogEntryA log entry (debug/info/warn/error)
"error"ErrorReportA captured error
"trace"SpanDataA completed span
"llm"LLMUsageReportAn LLM usage report

If the beforeSend callback throws, the event is sent anyway. The SDK never drops events due to a buggy hook.

Child loggers

withContext(name)

Create a logger that tags all events with a context name:

const authLogger = logger.withContext("auth")
authLogger.info("Login successful")
// → context: "auth"

forRequest(request)

Create a request-scoped logger that extracts trace IDs from headers:

const reqLogger = logger.forRequest(request)
reqLogger.info("Processing request")
// → trace_id, span_id, request_id from headers

Both child loggers share the same transport and batcher as the parent (one connection, one timer). They get independent copies of user, tags, and contexts.

Lifecycle management

flush()

Send all pending batched logs immediately. Use this before returning a response to ensure logs are delivered:

export async function POST(request: Request) {
  logger.info("Webhook received", { type: event.type })
  await processWebhook(event)
  await logger.flush() // ensure logs are sent
  return Response.json({ ok: true })
}

destroy(timeout?)

Stop the batch timer, flush remaining logs, and wait for in-flight HTTP requests:

process.on("SIGTERM", async () => {
  await logger.destroy(5000) // wait up to 5 seconds
  process.exit(0)
})

Default timeout is 2000ms. After the timeout, the promise resolves even if requests are still in-flight.

Serverless / Vercel

waitUntil on Vercel

On Vercel, @deeptracer/nextjs automatically wires up waitUntil from @vercel/functions. Logs written after the HTTP response is returned (e.g., from background callbacks) are kept alive until delivery.

No config needed.

Cloudflare Workers

Pass ctx.waitUntil manually:

import { createLogger } from "@deeptracer/core"

export default {
  async fetch(request, env, ctx) {
    const logger = createLogger({
      apiKey: env.DEEPTRACER_KEY,
      endpoint: env.DEEPTRACER_ENDPOINT,
      waitUntil: ctx.waitUntil.bind(ctx),
    })

    logger.info("Worker invoked")
    return new Response("OK")
    // logger keeps the worker alive until the log is sent
  },
}

Batch timing

On Vercel and AWS Lambda, the default flushIntervalMs is automatically reduced to 200ms (from 5000ms) to ensure logs are flushed before the function freezes.

Using @deeptracer/core directly

For custom runtimes, edge workers, or minimal setups:

import { createLogger } from "@deeptracer/core"

const logger = createLogger({
  apiKey: "dt_xxx",
  endpoint: "https://your-ingestion.example.com",
  service: "edge-worker",
})

logger.info("Running on a custom runtime")

@deeptracer/core has zero dependencies and works anywhere with fetch and crypto.getRandomValues().

noopLogger for testing

Use noopLogger in tests to avoid network requests and console noise:

import { noopLogger } from "@deeptracer/core"

// In your test setup or dependency injection
const service = new UserService({ logger: noopLogger })

// All logger methods are safe to call -- they do nothing
noopLogger.info("this goes nowhere")
noopLogger.captureError(new Error("silent"))

noopLogger is the same object returned by init() when API keys are missing. It has the full Logger interface: startSpan still calls your callback, flush and destroy resolve immediately, and child logger methods return the same noopLogger.

Next.js route handler and server action wrappers

withRouteHandler

Wrap a Next.js Route Handler with tracing and error capture:

// app/api/users/route.ts
import { withRouteHandler } from "@deeptracer/nextjs"
import { logger } from "@/instrumentation"

export const GET = withRouteHandler(logger, "GET /api/users", async (request) => {
  const users = await db.user.findMany()
  return Response.json(users)
})

withServerAction

Wrap a Server Action with tracing and error capture:

"use server"
import { withServerAction } from "@deeptracer/nextjs"
import { logger } from "@/instrumentation"

export async function createUser(formData: FormData) {
  return withServerAction(logger, "createUser", async () => {
    const name = formData.get("name") as string
    return await db.user.create({ data: { name } })
  })
}

Both wrappers create a span, capture any thrown errors with "high" severity, re-throw the original error so Next.js error handling still works, and flush before returning.

On this page