diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
index 64709dd1f999..8acac6fd2709 100644
--- a/.github/ISSUE_TEMPLATE/bug.yml
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -51,7 +51,6 @@ body:
- '@sentry/nestjs'
- '@sentry/nextjs'
- '@sentry/nuxt'
- - '@sentry/pino-transport'
- '@sentry/react'
- '@sentry/react-router'
- '@sentry/remix'
diff --git a/dev-packages/e2e-tests/verdaccio-config/config.yaml b/dev-packages/e2e-tests/verdaccio-config/config.yaml
index 1d565dbecda2..0773603b033e 100644
--- a/dev-packages/e2e-tests/verdaccio-config/config.yaml
+++ b/dev-packages/e2e-tests/verdaccio-config/config.yaml
@@ -122,12 +122,6 @@ packages:
unpublish: $all
# proxy: npmjs # Don't proxy for E2E tests!
- '@sentry/pino-transport':
- access: $all
- publish: $all
- unpublish: $all
- # proxy: npmjs # Don't proxy for E2E tests!
-
'@sentry/profiling-node':
access: $all
publish: $all
diff --git a/package.json b/package.json
index e74379564683..edbd645b3c97 100644
--- a/package.json
+++ b/package.json
@@ -71,7 +71,6 @@
"packages/node-native",
"packages/nuxt",
"packages/opentelemetry",
- "packages/pino-transport",
"packages/profiling-node",
"packages/react",
"packages/react-router",
diff --git a/packages/pino-transport/.eslintrc.js b/packages/pino-transport/.eslintrc.js
deleted file mode 100644
index 01c6be4c7080..000000000000
--- a/packages/pino-transport/.eslintrc.js
+++ /dev/null
@@ -1,12 +0,0 @@
-module.exports = {
- env: {
- node: true,
- },
- extends: ['../../.eslintrc.js'],
- overrides: [
- {
- files: ['src/**/*.ts'],
- rules: {},
- },
- ],
-};
diff --git a/packages/pino-transport/LICENSE b/packages/pino-transport/LICENSE
deleted file mode 100644
index 5251db3eaaca..000000000000
--- a/packages/pino-transport/LICENSE
+++ /dev/null
@@ -1,16 +0,0 @@
-MIT License
-
-Copyright (c) 2025 Functional Software, Inc. dba Sentry
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
-documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
-rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
-persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
-Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/packages/pino-transport/README.md b/packages/pino-transport/README.md
deleted file mode 100644
index fdc077aa2b01..000000000000
--- a/packages/pino-transport/README.md
+++ /dev/null
@@ -1,266 +0,0 @@
-
-
-
-
-
-
-# Official Sentry Pino Transport
-
-[](https://www.npmjs.com/package/@sentry/solid)
-[](https://www.npmjs.com/package/@sentry/solid)
-[](https://www.npmjs.com/package/@sentry/solid)
-
-**WARNING**: This transport is in a **pre-release alpha**. The API is unstable and may change at any time.
-
-A Pino transport for sending logs to Sentry using the Sentry JavaScript SDK.
-
-This transport forwards Pino logs to Sentry, allowing you to view and analyze your application logs alongside your errors and performance data in Sentry.
-
-## Installation
-
-```bash
-npm install @sentry/pino-transport pino
-# or
-yarn add @sentry/pino-transport pino
-# or
-pnpm add @sentry/pino-transport pino
-```
-
-## Requirements
-
-- Node.js 18+
-- Pino v8 or v9
-- `@sentry/node` SDK with `enableLogs: true`
-
-## Setup
-
-First, make sure Sentry is initialized with logging enabled:
-
-```javascript
-import * as Sentry from '@sentry/node';
-
-Sentry.init({
- dsn: 'YOUR_DSN',
- enableLogs: true,
-});
-```
-
-Then create a Pino logger with the Sentry transport:
-
-```javascript
-import pino from 'pino';
-
-const logger = pino({
- transport: {
- target: '@sentry/pino-transport',
- options: {
- // Optional: filter which log levels to send to Sentry
- levels: ['error', 'fatal'], // defaults to all levels
- },
- },
-});
-
-// Now your logs will be sent to Sentry
-logger.info('This is an info message');
-logger.error('This is an error message');
-```
-
-## Configuration Options
-
-The transport accepts the following options:
-
-### `logLevels`
-
-**Type:** `Array<'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'>`
-
-**Default:** `['trace', 'debug', 'info', 'warn', 'error', 'fatal']` (all log levels)
-
-Use this option to filter which log severity levels should be sent to Sentry.
-
-```javascript
-const transport = pino.transport({
- target: '@sentry/pino-transport',
- options: {
- logLevels: ['warn', 'error', 'fatal'], // Only send warnings and above
- },
-});
-```
-
-## Log Level Mapping
-
-Pino log levels are automatically mapped to Sentry log severity levels:
-
-| Pino Level | Pino Numeric | Sentry Level |
-| ---------- | ------------ | ------------ |
-| trace | 10 | trace |
-| debug | 20 | debug |
-| info | 30 | info |
-| warn | 40 | warn |
-| error | 50 | error |
-| fatal | 60 | fatal |
-
-### Custom Levels Support
-
-Custom numeric levels are mapped to Sentry levels using ranges, so levels like `11`, `23`, or `42` will map correctly:
-
-- `0-19` → `trace`
-- `20-29` → `debug`
-- `30-39` → `info`
-- `40-49` → `warn`
-- `50-59` → `error`
-- `60+` → `fatal`
-
-```javascript
-import pino from 'pino';
-
-const logger = pino({
- customLevels: {
- critical: 55, // Maps to 'fatal' (55+ range)
- notice: 35, // Maps to 'warn' (35-44 range)
- verbose: 11, // Maps to 'trace' (0-14 range)
- },
- transport: {
- target: '@sentry/pino-transport',
- },
-});
-
-logger.critical('Critical issue occurred'); // → Sent as 'fatal' to Sentry
-logger.notice('Important notice'); // → Sent as 'warn' to Sentry
-logger.verbose('Detailed information'); // → Sent as 'trace' to Sentry
-```
-
-#### Custom Level Attributes
-
-When using custom string levels, the original level name is preserved as `sentry.pino.level` attribute for better traceability:
-
-```javascript
-// Log entry in Sentry will include:
-// {
-// level: 'warn', // Mapped Sentry level
-// message: 'Audit event',
-// attributes: {
-// 'sentry.pino.level': 'audit', // Original custom level name
-// 'sentry.origin': 'auto.logging.pino',
-// // ... other log attributes
-// }
-// }
-```
-
-### Custom Message Key
-
-The transport respects Pino's `messageKey` configuration:
-
-```javascript
-const logger = pino({
- messageKey: 'message', // Use 'message' instead of default 'msg'
- transport: {
- target: '@sentry/pino-transport',
- },
-});
-
-logger.info({ message: 'Hello world' }); // Works correctly with custom messageKey
-```
-
-### Nested Key Support
-
-The transport automatically supports Pino's `nestedKey` configuration, which is used to avoid property conflicts by nesting logged objects under a specific key. When `nestedKey` is configured, the transport flattens these nested properties using dot notation for better searchability in Sentry.
-
-```javascript
-const logger = pino({
- nestedKey: 'payload', // Nest logged objects under 'payload' key
- transport: {
- target: '@sentry/pino-transport',
- },
-});
-
-const conflictingObject = {
- level: 'hi', // Conflicts with Pino's level
- time: 'never', // Conflicts with Pino's time
- foo: 'bar',
- userId: 123,
-};
-
-logger.info(conflictingObject);
-
-// Without nestedKey, this would cause property conflicts
-// With nestedKey, Pino creates: { level: 30, time: 1234567890, payload: conflictingObject }
-// The transport flattens it to:
-// {
-// level: 'info',
-// message: undefined,
-// attributes: {
-// 'payload.level': 'hi', // Flattened nested properties
-// 'payload.time': 'never',
-// 'payload.foo': 'bar',
-// 'payload.userId': 123,
-// 'sentry.origin': 'auto.logging.pino',
-// }
-// }
-```
-
-This flattening ensures that no property conflicts occur between logged objects and Pino's internal properties.
-
-## Usage Examples
-
-### Basic Logging
-
-```javascript
-import pino from 'pino';
-
-const logger = pino({
- transport: {
- target: '@sentry/pino-transport',
- },
-});
-
-logger.trace('Starting application');
-logger.debug('Debug information', { userId: 123 });
-logger.info('User logged in', { userId: 123, username: 'john_doe' });
-logger.warn('Deprecated API used', { endpoint: '/old-api' });
-logger.error('Database connection failed', { error: 'Connection timeout' });
-logger.fatal('Application crashed', { reason: 'Out of memory' });
-```
-
-### Multiple Transports
-
-```javascript
-import pino from 'pino';
-
-const logger = pino({
- transport: {
- targets: [
- {
- target: 'pino-pretty',
- options: { colorize: true },
- level: 'debug',
- },
- {
- target: '@sentry/pino-transport',
- options: {
- logLevels: ['warn', 'error', 'fatal'],
- },
- level: 'warn',
- },
- ],
- },
-});
-```
-
-## Troubleshooting
-
-### Logs not appearing in Sentry
-
-1. Ensure `enableLogs: true` is set in your Sentry configuration.
-2. Check that your DSN is correct and the SDK is properly initialized.
-3. Verify the log level is included in the `levels` configuration.
-4. Check your Sentry organization stats page to see if logs are being received by Sentry.
-
-## Related Documentation
-
-- [Sentry Logs Documentation](https://docs.sentry.io/platforms/javascript/guides/node/logs/)
-- [Pino Documentation](https://getpino.io/)
-- [Pino Transports](https://getpino.io/#/docs/transports)
-
-## License
-
-MIT
diff --git a/packages/pino-transport/package.json b/packages/pino-transport/package.json
deleted file mode 100644
index 13c83d19b6ee..000000000000
--- a/packages/pino-transport/package.json
+++ /dev/null
@@ -1,79 +0,0 @@
-{
- "name": "@sentry/pino-transport",
- "version": "10.17.0",
- "description": "Pino transport for Sentry SDK",
- "repository": "git://github.com/getsentry/sentry-javascript.git",
- "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/pino-transport",
- "author": "Sentry",
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "files": [
- "/build"
- ],
- "main": "build/cjs/index.js",
- "module": "build/esm/index.js",
- "types": "build/types/index.d.ts",
- "exports": {
- "./package.json": "./package.json",
- ".": {
- "import": {
- "types": "./build/types/index.d.ts",
- "default": "./build/esm/index.js"
- },
- "require": {
- "types": "./build/types/index.d.ts",
- "default": "./build/cjs/index.js"
- }
- }
- },
- "typesVersions": {
- "<5.0": {
- "build/types/index.d.ts": [
- "build/types-ts3.8/index.d.ts"
- ]
- }
- },
- "publishConfig": {
- "access": "public"
- },
- "dependencies": {
- "@sentry/core": "10.17.0",
- "@sentry/node": "10.17.0",
- "pino-abstract-transport": "^2.0.0"
- },
- "peerDependencies": {
- "pino": "^8.0.0 || ^9.0.0"
- },
- "devDependencies": {
- "@types/node": "^18.19.1",
- "pino": "^9.0.0"
- },
- "scripts": {
- "build": "run-p build:transpile build:types",
- "build:dev": "yarn build",
- "build:transpile": "rollup -c rollup.npm.config.mjs",
- "build:types": "run-s build:types:core build:types:downlevel",
- "build:types:core": "tsc -p tsconfig.types.json",
- "build:types:downlevel": "yarn downlevel-dts build/types build/types-ts3.8 --to ts3.8",
- "build:watch": "run-p build:transpile:watch build:types:watch",
- "build:dev:watch": "yarn build:watch",
- "build:transpile:watch": "rollup -c rollup.npm.config.mjs --watch",
- "build:types:watch": "tsc -p tsconfig.types.json --watch",
- "build:tarball": "npm pack",
- "circularDepCheck": "madge --circular src/index.ts",
- "clean": "rimraf build coverage sentry-pino-transport-*.tgz",
- "fix": "eslint . --format stylish --fix",
- "lint": "eslint . --format stylish",
- "lint:es-compatibility": "es-check es2022 ./build/cjs/*.js && es-check es2022 ./build/esm/*.js --module",
- "test": "yarn test:unit",
- "test:unit": "vitest run",
- "test:watch": "vitest --watch",
- "yalc:publish": "yalc publish --push --sig"
- },
- "volta": {
- "extends": "../../package.json"
- },
- "sideEffects": false
-}
diff --git a/packages/pino-transport/rollup.npm.config.mjs b/packages/pino-transport/rollup.npm.config.mjs
deleted file mode 100644
index 84a06f2fb64a..000000000000
--- a/packages/pino-transport/rollup.npm.config.mjs
+++ /dev/null
@@ -1,3 +0,0 @@
-import { makeBaseNPMConfig, makeNPMConfigVariants } from '@sentry-internal/rollup-utils';
-
-export default makeNPMConfigVariants(makeBaseNPMConfig());
diff --git a/packages/pino-transport/src/debug-build.ts b/packages/pino-transport/src/debug-build.ts
deleted file mode 100644
index 60aa50940582..000000000000
--- a/packages/pino-transport/src/debug-build.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-declare const __DEBUG_BUILD__: boolean;
-
-/**
- * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code.
- *
- * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking.
- */
-export const DEBUG_BUILD = __DEBUG_BUILD__;
diff --git a/packages/pino-transport/src/index.ts b/packages/pino-transport/src/index.ts
deleted file mode 100644
index 986c7e892fc2..000000000000
--- a/packages/pino-transport/src/index.ts
+++ /dev/null
@@ -1,244 +0,0 @@
-import type { LogSeverityLevel } from '@sentry/core';
-import { _INTERNAL_captureLog, debug, isPrimitive, normalize } from '@sentry/core';
-import type buildType from 'pino-abstract-transport';
-import * as pinoAbstractTransport from 'pino-abstract-transport';
-import { DEBUG_BUILD } from './debug-build';
-
-// Handle both CommonJS and ES module exports
-// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
-const build = (pinoAbstractTransport as any).default || pinoAbstractTransport;
-
-/**
- * The default log levels that will be captured by the Sentry Pino transport.
- */
-const DEFAULT_CAPTURED_LEVELS: Array = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];
-
-/**
- * Options for the Sentry Pino transport.
- */
-export interface SentryPinoTransportOptions {
- /**
- * Use this option to filter which levels should be captured as logs.
- * By default, all levels are captured as logs.
- *
- * @example
- * ```ts
- * const logger = pino({
- * transport: {
- * target: '@sentry/pino-transport',
- * options: {
- * logLevels: ['error', 'warn'], // Only capture error and warn logs
- * },
- * },
- * });
- * ```
- */
- logLevels?: Array;
-}
-
-/**
- * Pino source configuration passed to the transport.
- * This interface represents the configuration options that Pino provides to transports.
- */
-interface PinoSourceConfig {
- /**
- * Custom levels configuration from Pino.
- * Contains the mapping of custom level names to numeric values.
- *
- * @default undefined
- * @example { values: { critical: 55, notice: 35 } }
- */
- levels?: unknown;
-
- /**
- * The property name used for the log message.
- * Pino allows customizing which property contains the main log message.
- *
- * @default 'msg'
- * @example 'message' when configured with messageKey: 'message'
- * @see https://getpino.io/#/docs/api?id=messagekey-string
- */
- messageKey?: string;
-
- /**
- * The property name used for error objects.
- * Pino allows customizing which property contains error information.
- *
- * @default 'err'
- * @example 'error' when configured with errorKey: 'error'
- * @see https://getpino.io/#/docs/api?id=errorkey-string
- */
- errorKey?: string;
-
- /**
- * The property name used to nest logged objects to avoid conflicts.
- * When set, Pino nests all logged objects under this key to prevent
- * conflicts with Pino's internal properties (level, time, pid, etc.).
- * The transport flattens these nested properties using dot notation.
- *
- * @default undefined (no nesting)
- * @example 'payload' - objects logged will be nested under { payload: {...} }
- * @see https://getpino.io/#/docs/api?id=nestedkey-string
- */
- nestedKey?: string;
-}
-
-/**
- * Creates a new Sentry Pino transport that forwards logs to Sentry. Requires the `enableLogs` option to be enabled.
- *
- * Supports Pino v8 and v9.
- *
- * @param options - Options for the transport.
- * @returns A Pino transport that forwards logs to Sentry.
- *
- * @experimental This method will experience breaking changes. This is not yet part of
- * the stable Sentry SDK API and can be changed or removed without warning.
- */
-export function createSentryPinoTransport(options?: SentryPinoTransportOptions): ReturnType {
- DEBUG_BUILD && debug.log('Initializing Sentry Pino transport');
- const capturedLogLevels = new Set(options?.logLevels ?? DEFAULT_CAPTURED_LEVELS);
-
- return build(
- async function (source: AsyncIterable & PinoSourceConfig) {
- for await (const log of source) {
- try {
- if (!isObject(log)) {
- continue;
- }
-
- // Use Pino's messageKey if available, fallback to 'msg'
- const messageKey = source.messageKey || 'msg';
- const message = log[messageKey];
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- const { [messageKey]: _, level, time, ...attributes } = log;
-
- // Handle nestedKey flattening if configured
- if (source.nestedKey && attributes[source.nestedKey] && isObject(attributes[source.nestedKey])) {
- const nestedObject = attributes[source.nestedKey] as Record;
- // Remove the nested object and flatten its properties
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
- delete attributes[source.nestedKey];
-
- // Flatten nested properties with dot notation
- for (const [key, value] of Object.entries(nestedObject)) {
- attributes[`${source.nestedKey}.${key}`] = value;
- }
- }
-
- const logSeverityLevel = mapPinoLevelToSentryLevel(log.level, source.levels);
-
- if (capturedLogLevels.has(logSeverityLevel)) {
- const logAttributes: Record = {
- ...attributes,
- 'sentry.origin': 'auto.logging.pino',
- };
-
- // Attach custom level as an attribute if it's a string (custom level)
- if (typeof log.level === 'string') {
- logAttributes['sentry.pino.level'] = log.level;
- }
-
- _INTERNAL_captureLog({
- level: logSeverityLevel,
- message: formatMessage(message),
- attributes: logAttributes,
- });
- }
- } catch {
- // Silently ignore errors to prevent breaking the logging pipeline
- }
- }
- },
- {
- expectPinoConfig: true,
- },
- );
-}
-
-function formatMessage(message: unknown): string {
- if (message === undefined) {
- return '';
- }
-
- if (isPrimitive(message)) {
- return String(message);
- }
- return JSON.stringify(normalize(message));
-}
-
-/**
- * Maps a Pino log level (numeric or custom string) to a Sentry log severity level.
- *
- * Handles both standard and custom levels, including when `useOnlyCustomLevels` is enabled.
- * Uses range-based mapping for numeric levels to handle custom values (e.g., 11 -> trace).
- */
-function mapPinoLevelToSentryLevel(level: unknown, levelsConfig?: unknown): LogSeverityLevel {
- // Handle numeric levels
- if (typeof level === 'number') {
- return mapNumericLevelToSentryLevel(level);
- }
-
- // Handle custom string levels
- if (
- typeof level === 'string' &&
- isObject(levelsConfig) &&
- 'values' in levelsConfig &&
- isObject(levelsConfig.values)
- ) {
- // Map custom string levels to numeric then to Sentry levels
- const numericLevel = levelsConfig.values[level];
- if (typeof numericLevel === 'number') {
- return mapNumericLevelToSentryLevel(numericLevel);
- }
- }
-
- // Default fallback
- return 'info';
-}
-
-/**
- * Maps a numeric level to the closest Sentry severity level using range-based mapping.
- * Handles both standard Pino levels and custom numeric levels.
- *
- * - `0-19` -> `trace`
- * - `20-29` -> `debug`
- * - `30-39` -> `info`
- * - `40-49` -> `warn`
- * - `50-59` -> `error`
- * - `60+` -> `fatal`
- *
- * @see https://github.com/pinojs/pino/blob/116b1b17935630b97222fbfd1c053d199d18ca4b/lib/constants.js#L6-L13
- */
-function mapNumericLevelToSentryLevel(numericLevel: number): LogSeverityLevel {
- // 0-19 -> trace
- if (numericLevel < 20) {
- return 'trace';
- }
- // 20-29 -> debug
- if (numericLevel < 30) {
- return 'debug';
- }
- // 30-39 -> info
- if (numericLevel < 40) {
- return 'info';
- }
- // 40-49 -> warn
- if (numericLevel < 50) {
- return 'warn';
- }
- // 50-59 -> error
- if (numericLevel < 60) {
- return 'error';
- }
- // 60+ -> fatal
- return 'fatal';
-}
-
-/**
- * Type guard to check if a value is an object.
- */
-function isObject(value: unknown): value is Record {
- return typeof value === 'object' && value != null;
-}
-
-export default createSentryPinoTransport;
diff --git a/packages/pino-transport/test/index.test.ts b/packages/pino-transport/test/index.test.ts
deleted file mode 100644
index a93d56f340cd..000000000000
--- a/packages/pino-transport/test/index.test.ts
+++ /dev/null
@@ -1,708 +0,0 @@
-import { _INTERNAL_captureLog } from '@sentry/core';
-import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
-import { createSentryPinoTransport } from '../src';
-
-// Mock the _INTERNAL_captureLog function
-vi.mock('@sentry/core', async actual => {
- const actualModule = (await actual()) as any;
- return {
- ...actualModule,
- _INTERNAL_captureLog: vi.fn(),
- };
-});
-
-const mockCaptureLog = vi.mocked(_INTERNAL_captureLog);
-
-describe('createSentryPinoTransport', () => {
- beforeEach(() => {
- vi.clearAllMocks();
- });
-
- afterEach(() => {
- vi.resetAllMocks();
- });
-
- it('should be defined', () => {
- expect(createSentryPinoTransport).toBeDefined();
- });
-
- it('should create a transport that forwards logs to Sentry', async () => {
- const transport = await createSentryPinoTransport();
- expect(transport).toBeDefined();
- expect(typeof transport.write).toBe('function');
- });
-
- it('should capture logs with correct level mapping', async () => {
- const transport = await createSentryPinoTransport();
-
- // Simulate a Pino log entry
- const testLog = {
- level: 30, // info level in Pino
- msg: 'Test message',
- time: Date.now(),
- hostname: 'test-host',
- pid: 12345,
- };
-
- // Write the log to the transport
- transport.write(`${JSON.stringify(testLog)}\n`);
-
- // Give it a moment to process
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'info',
- message: 'Test message',
- attributes: expect.objectContaining({
- hostname: 'test-host',
- pid: 12345,
- 'sentry.origin': 'auto.logging.pino',
- }),
- });
- });
-
- it('should map all Pino log levels correctly', async () => {
- const transport = await createSentryPinoTransport();
-
- const testCases = [
- { pinoLevel: 10, expectedSentryLevel: 'trace' },
- { pinoLevel: 20, expectedSentryLevel: 'debug' },
- { pinoLevel: 30, expectedSentryLevel: 'info' },
- { pinoLevel: 40, expectedSentryLevel: 'warn' },
- { pinoLevel: 50, expectedSentryLevel: 'error' },
- { pinoLevel: 60, expectedSentryLevel: 'fatal' },
- ];
-
- for (const { pinoLevel, expectedSentryLevel } of testCases) {
- const testLog = {
- level: pinoLevel,
- msg: `Test ${expectedSentryLevel} message`,
- time: Date.now(),
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
- }
-
- // Give it a moment to process all logs
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledTimes(6);
-
- testCases.forEach(({ expectedSentryLevel }, index) => {
- expect(mockCaptureLog).toHaveBeenNthCalledWith(index + 1, {
- level: expectedSentryLevel,
- message: `Test ${expectedSentryLevel} message`,
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- }),
- });
- });
- });
-
- it('should respect level filtering', async () => {
- const transport = await createSentryPinoTransport({
- logLevels: ['error', 'fatal'],
- });
-
- const testLogs = [
- { level: 30, msg: 'Info message' }, // Should be filtered out
- { level: 50, msg: 'Error message' }, // Should be captured
- { level: 60, msg: 'Fatal message' }, // Should be captured
- ];
-
- for (const testLog of testLogs) {
- transport.write(`${JSON.stringify(testLog)}\n`);
- }
-
- // Give it a moment to process all logs
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledTimes(2);
- expect(mockCaptureLog).toHaveBeenNthCalledWith(
- 1,
- expect.objectContaining({
- level: 'error',
- message: 'Error message',
- }),
- );
- expect(mockCaptureLog).toHaveBeenNthCalledWith(
- 2,
- expect.objectContaining({
- level: 'fatal',
- message: 'Fatal message',
- }),
- );
- });
-
- it('should handle unknown levels gracefully', async () => {
- const transport = await createSentryPinoTransport();
-
- const testLog = {
- level: 999, // Unknown level
- msg: 'Unknown level message',
- time: Date.now(),
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
-
- // Give it a moment to process
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'fatal', // 999 maps to fatal (55+ range)
- message: 'Unknown level message',
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- }),
- });
- });
-
- it('should handle non-numeric levels gracefully', async () => {
- const transport = await createSentryPinoTransport();
-
- const testLog = {
- level: 'invalid', // Non-numeric level
- msg: 'Invalid level message',
- time: Date.now(),
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
-
- // Give it a moment to process
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'info', // Default fallback
- message: 'Invalid level message',
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- 'sentry.pino.level': 'invalid',
- }),
- });
- });
-
- it('should handle malformed JSON gracefully', async () => {
- const transport = await createSentryPinoTransport();
-
- // Write invalid JSON
- transport.write('{ invalid json \n');
-
- // Give it a moment to process
- await new Promise(resolve => setTimeout(resolve, 10));
-
- // Should not crash and should not call captureLog
- expect(mockCaptureLog).not.toHaveBeenCalled();
- });
-
- it('should handle non-object logs gracefully', async () => {
- const transport = await createSentryPinoTransport();
-
- // Write a string instead of an object
- transport.write('"just a string"\n');
-
- // Give it a moment to process
- await new Promise(resolve => setTimeout(resolve, 10));
-
- // pino-abstract-transport parses JSON, so this actually becomes an object
- // The transport should handle it gracefully by logging it
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'info', // Default fallback since no level provided
- message: '', // Empty string for undefined message
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- }),
- });
- });
-
- it('should handle string levels gracefully when no custom levels config is available', async () => {
- const transport = await createSentryPinoTransport();
-
- const testLog = {
- level: 'custom', // String level without custom levels config
- msg: 'Custom string level message',
- time: Date.now(),
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
-
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'info', // Should fallback to info for unknown string levels
- message: 'Custom string level message',
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- 'sentry.pino.level': 'custom',
- }),
- });
- });
-
- it('should attach custom level name as attribute for string levels', async () => {
- const transport = await createSentryPinoTransport();
-
- const testLog = {
- level: 'critical', // Custom string level
- msg: 'Critical level message',
- time: Date.now(),
- userId: 123,
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
-
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'info', // Mapped level
- message: 'Critical level message',
- attributes: expect.objectContaining({
- userId: 123,
- 'sentry.origin': 'auto.logging.pino',
- 'sentry.pino.level': 'critical', // Original custom level name preserved
- }),
- });
- });
-
- it('should not attach custom level attribute for numeric levels', async () => {
- const transport = await createSentryPinoTransport();
-
- const testLog = {
- level: 30, // Standard numeric level
- msg: 'Standard level message',
- time: Date.now(),
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
-
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'info',
- message: 'Standard level message',
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- // Should NOT have 'sentry.pino.level' for numeric levels
- }),
- });
-
- // Explicitly check that the custom level attribute is not present
- const capturedCall = mockCaptureLog.mock.calls[0][0];
- expect(capturedCall.attributes).not.toHaveProperty('sentry.pino.level');
- });
-
- it('should handle custom numeric levels with range-based mapping', async () => {
- const transport = await createSentryPinoTransport();
-
- const testCases = [
- { level: 11, expectedSentryLevel: 'trace' }, // 11 is in trace range (0-14)
- { level: 23, expectedSentryLevel: 'debug' }, // 23 is in debug range (15-24)
- { level: 33, expectedSentryLevel: 'info' }, // 33 is in info range (25-34)
- { level: 42, expectedSentryLevel: 'warn' }, // 42 is in warn range (35-44)
- { level: 52, expectedSentryLevel: 'error' }, // 52 is in error range (45-54)
- { level: 75, expectedSentryLevel: 'fatal' }, // 75 is in fatal range (55+)
- ];
-
- for (const { level } of testCases) {
- const testLog = {
- level,
- msg: `Custom numeric level ${level}`,
- time: Date.now(),
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
- }
-
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledTimes(6);
-
- testCases.forEach(({ level, expectedSentryLevel }, index) => {
- expect(mockCaptureLog).toHaveBeenNthCalledWith(index + 1, {
- level: expectedSentryLevel,
- message: `Custom numeric level ${level}`,
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- }),
- });
- });
- });
-
- it('should handle nested keys', async () => {
- const transport = await createSentryPinoTransport();
-
- // Test with logs that include a nested object structure as Pino would create
- // when nestedKey is configured (we'll test by manually checking the flattening logic)
- const testLog = {
- level: 30,
- msg: 'Test message with nested payload',
- time: Date.now(),
- payload: {
- level: 'hi', // Conflicting with Pino's level
- time: 'never', // Conflicting with Pino's time
- foo: 'bar',
- userId: 123,
- },
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
-
- await new Promise(resolve => setTimeout(resolve, 10));
-
- // Without nestedKey configuration, the nested object should remain as-is
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'info',
- message: 'Test message with nested payload',
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- payload: {
- level: 'hi',
- time: 'never',
- foo: 'bar',
- userId: 123,
- }, // Should remain nested without nestedKey config
- }),
- });
- });
-
- it('should handle logs without conflicting nested objects', async () => {
- const transport = await createSentryPinoTransport();
-
- const testLog = {
- level: 40,
- msg: 'Warning with simple nested data',
- time: Date.now(),
- data: {
- errorCode: 'E001',
- module: 'auth',
- details: 'Invalid credentials',
- },
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
-
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'warn',
- message: 'Warning with simple nested data',
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- data: {
- errorCode: 'E001',
- module: 'auth',
- details: 'Invalid credentials',
- }, // Should remain as nested object
- }),
- });
- });
-
- it('should handle logs with multiple nested objects', async () => {
- const transport = await createSentryPinoTransport();
-
- const testLog = {
- level: 30,
- msg: 'Test message with multiple nested objects',
- time: Date.now(),
- user: {
- id: 123,
- name: 'John Doe',
- },
- request: {
- method: 'POST',
- url: '/api/users',
- headers: {
- 'content-type': 'application/json',
- },
- },
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
-
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'info',
- message: 'Test message with multiple nested objects',
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- user: {
- id: 123,
- name: 'John Doe',
- },
- request: {
- method: 'POST',
- url: '/api/users',
- headers: {
- 'content-type': 'application/json',
- },
- },
- }),
- });
- });
-
- it('should handle null nested objects', async () => {
- const transport = await createSentryPinoTransport();
-
- const testLog = {
- level: 30,
- msg: 'Test message with null values',
- time: Date.now(),
- data: null,
- user: undefined,
- config: {
- setting: null,
- },
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
-
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'info',
- message: 'Test message with null values',
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- data: null,
- config: {
- setting: null,
- },
- }),
- });
- });
-
- it('should work normally with mixed data types', async () => {
- const transport = await createSentryPinoTransport();
-
- const testLog = {
- level: 30,
- msg: 'Mixed data types log',
- time: Date.now(),
- stringValue: 'test',
- numberValue: 42,
- booleanValue: true,
- arrayValue: [1, 2, 3],
- objectValue: { nested: 'value' },
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
-
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'info',
- message: 'Mixed data types log',
- attributes: expect.objectContaining({
- stringValue: 'test',
- numberValue: 42,
- booleanValue: true,
- arrayValue: [1, 2, 3],
- objectValue: { nested: 'value' },
- 'sentry.origin': 'auto.logging.pino',
- }),
- });
- });
-
- it('should handle string messages', async () => {
- const transport = await createSentryPinoTransport();
-
- const testLog = {
- level: 30,
- msg: 'This is a string message',
- time: Date.now(),
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
-
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'info',
- message: 'This is a string message',
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- }),
- });
- });
-
- it('should handle number messages', async () => {
- const transport = await createSentryPinoTransport();
-
- const testLog = {
- level: 30,
- msg: 42,
- time: Date.now(),
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
-
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'info',
- message: '42',
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- }),
- });
- });
-
- it('should handle boolean messages', async () => {
- const transport = await createSentryPinoTransport();
-
- const testCases = [{ msg: true }, { msg: false }];
-
- for (const { msg } of testCases) {
- const testLog = {
- level: 30,
- msg,
- time: Date.now(),
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
- }
-
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledTimes(2);
- expect(mockCaptureLog).toHaveBeenNthCalledWith(1, {
- level: 'info',
- message: 'true',
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- }),
- });
- expect(mockCaptureLog).toHaveBeenNthCalledWith(2, {
- level: 'info',
- message: 'false',
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- }),
- });
- });
-
- it('should handle null and undefined messages', async () => {
- const transport = await createSentryPinoTransport();
-
- const testCases = [{ msg: null }, { msg: undefined }];
-
- for (const { msg } of testCases) {
- const testLog = {
- level: 30,
- msg,
- time: Date.now(),
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
- }
-
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledTimes(2);
- expect(mockCaptureLog).toHaveBeenNthCalledWith(1, {
- level: 'info',
- message: 'null',
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- }),
- });
- expect(mockCaptureLog).toHaveBeenNthCalledWith(2, {
- level: 'info',
- message: '',
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- }),
- });
- });
-
- it('should handle object messages', async () => {
- const transport = await createSentryPinoTransport();
-
- const testLog = {
- level: 30,
- msg: { key: 'value', nested: { prop: 123 } },
- time: Date.now(),
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
-
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'info',
- message: '{"key":"value","nested":{"prop":123}}',
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- }),
- });
- });
-
- it('should handle array messages', async () => {
- const transport = await createSentryPinoTransport();
-
- const testLog = {
- level: 30,
- msg: [1, 'two', { three: 3 }],
- time: Date.now(),
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
-
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'info',
- message: '[1,"two",{"three":3}]',
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- }),
- });
- });
-
- it('should handle circular object messages gracefully', async () => {
- const transport = await createSentryPinoTransport();
-
- // Create a test log with a circular object as the message
- // We can't use JSON.stringify directly, so we'll simulate what happens
- const testLog = {
- level: 30,
- msg: { name: 'test', circular: true }, // Simplified object that represents circular data
- time: Date.now(),
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
-
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'info',
- message: '{"name":"test","circular":true}', // The object should be serialized normally
- attributes: expect.objectContaining({
- 'sentry.origin': 'auto.logging.pino',
- }),
- });
- });
-
- it('should handle missing message gracefully', async () => {
- const transport = await createSentryPinoTransport();
-
- const testLog = {
- level: 30,
- // No msg property
- time: Date.now(),
- someOtherData: 'value',
- };
-
- transport.write(`${JSON.stringify(testLog)}\n`);
-
- await new Promise(resolve => setTimeout(resolve, 10));
-
- expect(mockCaptureLog).toHaveBeenCalledWith({
- level: 'info',
- message: '', // Empty string for undefined message
- attributes: expect.objectContaining({
- someOtherData: 'value',
- 'sentry.origin': 'auto.logging.pino',
- }),
- });
- });
-});
diff --git a/packages/pino-transport/tsconfig.json b/packages/pino-transport/tsconfig.json
deleted file mode 100644
index 64d6f3a1b9e0..000000000000
--- a/packages/pino-transport/tsconfig.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "extends": "../../tsconfig.json",
-
- "include": ["src/**/*"],
-
- "compilerOptions": {
- "lib": ["es2020"],
- "module": "Node16"
- }
-}
diff --git a/packages/pino-transport/tsconfig.test.json b/packages/pino-transport/tsconfig.test.json
deleted file mode 100644
index 4c24dbbea96e..000000000000
--- a/packages/pino-transport/tsconfig.test.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "extends": "./tsconfig.json",
- "include": ["test/**/*", "src/**/*", "vite.config.ts"],
- "compilerOptions": {
- "types": ["vitest/globals", "node"]
- }
-}
diff --git a/packages/pino-transport/tsconfig.types.json b/packages/pino-transport/tsconfig.types.json
deleted file mode 100644
index f35cdd6b5d81..000000000000
--- a/packages/pino-transport/tsconfig.types.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "extends": "./tsconfig.json",
- "compilerOptions": {
- "outDir": "build/types",
- "declaration": true,
- "declarationMap": true,
- "emitDeclarationOnly": true,
- "stripInternal": true
- }
-}
diff --git a/packages/pino-transport/vite.config.ts b/packages/pino-transport/vite.config.ts
deleted file mode 100644
index ff64487a9265..000000000000
--- a/packages/pino-transport/vite.config.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { defineConfig } from 'vitest/config';
-import baseConfig from '../../vite/vite.config';
-
-export default defineConfig({
- ...baseConfig,
- test: {
- ...baseConfig.test,
- environment: 'node',
- },
-});
diff --git a/yarn.lock b/yarn.lock
index 2b7fc676accc..4d084a8cf3c7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -24777,7 +24777,7 @@ pino-std-serializers@^7.0.0:
resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz#7c625038b13718dbbd84ab446bd673dc52259e3b"
integrity sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==
-pino@9.9.4, pino@^9.0.0:
+pino@9.9.4:
version "9.9.4"
resolved "https://registry.yarnpkg.com/pino/-/pino-9.9.4.tgz#21ed2c27cc177f797e3249c99d340f0bcd6b248e"
integrity sha512-d1XorUQ7sSKqVcYdXuEYs2h1LKxejSorMEJ76XoZ0pPDf8VzJMe7GlPXpMBZeQ9gE4ZPIp5uGD+5Nw7scxiigg==