Skip to content

Logging, Tracing & Metrics

The run log shows exactly what happened in every task run — logs, traces, and spans are all captured.

Logs

Use standard console.log(), console.error(), etc. — all output is captured in your run log.

Structured Logging with logger

Use the logger object for structured logs that are easier to search and filter:

ts
import { task, logger } from "@trigger.dev/sdk";

export const loggingExample = task({
  id: "logging-example",
  run: async (payload: { data: Record<string, string> }) => {
    logger.debug("Debug message", payload.data);
    logger.log("Log message", payload.data);
    logger.info("Info message", payload.data);
    logger.warn("You've been warned", payload.data);
    logger.error("Error message", payload.data);
  },
});

Tracing and Spans

Trigger.dev uses OpenTelemetry tracing. Automatic tracing covers:

  • Task triggers
  • Task attempts
  • HTTP requests

Add Instrumentations

Configure in trigger.config.ts. Example: Prisma instrumentation auto-traces all queries.

ts
import { defineConfig } from "@trigger.dev/sdk";
import { PrismaInstrumentation } from "@prisma/instrumentation";

export default defineConfig({
  instrumentations: [new PrismaInstrumentation()],
});

Custom Traces

ts
import { logger, task } from "@trigger.dev/sdk";

export const customTrace = task({
  id: "custom-trace",
  run: async (payload) => {
    const user = await logger.trace("fetch-user", async (span) => {
      span.setAttribute("user.id", "1");
      return { id: "1", name: "John Doe", fetchedAt: new Date() };
    });
  },
});

Custom Metrics (SDK 4.4.1+)

Import otel from @trigger.dev/sdk. Create instruments at module level (outside run):

ts
import { task, otel } from "@trigger.dev/sdk";

const meter = otel.metrics.getMeter("my-app");

// Create instruments at module level
const itemsProcessed = meter.createCounter("items.processed", {
  description: "Total items processed",
  unit: "items",
});

const itemDuration = meter.createHistogram("item.duration", {
  description: "Time per item",
  unit: "ms",
});

const queueDepth = meter.createUpDownCounter("queue.depth", {
  description: "Current queue depth",
  unit: "items",
});

export const processQueue = task({
  id: "process-queue",
  run: async (payload: { items: string[] }) => {
    queueDepth.add(payload.items.length);
    for (const item of payload.items) {
      const start = performance.now();
      // process item...
      itemsProcessed.add(1, { "item.type": "order" });
      itemDuration.record(performance.now() - start, { "item.type": "order" });
      queueDepth.add(-1);
    }
  },
});

Instrument Types

InstrumentMethodUse case
Countermeter.createCounter()Monotonically increasing values
Histogrammeter.createHistogram()Distributions (durations, sizes)
UpDownCountermeter.createUpDownCounter()Values that go up and down (queue depth)

Automatic System Metrics (SDK 4.4.1+)

MetricTypeUnitDescription
process.cpu.utilizationgaugeratioCPU usage (0–1)
process.cpu.timecountersecondsCPU time consumed
process.memory.usagegaugebytesProcess memory
nodejs.event_loop.utilizationgaugeratioEvent loop utilization
nodejs.event_loop.delay.p95gaugesecondsp95 event loop delay
nodejs.heap.usedgaugebytesV8 heap used
nodejs.heap.totalgaugebytesV8 heap total

All metrics include context attributes: run_id, task_identifier, attempt_number, machine_name, worker_version, environment_type.

Querying Metrics (TRQL)

sql
SELECT timeBucket(), avg(value) AS avg_cpu
FROM metrics
WHERE metric_name = 'process.cpu.utilization'
GROUP BY timeBucket
ORDER BY timeBucket
LIMIT 1000

Exporting Metrics

Configure telemetry exporters in trigger.config.ts to send to Axiom, Honeycomb, Datadog, or any OTLP-compatible service.

Built from official Trigger.dev documentation