@platformatic/telemetry 3.4.1 → 3.5.0

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.
@@ -0,0 +1,137 @@
1
+ import { context, propagation, SpanKind, SpanStatusCode, trace } from '@opentelemetry/api'
2
+ import fastUri from 'fast-uri'
3
+ import { formatSpanAttributes, formatSpanName } from './telemetry-config.js'
4
+ import { name as moduleName, version as moduleVersion } from './version.js'
5
+
6
+ const tracer = trace.getTracer(moduleName, moduleVersion)
7
+
8
+ export function createTelemetryThreadInterceptorHooks () {
9
+ const onServerRequest = (req, cb) => {
10
+ const activeContext = propagation.extract(context.active(), req.headers)
11
+
12
+ const route = req.routeOptions?.url ?? null
13
+ const span = tracer.startSpan(
14
+ formatSpanName(req, route),
15
+ {
16
+ attributes: formatSpanAttributes.request(req, route),
17
+ kind: SpanKind.SERVER
18
+ },
19
+ activeContext
20
+ )
21
+ const ctx = trace.setSpan(activeContext, span)
22
+
23
+ context.with(ctx, cb)
24
+ }
25
+
26
+ const onServerResponse = (_req, _res) => {
27
+ const activeContext = context.active()
28
+ const span = trace.getSpan(activeContext)
29
+ if (span) {
30
+ span.end()
31
+ }
32
+ }
33
+
34
+ const onServerError = (_req, _res, error) => {
35
+ const activeContext = context.active()
36
+ const span = trace.getSpan(activeContext)
37
+ if (span) {
38
+ span.setAttributes(formatSpanAttributes.error(error))
39
+ }
40
+ }
41
+
42
+ const onClientRequest = (req, ctx) => {
43
+ const activeContext = context.active()
44
+
45
+ const { origin, method = '', path } = req
46
+ const targetUrl = `${origin}${path}`
47
+ const urlObj = fastUri.parse(targetUrl)
48
+
49
+ let name
50
+ if (urlObj.port) {
51
+ name = `${method} ${urlObj.scheme}://${urlObj.host}:${urlObj.port}${urlObj.path}`
52
+ } else {
53
+ name = `${method} ${urlObj.scheme}://${urlObj.host}${urlObj.path}`
54
+ }
55
+ const span = tracer.startSpan(
56
+ name,
57
+ {
58
+ attributes: {
59
+ 'server.address': urlObj.host,
60
+ 'server.port': urlObj.port,
61
+ 'http.request.method': method,
62
+ 'url.full': targetUrl,
63
+ 'url.path': urlObj.path,
64
+ 'url.scheme': urlObj.scheme
65
+ },
66
+ kind: SpanKind.CLIENT
67
+ },
68
+ activeContext
69
+ )
70
+
71
+ // Headers propagation
72
+ const headers = {}
73
+ // This line is important, otherwise it will use the old context
74
+ const newCtx = trace.setSpan(activeContext, span)
75
+ propagation.inject(newCtx, headers, {
76
+ set (_carrier, key, value) {
77
+ headers[key] = value
78
+ }
79
+ })
80
+ req.headers = {
81
+ ...req.headers,
82
+ ...headers
83
+ }
84
+
85
+ ctx.span = span
86
+ }
87
+
88
+ const onClientResponseEnd = (_req, res, ctx) => {
89
+ const span = ctx.span ?? null
90
+ if (!span) {
91
+ return
92
+ }
93
+ if (res) {
94
+ const spanStatus = { code: SpanStatusCode.OK }
95
+ if (res.statusCode >= 400) {
96
+ spanStatus.code = SpanStatusCode.ERROR
97
+ }
98
+ span.setAttributes({
99
+ 'http.response.status_code': res.statusCode
100
+ })
101
+
102
+ const httpCacheId = res.headers?.['x-plt-http-cache-id']
103
+ const isCacheHit = res.headers?.age !== undefined
104
+ if (httpCacheId) {
105
+ span.setAttributes({
106
+ 'http.cache.id': httpCacheId,
107
+ 'http.cache.hit': isCacheHit.toString()
108
+ })
109
+ }
110
+
111
+ span.setStatus(spanStatus)
112
+ } else {
113
+ span.setStatus({
114
+ code: SpanStatusCode.ERROR,
115
+ message: 'No response received'
116
+ })
117
+ }
118
+ span.end()
119
+ }
120
+
121
+ const onClientError = (_req, _res, ctx, error) => {
122
+ const span = ctx.span ?? null
123
+ if (!span) {
124
+ return
125
+ }
126
+ span.setAttributes(formatSpanAttributes.error(error))
127
+ }
128
+
129
+ return {
130
+ onServerRequest,
131
+ onServerResponse,
132
+ onServerError,
133
+ onClientRequest,
134
+ onClientResponseEnd,
135
+ onClientError
136
+ }
137
+ }
package/lib/version.js ADDED
@@ -0,0 +1,7 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import { resolve } from 'node:path'
3
+
4
+ const packageJson = JSON.parse(readFileSync(resolve(import.meta.dirname, '../package.json'), 'utf-8'))
5
+
6
+ export const name = packageJson.name
7
+ export const version = packageJson.version
package/package.json CHANGED
@@ -1,37 +1,48 @@
1
1
  {
2
2
  "name": "@platformatic/telemetry",
3
- "version": "3.4.1",
3
+ "version": "3.5.0",
4
4
  "description": "OpenTelemetry integration for Platformatic",
5
5
  "main": "index.js",
6
- "author": "Marco Piraccini <marco.piraccini@gmail.com>",
6
+ "type": "module",
7
+ "author": "Platformatic Inc. <oss@platformatic.dev> (https://platformatic.dev)",
7
8
  "repository": {
8
9
  "type": "git",
9
10
  "url": "git+https://github.com/platformatic/platformatic.git"
10
11
  },
11
12
  "license": "Apache-2.0",
12
13
  "devDependencies": {
13
- "borp": "^0.17.0",
14
- "fastify": "^5.0.0",
15
- "express": "^4.19.2",
16
- "neostandard": "^0.11.1",
17
- "typescript": "^5.5.4"
14
+ "@databases/pg": "^5.5.0",
15
+ "@opentelemetry/instrumentation-express": "^0.52.0",
16
+ "@opentelemetry/instrumentation-pg": "^0.55.0",
17
+ "cleaner-spec-reporter": "^0.5.0",
18
+ "express": "^5.1.0",
19
+ "fastify": "^5.4.0",
20
+ "neostandard": "^0.12.2",
21
+ "protobufjs": "^7.5.3",
22
+ "typescript": "^5.9.2"
18
23
  },
19
24
  "dependencies": {
20
- "@fastify/swagger": "^9.0.0",
21
- "@opentelemetry/api": "^1.8.0",
22
- "@opentelemetry/auto-instrumentations-node": "^0.50.0",
23
- "@opentelemetry/core": "^1.22.0",
24
- "@opentelemetry/exporter-trace-otlp-proto": "^0.53.0",
25
- "@opentelemetry/exporter-zipkin": "^1.22.0",
26
- "@opentelemetry/resources": "^1.22.0",
27
- "@opentelemetry/sdk-node": "^0.53.0",
28
- "@opentelemetry/sdk-trace-base": "^1.22.0",
29
- "@opentelemetry/semantic-conventions": "^1.22.0",
30
- "fast-uri": "^2.3.0",
31
- "fastify-plugin": "^5.0.0"
25
+ "@fastify/swagger": "^9.5.1",
26
+ "@opentelemetry/api": "^1.9.0",
27
+ "@opentelemetry/core": "^2.0.1",
28
+ "@opentelemetry/exporter-trace-otlp-proto": "^0.203.0",
29
+ "@opentelemetry/exporter-zipkin": "^2.0.1",
30
+ "@opentelemetry/instrumentation": "^0.203.0",
31
+ "@opentelemetry/instrumentation-http": "^0.203.0",
32
+ "@opentelemetry/instrumentation-undici": "^0.14.0",
33
+ "@opentelemetry/resources": "^2.0.1",
34
+ "@opentelemetry/sdk-node": "^0.203.0",
35
+ "@opentelemetry/sdk-trace-base": "^2.0.1",
36
+ "@opentelemetry/semantic-conventions": "1.36.0",
37
+ "fast-uri": "^3.0.6",
38
+ "fastify-plugin": "^5.0.1",
39
+ "@platformatic/foundation": "3.5.0"
40
+ },
41
+ "engines": {
42
+ "node": ">=22.19.0"
32
43
  },
33
44
  "scripts": {
34
- "test": "npm run lint && borp",
45
+ "test": "node --test --test-reporter=cleaner-spec-reporter --test-concurrency=1 --test-timeout=2000000 test/*.test.js test/**/*.test.js",
35
46
  "lint": "eslint"
36
47
  }
37
48
  }
@@ -1,33 +0,0 @@
1
- 'use strict'
2
- const process = require('node:process')
3
- const opentelemetry = require('@opentelemetry/sdk-node')
4
- const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http')
5
- const { Resource } = require('@opentelemetry/resources')
6
- const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions')
7
- const setupTelemetry = require('./telemetry-config')
8
-
9
- const setupNodeHTTPTelemetry = (opts, logger) => {
10
- const { serviceName } = opts
11
- logger.info(`Setting up Node.js HTTP telemetry for service: ${serviceName}`)
12
- // We setup the telemetry to init the spanProcessors, then we pass them to the SDK
13
- const { spanProcessors } = setupTelemetry(opts, logger)
14
- const sdk = new opentelemetry.NodeSDK({
15
- spanProcessors, // https://github.com/open-telemetry/opentelemetry-js/issues/4881#issuecomment-2358059714
16
- instrumentations: [
17
- new HttpInstrumentation(),
18
- ],
19
- resource: new Resource({
20
- [SemanticResourceAttributes.SERVICE_NAME]: serviceName
21
- })
22
- })
23
- sdk.start()
24
-
25
- // gracefully shut down the SDK on process exit
26
- process.on('SIGTERM', () => {
27
- sdk.shutdown()
28
- .then(() => console.log('Tracing terminated'))
29
- .catch((error) => console.log('Error terminating tracing', error))
30
- })
31
- }
32
-
33
- module.exports = setupNodeHTTPTelemetry