sentry-javascript icon indicating copy to clipboard operation
sentry-javascript copied to clipboard

Pino integration not sending logs to Sentry

Open rodolfoBee opened this issue 2 months ago • 18 comments

Is there an existing issue for this?

  • [x] I have checked for existing issues https://github.com/getsentry/sentry-javascript/issues
  • [x] I have reviewed the documentation https://docs.sentry.io/
  • [x] I am using the latest SDK release https://github.com/getsentry/sentry-javascript/releases

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/node

SDK Version

10.20.0

Framework Version

Pino 10.0.0

Link to Sentry event

No response

Reproduction Example/SDK Setup

PinoIntegration and enableLogs:true are set in the SDK initialisation

Two code examples. From a Discord thread.

// Internal log method with type-safe logging
  private log(level: LogLevel, message: string, data?: any) {
    const parsedData = this.safeJson(data); // Parse data to JSON


    const logEntry: StandardLog = {
      level,
      timestamp: dateNow(),
      requestId: this.requestId,
      message,
      userId: this.userId,
      data: parsedData === null ? undefined : parsedData, // Set data if parsedData is not null
    };


    // Use the correct Pino method based on the log level
    switch (level) {
      case "trace":
        this.logger.trace(logEntry);
        break;
      case "debug":
        this.logger.debug(logEntry);
        break;
      case "info":
        this.logger.info(logEntry);
        break;
      case "warn":
        this.logger.warn(logEntry);
        break;
      case "error":
        this.logger.error(logEntry);
        break;
      case "fatal":
        this.logger.fatal(logEntry);
        break;
      default:
        this.logger.info(logEntry); // Default to info if level is not recognized
        break;
    }
  }

From an internal support ticket : The logger is set-up as a Sentry module.

export const PinoHttpModule = LoggerModule.forRootAsync({...})

@Module({...
PinoHttpModule,
...})
export class AppModule {

The app startup code:

const pinoLogger = app.get(PinoLogger);
app.useLogger(pinoLogger);

//Send the log
private readonly logger = new Logger(MyService.name);
...
this.logger.log('log msg');

Steps to Reproduce

Use the example codes above to send logs to Sentry.

Expected Result

Logs are sent to Sentry and visible on the logs page.

Actual Result

No logs are reported.

Quick tests with simple logs (logger.info("Info log")) are sent correctly. Might be an integration's limitation where more complex logs are dropped.

My example that works:

//instrument.js
const Sentry = require("@sentry/node");

Sentry.init({
  debug:true,
  dsn: "...",
  integrations: [
    Sentry.pinoIntegration({ 
      log: { levels: ["info", "warn", "error"] }
    })
  ],
  enableLogs: true,
});

//script
require("./instrument");

const logger = require('pino')

logger.info('hello world')

Additional Context

Tip: React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it.

rodolfoBee avatar Oct 23 '25 13:10 rodolfoBee

JS-1086

linear[bot] avatar Oct 23 '25 13:10 linear[bot]

@timfish could you help take a look?

AbhiPrasad avatar Oct 23 '25 13:10 AbhiPrasad

There's not enough context from these small snippets for me to be able to help. Can you supply a full example?

timfish avatar Oct 23 '25 13:10 timfish

@timfish I have requested more context from the affected users, haven't got it yet. Will update when available.

rodolfoBee avatar Oct 24 '25 10:10 rodolfoBee

@timfish actually got the same issue. Starter Next.js app with pino integration: https://github.com/lforst/sentry-logger-repro Check instrumentation.ts for the logger.

lforst avatar Oct 26 '25 16:10 lforst

Thanks, I'll take a look!

timfish avatar Oct 27 '25 08:10 timfish

I just enabled debug: true for the SDK and got this:

{"level":30,"time":1761557244695,"pid":88141,"hostname":"Tims-MacBook-Pro.local","msg":"TEST LOG"}
Sentry Logger [log]: Initializing SDK...
Sentry Logger [log]: Initializing Sentry: process: 88141, thread: main.

This suggests that the SDK is getting initialised (ie. register is called) after the logging has actually occurred. You need to init the SDK before any logging will be captured.

For example, if I change this:

export async function register() {
  if (process.env.NEXT_RUNTIME === "nodejs") {
    await import("./sentry.server.config");
  }

  if (process.env.NEXT_RUNTIME === "edge") {
    await import("./sentry.edge.config");
  }
}

const logger = pino();

logger.info("TEST LOG");

To this, the logging works:

export async function register() {
  if (process.env.NEXT_RUNTIME === "nodejs") {
    await import("./sentry.server.config");
  }

  if (process.env.NEXT_RUNTIME === "edge") {
    await import("./sentry.edge.config");
  }

  const logger = pino();

  logger.info("TEST LOG");
}

timfish avatar Oct 27 '25 09:10 timfish

I am an idiot - nothing new 😂 In my more complex app, logs are not sending though. I'll try to figure out why...

lforst avatar Oct 29 '25 19:10 lforst

No problem. Let me know if I can help!

timfish avatar Oct 30 '25 14:10 timfish

@timfish I'm having the same issue. I have a TRPC server bundling via esbuild and deploying to AWS lambda, but this is all in dev/local mode. The issue is twofold. First, I get this warning: Failed to register '@apm-js-collab/tracing-hooks' hook Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@apm-js-collab/tracing-hooks' imported from /workspaces/dmca-aws/.sst/artifacts/trpc-dev/bundle.mjs. After I install that package, that warning goes away. However, I still don't get any logs. @sentry/aws-serverless is at 10.22.0 and pino is at 9.9.0.

index.ts

import { createLogger } from "@dmca/utils/logger";
import { awsLambdaRequestHandler, type CreateAWSLambdaContextOptions } from "@trpc/server/adapters/aws-lambda";
import type { APIGatewayProxyEventV2 } from "aws-lambda";
import { appRouter } from "@dmca/api/router";
import { captureException, init, pinoIntegration, setContext, setTag, wrapHandler } from "@sentry/aws-serverless";

if (process.env.SST_STAGE) {
    setTag("stage", process.env.SST_STAGE);
}

if (process.env.SENTRY_DSN) {
    init({
        enabled: true,
        dsn: process.env.SENTRY_DSN,
        sendDefaultPii: true,
        debug: true,
        integrations: [pinoIntegration()],
        enableLogs: true,
        beforeSendLog: (log) => {
            console.log("sentry testing 123455", log);
            return log;
        },
    });
}
const [logger] = createLogger();

const createContext = async ({ event, context }: CreateAWSLambdaContextOptions<APIGatewayProxyEventV2>) => {
    setContext("event", { ...event });
    logger.info({ path: event.rawPath }, "hello asdf");
    ... // TRPC implementation
};

const inner = awsLambdaRequestHandler({
    router: appRouter,
    createContext,
    onError: (opts) => {
        const { error } = opts;
        logger.error(error, "TRPC error");
        captureException(error);
    },
});

export const handler = process.env.SENTRY_DSN ? wrapHandler(inner) : inner;

createLogger.ts

import pino, { type DestinationStream, type Logger, type LoggerOptions } from "pino";
import { pinoLambdaDestination, StructuredLogFormatter } from "pino-lambda";
import pretty from "pino-pretty";

const destination = pinoLambdaDestination({
    formatter: new StructuredLogFormatter(),
});

export const createLogger = <TEnvironment extends "local" | "aws" = "aws">(
    opts?: LoggerOptions & { stream?: DestinationStream },
    environment?: TEnvironment
): [Logger, HandlerLoggerFunction] => {
    const { stream, ...rest } = opts || {};
    if (!environment) {
        if (process.env.SST_DEV) {
            environment = "local" as TEnvironment;
        } else {
            environment = "aws" as TEnvironment;
        }
    }

    const logger = pino(
        {
            level: (process.env.LOG_LEVEL || "info").toLocaleLowerCase(),
            ...rest,
        },
        stream ||
            (environment === "aws"
                ? destination
                : pretty({ colorize: true, ignore: "lambda_event" }))
    );

    if (environment === "aws") {
        return [logger, withRequest]; // withRequest is needed to setup pino in a lambda environment, but not called in local dev
    }

    return [logger, () => {}];
};

Sentry logs don't show any errors:

Sentry Logger [log]: Initializing Sentry: process: 400685, thread: main.
Sentry Logger [log]: Integration installed: InboundFilters
Sentry Logger [log]: Integration installed: FunctionToString
Sentry Logger [log]: Integration installed: LinkedErrors
Sentry Logger [log]: Integration installed: RequestData
Sentry Logger [log]: Integration installed: NodeSystemError
Sentry Logger [log]: Integration installed: Console
Sentry Logger [log]: Integration installed: OnUncaughtException
Sentry Logger [log]: Integration installed: OnUnhandledRejection
Sentry Logger [log]: Integration installed: ContextLines
Sentry Logger [log]: Integration installed: LocalVariablesAsync
Sentry Logger [log]: Integration installed: Context
Sentry Logger [log]: Integration installed: ChildProcess
Sentry Logger [log]: Integration installed: ProcessSession
Sentry Logger [log]: Integration installed: Modules
Sentry Logger [log]: Integration installed: Http
Sentry Logger [log]: Integration installed: NodeFetch
Sentry Logger [log]: Integration installed: Aws
Sentry Logger [log]: Integration installed: AwsLambda
Sentry Logger [log]: Integration installed: Pino
Sentry Logger [log]: SDK initialized from ESM
Sentry Logger [log]: @opentelemetry/api: Registered a global for diag v1.9.0.
Sentry Logger [log]: @opentelemetry/api: Registered a global for trace v1.9.0.
Sentry Logger [log]: @opentelemetry/api: Registered a global for propagation v1.9.0.
Sentry Logger [log]: @opentelemetry/api: Registered a global for context v1.9.0.
/workspaces/dmca-aws/apps/functions/src/api/index.handler
[14:28:08.114] INFO (400685 on e9076ad108f6): hello asdf
    path: "/trpc/auth.getTenantPermissions,cell.getAll,productionJob.getAllWithLocationInfinite,productionJob.getAllWithLocationInfinite,productionJob.getAllWithLocationInfinite"
Sentry Logger [log]: SpanExporter exported 0 spans, 0 spans are waiting for their parent spans to finish
Sentry Logger [log]: Flushing outcomes...
Sentry Logger [log]: No outcomes to send

Sentry is init-ed properly in dev mode, I made sure with a test error.

anthonyma94 avatar Oct 31 '25 14:10 anthonyma94

@anthonyma94 what version of Pino are you using? The warning about not being able to register suggests your code is bundled.

timfish avatar Oct 31 '25 14:10 timfish

@timfish I'm using pino 9.9.0 and @sentry/aws-serverless 10.22.0.

anthonyma94 avatar Oct 31 '25 15:10 anthonyma94

If you are using a bundler you'll need to use Pino v9.10.0 or newer.

I need to add this to the docs because it has come up multiple times.

timfish avatar Oct 31 '25 15:10 timfish

That works, thank you for your help!

anthonyma94 avatar Oct 31 '25 17:10 anthonyma94

I'm running into this issue with @sentry/node 10.25.0 and pino 8.21.0.

Is there a recommended workaround? Thank you.

arun-ekline avatar Nov 20 '25 22:11 arun-ekline

use Pino v9.10.0 or newer

Before this version we rely on injecting diagnostic channels into Pino. After this version Pino added the channel natively.

timfish avatar Nov 21 '25 02:11 timfish

I'm running into this issue with @sentry/node 10.25.0 and pino 8.21.0.

If you're using ESM, please make sure you are following the initialization instructions from https://docs.sentry.io/platforms/javascript/guides/node/install/esm/.

Otherwise the only other scenario where this breaks is with bundling. Are you bundling your app @arun-ekline?

AbhiPrasad avatar Nov 24 '25 15:11 AbhiPrasad

I'm running into this issue with @sentry/node 10.25.0 and pino 8.21.0.

Otherwise the only other scenario where this breaks is with bundling. Are you bundling your app @arun-ekline?

Yes, we are bundling with pkg. However, I was testing prior to bundling. I will try again using Pino 9.10+. Thank you.

arun-ekline avatar Nov 25 '25 00:11 arun-ekline

This issue has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you remove the label Waiting for: Community, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

getsantry[bot] avatar Dec 17 '25 08:12 getsantry[bot]