@openapi-typescript-infra/service 2.9.2 → 3.0.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.
Files changed (39) hide show
  1. package/.eslintrc.js +1 -1
  2. package/.prettierrc.js +1 -1
  3. package/.trunk/trunk.yaml +4 -4
  4. package/CHANGELOG.md +25 -0
  5. package/README.md +1 -1
  6. package/build/config/index.d.ts +3 -3
  7. package/build/config/index.js +5 -9
  8. package/build/config/index.js.map +1 -1
  9. package/build/config/schema.d.ts +1 -1
  10. package/build/config/shortstops.d.ts +2 -29
  11. package/build/config/shortstops.js +12 -18
  12. package/build/config/shortstops.js.map +1 -1
  13. package/build/express-app/app.js +2 -0
  14. package/build/express-app/app.js.map +1 -1
  15. package/build/telemetry/DummyExporter.d.ts +3 -1
  16. package/build/telemetry/DummyExporter.js.map +1 -1
  17. package/build/telemetry/instrumentations.d.ts +2 -2
  18. package/build/telemetry/instrumentations.js +2 -2
  19. package/build/telemetry/instrumentations.js.map +1 -1
  20. package/build/tsconfig.build.tsbuildinfo +1 -1
  21. package/build/types.d.ts +4 -3
  22. package/package.json +31 -33
  23. package/src/config/index.ts +14 -19
  24. package/src/config/schema.ts +1 -1
  25. package/src/config/shortstops.ts +21 -23
  26. package/src/express-app/app.ts +3 -0
  27. package/src/telemetry/DummyExporter.ts +1 -1
  28. package/src/telemetry/instrumentations.ts +2 -3
  29. package/src/types.ts +4 -3
  30. package/vitest.config.ts +1 -1
  31. package/@types/config.d.ts +0 -64
  32. package/build/config/types.d.ts +0 -4
  33. package/build/config/types.js +0 -3
  34. package/build/config/types.js.map +0 -1
  35. package/build/telemetry/fetchInstrumentation.d.ts +0 -49
  36. package/build/telemetry/fetchInstrumentation.js +0 -143
  37. package/build/telemetry/fetchInstrumentation.js.map +0 -1
  38. package/src/config/types.ts +0 -6
  39. package/src/telemetry/fetchInstrumentation.ts +0 -214
@@ -1,143 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.FetchInstrumentation = void 0;
7
- const node_diagnostics_channel_1 = __importDefault(require("node:diagnostics_channel"));
8
- const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
9
- const api_1 = require("@opentelemetry/api");
10
- // Get the content-length from undici response headers.
11
- // `headers` is an Array of buffers: [k, v, k, v, ...].
12
- // If the header is not present, or has an invalid value, this returns null.
13
- function contentLengthFromResponseHeaders(headers) {
14
- const name = 'content-length';
15
- for (let i = 0; i < headers.length; i += 2) {
16
- const k = headers[i];
17
- if (k.length === name.length && k.toString().toLowerCase() === name) {
18
- const v = Number(headers[i + 1]);
19
- if (!Number.isNaN(Number(v))) {
20
- return v;
21
- }
22
- return undefined;
23
- }
24
- }
25
- return undefined;
26
- }
27
- // A combination of https://github.com/elastic/apm-agent-nodejs and
28
- // https://github.com/gadget-inc/opentelemetry-instrumentations/blob/main/packages/opentelemetry-instrumentation-undici/src/index.ts
29
- class FetchInstrumentation {
30
- // Keep ref to avoid https://github.com/nodejs/node/issues/42170 bug and for
31
- // unsubscribing.
32
- channelSubs;
33
- spanFromReq = new WeakMap();
34
- tracer;
35
- config;
36
- meter;
37
- instrumentationName = 'opentelemetry-instrumentation-node-18-fetch';
38
- instrumentationVersion = '1.0.0';
39
- instrumentationDescription = 'Instrumentation for Node 18 fetch via diagnostics_channel';
40
- subscribeToChannel(diagnosticChannel, onMessage) {
41
- const channel = node_diagnostics_channel_1.default.channel(diagnosticChannel);
42
- channel.subscribe(onMessage);
43
- this.channelSubs.push({
44
- name: diagnosticChannel,
45
- channel,
46
- onMessage,
47
- });
48
- }
49
- constructor(config) {
50
- // Force load fetch API (since it's lazy loaded in Node 18)
51
- fetch('').catch(() => Promise.resolve());
52
- this.channelSubs = [];
53
- this.meter = api_1.metrics.getMeter(this.instrumentationName, this.instrumentationVersion);
54
- this.tracer = api_1.trace.getTracer(this.instrumentationName, this.instrumentationVersion);
55
- this.config = { ...config };
56
- }
57
- disable() {
58
- this.channelSubs?.forEach((sub) => sub.channel.unsubscribe(sub.onMessage));
59
- }
60
- enable() {
61
- this.subscribeToChannel('undici:request:create', (args) => this.onRequest(args));
62
- this.subscribeToChannel('undici:request:headers', (args) => this.onHeaders(args));
63
- this.subscribeToChannel('undici:request:trailers', (args) => this.onDone(args));
64
- this.subscribeToChannel('undici:request:error', (args) => this.onError(args));
65
- }
66
- setTracerProvider(tracerProvider) {
67
- this.tracer = tracerProvider.getTracer(this.instrumentationName, this.instrumentationVersion);
68
- }
69
- setMeterProvider(meterProvider) {
70
- this.meter = meterProvider.getMeter(this.instrumentationName, this.instrumentationVersion);
71
- }
72
- setConfig(config) {
73
- this.config = { ...config };
74
- }
75
- getConfig() {
76
- return this.config;
77
- }
78
- onRequest({ request }) {
79
- // We do not handle instrumenting HTTP CONNECT. See limitation notes above.
80
- if (request.method === 'CONNECT') {
81
- return;
82
- }
83
- const span = this.tracer.startSpan(`HTTP ${request.method}`, {
84
- kind: api_1.SpanKind.CLIENT,
85
- attributes: {
86
- [semantic_conventions_1.SemanticAttributes.HTTP_URL]: String(request.origin),
87
- [semantic_conventions_1.SemanticAttributes.HTTP_METHOD]: request.method,
88
- [semantic_conventions_1.SemanticAttributes.HTTP_TARGET]: request.path,
89
- 'http.client': 'fetch',
90
- },
91
- });
92
- const requestContext = api_1.trace.setSpan(api_1.context.active(), span);
93
- const addedHeaders = {};
94
- api_1.propagation.inject(requestContext, addedHeaders);
95
- if (this.config.onRequest) {
96
- this.config.onRequest({ request, span, additionalHeaders: addedHeaders });
97
- }
98
- request.headers += Object.entries(addedHeaders)
99
- .map(([k, v]) => `${k}: ${v}\r\n`)
100
- .join('');
101
- this.spanFromReq.set(request, span);
102
- }
103
- onHeaders({ request, response }) {
104
- const span = this.spanFromReq.get(request);
105
- if (span !== undefined) {
106
- // We are currently *not* capturing response headers, even though the
107
- // intake API does allow it, because none of the other `setHttpContext`
108
- // uses currently do.
109
- const cLen = contentLengthFromResponseHeaders(response.headers);
110
- const attrs = {
111
- [semantic_conventions_1.SemanticAttributes.HTTP_STATUS_CODE]: response.statusCode,
112
- };
113
- if (cLen) {
114
- attrs[semantic_conventions_1.SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH] = cLen;
115
- }
116
- span.setAttributes(attrs);
117
- span.setStatus({
118
- code: response.statusCode >= 400 ? api_1.SpanStatusCode.ERROR : api_1.SpanStatusCode.OK,
119
- message: String(response.statusCode),
120
- });
121
- }
122
- }
123
- onDone({ request }) {
124
- const span = this.spanFromReq.get(request);
125
- if (span !== undefined) {
126
- span.end();
127
- this.spanFromReq.delete(request);
128
- }
129
- }
130
- onError({ request, error }) {
131
- const span = this.spanFromReq.get(request);
132
- if (span !== undefined) {
133
- span.recordException(error);
134
- span.setStatus({
135
- code: api_1.SpanStatusCode.ERROR,
136
- message: error.message,
137
- });
138
- span.end();
139
- }
140
- }
141
- }
142
- exports.FetchInstrumentation = FetchInstrumentation;
143
- //# sourceMappingURL=fetchInstrumentation.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fetchInstrumentation.js","sourceRoot":"","sources":["../../src/telemetry/fetchInstrumentation.ts"],"names":[],"mappings":"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"}
@@ -1,6 +0,0 @@
1
- export interface ConfigStore {
2
- // Confit supports more things (e.g. use), but that's not how we
3
- // intend it to be used.
4
- get<T>(name: string): T | undefined;
5
- set<T>(name: string, value: T): void;
6
- }
@@ -1,214 +0,0 @@
1
- import diagch from 'node:diagnostics_channel';
2
-
3
- import { SemanticAttributes } from '@opentelemetry/semantic-conventions';
4
- import { Instrumentation, InstrumentationConfig } from '@opentelemetry/instrumentation';
5
- import {
6
- Attributes,
7
- context,
8
- propagation,
9
- metrics,
10
- Meter,
11
- MeterProvider,
12
- Span,
13
- SpanKind,
14
- SpanStatusCode,
15
- trace,
16
- Tracer,
17
- TracerProvider,
18
- } from '@opentelemetry/api';
19
-
20
- interface ListenerRecord {
21
- name: string;
22
- channel: diagch.Channel;
23
- onMessage: diagch.ChannelListener;
24
- }
25
-
26
- interface FetchRequestArguments {
27
- request: {
28
- path: string;
29
- method: string;
30
- origin: string;
31
- headers: string;
32
- };
33
- span: Span;
34
- additionalHeaders: Record<string, unknown>;
35
- error?: Error;
36
- }
37
-
38
- type ErrorFetchRequestArguments = FetchRequestArguments & { error: Error };
39
- type ResponseFetchRequestArguments = FetchRequestArguments & {
40
- response: {
41
- statusCode: number;
42
- headers: Buffer[];
43
- };
44
- };
45
-
46
- interface FetchInstrumentationConfig extends InstrumentationConfig {
47
- onRequest?: (args: FetchRequestArguments) => void;
48
- }
49
-
50
- // Get the content-length from undici response headers.
51
- // `headers` is an Array of buffers: [k, v, k, v, ...].
52
- // If the header is not present, or has an invalid value, this returns null.
53
- function contentLengthFromResponseHeaders(headers: Buffer[]) {
54
- const name = 'content-length';
55
- for (let i = 0; i < headers.length; i += 2) {
56
- const k = headers[i];
57
- if (k.length === name.length && k.toString().toLowerCase() === name) {
58
- const v = Number(headers[i + 1]);
59
- if (!Number.isNaN(Number(v))) {
60
- return v;
61
- }
62
- return undefined;
63
- }
64
- }
65
- return undefined;
66
- }
67
-
68
- // A combination of https://github.com/elastic/apm-agent-nodejs and
69
- // https://github.com/gadget-inc/opentelemetry-instrumentations/blob/main/packages/opentelemetry-instrumentation-undici/src/index.ts
70
- export class FetchInstrumentation implements Instrumentation {
71
- // Keep ref to avoid https://github.com/nodejs/node/issues/42170 bug and for
72
- // unsubscribing.
73
- private channelSubs: ListenerRecord[];
74
-
75
- private spanFromReq = new WeakMap<object, Span>();
76
-
77
- private tracer: Tracer;
78
-
79
- private config: FetchInstrumentationConfig;
80
-
81
- private meter: Meter;
82
-
83
- public readonly instrumentationName = 'opentelemetry-instrumentation-node-18-fetch';
84
-
85
- public readonly instrumentationVersion = '1.0.0';
86
-
87
- public readonly instrumentationDescription =
88
- 'Instrumentation for Node 18 fetch via diagnostics_channel';
89
-
90
- private subscribeToChannel(diagnosticChannel: string, onMessage: diagch.ChannelListener) {
91
- const channel = diagch.channel(diagnosticChannel);
92
- channel.subscribe(onMessage);
93
- this.channelSubs.push({
94
- name: diagnosticChannel,
95
- channel,
96
- onMessage,
97
- });
98
- }
99
-
100
- constructor(config: FetchInstrumentationConfig) {
101
- // Force load fetch API (since it's lazy loaded in Node 18)
102
- fetch('').catch(() => Promise.resolve());
103
- this.channelSubs = [];
104
- this.meter = metrics.getMeter(this.instrumentationName, this.instrumentationVersion);
105
- this.tracer = trace.getTracer(this.instrumentationName, this.instrumentationVersion);
106
- this.config = { ...config };
107
- }
108
-
109
- disable(): void {
110
- this.channelSubs?.forEach((sub) => sub.channel.unsubscribe(sub.onMessage));
111
- }
112
-
113
- enable(): void {
114
- this.subscribeToChannel('undici:request:create', (args) =>
115
- this.onRequest(args as FetchRequestArguments),
116
- );
117
- this.subscribeToChannel('undici:request:headers', (args) =>
118
- this.onHeaders(args as ResponseFetchRequestArguments),
119
- );
120
- this.subscribeToChannel('undici:request:trailers', (args) =>
121
- this.onDone(args as FetchRequestArguments),
122
- );
123
- this.subscribeToChannel('undici:request:error', (args) =>
124
- this.onError(args as ErrorFetchRequestArguments),
125
- );
126
- }
127
-
128
- setTracerProvider(tracerProvider: TracerProvider): void {
129
- this.tracer = tracerProvider.getTracer(this.instrumentationName, this.instrumentationVersion);
130
- }
131
-
132
- public setMeterProvider(meterProvider: MeterProvider): void {
133
- this.meter = meterProvider.getMeter(this.instrumentationName, this.instrumentationVersion);
134
- }
135
-
136
- setConfig(config: InstrumentationConfig): void {
137
- this.config = { ...config };
138
- }
139
-
140
- getConfig(): InstrumentationConfig {
141
- return this.config;
142
- }
143
-
144
- onRequest({ request }: FetchRequestArguments): void {
145
- // We do not handle instrumenting HTTP CONNECT. See limitation notes above.
146
- if (request.method === 'CONNECT') {
147
- return;
148
- }
149
- const span = this.tracer.startSpan(`HTTP ${request.method}`, {
150
- kind: SpanKind.CLIENT,
151
- attributes: {
152
- [SemanticAttributes.HTTP_URL]: String(request.origin),
153
- [SemanticAttributes.HTTP_METHOD]: request.method,
154
- [SemanticAttributes.HTTP_TARGET]: request.path,
155
- 'http.client': 'fetch',
156
- },
157
- });
158
- const requestContext = trace.setSpan(context.active(), span);
159
- const addedHeaders: Record<string, string> = {};
160
- propagation.inject(requestContext, addedHeaders);
161
-
162
- if (this.config.onRequest) {
163
- this.config.onRequest({ request, span, additionalHeaders: addedHeaders });
164
- }
165
-
166
- request.headers += Object.entries(addedHeaders)
167
- .map(([k, v]) => `${k}: ${v}\r\n`)
168
- .join('');
169
- this.spanFromReq.set(request, span);
170
- }
171
-
172
- onHeaders({ request, response }: ResponseFetchRequestArguments): void {
173
- const span = this.spanFromReq.get(request);
174
-
175
- if (span !== undefined) {
176
- // We are currently *not* capturing response headers, even though the
177
- // intake API does allow it, because none of the other `setHttpContext`
178
- // uses currently do.
179
-
180
- const cLen = contentLengthFromResponseHeaders(response.headers);
181
- const attrs: Attributes = {
182
- [SemanticAttributes.HTTP_STATUS_CODE]: response.statusCode,
183
- };
184
- if (cLen) {
185
- attrs[SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH] = cLen;
186
- }
187
- span.setAttributes(attrs);
188
- span.setStatus({
189
- code: response.statusCode >= 400 ? SpanStatusCode.ERROR : SpanStatusCode.OK,
190
- message: String(response.statusCode),
191
- });
192
- }
193
- }
194
-
195
- onDone({ request }: FetchRequestArguments): void {
196
- const span = this.spanFromReq.get(request);
197
- if (span !== undefined) {
198
- span.end();
199
- this.spanFromReq.delete(request);
200
- }
201
- }
202
-
203
- onError({ request, error }: ErrorFetchRequestArguments): void {
204
- const span = this.spanFromReq.get(request);
205
- if (span !== undefined) {
206
- span.recordException(error);
207
- span.setStatus({
208
- code: SpanStatusCode.ERROR,
209
- message: error.message,
210
- });
211
- span.end();
212
- }
213
- }
214
- }