Skip to content

Commit 267f0a7

Browse files
authored
feat(otlp): Update to latest OpenTelemetry SDKs (#18)
* Update to latest OpenTelemetry SDKs * add a comment * remove unnecessary dependencies
1 parent 043a20a commit 267f0a7

File tree

6 files changed

+335
-584
lines changed

6 files changed

+335
-584
lines changed

__tests__/fake-serv.test.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
import http from 'http';
22
import path from 'path';
33

4-
import { afterAll, beforeAll, describe, expect, test } from 'vitest';
4+
import { describe, expect, test } from 'vitest';
55
import request from 'supertest';
66

77
import {
88
listen,
99
ServiceStartOptions,
10-
shutdownGlobalTelemetry,
1110
startApp,
12-
startGlobalTelemetry,
1311
} from '../src/index';
1412

15-
import { FakeServLocals, service } from './fake-serv/src/index';
13+
import { type FakeServLocals, service } from './fake-serv/src/index';
1614

1715
function httpRequest(options: http.RequestOptions) {
1816
return new Promise((resolve, reject) => {
@@ -33,14 +31,6 @@ function httpRequest(options: http.RequestOptions) {
3331
}
3432

3533
describe('fake-serv', () => {
36-
beforeAll(() => {
37-
startGlobalTelemetry('fake-serv');
38-
});
39-
40-
afterAll(async () => {
41-
await shutdownGlobalTelemetry();
42-
});
43-
4434
test('basic service functionality', async () => {
4535
const options: ServiceStartOptions<FakeServLocals> = {
4636
service,
@@ -101,7 +91,6 @@ describe('fake-serv', () => {
10191
.get('/metrics')
10292
.expect(200)
10393
.expect((res) => {
104-
// console.error(`---\n${res.text}\n---`);
10594
expect(res.text).toMatch(/nodejs_version_info{version/);
10695
expect(res.text).toMatch(/# UNIT http_server_duration ms/);
10796
expect(res.text).toMatch(/world_requests_total{method="get"} 1/);

__tests__/vitest.test-setup.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { afterAll, beforeAll } from 'vitest';
2+
3+
import { shutdownGlobalTelemetry, startGlobalTelemetry } from '../src/telemetry';
4+
5+
// Even in testing, this needs to run first so that the instrumentation
6+
// is loaded BEFORE express is loaded.
7+
const startPromise = startGlobalTelemetry('fake-serv');
8+
9+
beforeAll(async () => {
10+
await startPromise;
11+
});
12+
13+
afterAll(async () => {
14+
await shutdownGlobalTelemetry();
15+
});

package.json

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -59,26 +59,22 @@
5959
"homepage": "https://github.com/openapi-typescript-infra/service#readme",
6060
"dependencies": {
6161
"@godaddy/terminus": "^4.12.1",
62-
"@opentelemetry/api": "^1.7.0",
63-
"@opentelemetry/exporter-prometheus": "^0.43.0",
64-
"@opentelemetry/exporter-trace-otlp-proto": "^0.43.0",
65-
"@opentelemetry/instrumentation": "^0.43.0",
66-
"@opentelemetry/instrumentation-dns": "^0.32.4",
67-
"@opentelemetry/instrumentation-express": "^0.33.3",
68-
"@opentelemetry/instrumentation-generic-pool": "^0.32.4",
69-
"@opentelemetry/instrumentation-graphql": "^0.35.2",
70-
"@opentelemetry/instrumentation-http": "^0.43.0",
71-
"@opentelemetry/instrumentation-ioredis": "^0.35.3",
72-
"@opentelemetry/instrumentation-net": "^0.32.4",
73-
"@opentelemetry/instrumentation-pg": "^0.36.2",
74-
"@opentelemetry/instrumentation-pino": "^0.34.4",
75-
"@opentelemetry/resource-detector-container": "^0.3.4",
76-
"@opentelemetry/resource-detector-gcp": "^0.29.4",
77-
"@opentelemetry/resources": "^1.18.1",
78-
"@opentelemetry/sdk-metrics": "^1.18.1",
79-
"@opentelemetry/sdk-node": "^0.43.0",
80-
"@opentelemetry/sdk-trace-base": "^1.18.1",
81-
"@opentelemetry/semantic-conventions": "^1.18.1",
62+
"@opentelemetry/api": "^1.8.0",
63+
"@opentelemetry/exporter-prometheus": "^0.51.0",
64+
"@opentelemetry/instrumentation-dns": "^0.36.0",
65+
"@opentelemetry/instrumentation-express": "^0.38.0",
66+
"@opentelemetry/instrumentation-generic-pool": "^0.36.0",
67+
"@opentelemetry/instrumentation-graphql": "^0.40.0",
68+
"@opentelemetry/instrumentation-http": "^0.51.0",
69+
"@opentelemetry/instrumentation-ioredis": "^0.40.0",
70+
"@opentelemetry/instrumentation-net": "^0.36.0",
71+
"@opentelemetry/instrumentation-pg": "^0.41.0",
72+
"@opentelemetry/instrumentation-pino": "^0.38.0",
73+
"@opentelemetry/instrumentation-undici": "^0.2.0",
74+
"@opentelemetry/resource-detector-container": "^0.3.9",
75+
"@opentelemetry/resource-detector-gcp": "^0.29.9",
76+
"@opentelemetry/sdk-node": "^0.51.0",
77+
"@opentelemetry/semantic-conventions": "^1.24.0",
8278
"@sesamecare-oss/confit": "^2.2.1",
8379
"@sesamecare-oss/opentelemetry-node-metrics": "^1.0.1",
8480
"ajv": "^8.12.0",
@@ -89,15 +85,14 @@
8985
"glob": "^8.1.0",
9086
"lodash": "^4.17.21",
9187
"minimist": "^1.2.8",
92-
"opentelemetry-instrumentation-fetch-node": "^1.2.0",
9388
"pino": "^8.21.0",
9489
"read-pkg-up": "^7.0.1",
9590
"request-ip": "^3.3.0"
9691
},
9792
"devDependencies": {
9893
"@commitlint/cli": "^19.3.0",
9994
"@commitlint/config-conventional": "^19.2.2",
100-
"@openapi-typescript-infra/coconfig": "^4.3.0",
95+
"@openapi-typescript-infra/coconfig": "^4.4.0",
10196
"@semantic-release/commit-analyzer": "^12.0.0",
10297
"@semantic-release/exec": "^6.0.3",
10398
"@semantic-release/github": "^10.0.3",

src/telemetry/index.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { diag, DiagConsoleLogger, DiagLogLevel } from '@opentelemetry/api';
21
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
32
import * as opentelemetry from '@opentelemetry/sdk-node';
43
import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
@@ -13,11 +12,11 @@ import type {
1312
import type { ListenFn, StartAppFn } from '../express-app/index';
1413
import type { ConfigurationSchema } from '../config/schema';
1514

16-
import { getAutoInstrumentations, getResourceDetectors } from './instrumentations';
15+
import { getAutoInstrumentations, getResource } from './instrumentations';
1716
import { DummySpanExporter } from './DummyExporter';
1817

1918
// For troubleshooting, set the log level to DiagLogLevel.DEBUG
20-
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.INFO);
19+
opentelemetry.api.diag.setLogger(new (opentelemetry.api.DiagConsoleLogger)(), opentelemetry.api.DiagLogLevel.INFO);
2120

2221
function getExporter() {
2322
if (
@@ -46,16 +45,17 @@ let telemetrySdk: opentelemetry.NodeSDK | undefined;
4645
* In addition, since we have to load it right away before configuration
4746
* is available, we can't use configuration to decide anything.
4847
*/
49-
export function startGlobalTelemetry(serviceName: string) {
48+
export async function startGlobalTelemetry(serviceName: string) {
5049
if (!prometheusExporter) {
5150
prometheusExporter = new PrometheusExporter({ preventServerStart: true });
51+
const instrumentations = getAutoInstrumentations();
5252
telemetrySdk = new opentelemetry.NodeSDK({
5353
serviceName,
54-
autoDetectResources: true,
54+
autoDetectResources: false,
5555
traceExporter: getExporter(),
56-
resourceDetectors: getResourceDetectors(),
56+
resource: await getResource(),
5757
metricReader: prometheusExporter,
58-
instrumentations: [getAutoInstrumentations()],
58+
instrumentations,
5959
views: [
6060
new opentelemetry.metrics.View({
6161
instrumentName: 'http_request_duration_seconds',
@@ -76,7 +76,6 @@ export function getGlobalPrometheusExporter() {
7676
}
7777

7878
export async function shutdownGlobalTelemetry() {
79-
await prometheusExporter?.shutdown();
8079
await telemetrySdk?.shutdown();
8180
telemetrySdk = undefined;
8281
prometheusExporter = undefined;
@@ -86,7 +85,7 @@ export async function startWithTelemetry<
8685
SLocals extends AnyServiceLocals = ServiceLocals<ConfigurationSchema>,
8786
RLocals extends RequestLocals = RequestLocals,
8887
>(options: DelayLoadServiceStartOptions) {
89-
startGlobalTelemetry(options.name);
88+
await startGlobalTelemetry(options.name);
9089

9190
// eslint-disable-next-line import/no-unresolved, @typescript-eslint/no-var-requires
9291
const { startApp, listen } = require('../express-app/app.js') as {

src/telemetry/instrumentations.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Instrumentation } from '@opentelemetry/instrumentation';
22
import { DnsInstrumentation } from '@opentelemetry/instrumentation-dns';
33
import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express';
4-
import { FetchInstrumentation } from 'opentelemetry-instrumentation-fetch-node';
4+
import { UndiciInstrumentation } from '@opentelemetry/instrumentation-undici';
55
import { GenericPoolInstrumentation } from '@opentelemetry/instrumentation-generic-pool';
66
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
77
import { IORedisInstrumentation } from '@opentelemetry/instrumentation-ioredis';
@@ -11,8 +11,9 @@ import { PinoInstrumentation } from '@opentelemetry/instrumentation-pino';
1111
import { containerDetector } from '@opentelemetry/resource-detector-container';
1212
import { gcpDetector } from '@opentelemetry/resource-detector-gcp';
1313
import {
14-
Detector,
15-
DetectorSync,
14+
Resource,
15+
detectResources,
16+
detectResourcesSync,
1617
envDetectorSync,
1718
hostDetectorSync,
1819
osDetectorSync,
@@ -23,7 +24,7 @@ const InstrumentationMap = {
2324
'@opentelemetry/instrumentation-http': HttpInstrumentation,
2425
'@opentelemetry/instrumentation-dns': DnsInstrumentation,
2526
'@opentelemetry/instrumentation-express': ExpressInstrumentation,
26-
'opentelemetry-instrumentation-fetch-node': FetchInstrumentation,
27+
'@opentelemetry/instrumentation-undici': UndiciInstrumentation,
2728
'@opentelemetry/instrumentation-generic-pool': GenericPoolInstrumentation,
2829
'@opentelemetry/instrumentation-ioredis': IORedisInstrumentation,
2930
'@opentelemetry/instrumentation-net': NetInstrumentation,
@@ -58,13 +59,22 @@ export function getAutoInstrumentations(
5859
.filter((i) => !!i) as Instrumentation[];
5960
}
6061

61-
export function getResourceDetectors(): (Detector | DetectorSync)[] {
62-
return [
63-
containerDetector,
62+
// Async function to get combined resources
63+
export async function getResource(): Promise<Resource> {
64+
const syncDetectors = [
6465
envDetectorSync,
6566
hostDetectorSync,
6667
osDetectorSync,
6768
processDetectorSync,
69+
];
70+
const asyncDetectors = [
71+
containerDetector,
6872
gcpDetector,
6973
];
74+
75+
const asyncResources = await detectResources({ detectors: asyncDetectors });
76+
const syncResources = detectResourcesSync({ detectors: syncDetectors });
77+
78+
// Combine async and sync resources
79+
return syncResources.merge(asyncResources);
7080
}

0 commit comments

Comments
 (0)