@openapi-typescript-infra/service 5.13.0 → 5.14.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.
- package/build/bootstrap.js +11 -1
- package/build/bootstrap.js.map +1 -1
- package/build/express-app/app.js +1 -1
- package/build/express-app/app.js.map +1 -1
- package/build/telemetry/index.d.ts +2 -1
- package/build/telemetry/index.js +5 -4
- package/build/telemetry/index.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/build/types.d.ts +6 -1
- package/package.json +1 -1
- package/src/bootstrap.ts +14 -1
- package/src/express-app/app.ts +1 -1
- package/src/telemetry/index.ts +12 -4
- package/src/types.ts +8 -1
package/build/types.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { Request, Response } from 'express';
|
|
|
5
5
|
import type { Application } from 'express-serve-static-core';
|
|
6
6
|
import type { middleware } from 'express-openapi-validator';
|
|
7
7
|
import type { Meter } from '@opentelemetry/api';
|
|
8
|
+
import type { NodeSDKConfiguration } from '@opentelemetry/sdk-node';
|
|
8
9
|
import { ShortstopHandler } from '@sesamecare-oss/confit';
|
|
9
10
|
import { ConfigurationSchema } from './config/schema.js';
|
|
10
11
|
export interface InternalLocals<SLocals extends AnyServiceLocals = ServiceLocals<ConfigurationSchema>> extends Record<string, unknown> {
|
|
@@ -42,7 +43,10 @@ export interface Service<SLocals extends AnyServiceLocals = ServiceLocals<Config
|
|
|
42
43
|
configure?: (startOptions: ServiceStartOptions<SLocals, RLocals>, options: ServiceOptions) => ServiceOptions;
|
|
43
44
|
attach?: (app: ServiceExpress<SLocals>) => void | Promise<void>;
|
|
44
45
|
attachServer?: (app: ServiceExpress<SLocals>, server: Server) => void | Promise<void>;
|
|
45
|
-
onListening?: (app: ServiceExpress<SLocals>,
|
|
46
|
+
onListening?: (app: ServiceExpress<SLocals>, info: {
|
|
47
|
+
port: number;
|
|
48
|
+
protocol: 'http' | 'https';
|
|
49
|
+
}) => void | Promise<void>;
|
|
46
50
|
start(app: ServiceExpress<SLocals>): void | Promise<void>;
|
|
47
51
|
stop?: (app: ServiceExpress<SLocals>) => void | Promise<void>;
|
|
48
52
|
healthy?: (app: ServiceExpress<SLocals>) => boolean | Promise<boolean>;
|
|
@@ -62,6 +66,7 @@ export interface ServiceStartOptions<SLocals extends AnyServiceLocals = ServiceL
|
|
|
62
66
|
}
|
|
63
67
|
export interface DelayLoadServiceStartOptions extends Omit<ServiceStartOptions, 'service'> {
|
|
64
68
|
service: string;
|
|
69
|
+
customizer?: ((options: Partial<NodeSDKConfiguration>) => Partial<NodeSDKConfiguration>) | undefined;
|
|
65
70
|
}
|
|
66
71
|
export interface ServiceOptions {
|
|
67
72
|
codepath?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openapi-typescript-infra/service",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.14.0",
|
|
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
|
".": {
|
package/src/bootstrap.ts
CHANGED
|
@@ -4,6 +4,7 @@ import assert from 'node:assert';
|
|
|
4
4
|
import { config } from 'dotenv';
|
|
5
5
|
import { readPackageUp } from 'read-package-up';
|
|
6
6
|
import type { NormalizedPackageJson } from 'read-package-up';
|
|
7
|
+
import { NodeSDKConfiguration } from '@opentelemetry/sdk-node';
|
|
7
8
|
|
|
8
9
|
import type {
|
|
9
10
|
AnyServiceLocals,
|
|
@@ -64,6 +65,7 @@ async function getServiceDetails(argv: BootstrapArguments = {}) {
|
|
|
64
65
|
rootDirectory: path.dirname(pkg.path),
|
|
65
66
|
name: parts[parts.length - 1],
|
|
66
67
|
version: pkg.packageJson.version,
|
|
68
|
+
customizer: (pkg.packageJson.config?.telemetry as { customizer?: string })?.customizer,
|
|
67
69
|
};
|
|
68
70
|
}
|
|
69
71
|
|
|
@@ -81,7 +83,7 @@ export async function bootstrap<
|
|
|
81
83
|
SLocals extends AnyServiceLocals = ServiceLocals<ConfigurationSchema>,
|
|
82
84
|
RLocals extends RequestLocals = RequestLocals,
|
|
83
85
|
>(argv?: BootstrapArguments) {
|
|
84
|
-
const { main, rootDirectory, name, version } = await getServiceDetails(argv);
|
|
86
|
+
const { main, rootDirectory, name, version, customizer } = await getServiceDetails(argv);
|
|
85
87
|
|
|
86
88
|
let entrypoint: string;
|
|
87
89
|
let codepath: 'build' | 'dist' | 'src' = 'build';
|
|
@@ -104,12 +106,23 @@ export async function bootstrap<
|
|
|
104
106
|
|
|
105
107
|
const absoluteEntrypoint = path.resolve(rootDirectory, entrypoint);
|
|
106
108
|
if (argv?.telemetry) {
|
|
109
|
+
let otelCustomizer:
|
|
110
|
+
| ((options: Partial<NodeSDKConfiguration>) => Partial<NodeSDKConfiguration>)
|
|
111
|
+
| undefined = undefined;
|
|
112
|
+
if (customizer) {
|
|
113
|
+
// Customize OTEL with a dynamic import based on the codePath (so put it in src, generally)
|
|
114
|
+
otelCustomizer = (await import(`$(codePath}/${customizer}`)).NodeSDKConfiguration;
|
|
115
|
+
if (typeof otelCustomizer === 'object') {
|
|
116
|
+
otelCustomizer = (v) => ({ ...v, ...(otelCustomizer as Partial<NodeSDKConfiguration>) });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
107
119
|
return startWithTelemetry<SLocals, RLocals>({
|
|
108
120
|
name,
|
|
109
121
|
rootDirectory,
|
|
110
122
|
service: absoluteEntrypoint,
|
|
111
123
|
codepath,
|
|
112
124
|
version,
|
|
125
|
+
customizer: otelCustomizer,
|
|
113
126
|
});
|
|
114
127
|
}
|
|
115
128
|
|
package/src/express-app/app.ts
CHANGED
|
@@ -429,7 +429,7 @@ export async function listen<SLocals extends AnyServiceLocals = ServiceLocals<Co
|
|
|
429
429
|
});
|
|
430
430
|
|
|
431
431
|
await listenPromise;
|
|
432
|
-
await service.onListening?.(app, port);
|
|
432
|
+
await service.onListening?.(app, { port, protocol: config.certificate ? 'https' : 'http' });
|
|
433
433
|
return server;
|
|
434
434
|
}
|
|
435
435
|
|
package/src/telemetry/index.ts
CHANGED
|
@@ -72,7 +72,14 @@ let telemetrySdk: opentelemetry.NodeSDK | undefined;
|
|
|
72
72
|
* In addition, since we have to load it right away before configuration
|
|
73
73
|
* is available, we can't use configuration to decide anything.
|
|
74
74
|
*/
|
|
75
|
-
export async function startGlobalTelemetry(
|
|
75
|
+
export async function startGlobalTelemetry(
|
|
76
|
+
serviceName: string,
|
|
77
|
+
customizer?:
|
|
78
|
+
| ((
|
|
79
|
+
options: Partial<opentelemetry.NodeSDKConfiguration>,
|
|
80
|
+
) => Partial<opentelemetry.NodeSDKConfiguration>)
|
|
81
|
+
| undefined,
|
|
82
|
+
) {
|
|
76
83
|
if (!prometheusExporter) {
|
|
77
84
|
const { metrics, logs, NodeSDK } = opentelemetry;
|
|
78
85
|
|
|
@@ -90,7 +97,7 @@ export async function startGlobalTelemetry(serviceName: string) {
|
|
|
90
97
|
prometheusExporter = new PrometheusExporter({ preventServerStart: true });
|
|
91
98
|
const instrumentations = getAutoInstrumentations();
|
|
92
99
|
const logExporter = getLogExporter();
|
|
93
|
-
|
|
100
|
+
const options: Partial<opentelemetry.NodeSDKConfiguration> = {
|
|
94
101
|
serviceName,
|
|
95
102
|
autoDetectResources: false,
|
|
96
103
|
resource,
|
|
@@ -111,7 +118,8 @@ export async function startGlobalTelemetry(serviceName: string) {
|
|
|
111
118
|
},
|
|
112
119
|
},
|
|
113
120
|
],
|
|
114
|
-
}
|
|
121
|
+
};
|
|
122
|
+
telemetrySdk = new NodeSDK(customizer ? customizer(options) : options);
|
|
115
123
|
telemetrySdk.start();
|
|
116
124
|
}
|
|
117
125
|
}
|
|
@@ -130,7 +138,7 @@ export async function startWithTelemetry<
|
|
|
130
138
|
SLocals extends AnyServiceLocals = ServiceLocals<ConfigurationSchema>,
|
|
131
139
|
RLocals extends RequestLocals = RequestLocals,
|
|
132
140
|
>(options: DelayLoadServiceStartOptions) {
|
|
133
|
-
await startGlobalTelemetry(options.name);
|
|
141
|
+
await startGlobalTelemetry(options.name, options.customizer);
|
|
134
142
|
|
|
135
143
|
// eslint-disable-next-line import/no-unresolved, @typescript-eslint/no-var-requires
|
|
136
144
|
const { startApp, listen } = (await import('../express-app/app.js')) as {
|
package/src/types.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { Request, Response } from 'express';
|
|
|
6
6
|
import type { Application } from 'express-serve-static-core';
|
|
7
7
|
import type { middleware } from 'express-openapi-validator';
|
|
8
8
|
import type { Meter } from '@opentelemetry/api';
|
|
9
|
+
import type { NodeSDKConfiguration } from '@opentelemetry/sdk-node';
|
|
9
10
|
import { ShortstopHandler } from '@sesamecare-oss/confit';
|
|
10
11
|
|
|
11
12
|
import { ConfigurationSchema } from './config/schema.js';
|
|
@@ -79,7 +80,10 @@ export interface Service<
|
|
|
79
80
|
// Called after a server is created but before the server starts listening
|
|
80
81
|
attachServer?: (app: ServiceExpress<SLocals>, server: Server) => void | Promise<void>;
|
|
81
82
|
// Called after the server is listening
|
|
82
|
-
onListening?: (
|
|
83
|
+
onListening?: (
|
|
84
|
+
app: ServiceExpress<SLocals>,
|
|
85
|
+
info: { port: number; protocol: 'http' | 'https' },
|
|
86
|
+
) => void | Promise<void>;
|
|
83
87
|
|
|
84
88
|
start(app: ServiceExpress<SLocals>): void | Promise<void>;
|
|
85
89
|
|
|
@@ -141,6 +145,9 @@ export interface ServiceStartOptions<
|
|
|
141
145
|
|
|
142
146
|
export interface DelayLoadServiceStartOptions extends Omit<ServiceStartOptions, 'service'> {
|
|
143
147
|
service: string;
|
|
148
|
+
customizer?:
|
|
149
|
+
| ((options: Partial<NodeSDKConfiguration>) => Partial<NodeSDKConfiguration>)
|
|
150
|
+
| undefined;
|
|
144
151
|
}
|
|
145
152
|
|
|
146
153
|
// Handled by service.configure
|