-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat(pino-transport): Add functionality to send logs to sentry #16667
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
04b2d0a
540b1ac
81afabd
57434de
1a65d1d
e9f3ccc
8904cc9
55981ec
1abd8e8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,267 @@ | ||
# @sentry/pino-transport | ||
<p align="center"> | ||
<a href="https://sentry.io/?utm_source=github&utm_medium=logo" target="_blank"> | ||
<img src="https://sentry-brand.storage.googleapis.com/sentry-wordmark-dark-280x84.png" alt="Sentry" width="280" height="84"> | ||
</a> | ||
</p> | ||
|
||
[](https://www.npmjs.com/package/@sentry/pino-transport) | ||
[](https://www.npmjs.com/package/@sentry/pino-transport) | ||
[](https://www.npmjs.com/package/@sentry/pino-transport) | ||
# Official Sentry Pino Transport | ||
|
||
**This package is currently in alpha. Breaking changes may still occur.** | ||
[](https://www.npmjs.com/package/@sentry/solid) | ||
[](https://www.npmjs.com/package/@sentry/solid) | ||
[](https://www.npmjs.com/package/@sentry/solid) | ||
|
||
A Pino transport for integrating [Pino](https://github.com/pinojs/pino) logging with [Sentry](https://sentry.io). This transport automatically captures log messages as Sentry events and breadcrumbs, making it easy to monitor your application's logs in Sentry. | ||
**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/node @sentry/pino-transport | ||
npm install @sentry/pino-transport pino | ||
# or | ||
yarn add @sentry/node @sentry/pino-transport | ||
yarn add @sentry/pino-transport pino | ||
# or | ||
pnpm add @sentry/pino-transport pino | ||
``` | ||
|
||
## Usage | ||
## Requirements | ||
|
||
- Node.js 18+ | ||
- Pino v8 or v9 | ||
- `@sentry/node` SDK with `_experiments.enableLogs: true` | ||
|
||
TODO: Add usage instructions | ||
## Setup | ||
|
||
## Requirements | ||
First, make sure Sentry is initialized with logging enabled: | ||
|
||
```javascript | ||
import * as Sentry from '@sentry/node'; | ||
|
||
Sentry.init({ | ||
dsn: 'YOUR_DSN', | ||
_experiments: { | ||
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 | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm still undecided about this behaviour. See https://getpino.io/#/docs/api?id=opt-customlevels for details about pino custom levels. What does everyone think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean the level ranges? Currently, you're "cutting" it in the middle of the range (or are those already the Pino level cuts?). How about cutting it at the point where the level changes? Like this:
But I am not quite sure how pino works here 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bit hard to map, your call! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think that feels better, just tried it out in my test app. Feels easier to explain to users as well. |
||
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 `_experiments.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 | ||
|
||
- Node.js 18 or higher | ||
- Pino 8.0.0 or higher | ||
- @sentry/node must be configured in your application | ||
- [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 | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
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__; |
Uh oh!
There was an error while loading. Please reload this page.