@platformatic/telemetry 2.35.0 → 2.36.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -48,6 +48,7 @@ class FileSpanExporter {
48
48
  events: span.events,
49
49
  links: span.links,
50
50
  resource: span.resource,
51
+ instrumentationLibrary: span.instrumentationLibrary,
51
52
  }
52
53
  }
53
54
  }
@@ -0,0 +1,18 @@
1
+ 'use strict'
2
+
3
+ const { pathToFileURL } = require('node:url')
4
+ const { createRequire } = require('node:module')
5
+ const { join } = require('node:path')
6
+
7
+ async function importOrLocal ({ projectDir, pkg }) {
8
+ try {
9
+ return import(pkg)
10
+ } catch (err) {
11
+ const pkgJsonPath = join(projectDir, 'package.json')
12
+ const _require = createRequire(pkgJsonPath)
13
+ const fileToImport = _require.resolve(pkg)
14
+ return import(pathToFileURL(fileToImport))
15
+ }
16
+ }
17
+
18
+ module.exports = importOrLocal
@@ -12,6 +12,8 @@ const { tmpdir } = require('node:os')
12
12
  const logger = require('abstract-logging')
13
13
  const { statSync, readFileSync } = require('node:fs') // We want to have all this synch
14
14
  const util = require('node:util')
15
+ const { getInstrumentations } = require('./pluggable-instrumentations')
16
+
15
17
  const debuglog = util.debuglog('@platformatic/telemetry')
16
18
  const {
17
19
  ConsoleSpanExporter,
@@ -31,8 +33,9 @@ const {
31
33
  // https://github.com/open-telemetry/opentelemetry-js/issues/5103
32
34
  process.env.OTEL_SEMCONV_STABILITY_OPT_IN = 'http/dup'
33
35
 
34
- const setupNodeHTTPTelemetry = (opts) => {
35
- const { serviceName } = opts
36
+ const setupNodeHTTPTelemetry = async (opts, serviceDir) => {
37
+ const { serviceName, instrumentations = [] } = opts
38
+ const additionalInstrumentations = await getInstrumentations(instrumentations, serviceDir)
36
39
 
37
40
  let exporter = opts.exporter
38
41
  if (!exporter) {
@@ -96,6 +99,7 @@ const setupNodeHTTPTelemetry = (opts) => {
96
99
  }),
97
100
  new HttpInstrumentation(),
98
101
  new PgInstrumentation(),
102
+ ...additionalInstrumentations
99
103
  ],
100
104
  resource: new Resource({
101
105
  [ATTR_SERVICE_NAME]: serviceName
@@ -110,28 +114,37 @@ const setupNodeHTTPTelemetry = (opts) => {
110
114
  })
111
115
  }
112
116
 
113
- let data = null
114
- const useWorkerData = !!workerData
117
+ const main = async () => {
118
+ let data = null
119
+ const useWorkerData = !!workerData
115
120
 
116
- if (useWorkerData) {
117
- data = workerData
118
- } else if (process.env.PLT_MANAGER_ID) {
119
- try {
120
- const dataPath = resolve(tmpdir(), 'platformatic', 'runtimes', `${process.env.PLT_MANAGER_ID}.json`)
121
- statSync(dataPath)
122
- const jsonData = JSON.parse(readFileSync(dataPath, 'utf8'))
123
- data = jsonData.data
124
- debuglog(`Loaded data from ${dataPath}`)
125
- } catch (e) {
126
- debuglog('Error reading data from file %o', e)
121
+ if (useWorkerData) {
122
+ data = workerData
123
+ } else if (process.env.PLT_MANAGER_ID) {
124
+ try {
125
+ const dataPath = resolve(tmpdir(), 'platformatic', 'runtimes', `${process.env.PLT_MANAGER_ID}.json`)
126
+ statSync(dataPath)
127
+ const jsonData = JSON.parse(readFileSync(dataPath, 'utf8'))
128
+ data = jsonData.data
129
+ debuglog(`Loaded data from ${dataPath}`)
130
+ } catch (e) {
131
+ debuglog('Error reading data from file %o', e)
132
+ }
127
133
  }
128
- }
129
134
 
130
- if (data) {
131
- debuglog('Setting up telemetry %o', data)
132
- const telemetryConfig = useWorkerData ? data?.serviceConfig?.telemetry : data?.telemetryConfig
133
- if (telemetryConfig) {
134
- debuglog('telemetryConfig %o', telemetryConfig)
135
- setupNodeHTTPTelemetry(telemetryConfig)
135
+ if (data) {
136
+ debuglog('Setting up telemetry %o', data)
137
+ const serviceDir = data.serviceConfig?.path
138
+ const telemetryConfig = useWorkerData ? data?.serviceConfig?.telemetry : data?.telemetryConfig
139
+ if (telemetryConfig) {
140
+ debuglog('telemetryConfig %o', telemetryConfig)
141
+ setupNodeHTTPTelemetry(telemetryConfig, serviceDir)
142
+ }
136
143
  }
137
144
  }
145
+
146
+ try {
147
+ main()
148
+ } catch (e) {
149
+ debuglog('Error in main %o', e)
150
+ }
@@ -0,0 +1,66 @@
1
+ 'use strict'
2
+
3
+ const importOrLocal = require('./import-or-local')
4
+
5
+ // These are already set automatically by the runtime, so we throw
6
+ // if set again.
7
+ const defaultInstrumentations = [
8
+ '@opentelemetry/instrumentation-pg',
9
+ '@opentelemetry/instrumentation-http',
10
+ '@opentelemetry/instrumentation-undici'
11
+ ]
12
+
13
+ const getInstrumentationInstance = async (instrumentationConfig, serviceDir) => {
14
+ if (typeof instrumentationConfig === 'string') {
15
+ instrumentationConfig = { package: instrumentationConfig, exportName: 'default', options: {} }
16
+ }
17
+ const { package: packageName, exportName = 'default', options = {} } = instrumentationConfig
18
+
19
+ if (defaultInstrumentations.includes(packageName)) {
20
+ throw new Error(`Instrumentation package ${packageName} is already included by default, please remove it from your config.`)
21
+ }
22
+
23
+ let mod
24
+ try {
25
+ mod = await importOrLocal({ pkg: packageName, projectDir: serviceDir })
26
+ } catch (err) {
27
+ throw new Error(`Instrumentation package not found: ${instrumentationConfig.package}, please add it to your dependencies.`)
28
+ }
29
+
30
+ let Instrumenter = mod[exportName]
31
+ if (!Instrumenter || typeof Instrumenter !== 'function') {
32
+ // Check for for an export that ends with 'Instrumentation'. We need to do that because unfortunately
33
+ // each instrumenttions has different named export. But all of them ends with 'Instrumentation'.
34
+ const possibleExports = Object.keys(mod).filter((key) => key.endsWith('Instrumentation'))
35
+ if (possibleExports.length === 0) {
36
+ throw new Error(`Instrumentation export not found: ${exportName} in ${packageName}. Please specify in config`)
37
+ }
38
+ if (possibleExports.length > 1) {
39
+ throw new Error(`Multiple Instrumentation exports found: ${possibleExports} in ${packageName}. Please specify in config`)
40
+ }
41
+ Instrumenter = mod[possibleExports[0]]
42
+ }
43
+ const instance = new Instrumenter(options)
44
+ return instance
45
+ }
46
+
47
+ // Example of instrumentations config:
48
+ // "instrumentations": [
49
+ // "@opentelemetry/instrumentation-express",
50
+ // {
51
+ // "package": "@opentelemetry/instrumentation-redisjs",
52
+ // "exportName": "RedisInstrumentation",
53
+ // "options": { "foo": "bar" }
54
+ // }
55
+ const getInstrumentations = async (configs = [], serviceDir) => {
56
+ const instrumentations = []
57
+ for (const instrumentationConfig of configs) {
58
+ const instance = await getInstrumentationInstance(instrumentationConfig, serviceDir)
59
+ instrumentations.push(instance)
60
+ }
61
+ return instrumentations
62
+ }
63
+
64
+ module.exports = {
65
+ getInstrumentations,
66
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/telemetry",
3
- "version": "2.35.0",
3
+ "version": "2.36.1",
4
4
  "description": "OpenTelemetry integration for Platformatic",
5
5
  "main": "index.js",
6
6
  "author": "Platformatic Inc. <oss@platformatic.dev> (https://platformatic.dev)",
@@ -10,6 +10,8 @@
10
10
  },
11
11
  "license": "Apache-2.0",
12
12
  "devDependencies": {
13
+ "@databases/pg": "^5.5.0",
14
+ "@opentelemetry/instrumentation-express": "^0.47.0",
13
15
  "borp": "^0.19.0",
14
16
  "express": "^4.19.2",
15
17
  "fastify": "^5.0.0",
@@ -21,21 +23,23 @@
21
23
  "@fastify/swagger": "^9.0.0",
22
24
  "@opentelemetry/api": "^1.8.0",
23
25
  "@opentelemetry/core": "^1.22.0",
24
- "@opentelemetry/exporter-trace-otlp-proto": "^0.56.0",
26
+ "@opentelemetry/exporter-trace-otlp-proto": "^0.57.0",
25
27
  "@opentelemetry/exporter-zipkin": "^1.22.0",
28
+ "@opentelemetry/instrumentation": "^0.57.0",
26
29
  "@opentelemetry/instrumentation-http": "^0.56.0",
27
30
  "@opentelemetry/instrumentation-pg": "^0.50.0",
28
31
  "@opentelemetry/instrumentation-undici": "^0.10.0",
29
32
  "@opentelemetry/resources": "^1.22.0",
30
- "@opentelemetry/sdk-node": "^0.56.0",
33
+ "@opentelemetry/sdk-node": "^0.57.0",
31
34
  "@opentelemetry/sdk-trace-base": "^1.22.0",
32
35
  "@opentelemetry/semantic-conventions": "^1.27.0",
33
36
  "abstract-logging": "^2.0.1",
34
37
  "fast-uri": "^3.0.0",
35
- "fastify-plugin": "^5.0.0"
38
+ "fastify-plugin": "^5.0.0",
39
+ "@platformatic/config": "2.36.1"
36
40
  },
37
41
  "scripts": {
38
- "test": "npm run lint && borp --timeout=60000 --concurrency=1",
42
+ "test": "npm run lint && borp --timeout=120000 --concurrency=1",
39
43
  "lint": "eslint"
40
44
  }
41
45
  }