From 27c842d29b8fa015318254b867be9c64f435cec6 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Thu, 13 Jun 2024 10:16:00 -0700 Subject: [PATCH] feat: instr-pino (#225) Closes: #33 --- package-lock.json | 86 ++++++++++++------- .../docs/supported-technologies.mdx | 1 + .../lib/instrumentations.js | 4 + packages/opentelemetry-node/package.json | 2 + .../test/fixtures/use-pino.js | 33 +++++++ .../test/instr-pino.test.js | 66 ++++++++++++++ .../types/instrumentations.d.ts | 1 + 7 files changed, 163 insertions(+), 30 deletions(-) create mode 100644 packages/opentelemetry-node/test/fixtures/use-pino.js create mode 100644 packages/opentelemetry-node/test/instr-pino.test.js diff --git a/package-lock.json b/package-lock.json index 54bab949..795f4a41 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4397,6 +4397,20 @@ "@opentelemetry/api": "^1.3.0" } }, + "node_modules/@opentelemetry/instrumentation-pino": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pino/-/instrumentation-pino-0.40.0.tgz", + "integrity": "sha512-29B7mpabiB5m9YeVuUpWNceKv2E2semh44Y0EngFn7Z/Dwg13j+jsD3h6RaLPLUmUynWKSa160jZm0XrWbx40w==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.52.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, "node_modules/@opentelemetry/instrumentation-redis-4": { "version": "0.40.0", "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.40.0.tgz", @@ -10182,22 +10196,22 @@ } }, "node_modules/pino": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-9.0.0.tgz", - "integrity": "sha512-uI1ThkzTShNSwvsUM6b4ND8ANzWURk9zTELMztFkmnCQeR/4wkomJ+echHee5GMWGovoSfjwdeu80DsFIt7mbA==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.2.0.tgz", + "integrity": "sha512-g3/hpwfujK5a4oVbaefoJxezLzsDgLcNJeITvC6yrfwYeT9la+edCK42j5QpEQSQCZgTKapXvnQIdgZwvRaZug==", "dev": true, "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^1.2.0", - "pino-std-serializers": "^6.0.0", + "pino-std-serializers": "^7.0.0", "process-warning": "^3.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", - "sonic-boom": "^3.7.0", - "thread-stream": "^2.6.0" + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" @@ -10214,9 +10228,9 @@ } }, "node_modules/pino-std-serializers": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", - "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz", + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==", "dev": true }, "node_modules/pkg-up": { @@ -11111,9 +11125,9 @@ } }, "node_modules/sonic-boom": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz", - "integrity": "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.0.1.tgz", + "integrity": "sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ==", "dev": true, "dependencies": { "atomic-sleep": "^1.0.0" @@ -11556,9 +11570,9 @@ "license": "MIT" }, "node_modules/thread-stream": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.7.0.tgz", - "integrity": "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.0.2.tgz", + "integrity": "sha512-cBL4xF2A3lSINV4rD5tyqnKH4z/TgWPvT+NaVhJDSwK962oo/Ye7cHSMbDzwcu7tAE1SfU6Q4XtV6Hucmi6Hlw==", "dev": true, "dependencies": { "real-require": "^0.2.0" @@ -12173,6 +12187,7 @@ "@opentelemetry/instrumentation-ioredis": "^0.41.0", "@opentelemetry/instrumentation-mongodb": "^0.45.0", "@opentelemetry/instrumentation-pg": "^0.42.0", + "@opentelemetry/instrumentation-pino": "^0.40.0", "@opentelemetry/instrumentation-redis-4": "^0.40.0", "@opentelemetry/instrumentation-tedious": "^0.11.0", "@opentelemetry/instrumentation-undici": "^0.3.0", @@ -12207,6 +12222,7 @@ "module-details-from-path": "^1.0.3", "mongodb": "^6.7.0", "pg": "^8.12.0", + "pino": "^9.2.0", "redis": "^4.6.14", "semver": "^7.6.2", "tape": "^5.7.5", @@ -14363,6 +14379,7 @@ "@opentelemetry/instrumentation-ioredis": "^0.41.0", "@opentelemetry/instrumentation-mongodb": "^0.45.0", "@opentelemetry/instrumentation-pg": "^0.42.0", + "@opentelemetry/instrumentation-pino": "^0.40.0", "@opentelemetry/instrumentation-redis-4": "^0.40.0", "@opentelemetry/instrumentation-tedious": "^0.11.0", "@opentelemetry/instrumentation-undici": "^0.3.0", @@ -14385,6 +14402,7 @@ "module-details-from-path": "^1.0.3", "mongodb": "^6.7.0", "pg": "^8.12.0", + "pino": "^9.2.0", "redis": "^4.6.14", "safe-stable-stringify": "^2.4.3", "semver": "^7.6.2", @@ -15812,6 +15830,14 @@ "@types/pg-pool": "2.0.4" } }, + "@opentelemetry/instrumentation-pino": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pino/-/instrumentation-pino-0.40.0.tgz", + "integrity": "sha512-29B7mpabiB5m9YeVuUpWNceKv2E2semh44Y0EngFn7Z/Dwg13j+jsD3h6RaLPLUmUynWKSa160jZm0XrWbx40w==", + "requires": { + "@opentelemetry/instrumentation": "^0.52.0" + } + }, "@opentelemetry/instrumentation-redis-4": { "version": "0.40.0", "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.40.0.tgz", @@ -19918,22 +19944,22 @@ "dev": true }, "pino": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-9.0.0.tgz", - "integrity": "sha512-uI1ThkzTShNSwvsUM6b4ND8ANzWURk9zTELMztFkmnCQeR/4wkomJ+echHee5GMWGovoSfjwdeu80DsFIt7mbA==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.2.0.tgz", + "integrity": "sha512-g3/hpwfujK5a4oVbaefoJxezLzsDgLcNJeITvC6yrfwYeT9la+edCK42j5QpEQSQCZgTKapXvnQIdgZwvRaZug==", "dev": true, "requires": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^1.2.0", - "pino-std-serializers": "^6.0.0", + "pino-std-serializers": "^7.0.0", "process-warning": "^3.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", - "sonic-boom": "^3.7.0", - "thread-stream": "^2.6.0" + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" } }, "pino-abstract-transport": { @@ -19947,9 +19973,9 @@ } }, "pino-std-serializers": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", - "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz", + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==", "dev": true }, "pkg-up": { @@ -20554,9 +20580,9 @@ "dev": true }, "sonic-boom": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz", - "integrity": "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.0.1.tgz", + "integrity": "sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ==", "dev": true, "requires": { "atomic-sleep": "^1.0.0" @@ -20866,9 +20892,9 @@ "dev": true }, "thread-stream": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.7.0.tgz", - "integrity": "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.0.2.tgz", + "integrity": "sha512-cBL4xF2A3lSINV4rD5tyqnKH4z/TgWPvT+NaVhJDSwK962oo/Ye7cHSMbDzwcu7tAE1SfU6Q4XtV6Hucmi6Hlw==", "dev": true, "requires": { "real-require": "^0.2.0" diff --git a/packages/opentelemetry-node/docs/supported-technologies.mdx b/packages/opentelemetry-node/docs/supported-technologies.mdx index 131b5824..78e0ccfa 100644 --- a/packages/opentelemetry-node/docs/supported-technologies.mdx +++ b/packages/opentelemetry-node/docs/supported-technologies.mdx @@ -32,6 +32,7 @@ This follows from the [OpenTelemetry JS supported runtimes](https://github.com/o | `@opentelemetry/instrumentation-http` | `http` module for Node.js `>=14` | [README](https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-instrumentation-http#readme) | | `@opentelemetry/instrumentation-ioredis` | `ioredis` version range `>=2 <6` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-ioredis#readme) | | `@opentelemetry/instrumentation-mongodb` | `mongodb` version range `>=3.3 <7` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-mongodb#readme) | +| `@opentelemetry/instrumentation-pino` | `pino` version range `>=5.14.0 <10` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-pino#readme) | | `@opentelemetry/instrumentation-pg` | `pg` version range `>=8 <9` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-pg#readme) | | `@opentelemetry/instrumentation-redis-4` | `redis` version range `^4.0.0` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-redis-4#readme) | | `@opentelemetry/instrumentation-tedious` | `tedious` version range `>=1.11.0 <=15` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/instrumentation-tedious#readme) | diff --git a/packages/opentelemetry-node/lib/instrumentations.js b/packages/opentelemetry-node/lib/instrumentations.js index 3cd41f6d..f3c0dba5 100644 --- a/packages/opentelemetry-node/lib/instrumentations.js +++ b/packages/opentelemetry-node/lib/instrumentations.js @@ -33,6 +33,7 @@ * "@opentelemetry/instrumentation-grpc": import('@opentelemetry/instrumentation-grpc').GrpcInstrumentation | InstrumentationFactory, * "@opentelemetry/instrumentation-hapi": import('@opentelemetry/instrumentation-hapi').HapiInstrumentation | InstrumentationFactory, * "@opentelemetry/instrumentation-mongodb": import('@opentelemetry/instrumentation-mongodb').MongoDBInstrumentation | InstrumentationFactory + * "@opentelemetry/instrumentation-pino": import('@opentelemetry/instrumentation-pino').PinoInstrumentation | InstrumentationFactory * "@opentelemetry/instrumentation-pg": import('@opentelemetry/instrumentation-pg').PgInstrumentation | InstrumentationFactory * "@opentelemetry/instrumentation-winston": import('@opentelemetry/instrumentation-winston').WinstonInstrumentationConfig | InstrumentationFactory, * "@opentelemetry/instrumentation-tedious": import('@opentelemetry/instrumentation-tedious').TediousInstrumentation | InstrumentationFactory, @@ -63,6 +64,7 @@ const { const { MongoDBInstrumentation, } = require('@opentelemetry/instrumentation-mongodb'); +const {PinoInstrumentation} = require('@opentelemetry/instrumentation-pino'); const {PgInstrumentation} = require('@opentelemetry/instrumentation-pg'); const { WinstonInstrumentation, @@ -102,6 +104,8 @@ const INSTRUMENTATIONS = { new IORedisInstrumentation(cfg), '@opentelemetry/instrumentation-mongodb': (cfg) => new MongoDBInstrumentation(cfg), + '@opentelemetry/instrumentation-pino': (cfg) => + new PinoInstrumentation(cfg), '@opentelemetry/instrumentation-pg': (cfg) => new PgInstrumentation(cfg), '@opentelemetry/instrumentation-winston': (cfg) => new WinstonInstrumentation(cfg), diff --git a/packages/opentelemetry-node/package.json b/packages/opentelemetry-node/package.json index 37566bbd..70f5413b 100644 --- a/packages/opentelemetry-node/package.json +++ b/packages/opentelemetry-node/package.json @@ -82,6 +82,7 @@ "@opentelemetry/instrumentation-ioredis": "^0.41.0", "@opentelemetry/instrumentation-mongodb": "^0.45.0", "@opentelemetry/instrumentation-pg": "^0.42.0", + "@opentelemetry/instrumentation-pino": "^0.40.0", "@opentelemetry/instrumentation-redis-4": "^0.40.0", "@opentelemetry/instrumentation-tedious": "^0.11.0", "@opentelemetry/instrumentation-undici": "^0.3.0", @@ -116,6 +117,7 @@ "module-details-from-path": "^1.0.3", "mongodb": "^6.7.0", "pg": "^8.12.0", + "pino": "^9.2.0", "redis": "^4.6.14", "semver": "^7.6.2", "tape": "^5.7.5", diff --git a/packages/opentelemetry-node/test/fixtures/use-pino.js b/packages/opentelemetry-node/test/fixtures/use-pino.js new file mode 100644 index 00000000..ec98c602 --- /dev/null +++ b/packages/opentelemetry-node/test/fixtures/use-pino.js @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// Usage: node -r @elastic/opentelemetry-node use-pino.js + +const pino = require('pino'); +const otel = require('@opentelemetry/api'); + +const log = pino(); + +log.info({foo: 'bar'}, 'hi'); + +const tracer = otel.trace.getTracer('test'); +tracer.startActiveSpan('manual-span', (span) => { + log.info('with span info'); + span.end(); +}); diff --git a/packages/opentelemetry-node/test/instr-pino.test.js b/packages/opentelemetry-node/test/instr-pino.test.js new file mode 100644 index 00000000..2ef00fb0 --- /dev/null +++ b/packages/opentelemetry-node/test/instr-pino.test.js @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// Test that 'pino' instrumentation generates the telemetry we expect. + +const test = require('tape'); +const {runTestFixtures} = require('./testutils'); + +/** @type {import('./testutils').TestFixture[]} */ +const testFixtures = [ + { + name: 'use-pino', + args: ['./fixtures/use-pino.js'], + cwd: __dirname, + env: { + NODE_OPTIONS: '--require=@elastic/opentelemetry-node', + OTEL_LOG_LEVEL: 'none', + }, + // verbose: true, + checkResult: (t, err, stdout, _stderr) => { + t.error(err, `exited successfully: err=${err}`); + // Clumsy pass of stdout info to `checkTelemetry`. + t.recs = stdout.trim().split(/\n/g).map(JSON.parse); + }, + checkTelemetry: (t, col) => { + const recs = t.recs; + const spans = col.sortedSpans; + t.equal(spans.length, 1); + + // Check log records to stdout. + t.equal(recs.length, 2); + t.equal(recs[0].level, 30 /* pino INFO */); + t.equal(recs[0].msg, 'hi'); + t.equal(recs[1].level, 30 /* pino INFO */); + t.equal(recs[1].msg, 'with span info'); + t.equal(recs[1].trace_id, spans[0].traceId); + t.equal(recs[1].span_id, spans[0].spanId); + + // TODO: instr-pino doesn't yet support log-sending, so we don't + // yet expect logs sent via OTLP. + // const logs = col.logs; + // ... + }, + }, +]; + +test('pino instrumentation', (suite) => { + runTestFixtures(suite, testFixtures); + suite.end(); +}); diff --git a/packages/opentelemetry-node/types/instrumentations.d.ts b/packages/opentelemetry-node/types/instrumentations.d.ts index 609310bf..b2cdf1f7 100644 --- a/packages/opentelemetry-node/types/instrumentations.d.ts +++ b/packages/opentelemetry-node/types/instrumentations.d.ts @@ -10,6 +10,7 @@ export type InstrumentaionsMap = { "@opentelemetry/instrumentation-grpc": import('@opentelemetry/instrumentation-grpc').GrpcInstrumentation | InstrumentationFactory; "@opentelemetry/instrumentation-hapi": import('@opentelemetry/instrumentation-hapi').HapiInstrumentation | InstrumentationFactory; "@opentelemetry/instrumentation-mongodb": import('@opentelemetry/instrumentation-mongodb').MongoDBInstrumentation | InstrumentationFactory; + "@opentelemetry/instrumentation-pino": import('@opentelemetry/instrumentation-pino').PinoInstrumentation | InstrumentationFactory; "@opentelemetry/instrumentation-pg": import('@opentelemetry/instrumentation-pg').PgInstrumentation | InstrumentationFactory; "@opentelemetry/instrumentation-winston": import('@opentelemetry/instrumentation-winston').WinstonInstrumentationConfig | InstrumentationFactory; "@opentelemetry/instrumentation-tedious": import('@opentelemetry/instrumentation-tedious').TediousInstrumentation | InstrumentationFactory;