@openapi-typescript-infra/service 5.13.1 → 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/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> {
@@ -65,6 +66,7 @@ export interface ServiceStartOptions<SLocals extends AnyServiceLocals = ServiceL
65
66
  }
66
67
  export interface DelayLoadServiceStartOptions extends Omit<ServiceStartOptions, 'service'> {
67
68
  service: string;
69
+ customizer?: ((options: Partial<NodeSDKConfiguration>) => Partial<NodeSDKConfiguration>) | undefined;
68
70
  }
69
71
  export interface ServiceOptions {
70
72
  codepath?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openapi-typescript-infra/service",
3
- "version": "5.13.1",
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
 
@@ -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(serviceName: string) {
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
- telemetrySdk = new NodeSDK({
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';
@@ -144,6 +145,9 @@ export interface ServiceStartOptions<
144
145
 
145
146
  export interface DelayLoadServiceStartOptions extends Omit<ServiceStartOptions, 'service'> {
146
147
  service: string;
148
+ customizer?:
149
+ | ((options: Partial<NodeSDKConfiguration>) => Partial<NodeSDKConfiguration>)
150
+ | undefined;
147
151
  }
148
152
 
149
153
  // Handled by service.configure