Skip to content

Commit ad39866

Browse files
committed
feat(pino-transport): Add functionality to send logs to sentry
1 parent 4bbe610 commit ad39866

File tree

5 files changed

+1298
-24
lines changed

5 files changed

+1298
-24
lines changed

packages/pino-transport/README.md

Lines changed: 264 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,279 @@
1-
# @sentry/pino-transport
1+
# Sentry Pino Transport
22

3-
[![npm version](https://img.shields.io/npm/v/@sentry/pino-transport.svg)](https://www.npmjs.com/package/@sentry/pino-transport)
4-
[![npm dm](https://img.shields.io/npm/dm/@sentry/pino-transport.svg)](https://www.npmjs.com/package/@sentry/pino-transport)
5-
[![npm dt](https://img.shields.io/npm/dt/@sentry/pino-transport.svg)](https://www.npmjs.com/package/@sentry/pino-transport)
3+
A Pino transport for sending logs to Sentry using the Sentry JavaScript SDK.
64

7-
**This package is currently in alpha. Breaking changes may still occur.**
8-
9-
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.
5+
This transport forwards Pino logs to Sentry, allowing you to view and analyze your application logs alongside your errors and performance data in Sentry.
106

117
## Installation
128

139
```bash
14-
npm install @sentry/node @sentry/pino-transport
10+
npm install @sentry/pino-transport pino
1511
# or
16-
yarn add @sentry/node @sentry/pino-transport
12+
yarn add @sentry/pino-transport pino
1713
```
1814

19-
## Usage
15+
## Requirements
2016

21-
TODO: Add usage instructions
17+
- Node.js 18+
18+
- Pino v8 or v9
19+
- `@sentry/node` SDK with `_experiments.enableLogs: true`
2220

23-
## Requirements
21+
## Setup
22+
23+
First, make sure Sentry is initialized with logging enabled:
24+
25+
```javascript
26+
import * as Sentry from '@sentry/node';
27+
28+
Sentry.init({
29+
dsn: 'YOUR_DSN',
30+
_experiments: {
31+
enableLogs: true,
32+
},
33+
});
34+
```
35+
36+
Then create a Pino logger with the Sentry transport:
37+
38+
```javascript
39+
import pino from 'pino';
40+
41+
const logger = pino({
42+
transport: {
43+
target: '@sentry/pino-transport',
44+
options: {
45+
// Optional: filter which log levels to send to Sentry
46+
levels: ['error', 'fatal'], // defaults to all levels
47+
},
48+
},
49+
});
50+
51+
// Now your logs will be sent to Sentry
52+
logger.info('This is an info message');
53+
logger.error('This is an error message');
54+
```
55+
56+
### Programmatic Usage
57+
58+
You can also create the transport programmatically:
59+
60+
```javascript
61+
import pino from 'pino';
62+
import { createSentryPinoTransport } from '@sentry/pino-transport';
63+
64+
const transport = pino.transport({
65+
targets: [
66+
{
67+
target: 'pino-pretty', // Console output
68+
level: 'info',
69+
},
70+
{
71+
target: createSentryPinoTransport,
72+
level: 'error',
73+
options: {
74+
levels: ['error', 'fatal'], // Only send errors and fatal logs to Sentry
75+
},
76+
},
77+
],
78+
});
79+
80+
const logger = pino(transport);
81+
```
82+
83+
## Configuration Options
84+
85+
The transport accepts the following options:
86+
87+
### `levels`
88+
89+
**Type:** `Array<'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'>`
90+
**Default:** `['trace', 'debug', 'info', 'warn', 'error', 'fatal']` (all levels)
91+
92+
Use this option to filter which log levels should be sent to Sentry.
93+
94+
```javascript
95+
const transport = pino.transport({
96+
target: '@sentry/pino-transport',
97+
options: {
98+
levels: ['warn', 'error', 'fatal'], // Only send warnings and above
99+
},
100+
});
101+
```
102+
103+
## Log Level Mapping
104+
105+
Pino log levels are automatically mapped to Sentry log severity levels:
106+
107+
| Pino Level | Pino Numeric | Sentry Level |
108+
| ---------- | ------------ | ------------ |
109+
| trace | 10 | trace |
110+
| debug | 20 | debug |
111+
| info | 30 | info |
112+
| warn | 40 | warn |
113+
| error | 50 | error |
114+
| fatal | 60 | fatal |
115+
116+
### Custom Levels Support
117+
118+
Custom numeric levels are mapped to Sentry levels using ranges, so levels like `11`, `23`, or `42` will map correctly:
119+
120+
- `0-14``trace`
121+
- `15-24``debug`
122+
- `25-34``info`
123+
- `35-44``warn`
124+
- `45-54``error`
125+
- `55+``fatal`
126+
127+
```javascript
128+
import pino from 'pino';
129+
130+
const logger = pino({
131+
customLevels: {
132+
critical: 55, // Maps to 'fatal' (55+ range)
133+
notice: 35, // Maps to 'warn' (35-44 range)
134+
verbose: 11, // Maps to 'trace' (0-14 range)
135+
},
136+
transport: {
137+
target: '@sentry/pino-transport',
138+
},
139+
});
140+
141+
logger.critical('Critical issue occurred'); // → Sent as 'fatal' to Sentry
142+
logger.notice('Important notice'); // → Sent as 'warn' to Sentry
143+
logger.verbose('Detailed information'); // → Sent as 'trace' to Sentry
144+
```
145+
146+
#### Custom Level Attributes
147+
148+
When using custom string levels, the original level name is preserved as `sentry.pino.level` attribute for better traceability:
149+
150+
```javascript
151+
// Log entry in Sentry will include:
152+
// {
153+
// level: 'warn', // Mapped Sentry level
154+
// message: 'Audit event',
155+
// attributes: {
156+
// 'sentry.pino.level': 'audit', // Original custom level name
157+
// 'sentry.origin': 'auto.logging.pino',
158+
// // ... other log attributes
159+
// }
160+
// }
161+
```
162+
163+
### Custom Message Key
164+
165+
The transport respects Pino's `messageKey` configuration:
166+
167+
```javascript
168+
const logger = pino({
169+
messageKey: 'message', // Use 'message' instead of default 'msg'
170+
transport: {
171+
target: '@sentry/pino-transport',
172+
},
173+
});
174+
175+
logger.info({ message: 'Hello world' }); // Works correctly with custom messageKey
176+
```
177+
178+
### Nested Key Support
179+
180+
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.
181+
182+
```javascript
183+
const logger = pino({
184+
nestedKey: 'payload', // Nest logged objects under 'payload' key
185+
transport: {
186+
target: '@sentry/pino-transport',
187+
},
188+
});
189+
190+
const conflictingObject = {
191+
level: 'hi', // Conflicts with Pino's level
192+
time: 'never', // Conflicts with Pino's time
193+
foo: 'bar',
194+
userId: 123,
195+
};
196+
197+
logger.info(conflictingObject);
198+
199+
// Without nestedKey, this would cause property conflicts
200+
// With nestedKey, Pino creates: { level: 30, time: 1234567890, payload: conflictingObject }
201+
// The transport flattens it to:
202+
// {
203+
// level: 'info',
204+
// message: undefined,
205+
// attributes: {
206+
// 'payload.level': 'hi', // Flattened nested properties
207+
// 'payload.time': 'never',
208+
// 'payload.foo': 'bar',
209+
// 'payload.userId': 123,
210+
// 'sentry.origin': 'auto.logging.pino',
211+
// }
212+
// }
213+
```
214+
215+
This flattening ensures that no property conflicts occur between logged objects and Pino's internal properties.
216+
217+
## Usage Examples
218+
219+
### Basic Logging
220+
221+
```javascript
222+
import pino from 'pino';
223+
224+
const logger = pino({
225+
transport: {
226+
target: '@sentry/pino-transport',
227+
},
228+
});
229+
230+
logger.trace('Starting application');
231+
logger.debug('Debug information', { userId: 123 });
232+
logger.info('User logged in', { userId: 123, username: 'john_doe' });
233+
logger.warn('Deprecated API used', { endpoint: '/old-api' });
234+
logger.error('Database connection failed', { error: 'Connection timeout' });
235+
logger.fatal('Application crashed', { reason: 'Out of memory' });
236+
```
237+
238+
### Multiple Transports
239+
240+
```javascript
241+
import pino from 'pino';
242+
243+
const logger = pino({
244+
transport: {
245+
targets: [
246+
{
247+
target: 'pino-pretty',
248+
options: { colorize: true },
249+
level: 'debug',
250+
},
251+
{
252+
target: '@sentry/pino-transport',
253+
options: {
254+
logLevels: ['warn', 'error', 'fatal'],
255+
},
256+
level: 'warn',
257+
},
258+
],
259+
},
260+
});
261+
```
262+
263+
## Troubleshooting
264+
265+
### Logs not appearing in Sentry
266+
267+
1. Ensure `_experiments.enableLogs: true` is set in your Sentry configuration.
268+
2. Check that your DSN is correct and the SDK is properly initialized.
269+
3. Verify the log level is included in the `levels` configuration.
270+
4. Check your Sentry organization stats page to see if logs are being received by Sentry.
271+
272+
## Related Documentation
24273

25-
- Node.js 18 or higher
26-
- Pino 8.0.0 or higher
27-
- @sentry/node must be configured in your application
274+
- [Sentry Logs Documentation](https://docs.sentry.io/platforms/javascript/guides/node/logs/)
275+
- [Pino Documentation](https://getpino.io/)
276+
- [Pino Transports](https://getpino.io/#/docs/transports)
28277

29278
## License
30279

packages/pino-transport/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
"access": "public"
4040
},
4141
"dependencies": {
42-
"@sentry/core": "9.30.0"
42+
"@sentry/core": "9.30.0",
43+
"pino-abstract-transport": "^2.0.0"
4344
},
4445
"peerDependencies": {
4546
"pino": "^8.0.0 || ^9.0.0"

0 commit comments

Comments
 (0)