Documentation

Backend/Jobs

Job Sampling

Reduce trace volume for high-throughput jobs while keeping failed executions

Job sampling lets you reduce trace volume for noisy background jobs without disabling job monitoring entirely. It is useful when a small number of jobs run very often or create very large traces.

Job sampling is currently available only through the @monocle.sh/adonisjs-agent.

With the Monocle AdonisJS agent, sampling is configured in config/monocle.ts with the Sample helper

config/monocle.ts
import { defineConfig, Sample } from '@monocle.sh/adonisjs-agent'

export default defineConfig({
  // ...
  sampling(ctx) {
    if (ctx.kind !== 'job') return Sample.default()

    if (ctx.name === 'SendNewsletterEmail') {
      return Sample.rate(0.01).keepErrors()
    }

    return Sample.default()
  },
})

This keeps roughly 1% of successful SendNewsletterEmail executions, but still exports failed executions.

Sampling rules

Keep default behavior

Use Sample.default() when you do not want to override sampling for an execution.

TypeScript
sampling(ctx) {
  return Sample.default();
}

Always keep

Use Sample.always() when a specific job should always be exported.

TypeScript
sampling(ctx) {
  if (ctx.kind === "job" && ctx.name === "BillingReport") {
    return Sample.always();
  }

  return Sample.default();
}

Never keep

Use Sample.never() for jobs you do not want to export.

TypeScript
sampling(ctx) {
  if (ctx.kind === "job" && ctx.name === "HeartbeatJob") {
    return Sample.never();
  }

  return Sample.default();
}

Sample by rate

Use Sample.rate(rate) to keep a percentage of executions. The rate is a number between 0 and 1.

TypeScript
sampling(ctx) {
  if (ctx.kind === "job" && ctx.name === "SyncContacts") {
    return Sample.rate(0.1); // keep 10%
  }

  return Sample.default();
}

Keep failed executions

Use .keepErrors() when successful executions should be sampled, but failed executions should still be exported.

TypeScript
sampling(ctx) {
  if (ctx.kind === "job" && ctx.name === "SendNewsletterEmail") {
    return Sample.rate(0).keepErrors();
  }

  return Sample.default();
}

Sample.rate(0).keepErrors() drops successful executions and keeps failed executions. This is the most aggressive setting for high-volume jobs where you mainly care about failures.

Limit buffered spans

When using keepErrors(), the agent buffers spans locally until the job finishes so it can decide whether to export the trace. You can cap the number of buffered spans with maxSpans.

TypeScript
sampling(ctx) {
  if (ctx.kind === "job" && ctx.name === "SendNewsletterEmail") {
    return Sample.rate(0.01).keepErrors({ maxSpans: 500 });
  }

  return Sample.default();
}

If a trace exceeds the limit, Monocle keeps the root span and marks it with truncation attributes:

AttributeDescription
monocle.sampling.truncatedtrue when spans were dropped from the local buffer
monocle.sampling.dropped_spansNumber of spans dropped from the local buffer

Sampling context

For job executions, the sampling(ctx) callback receives:

FieldDescription
ctx.kindAlways "job" for job executions
ctx.systemQueue system, for example "bullmq" or "boringqueue"
ctx.nameJob name
ctx.queueQueue name, when available
ctx.jobIdJob ID, when available
ctx.attemptRetry attempt, when available

Example:

TypeScript
sampling(ctx) {
  if (ctx.kind !== "job") return Sample.default();

  if (ctx.system === "bullmq" && ctx.queue === "critical") {
    return Sample.always();
  }

  if (ctx.name.includes("Import")) {
    return Sample.rate(0.01).keepErrors();
  }

  return Sample.default();
}

Supported job libraries

BullMQ

Install @monocle.sh/instrumentation-bullmq and add bullmq() to the agent's integrations array to enable native BullMQ sampling. The integration inherits the agent's sampling callback unless you provide an override.

BullMQ sampling is applied before the worker body runs. When a job is dropped with Sample.never() or an unsampled rate rule without keepErrors(), Monocle suppresses tracing for the worker execution, so child spans are not created.

See the BullMQ instrumentation guide for setup and span details.

@adonisjs/queue

@adonisjs/queue job executions are detected from their root job spans. Sampling works with Sample.rate(), Sample.never(), and keepErrors().

See the @boringnode/queue instrumentation guide for span details.

How keepErrors works

keepErrors() is application-side tail sampling. The agent records spans locally for the job execution, buffers them until the root job span ends, and then exports the trace if the execution was sampled or ended with an error.

Because the decision happens after spans are recorded, Monocle configures the default OpenTelemetry head sampling ratio to 1 when sampling is enabled. If you provide a custom OpenTelemetry sampler, traces dropped by that sampler cannot be recovered by keepErrors().

Search documentation

Search pages and sections of the Monocle documentation