Skip to content

Commit f84fd61

Browse files
authored
fix: introduce pino mixin function to handle trace/span id injection issue (#163)
## Issue The pino instrumentation won't work (https://www.npmjs.com/package/@opentelemetry/instrumentation-pino) with programmatic import. it seems tricky to attach span/trace id on the transport layer due to the async stream implementation. ## Solution Giving user the custom mixin function which attaches span/trace id
1 parent 1b37576 commit f84fd61

File tree

5 files changed

+57
-15
lines changed

5 files changed

+57
-15
lines changed

.changeset/silly-ravens-invent.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@hyperdx/node-opentelemetry': patch
3+
---
4+
5+
fix: introduce pino mixin function to handle trace/span id injection issue

packages/node-opentelemetry/README.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ configure your logging module.
2525

2626
```ts
2727
import winston from 'winston';
28-
import { getWinstonTransport } from '@hyperdx/node-opentelemetry';
28+
import * as HyperDX from '@hyperdx/node-opentelemetry';
2929

3030
const MAX_LEVEL = 'info';
3131

@@ -34,7 +34,7 @@ const logger = winston.createLogger({
3434
format: winston.format.json(),
3535
transports: [
3636
new winston.transports.Console(),
37-
getWinstonTransport(MAX_LEVEL), // append this to the existing transports
37+
HyperDX.getWinstonTransport(MAX_LEVEL), // append this to the existing transports
3838
],
3939
});
4040

@@ -45,18 +45,21 @@ export default logger;
4545

4646
```ts
4747
import pino from 'pino';
48-
import { getPinoTransport } from '@hyperdx/node-opentelemetry';
48+
import * as HyperDX from '@hyperdx/node-opentelemetry';
4949

5050
const MAX_LEVEL = 'info';
5151

52-
const logger = pino(
53-
pino.transport({
52+
const logger = pino({
53+
mixin: HyperDX.getPinoMixinFunction,
54+
transport: {
5455
targets: [
55-
getPinoTransport(MAX_LEVEL),
56+
HyperDX.getPinoTransport(MAX_LEVEL),
5657
// other transports
5758
],
58-
}),
59-
);
59+
},
60+
});
61+
62+
export default logger;
6063
```
6164

6265
### Configure Environment Variables

packages/node-opentelemetry/examples/dummy.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ const mongoose = require('mongoose');
2525
const mysql = require('mysql');
2626
const mysql2 = require('mysql2');
2727
const pg = require('pg');
28-
const pino = require('pino');
2928
const winston = require('winston');
29+
const pino = require('pino');
3030

3131
const HyperDX = require('../build/src');
3232

3333
HyperDX.init({
34-
apiKey: 'blabla',
34+
apiKey: '',
3535
});
3636

3737
// setTimeout(() => {
@@ -80,14 +80,15 @@ const logger = winston.createLogger({
8080
],
8181
});
8282

83-
const pinoLogger = pino(
84-
pino.transport({
83+
const pinoLogger = pino({
84+
mixin: HyperDX.getPinoMixinFunction,
85+
transport: {
8586
targets: [
8687
HyperDX.getPinoTransport('info'),
8788
// other transports
8889
],
89-
}),
90-
);
90+
},
91+
});
9192

9293
const bunyanLogger = bunyan.createLogger({ name: 'myapp' });
9394

packages/node-opentelemetry/src/logger.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
DEFAULT_HDX_NODE_BETA_MODE,
66
DEFAULT_SERVICE_NAME,
77
} from './constants';
8+
import * as HyperDXPino from './otel-logger/pino';
89
import HyperDXWinston from './otel-logger/winston';
910

1011
import type { HyperDXPinoOptions } from './otel-logger/pino';
@@ -55,11 +56,13 @@ export const getWinstonTransport = (
5556
// TODO: WILL BE DEPRECATED
5657
export const getWinsonTransport = getWinstonTransport;
5758

59+
export const getPinoMixinFunction = HyperDXPino.getMixinFunction;
5860
export const getPinoTransport = (
5961
maxLevel = 'info',
6062
options: PinotTransportOptions = {},
6163
) => {
6264
const apiKey = DEFAULT_HDX_API_KEY();
65+
6366
return {
6467
target: '@hyperdx/node-opentelemetry/build/src/otel-logger/pino',
6568
options: {

packages/node-opentelemetry/src/otel-logger/pino.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import build from 'pino-abstract-transport';
22
import isString from 'lodash.isstring';
3-
import { Attributes, diag } from '@opentelemetry/api';
3+
import {
4+
Attributes,
5+
context,
6+
diag,
7+
isSpanContextValid,
8+
trace,
9+
} from '@opentelemetry/api';
410

511
import { Logger } from './';
612
import { jsonToString } from '../utils';
@@ -48,6 +54,30 @@ export type HyperDXPinoOptions = LoggerOptions & {
4854
getCustomMeta?: () => Attributes;
4955
};
5056

57+
// https://github.com/open-telemetry/opentelemetry-js-contrib/blob/65bc979f9f04410e9a78b4d546f5e08471c1fb6d/plugins/node/opentelemetry-instrumentation-pino/src/instrumentation.ts#L167C11-L167C30
58+
const DEFAULT_LOG_KEYS = {
59+
traceId: 'trace_id',
60+
spanId: 'span_id',
61+
traceFlags: 'trace_flags',
62+
};
63+
export const getMixinFunction = () => {
64+
const span = trace.getSpan(context.active());
65+
if (!span) {
66+
return {};
67+
}
68+
69+
const spanContext = span.spanContext();
70+
71+
if (!isSpanContextValid(spanContext)) {
72+
return {};
73+
}
74+
return {
75+
[DEFAULT_LOG_KEYS.traceId]: spanContext.traceId,
76+
[DEFAULT_LOG_KEYS.spanId]: spanContext.spanId,
77+
[DEFAULT_LOG_KEYS.traceFlags]: `0${spanContext.traceFlags.toString(16)}`,
78+
};
79+
};
80+
5181
export default async ({
5282
apiKey,
5383
getCustomMeta,

0 commit comments

Comments
 (0)