@openapi-typescript-infra/service 5.10.0 → 5.11.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.
- package/.eslintignore +1 -0
- package/.eslintrc.cjs +1 -1
- package/.prettierrc.cjs +1 -1
- package/build/express-app/app.js +3 -2
- package/build/express-app/app.js.map +1 -1
- package/build/telemetry/index.d.ts +1 -0
- package/build/telemetry/index.js +22 -21
- package/build/telemetry/index.js.map +1 -1
- package/build/telemetry/instrumentations.d.ts +8 -2
- package/build/telemetry/instrumentations.js +33 -1
- package/build/telemetry/instrumentations.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +36 -35
- package/src/express-app/app.ts +3 -2
- package/src/telemetry/index.ts +28 -33
- package/src/telemetry/instrumentations.ts +42 -3
- package/vitest.config.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openapi-typescript-infra/service",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.11.1",
|
|
4
4
|
"description": "An opinionated framework for building configuration driven services - web, api, or ob. Uses OpenAPI, pino logging, express, confit, Typescript and vitest.",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -70,66 +70,67 @@
|
|
|
70
70
|
"dependencies": {
|
|
71
71
|
"@godaddy/terminus": "^4.12.1",
|
|
72
72
|
"@opentelemetry/api": "^1.9.0",
|
|
73
|
-
"@opentelemetry/auto-instrumentations-node": "^0.
|
|
74
|
-
"@opentelemetry/exporter-prometheus": "^0.
|
|
75
|
-
"@opentelemetry/instrumentation-dns": "^0.
|
|
76
|
-
"@opentelemetry/instrumentation-express": "^0.
|
|
77
|
-
"@opentelemetry/instrumentation-generic-pool": "^0.
|
|
78
|
-
"@opentelemetry/instrumentation-graphql": "^0.
|
|
79
|
-
"@opentelemetry/instrumentation-http": "^0.
|
|
80
|
-
"@opentelemetry/instrumentation-ioredis": "^0.
|
|
81
|
-
"@opentelemetry/instrumentation-net": "^0.
|
|
82
|
-
"@opentelemetry/instrumentation-pg": "^0.
|
|
83
|
-
"@opentelemetry/instrumentation-pino": "^0.
|
|
84
|
-
"@opentelemetry/instrumentation-undici": "^0.
|
|
85
|
-
"@opentelemetry/resource-detector-container": "^0.
|
|
86
|
-
"@opentelemetry/resource-detector-gcp": "^0.
|
|
87
|
-
"@opentelemetry/sdk-node": "^0.
|
|
88
|
-
"@opentelemetry/semantic-conventions": "^1.
|
|
73
|
+
"@opentelemetry/auto-instrumentations-node": "^0.59.0",
|
|
74
|
+
"@opentelemetry/exporter-prometheus": "^0.201.1",
|
|
75
|
+
"@opentelemetry/instrumentation-dns": "^0.45.0",
|
|
76
|
+
"@opentelemetry/instrumentation-express": "^0.50.0",
|
|
77
|
+
"@opentelemetry/instrumentation-generic-pool": "^0.45.0",
|
|
78
|
+
"@opentelemetry/instrumentation-graphql": "^0.49.0",
|
|
79
|
+
"@opentelemetry/instrumentation-http": "^0.201.1",
|
|
80
|
+
"@opentelemetry/instrumentation-ioredis": "^0.49.0",
|
|
81
|
+
"@opentelemetry/instrumentation-net": "^0.45.0",
|
|
82
|
+
"@opentelemetry/instrumentation-pg": "^0.53.0",
|
|
83
|
+
"@opentelemetry/instrumentation-pino": "^0.48.0",
|
|
84
|
+
"@opentelemetry/instrumentation-undici": "^0.12.0",
|
|
85
|
+
"@opentelemetry/resource-detector-container": "^0.7.1",
|
|
86
|
+
"@opentelemetry/resource-detector-gcp": "^0.35.0",
|
|
87
|
+
"@opentelemetry/sdk-node": "^0.201.1",
|
|
88
|
+
"@opentelemetry/semantic-conventions": "^1.33.0",
|
|
89
89
|
"@sesamecare-oss/confit": "^2.2.1",
|
|
90
90
|
"@sesamecare-oss/opentelemetry-node-metrics": "^1.1.0",
|
|
91
91
|
"ajv": "^8.17.1",
|
|
92
92
|
"clean-stack": "^5.2.0",
|
|
93
93
|
"cookie-parser": "^1.4.7",
|
|
94
|
-
"dotenv": "^16.
|
|
94
|
+
"dotenv": "^16.5.0",
|
|
95
95
|
"express": "^5.1.0",
|
|
96
|
-
"express-openapi-validator": "^5.
|
|
97
|
-
"glob": "^11.0.
|
|
98
|
-
"import-in-the-middle": "^1.13.
|
|
96
|
+
"express-openapi-validator": "^5.5.2",
|
|
97
|
+
"glob": "^11.0.2",
|
|
98
|
+
"import-in-the-middle": "^1.13.2",
|
|
99
99
|
"minimist": "^1.2.8",
|
|
100
100
|
"moderndash": "^4.0.0",
|
|
101
|
-
"
|
|
101
|
+
"opentelemetry-resource-detector-sync-api": "^0.30.0",
|
|
102
|
+
"pino": "^9.7.0",
|
|
102
103
|
"read-package-up": "^11.0.0",
|
|
103
104
|
"request-ip": "^3.3.0"
|
|
104
105
|
},
|
|
105
106
|
"devDependencies": {
|
|
106
|
-
"@commitlint/cli": "^19.8.
|
|
107
|
-
"@commitlint/config-conventional": "^19.8.
|
|
108
|
-
"@openapi-typescript-infra/coconfig": "^4.
|
|
107
|
+
"@commitlint/cli": "^19.8.1",
|
|
108
|
+
"@commitlint/config-conventional": "^19.8.1",
|
|
109
|
+
"@openapi-typescript-infra/coconfig": "^4.7.1",
|
|
109
110
|
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
110
|
-
"@semantic-release/exec": "^7.0
|
|
111
|
-
"@semantic-release/github": "^11.0.
|
|
111
|
+
"@semantic-release/exec": "^7.1.0",
|
|
112
|
+
"@semantic-release/github": "^11.0.2",
|
|
112
113
|
"@semantic-release/release-notes-generator": "^14.0.3",
|
|
113
114
|
"@types/cookie-parser": "^1.4.8",
|
|
114
|
-
"@types/express": "^5.0.
|
|
115
|
+
"@types/express": "^5.0.2",
|
|
115
116
|
"@types/minimist": "^1.2.5",
|
|
116
|
-
"@types/node": "^22.
|
|
117
|
+
"@types/node": "^22.15.20",
|
|
117
118
|
"@types/request-ip": "^0.0.41",
|
|
118
119
|
"@types/supertest": "^6.0.3",
|
|
119
120
|
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
120
121
|
"@typescript-eslint/parser": "^7.18.0",
|
|
121
|
-
"coconfig": "^1.6.
|
|
122
|
+
"coconfig": "^1.6.2",
|
|
122
123
|
"eslint": "^8.57.1",
|
|
123
124
|
"eslint-config-prettier": "^9.1.0",
|
|
124
|
-
"eslint-import-resolver-typescript": "^4.3.
|
|
125
|
+
"eslint-import-resolver-typescript": "^4.3.5",
|
|
125
126
|
"eslint-plugin-import": "^2.31.0",
|
|
126
127
|
"pino-pretty": "^13.0.0",
|
|
127
128
|
"pinst": "^3.0.0",
|
|
128
|
-
"supertest": "^7.1.
|
|
129
|
+
"supertest": "^7.1.1",
|
|
129
130
|
"tsconfig-paths": "^4.2.0",
|
|
130
|
-
"tsx": "^4.19.
|
|
131
|
-
"typescript": "^5.8.
|
|
132
|
-
"vitest": "^3.1.
|
|
131
|
+
"tsx": "^4.19.4",
|
|
132
|
+
"typescript": "^5.8.3",
|
|
133
|
+
"vitest": "^3.1.4"
|
|
133
134
|
},
|
|
134
135
|
"resolutions": {
|
|
135
136
|
"qs": "^6.11.0"
|
package/src/express-app/app.ts
CHANGED
|
@@ -232,7 +232,7 @@ export async function startApp<
|
|
|
232
232
|
}
|
|
233
233
|
|
|
234
234
|
if (routing?.freezeQuery) {
|
|
235
|
-
app.use((req, res, next)
|
|
235
|
+
app.use(function freezeQuery(req, res, next) {
|
|
236
236
|
// Express 5 re-parses the query string every time. This causes problems with
|
|
237
237
|
// various libraries, namely the express OpenAPI parser. So we "freeze it" in place
|
|
238
238
|
// here, which runs right before the routing validation logic does. Note that this
|
|
@@ -259,7 +259,8 @@ export async function startApp<
|
|
|
259
259
|
);
|
|
260
260
|
}
|
|
261
261
|
if (routing?.openapi) {
|
|
262
|
-
|
|
262
|
+
const openApiMiddleware = await openApi(app, rootDirectory, codepath, codePattern, options.openApiOptions);
|
|
263
|
+
app.use(openApiMiddleware);
|
|
263
264
|
}
|
|
264
265
|
|
|
265
266
|
// Putting this here allows more flexible middleware insertion
|
package/src/telemetry/index.ts
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-proto';
|
|
2
2
|
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
osDetectorSync,
|
|
10
|
-
processDetectorSync,
|
|
11
|
-
ResourceDetectionConfig,
|
|
4
|
+
detectResources,
|
|
5
|
+
envDetector,
|
|
6
|
+
hostDetector,
|
|
7
|
+
osDetector,
|
|
8
|
+
processDetector,
|
|
12
9
|
} from '@opentelemetry/resources';
|
|
13
10
|
import { containerDetector } from '@opentelemetry/resource-detector-container';
|
|
14
11
|
import { gcpDetector } from '@opentelemetry/resource-detector-gcp';
|
|
@@ -67,17 +64,6 @@ function getLogExporter() {
|
|
|
67
64
|
let prometheusExporter: PrometheusExporter | undefined;
|
|
68
65
|
let telemetrySdk: opentelemetry.NodeSDK | undefined;
|
|
69
66
|
|
|
70
|
-
function awaitAttributes(detector: DetectorSync): Detector {
|
|
71
|
-
return {
|
|
72
|
-
async detect(config?: ResourceDetectionConfig): Promise<IResource> {
|
|
73
|
-
const resource = detector.detect(config)
|
|
74
|
-
await resource.waitForAsyncAttributes?.()
|
|
75
|
-
|
|
76
|
-
return resource
|
|
77
|
-
},
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
67
|
/**
|
|
82
68
|
* OpenTelemetry is not friendly to the idea of stopping
|
|
83
69
|
* and starting itself, it seems. So we can only keep a global
|
|
@@ -90,33 +76,40 @@ export async function startGlobalTelemetry(serviceName: string) {
|
|
|
90
76
|
if (!prometheusExporter) {
|
|
91
77
|
const { metrics, logs, NodeSDK } = opentelemetry;
|
|
92
78
|
|
|
79
|
+
const resource = await detectResources({
|
|
80
|
+
detectors: [
|
|
81
|
+
envDetector,
|
|
82
|
+
hostDetector,
|
|
83
|
+
osDetector,
|
|
84
|
+
processDetector,
|
|
85
|
+
containerDetector,
|
|
86
|
+
gcpDetector,
|
|
87
|
+
],
|
|
88
|
+
});
|
|
89
|
+
|
|
93
90
|
prometheusExporter = new PrometheusExporter({ preventServerStart: true });
|
|
94
91
|
const instrumentations = getAutoInstrumentations();
|
|
95
92
|
const logExporter = getLogExporter();
|
|
96
93
|
telemetrySdk = new NodeSDK({
|
|
97
94
|
serviceName,
|
|
98
95
|
autoDetectResources: false,
|
|
99
|
-
|
|
100
|
-
awaitAttributes(envDetectorSync),
|
|
101
|
-
awaitAttributes(hostDetectorSync),
|
|
102
|
-
awaitAttributes(osDetectorSync),
|
|
103
|
-
awaitAttributes(processDetectorSync),
|
|
104
|
-
awaitAttributes(containerDetector),
|
|
105
|
-
awaitAttributes(gcpDetector),
|
|
106
|
-
],
|
|
96
|
+
resource,
|
|
107
97
|
traceExporter: getSpanExporter(),
|
|
108
98
|
metricReader: prometheusExporter,
|
|
109
99
|
instrumentations,
|
|
110
100
|
logRecordProcessors: logExporter ? [new logs.BatchLogRecordProcessor(logExporter)] : [],
|
|
111
101
|
views: [
|
|
112
|
-
|
|
102
|
+
{
|
|
113
103
|
instrumentName: 'http_request_duration_seconds',
|
|
114
104
|
instrumentType: metrics.InstrumentType.HISTOGRAM,
|
|
115
|
-
aggregation:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
105
|
+
aggregation: {
|
|
106
|
+
type: metrics.AggregationType.EXPLICIT_BUCKET_HISTOGRAM,
|
|
107
|
+
options: {
|
|
108
|
+
boundaries: [0.003, 0.03, 0.1, 0.3, 1.5, 10],
|
|
109
|
+
recordMinMax: true,
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
},
|
|
120
113
|
],
|
|
121
114
|
});
|
|
122
115
|
telemetrySdk.start();
|
|
@@ -160,3 +153,5 @@ export async function startWithTelemetry<
|
|
|
160
153
|
});
|
|
161
154
|
return { app, codepath: options.codepath, server };
|
|
162
155
|
}
|
|
156
|
+
|
|
157
|
+
export { setTelemetryHooks } from './instrumentations.js';
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { Instrumentation } from '@opentelemetry/instrumentation';
|
|
2
2
|
import { DnsInstrumentation } from '@opentelemetry/instrumentation-dns';
|
|
3
|
-
import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express';
|
|
3
|
+
import { ExpressInstrumentation, SpanNameHook } from '@opentelemetry/instrumentation-express';
|
|
4
4
|
import { UndiciInstrumentation } from '@opentelemetry/instrumentation-undici';
|
|
5
5
|
import { GenericPoolInstrumentation } from '@opentelemetry/instrumentation-generic-pool';
|
|
6
|
-
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
|
|
6
|
+
import { HttpInstrumentation, IgnoreIncomingRequestFunction } from '@opentelemetry/instrumentation-http';
|
|
7
7
|
import { IORedisInstrumentation } from '@opentelemetry/instrumentation-ioredis';
|
|
8
8
|
import { NetInstrumentation } from '@opentelemetry/instrumentation-net';
|
|
9
|
+
import { GraphQLInstrumentation } from '@opentelemetry/instrumentation-graphql';
|
|
9
10
|
import { PgInstrumentation } from '@opentelemetry/instrumentation-pg';
|
|
10
11
|
import { PinoInstrumentation } from '@opentelemetry/instrumentation-pino';
|
|
11
12
|
|
|
@@ -13,6 +14,7 @@ const InstrumentationMap = {
|
|
|
13
14
|
'@opentelemetry/instrumentation-http': HttpInstrumentation,
|
|
14
15
|
'@opentelemetry/instrumentation-dns': DnsInstrumentation,
|
|
15
16
|
'@opentelemetry/instrumentation-express': ExpressInstrumentation,
|
|
17
|
+
'@opentelemetry/instrumentation-graphql': GraphQLInstrumentation,
|
|
16
18
|
'@opentelemetry/instrumentation-undici': UndiciInstrumentation,
|
|
17
19
|
'@opentelemetry/instrumentation-generic-pool': GenericPoolInstrumentation,
|
|
18
20
|
'@opentelemetry/instrumentation-ioredis': IORedisInstrumentation,
|
|
@@ -27,8 +29,45 @@ export type InstrumentationConfigMap = {
|
|
|
27
29
|
[Name in keyof typeof InstrumentationMap]?: ConfigArg<(typeof InstrumentationMap)[Name]>;
|
|
28
30
|
};
|
|
29
31
|
|
|
32
|
+
let ignoreIncomingRequestHook: IgnoreIncomingRequestFunction | undefined = (req) => {
|
|
33
|
+
return req.url === '/health' || req.url === '/metrics';
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
let spanNameHook: SpanNameHook | undefined;
|
|
37
|
+
|
|
38
|
+
export function setTelemetryHooks(hooks: {
|
|
39
|
+
ignoreIncomingRequestHook?: IgnoreIncomingRequestFunction;
|
|
40
|
+
spanNameHook?: SpanNameHook;
|
|
41
|
+
}) {
|
|
42
|
+
if ('ignoreIncomingRequestHook' in hooks) {
|
|
43
|
+
ignoreIncomingRequestHook = hooks.ignoreIncomingRequestHook;
|
|
44
|
+
}
|
|
45
|
+
if ('spanNameHook' in hooks) {
|
|
46
|
+
spanNameHook = hooks.spanNameHook;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const defaultConfigs: InstrumentationConfigMap = {
|
|
51
|
+
'@opentelemetry/instrumentation-http': {
|
|
52
|
+
ignoreIncomingRequestHook(req) {
|
|
53
|
+
if (ignoreIncomingRequestHook) {
|
|
54
|
+
return ignoreIncomingRequestHook(req);
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
'@opentelemetry/instrumentation-express': {
|
|
60
|
+
spanNameHook(info, defaultName) {
|
|
61
|
+
if (spanNameHook) {
|
|
62
|
+
return spanNameHook(info, defaultName);
|
|
63
|
+
}
|
|
64
|
+
return defaultName;
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
30
69
|
export function getAutoInstrumentations(
|
|
31
|
-
inputConfigs: InstrumentationConfigMap =
|
|
70
|
+
inputConfigs: InstrumentationConfigMap = defaultConfigs,
|
|
32
71
|
): Instrumentation[] {
|
|
33
72
|
const keys = Object.keys(InstrumentationMap) as Array<keyof typeof InstrumentationMap>;
|
|
34
73
|
return keys
|
package/vitest.config.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Instead, edit the coconfig.js or coconfig.ts file in your project root.
|
|
4
4
|
*
|
|
5
5
|
* See https://github.com/gas-buddy/coconfig for more information.
|
|
6
|
-
* @version coconfig@1.6.
|
|
6
|
+
* @version coconfig@1.6.2
|
|
7
7
|
*/
|
|
8
8
|
import cjs from '@openapi-typescript-infra/coconfig';
|
|
9
9
|
import * as esmToCjs from '@openapi-typescript-infra/coconfig';
|