@openapi-typescript-infra/service 1.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.
- package/.eslintignore +7 -0
- package/.eslintrc.js +14 -0
- package/.github/workflows/codeql-analysis.yml +74 -0
- package/.github/workflows/nodejs.yml +23 -0
- package/.github/workflows/npmpublish.yml +35 -0
- package/.husky/pre-commit +6 -0
- package/.prettierrc.js +14 -0
- package/@types/config.d.ts +56 -0
- package/CHANGELOG.md +5 -0
- package/LICENSE +21 -0
- package/README.md +28 -0
- package/SECURITY.md +12 -0
- package/__tests__/config.test.ts +31 -0
- package/__tests__/fake-serv/api/fake-serv.yaml +48 -0
- package/__tests__/fake-serv/config/config.json +15 -0
- package/__tests__/fake-serv/src/handlers/hello.ts +10 -0
- package/__tests__/fake-serv/src/index.ts +29 -0
- package/__tests__/fake-serv/src/routes/error.ts +13 -0
- package/__tests__/fake-serv/src/routes/index.ts +22 -0
- package/__tests__/fake-serv/src/routes/other/world.ts +7 -0
- package/__tests__/fake-serv.test.ts +74 -0
- package/build/bin/start-service.d.ts +2 -0
- package/build/bin/start-service.js +31 -0
- package/build/bin/start-service.js.map +1 -0
- package/build/bootstrap.d.ts +16 -0
- package/build/bootstrap.js +90 -0
- package/build/bootstrap.js.map +1 -0
- package/build/config/index.d.ts +10 -0
- package/build/config/index.js +98 -0
- package/build/config/index.js.map +1 -0
- package/build/config/schema.d.ts +48 -0
- package/build/config/schema.js +3 -0
- package/build/config/schema.js.map +1 -0
- package/build/config/shortstops.d.ts +31 -0
- package/build/config/shortstops.js +109 -0
- package/build/config/shortstops.js.map +1 -0
- package/build/config/types.d.ts +3 -0
- package/build/config/types.js +3 -0
- package/build/config/types.js.map +1 -0
- package/build/development/port-finder.d.ts +1 -0
- package/build/development/port-finder.js +41 -0
- package/build/development/port-finder.js.map +1 -0
- package/build/development/repl.d.ts +2 -0
- package/build/development/repl.js +29 -0
- package/build/development/repl.js.map +1 -0
- package/build/env.d.ts +2 -0
- package/build/env.js +19 -0
- package/build/env.js.map +1 -0
- package/build/error.d.ts +25 -0
- package/build/error.js +28 -0
- package/build/error.js.map +1 -0
- package/build/express-app/app.d.ts +6 -0
- package/build/express-app/app.js +327 -0
- package/build/express-app/app.js.map +1 -0
- package/build/express-app/index.d.ts +2 -0
- package/build/express-app/index.js +19 -0
- package/build/express-app/index.js.map +1 -0
- package/build/express-app/internal-server.d.ts +3 -0
- package/build/express-app/internal-server.js +34 -0
- package/build/express-app/internal-server.js.map +1 -0
- package/build/express-app/route-loader.d.ts +2 -0
- package/build/express-app/route-loader.js +46 -0
- package/build/express-app/route-loader.js.map +1 -0
- package/build/express-app/types.d.ts +14 -0
- package/build/express-app/types.js +3 -0
- package/build/express-app/types.js.map +1 -0
- package/build/index.d.ts +8 -0
- package/build/index.js +25 -0
- package/build/index.js.map +1 -0
- package/build/openapi.d.ts +5 -0
- package/build/openapi.js +78 -0
- package/build/openapi.js.map +1 -0
- package/build/service-calls/index.d.ts +16 -0
- package/build/service-calls/index.js +85 -0
- package/build/service-calls/index.js.map +1 -0
- package/build/telemetry/fetchInstrumentation.d.ts +50 -0
- package/build/telemetry/fetchInstrumentation.js +144 -0
- package/build/telemetry/fetchInstrumentation.js.map +1 -0
- package/build/telemetry/index.d.ts +6 -0
- package/build/telemetry/index.js +80 -0
- package/build/telemetry/index.js.map +1 -0
- package/build/telemetry/instrumentations.d.ts +29 -0
- package/build/telemetry/instrumentations.js +47 -0
- package/build/telemetry/instrumentations.js.map +1 -0
- package/build/telemetry/requestLogger.d.ts +6 -0
- package/build/telemetry/requestLogger.js +144 -0
- package/build/telemetry/requestLogger.js.map +1 -0
- package/build/tsconfig.build.tsbuildinfo +1 -0
- package/build/types.d.ts +77 -0
- package/build/types.js +3 -0
- package/build/types.js.map +1 -0
- package/config/config.json +31 -0
- package/config/development.json +11 -0
- package/config/test.json +5 -0
- package/jest.config.js +14 -0
- package/package.json +111 -0
- package/src/bin/start-service.ts +28 -0
- package/src/bootstrap.ts +112 -0
- package/src/config/index.ts +115 -0
- package/src/config/schema.ts +66 -0
- package/src/config/shortstops.ts +118 -0
- package/src/config/types.ts +5 -0
- package/src/development/port-finder.ts +40 -0
- package/src/development/repl.ts +24 -0
- package/src/env.ts +14 -0
- package/src/error.ts +44 -0
- package/src/express-app/app.ts +399 -0
- package/src/express-app/index.ts +2 -0
- package/src/express-app/internal-server.ts +31 -0
- package/src/express-app/route-loader.ts +48 -0
- package/src/express-app/types.ts +31 -0
- package/src/index.ts +8 -0
- package/src/openapi.ts +67 -0
- package/src/service-calls/index.ts +129 -0
- package/src/telemetry/fetchInstrumentation.ts +209 -0
- package/src/telemetry/index.ts +69 -0
- package/src/telemetry/instrumentations.ts +54 -0
- package/src/telemetry/requestLogger.ts +193 -0
- package/src/types.ts +139 -0
- package/tsconfig.build.json +10 -0
- package/tsconfig.json +36 -0
|
@@ -0,0 +1,85 @@
|
|
|
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.throwOrGetResponse = exports.createServiceInterface = void 0;
|
|
7
|
+
const node_url_1 = require("node:url");
|
|
8
|
+
const eventsource_1 = __importDefault(require("eventsource"));
|
|
9
|
+
const error_1 = require("../error");
|
|
10
|
+
class CustomEventSource extends eventsource_1.default {
|
|
11
|
+
activeListeners = [];
|
|
12
|
+
addEventListener(name, handler) {
|
|
13
|
+
super.addEventListener(name, handler);
|
|
14
|
+
this.activeListeners.push({ name, handler });
|
|
15
|
+
return this;
|
|
16
|
+
}
|
|
17
|
+
removeAllListeners() {
|
|
18
|
+
this.activeListeners.forEach((l) => {
|
|
19
|
+
super.removeEventListener(l.name, l.handler);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Return a factory that will make instances of an OpenAPI/Swagger client for each request
|
|
25
|
+
*/
|
|
26
|
+
function createServiceInterface(service, name, Implementation) {
|
|
27
|
+
const appConfig = service.locals.config;
|
|
28
|
+
const config = {
|
|
29
|
+
...(appConfig.get('connections:default') || {}),
|
|
30
|
+
...(appConfig.get(`connections:${name}`) || {}),
|
|
31
|
+
};
|
|
32
|
+
const protocol = config?.protocol || 'http';
|
|
33
|
+
const port = config?.port || 8000;
|
|
34
|
+
const host = config?.host || name;
|
|
35
|
+
const baseUrl = `${protocol}${protocol.endsWith(':') ? '//' : '://'}${host}:${port}${config?.basePath || ''}`;
|
|
36
|
+
const fetchConfig = {
|
|
37
|
+
fetch,
|
|
38
|
+
AbortController,
|
|
39
|
+
EventSource: CustomEventSource,
|
|
40
|
+
FormData,
|
|
41
|
+
baseUrl,
|
|
42
|
+
};
|
|
43
|
+
// In development, it can be useful to route requests through
|
|
44
|
+
// a centralized local proxy (we use https://github.com/gas-buddy/container-proxy).
|
|
45
|
+
// This allows you to run a subset of services locally and route the rest
|
|
46
|
+
// of the requests to another (typically remote) environment.
|
|
47
|
+
if (config?.proxy) {
|
|
48
|
+
const proxyUrl = new node_url_1.URL(config.proxy);
|
|
49
|
+
const proxyPort = proxyUrl.protocol === 'https:' ? '8443' : '8000';
|
|
50
|
+
fetchConfig.requestInterceptor = (params) => {
|
|
51
|
+
const parsedUrl = new node_url_1.URL(params.url);
|
|
52
|
+
const proto = parsedUrl.protocol.replace(/:$/, '');
|
|
53
|
+
const defaultPort = proto === 'https' ? 8443 : 8000;
|
|
54
|
+
const headers = {};
|
|
55
|
+
headers.host = `${proto}.${parsedUrl.hostname}.${port || defaultPort}`;
|
|
56
|
+
headers.source = service.locals.name;
|
|
57
|
+
parsedUrl.hostname = proxyUrl.hostname;
|
|
58
|
+
parsedUrl.protocol = proxyUrl.protocol;
|
|
59
|
+
parsedUrl.port = proxyUrl.port || proxyPort;
|
|
60
|
+
// eslint-disable-next-line no-param-reassign
|
|
61
|
+
params.headers = params.headers || {};
|
|
62
|
+
Object.assign(params.headers, headers);
|
|
63
|
+
// eslint-disable-next-line no-param-reassign
|
|
64
|
+
params.url = parsedUrl.href;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return new Implementation(fetchConfig);
|
|
68
|
+
}
|
|
69
|
+
exports.createServiceInterface = createServiceInterface;
|
|
70
|
+
function readResponse(app, response, errorSpec) {
|
|
71
|
+
if (response.responseType === 'response') {
|
|
72
|
+
return response;
|
|
73
|
+
}
|
|
74
|
+
const { message, ...spec } = errorSpec || {};
|
|
75
|
+
throw new error_1.ServiceError(app, message || response.body.message || 'Internal Error', {
|
|
76
|
+
status: response.status,
|
|
77
|
+
...spec,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
async function throwOrGetResponse(app, exec, errorSpec) {
|
|
81
|
+
const response = await exec();
|
|
82
|
+
return readResponse(app, response, errorSpec);
|
|
83
|
+
}
|
|
84
|
+
exports.throwOrGetResponse = throwOrGetResponse;
|
|
85
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/service-calls/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Instrumentation, InstrumentationConfig } from '@opentelemetry/instrumentation';
|
|
3
|
+
import { Span, TracerProvider } from '@opentelemetry/api';
|
|
4
|
+
import { MeterProvider } from '@opentelemetry/api-metrics';
|
|
5
|
+
interface FetchRequestArguments {
|
|
6
|
+
request: {
|
|
7
|
+
path: string;
|
|
8
|
+
method: string;
|
|
9
|
+
origin: string;
|
|
10
|
+
headers: string;
|
|
11
|
+
};
|
|
12
|
+
span: Span;
|
|
13
|
+
additionalHeaders: Record<string, unknown>;
|
|
14
|
+
error?: Error;
|
|
15
|
+
}
|
|
16
|
+
type ErrorFetchRequestArguments = FetchRequestArguments & {
|
|
17
|
+
error: Error;
|
|
18
|
+
};
|
|
19
|
+
type ResponseFetchRequestArguments = FetchRequestArguments & {
|
|
20
|
+
response: {
|
|
21
|
+
statusCode: number;
|
|
22
|
+
headers: Buffer[];
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
interface FetchInstrumentationConfig extends InstrumentationConfig {
|
|
26
|
+
onRequest?: (args: FetchRequestArguments) => void;
|
|
27
|
+
}
|
|
28
|
+
export declare class FetchInstrumentation implements Instrumentation {
|
|
29
|
+
private channelSubs;
|
|
30
|
+
private spanFromReq;
|
|
31
|
+
private tracer;
|
|
32
|
+
private config;
|
|
33
|
+
private meter;
|
|
34
|
+
readonly instrumentationName = "opentelemetry-instrumentation-node-18-fetch";
|
|
35
|
+
readonly instrumentationVersion = "1.0.0";
|
|
36
|
+
readonly instrumentationDescription = "Instrumentation for Node 18 fetch via diagnostics_channel";
|
|
37
|
+
private subscribeToChannel;
|
|
38
|
+
constructor(config: FetchInstrumentationConfig);
|
|
39
|
+
disable(): void;
|
|
40
|
+
enable(): void;
|
|
41
|
+
setTracerProvider(tracerProvider: TracerProvider): void;
|
|
42
|
+
setMeterProvider(meterProvider: MeterProvider): void;
|
|
43
|
+
setConfig(config: InstrumentationConfig): void;
|
|
44
|
+
getConfig(): InstrumentationConfig;
|
|
45
|
+
onRequest({ request }: FetchRequestArguments): void;
|
|
46
|
+
onHeaders({ request, response }: ResponseFetchRequestArguments): void;
|
|
47
|
+
onDone({ request }: FetchRequestArguments): void;
|
|
48
|
+
onError({ request, error }: ErrorFetchRequestArguments): void;
|
|
49
|
+
}
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,144 @@
|
|
|
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
|
+
const api_metrics_1 = require("@opentelemetry/api-metrics");
|
|
11
|
+
// Get the content-length from undici response headers.
|
|
12
|
+
// `headers` is an Array of buffers: [k, v, k, v, ...].
|
|
13
|
+
// If the header is not present, or has an invalid value, this returns null.
|
|
14
|
+
function contentLengthFromResponseHeaders(headers) {
|
|
15
|
+
const name = 'content-length';
|
|
16
|
+
for (let i = 0; i < headers.length; i += 2) {
|
|
17
|
+
const k = headers[i];
|
|
18
|
+
if (k.length === name.length && k.toString().toLowerCase() === name) {
|
|
19
|
+
const v = Number(headers[i + 1]);
|
|
20
|
+
if (!Number.isNaN(Number(v))) {
|
|
21
|
+
return v;
|
|
22
|
+
}
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
// A combination of https://github.com/elastic/apm-agent-nodejs and
|
|
29
|
+
// https://github.com/gadget-inc/opentelemetry-instrumentations/blob/main/packages/opentelemetry-instrumentation-undici/src/index.ts
|
|
30
|
+
class FetchInstrumentation {
|
|
31
|
+
// Keep ref to avoid https://github.com/nodejs/node/issues/42170 bug and for
|
|
32
|
+
// unsubscribing.
|
|
33
|
+
channelSubs;
|
|
34
|
+
spanFromReq = new WeakMap();
|
|
35
|
+
tracer;
|
|
36
|
+
config;
|
|
37
|
+
meter;
|
|
38
|
+
instrumentationName = 'opentelemetry-instrumentation-node-18-fetch';
|
|
39
|
+
instrumentationVersion = '1.0.0';
|
|
40
|
+
instrumentationDescription = 'Instrumentation for Node 18 fetch via diagnostics_channel';
|
|
41
|
+
subscribeToChannel(diagnosticChannel, onMessage) {
|
|
42
|
+
const channel = node_diagnostics_channel_1.default.channel(diagnosticChannel);
|
|
43
|
+
channel.subscribe(onMessage);
|
|
44
|
+
this.channelSubs.push({
|
|
45
|
+
name: diagnosticChannel,
|
|
46
|
+
channel,
|
|
47
|
+
onMessage,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
constructor(config) {
|
|
51
|
+
// Force load fetch API (since it's lazy loaded in Node 18)
|
|
52
|
+
fetch('').catch(Promise.resolve);
|
|
53
|
+
this.channelSubs = [];
|
|
54
|
+
this.meter = api_metrics_1.metrics.getMeter(this.instrumentationName, this.instrumentationVersion);
|
|
55
|
+
this.tracer = api_1.trace.getTracer(this.instrumentationName, this.instrumentationVersion);
|
|
56
|
+
this.config = { ...config };
|
|
57
|
+
}
|
|
58
|
+
disable() {
|
|
59
|
+
this.channelSubs?.forEach((sub) => sub.channel.unsubscribe(sub.onMessage));
|
|
60
|
+
}
|
|
61
|
+
enable() {
|
|
62
|
+
this.subscribeToChannel('undici:request:create', (args) => this.onRequest(args));
|
|
63
|
+
this.subscribeToChannel('undici:request:headers', (args) => this.onHeaders(args));
|
|
64
|
+
this.subscribeToChannel('undici:request:trailers', (args) => this.onDone(args));
|
|
65
|
+
this.subscribeToChannel('undici:request:error', (args) => this.onError(args));
|
|
66
|
+
}
|
|
67
|
+
setTracerProvider(tracerProvider) {
|
|
68
|
+
this.tracer = tracerProvider.getTracer(this.instrumentationName, this.instrumentationVersion);
|
|
69
|
+
}
|
|
70
|
+
setMeterProvider(meterProvider) {
|
|
71
|
+
this.meter = meterProvider.getMeter(this.instrumentationName, this.instrumentationVersion);
|
|
72
|
+
}
|
|
73
|
+
setConfig(config) {
|
|
74
|
+
this.config = { ...config };
|
|
75
|
+
}
|
|
76
|
+
getConfig() {
|
|
77
|
+
return this.config;
|
|
78
|
+
}
|
|
79
|
+
onRequest({ request }) {
|
|
80
|
+
// We do not handle instrumenting HTTP CONNECT. See limitation notes above.
|
|
81
|
+
if (request.method === 'CONNECT') {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const span = this.tracer.startSpan(`HTTP ${request.method}`, {
|
|
85
|
+
kind: api_1.SpanKind.CLIENT,
|
|
86
|
+
attributes: {
|
|
87
|
+
[semantic_conventions_1.SemanticAttributes.HTTP_URL]: String(request.origin),
|
|
88
|
+
[semantic_conventions_1.SemanticAttributes.HTTP_METHOD]: request.method,
|
|
89
|
+
[semantic_conventions_1.SemanticAttributes.HTTP_TARGET]: request.path,
|
|
90
|
+
'http.client': 'fetch',
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
const requestContext = api_1.trace.setSpan(api_1.context.active(), span);
|
|
94
|
+
const addedHeaders = {};
|
|
95
|
+
api_1.propagation.inject(requestContext, addedHeaders);
|
|
96
|
+
if (this.config.onRequest) {
|
|
97
|
+
this.config.onRequest({ request, span, additionalHeaders: addedHeaders });
|
|
98
|
+
}
|
|
99
|
+
request.headers += Object.entries(addedHeaders)
|
|
100
|
+
.map(([k, v]) => `${k}: ${v}\r\n`)
|
|
101
|
+
.join('');
|
|
102
|
+
this.spanFromReq.set(request, span);
|
|
103
|
+
}
|
|
104
|
+
onHeaders({ request, response }) {
|
|
105
|
+
const span = this.spanFromReq.get(request);
|
|
106
|
+
if (span !== undefined) {
|
|
107
|
+
// We are currently *not* capturing response headers, even though the
|
|
108
|
+
// intake API does allow it, because none of the other `setHttpContext`
|
|
109
|
+
// uses currently do.
|
|
110
|
+
const cLen = contentLengthFromResponseHeaders(response.headers);
|
|
111
|
+
const attrs = {
|
|
112
|
+
[semantic_conventions_1.SemanticAttributes.HTTP_STATUS_CODE]: response.statusCode,
|
|
113
|
+
};
|
|
114
|
+
if (cLen) {
|
|
115
|
+
attrs[semantic_conventions_1.SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH] = cLen;
|
|
116
|
+
}
|
|
117
|
+
span.setAttributes(attrs);
|
|
118
|
+
span.setStatus({
|
|
119
|
+
code: response.statusCode >= 400 ? api_1.SpanStatusCode.ERROR : api_1.SpanStatusCode.OK,
|
|
120
|
+
message: String(response.statusCode),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
onDone({ request }) {
|
|
125
|
+
const span = this.spanFromReq.get(request);
|
|
126
|
+
if (span !== undefined) {
|
|
127
|
+
span.end();
|
|
128
|
+
this.spanFromReq.delete(request);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
onError({ request, error }) {
|
|
132
|
+
const span = this.spanFromReq.get(request);
|
|
133
|
+
if (span !== undefined) {
|
|
134
|
+
span.recordException(error);
|
|
135
|
+
span.setStatus({
|
|
136
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
137
|
+
message: error.message,
|
|
138
|
+
});
|
|
139
|
+
span.end();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
exports.FetchInstrumentation = FetchInstrumentation;
|
|
144
|
+
//# sourceMappingURL=fetchInstrumentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetchInstrumentation.js","sourceRoot":"","sources":["../../src/telemetry/fetchInstrumentation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import type { DelayLoadServiceStartOptions, RequestLocals, ServiceLocals } from '../types';
|
|
3
|
+
export declare function startWithTelemetry<SLocals extends ServiceLocals = ServiceLocals, RLocals extends RequestLocals = RequestLocals>(options: DelayLoadServiceStartOptions): Promise<{
|
|
4
|
+
app: import("../types").ServiceExpress<SLocals>;
|
|
5
|
+
server: import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>;
|
|
6
|
+
}>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.startWithTelemetry = void 0;
|
|
27
|
+
const api_1 = require("@opentelemetry/api");
|
|
28
|
+
const exporter_trace_otlp_proto_1 = require("@opentelemetry/exporter-trace-otlp-proto");
|
|
29
|
+
const opentelemetry = __importStar(require("@opentelemetry/sdk-node"));
|
|
30
|
+
const instrumentations_1 = require("./instrumentations");
|
|
31
|
+
// For troubleshooting, set the log level to DiagLogLevel.DEBUG
|
|
32
|
+
api_1.diag.setLogger(new api_1.DiagConsoleLogger(), api_1.DiagLogLevel.INFO);
|
|
33
|
+
function getExporter() {
|
|
34
|
+
if (['production', 'staging'].includes(process.env.APP_ENV || process.env.NODE_ENV || '')) {
|
|
35
|
+
return new exporter_trace_otlp_proto_1.OTLPTraceExporter({
|
|
36
|
+
url: process.env.OTLP_EXPORTER || 'http://otlp-exporter:4318/v1/traces',
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return new opentelemetry.tracing.ConsoleSpanExporter();
|
|
40
|
+
}
|
|
41
|
+
async function startWithTelemetry(options) {
|
|
42
|
+
const sdk = new opentelemetry.NodeSDK({
|
|
43
|
+
serviceName: options.name,
|
|
44
|
+
autoDetectResources: true,
|
|
45
|
+
traceExporter: getExporter(),
|
|
46
|
+
instrumentations: [(0, instrumentations_1.getAutoInstrumentations)({
|
|
47
|
+
'opentelemetry-instrumentation-node-18-fetch': {
|
|
48
|
+
onRequest({ request, span, additionalHeaders }) {
|
|
49
|
+
// This particular line is "GasBuddy" specific, in that we have a number
|
|
50
|
+
// of services not yet on OpenTelemetry that look for this header instead.
|
|
51
|
+
// Putting traceId gives us a "shot in heck" of useful searches.
|
|
52
|
+
if (!/^correlationid:/m.test(request.headers)) {
|
|
53
|
+
const ctx = span.spanContext();
|
|
54
|
+
additionalHeaders.correlationid = ctx.traceId;
|
|
55
|
+
additionalHeaders.span = ctx.spanId;
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
})],
|
|
60
|
+
});
|
|
61
|
+
await sdk.start();
|
|
62
|
+
// eslint-disable-next-line import/no-unresolved
|
|
63
|
+
const { startApp, listen } = await import('../express-app/app.js');
|
|
64
|
+
// eslint-disable-next-line import/no-dynamic-require, global-require, @typescript-eslint/no-var-requires
|
|
65
|
+
const { default: service } = require(options.service);
|
|
66
|
+
const startOptions = {
|
|
67
|
+
...options,
|
|
68
|
+
service,
|
|
69
|
+
locals: { ...options.locals },
|
|
70
|
+
};
|
|
71
|
+
const app = await startApp(startOptions);
|
|
72
|
+
app.locals.logger.info('OpenTelemetry enabled');
|
|
73
|
+
const server = await listen(app, async () => {
|
|
74
|
+
await sdk.shutdown();
|
|
75
|
+
app.locals.logger.info('OpenTelemetry shut down');
|
|
76
|
+
});
|
|
77
|
+
return { app, server };
|
|
78
|
+
}
|
|
79
|
+
exports.startWithTelemetry = startWithTelemetry;
|
|
80
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/telemetry/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,4CAA2E;AAC3E,wFAA6E;AAC7E,uEAAyD;AASzD,yDAA6D;AAG7D,+DAA+D;AAC/D,UAAI,CAAC,SAAS,CAAC,IAAI,uBAAiB,EAAE,EAAE,kBAAY,CAAC,IAAI,CAAC,CAAC;AAE3D,SAAS,WAAW;IAClB,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE;QACzF,OAAO,IAAI,6CAAiB,CAAC;YAC3B,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,qCAAqC;SACxE,CAAC,CAAC;KACJ;IACD,OAAO,IAAI,aAAa,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC;AACzD,CAAC;AAEM,KAAK,UAAU,kBAAkB,CAGtC,OAAqC;IACrC,MAAM,GAAG,GAAG,IAAI,aAAa,CAAC,OAAO,CAAC;QACpC,WAAW,EAAE,OAAO,CAAC,IAAI;QACzB,mBAAmB,EAAE,IAAI;QACzB,aAAa,EAAE,WAAW,EAAE;QAC5B,gBAAgB,EAAE,CAAC,IAAA,0CAAuB,EAAC;gBACzC,6CAA6C,EAAE;oBAC7C,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE;wBAC5C,wEAAwE;wBACxE,0EAA0E;wBAC1E,gEAAgE;wBAChE,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;4BAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;4BAC/B,iBAAiB,CAAC,aAAa,GAAG,GAAG,CAAC,OAAO,CAAC;4BAC9C,iBAAiB,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC;yBACrC;oBACH,CAAC;iBACF;aACF,CAAC,CAAC;KACJ,CAAC,CAAC;IACH,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;IAElB,gDAAgD;IAChD,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;IACnE,yGAAyG;IACzG,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,MAAM,YAAY,GAAiC;QACjD,GAAG,OAAO;QACV,OAAO;QACP,MAAM,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,EAAsB;KAClD,CAAC;IACF,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAmB,YAAY,CAAC,CAAC;IAC3D,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IAEhD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,GAAG,CAAC,QAAQ,EAAE,CAAC;QACrB,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;AACzB,CAAC;AA1CD,gDA0CC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Instrumentation } from '@opentelemetry/instrumentation';
|
|
2
|
+
import { AwsInstrumentation } from '@opentelemetry/instrumentation-aws-sdk';
|
|
3
|
+
import { DnsInstrumentation } from '@opentelemetry/instrumentation-dns';
|
|
4
|
+
import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express';
|
|
5
|
+
import { GenericPoolInstrumentation } from '@opentelemetry/instrumentation-generic-pool';
|
|
6
|
+
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
|
|
7
|
+
import { IORedisInstrumentation } from '@opentelemetry/instrumentation-ioredis';
|
|
8
|
+
import { NetInstrumentation } from '@opentelemetry/instrumentation-net';
|
|
9
|
+
import { PgInstrumentation } from '@opentelemetry/instrumentation-pg';
|
|
10
|
+
import { PinoInstrumentation } from '@opentelemetry/instrumentation-pino';
|
|
11
|
+
import { FetchInstrumentation } from './fetchInstrumentation';
|
|
12
|
+
declare const InstrumentationMap: {
|
|
13
|
+
'@opentelemetry/instrumentation-http': typeof HttpInstrumentation;
|
|
14
|
+
'opentelemetry-instrumentation-node-18-fetch': typeof FetchInstrumentation;
|
|
15
|
+
'@opentelemetry/instrumentation-aws-sdk': typeof AwsInstrumentation;
|
|
16
|
+
'@opentelemetry/instrumentation-dns': typeof DnsInstrumentation;
|
|
17
|
+
'@opentelemetry/instrumentation-express': typeof ExpressInstrumentation;
|
|
18
|
+
'@opentelemetry/instrumentation-generic-pool': typeof GenericPoolInstrumentation;
|
|
19
|
+
'@opentelemetry/instrumentation-ioredis': typeof IORedisInstrumentation;
|
|
20
|
+
'@opentelemetry/instrumentation-net': typeof NetInstrumentation;
|
|
21
|
+
'@opentelemetry/instrumentation-pg': typeof PgInstrumentation;
|
|
22
|
+
'@opentelemetry/instrumentation-pino': typeof PinoInstrumentation;
|
|
23
|
+
};
|
|
24
|
+
type ConfigArg<T> = T extends new (...args: infer U) => unknown ? U[0] : never;
|
|
25
|
+
export type InstrumentationConfigMap = {
|
|
26
|
+
[Name in keyof typeof InstrumentationMap]?: ConfigArg<typeof InstrumentationMap[Name]>;
|
|
27
|
+
};
|
|
28
|
+
export declare function getAutoInstrumentations(inputConfigs?: InstrumentationConfigMap): Instrumentation[];
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAutoInstrumentations = void 0;
|
|
4
|
+
const instrumentation_aws_sdk_1 = require("@opentelemetry/instrumentation-aws-sdk");
|
|
5
|
+
const instrumentation_dns_1 = require("@opentelemetry/instrumentation-dns");
|
|
6
|
+
const instrumentation_express_1 = require("@opentelemetry/instrumentation-express");
|
|
7
|
+
const instrumentation_generic_pool_1 = require("@opentelemetry/instrumentation-generic-pool");
|
|
8
|
+
const instrumentation_http_1 = require("@opentelemetry/instrumentation-http");
|
|
9
|
+
const instrumentation_ioredis_1 = require("@opentelemetry/instrumentation-ioredis");
|
|
10
|
+
const instrumentation_net_1 = require("@opentelemetry/instrumentation-net");
|
|
11
|
+
const instrumentation_pg_1 = require("@opentelemetry/instrumentation-pg");
|
|
12
|
+
const instrumentation_pino_1 = require("@opentelemetry/instrumentation-pino");
|
|
13
|
+
const fetchInstrumentation_1 = require("./fetchInstrumentation");
|
|
14
|
+
const InstrumentationMap = {
|
|
15
|
+
// Disable this for now because it logs a stupid message
|
|
16
|
+
// '@opentelemetry/instrumentation-aws-lambda': AwsLambdaInstrumentation,
|
|
17
|
+
'@opentelemetry/instrumentation-http': instrumentation_http_1.HttpInstrumentation,
|
|
18
|
+
'opentelemetry-instrumentation-node-18-fetch': fetchInstrumentation_1.FetchInstrumentation,
|
|
19
|
+
'@opentelemetry/instrumentation-aws-sdk': instrumentation_aws_sdk_1.AwsInstrumentation,
|
|
20
|
+
'@opentelemetry/instrumentation-dns': instrumentation_dns_1.DnsInstrumentation,
|
|
21
|
+
'@opentelemetry/instrumentation-express': instrumentation_express_1.ExpressInstrumentation,
|
|
22
|
+
'@opentelemetry/instrumentation-generic-pool': instrumentation_generic_pool_1.GenericPoolInstrumentation,
|
|
23
|
+
'@opentelemetry/instrumentation-ioredis': instrumentation_ioredis_1.IORedisInstrumentation,
|
|
24
|
+
'@opentelemetry/instrumentation-net': instrumentation_net_1.NetInstrumentation,
|
|
25
|
+
'@opentelemetry/instrumentation-pg': instrumentation_pg_1.PgInstrumentation,
|
|
26
|
+
'@opentelemetry/instrumentation-pino': instrumentation_pino_1.PinoInstrumentation,
|
|
27
|
+
};
|
|
28
|
+
function getAutoInstrumentations(inputConfigs = {}) {
|
|
29
|
+
const keys = Object.keys(InstrumentationMap);
|
|
30
|
+
return keys
|
|
31
|
+
.map((name) => {
|
|
32
|
+
const Instance = InstrumentationMap[name];
|
|
33
|
+
// Defaults are defined by the instrumentation itself
|
|
34
|
+
const userConfig = inputConfigs[name] ?? {};
|
|
35
|
+
try {
|
|
36
|
+
return new Instance(userConfig);
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
// eslint-disable-next-line no-console
|
|
40
|
+
console.error(`Failed to load ${name}`, e);
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
.filter((i) => !!i);
|
|
45
|
+
}
|
|
46
|
+
exports.getAutoInstrumentations = getAutoInstrumentations;
|
|
47
|
+
//# sourceMappingURL=instrumentations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentations.js","sourceRoot":"","sources":["../../src/telemetry/instrumentations.ts"],"names":[],"mappings":";;;AACA,oFAA4E;AAC5E,4EAAwE;AACxE,oFAAgF;AAChF,8FAAyF;AACzF,8EAA0E;AAC1E,oFAAgF;AAChF,4EAAwE;AACxE,0EAAsE;AACtE,8EAA0E;AAE1E,iEAA8D;AAE9D,MAAM,kBAAkB,GAAG;IACzB,wDAAwD;IACxD,yEAAyE;IACzE,qCAAqC,EAAE,0CAAmB;IAC1D,6CAA6C,EAAE,2CAAoB;IACnE,wCAAwC,EAAE,4CAAkB;IAC5D,oCAAoC,EAAE,wCAAkB;IACxD,wCAAwC,EAAE,gDAAsB;IAChE,6CAA6C,EAAE,yDAA0B;IACzE,wCAAwC,EAAE,gDAAsB;IAChE,oCAAoC,EAAE,wCAAkB;IACxD,mCAAmC,EAAE,sCAAiB;IACtD,qCAAqC,EAAE,0CAAmB;CAC3D,CAAC;AAQF,SAAgB,uBAAuB,CACrC,eAAyC,EAAE;IAE3C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAA2C,CAAC;IACvF,OAAO,IAAI;SACR,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAC1C,qDAAqD;QACrD,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAE5C,IAAI;YACF,OAAO,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC;SACjC;QAAC,OAAO,CAAC,EAAE;YACV,sCAAsC;YACtC,OAAO,CAAC,KAAK,CAAC,kBAAkB,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;YAC3C,OAAO,IAAI,CAAC;SACb;IACH,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAsB,CAAC;AAC7C,CAAC;AAnBD,0DAmBC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/// <reference types="qs" />
|
|
2
|
+
import type { RequestHandler, ErrorRequestHandler } from 'express';
|
|
3
|
+
import type { ServiceExpress, ServiceLocals } from '../types';
|
|
4
|
+
export declare function loggerMiddleware<SLocals extends ServiceLocals = ServiceLocals>(app: ServiceExpress<SLocals>, logRequests?: boolean, logResponses?: boolean): RequestHandler;
|
|
5
|
+
export declare function errorHandlerMiddleware<SLocals extends ServiceLocals = ServiceLocals>(app: ServiceExpress<SLocals>, unnest?: boolean, returnError?: boolean): ErrorRequestHandler<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
|
|
6
|
+
export declare function notFoundMiddleware(): RequestHandler<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.notFoundMiddleware = exports.errorHandlerMiddleware = exports.loggerMiddleware = void 0;
|
|
4
|
+
const error_1 = require("../error");
|
|
5
|
+
const LOG_PREFS = Symbol('Logging information');
|
|
6
|
+
function getBasicInfo(req) {
|
|
7
|
+
const url = req.originalUrl || req.url;
|
|
8
|
+
const preInfo = {
|
|
9
|
+
url,
|
|
10
|
+
m: req.method,
|
|
11
|
+
};
|
|
12
|
+
return preInfo;
|
|
13
|
+
}
|
|
14
|
+
function finishLog(app, error, req, res) {
|
|
15
|
+
const prefs = res.locals[LOG_PREFS];
|
|
16
|
+
if (prefs.logged) {
|
|
17
|
+
// This happens when error handler runs, but onEnd hasn't fired yet. We only log the first one.
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const { logger, service } = app.locals;
|
|
21
|
+
const hrdur = process.hrtime(prefs.start);
|
|
22
|
+
const dur = hrdur[0] + hrdur[1] / 1000000000;
|
|
23
|
+
const endLog = {
|
|
24
|
+
...getBasicInfo(req),
|
|
25
|
+
s: error?.status || res.statusCode || 0,
|
|
26
|
+
dur,
|
|
27
|
+
};
|
|
28
|
+
if (res.locals.user?.id) {
|
|
29
|
+
endLog.u = res.locals.user.id;
|
|
30
|
+
}
|
|
31
|
+
if (error) {
|
|
32
|
+
endLog.e = error.message;
|
|
33
|
+
if (!(error instanceof error_1.ServiceError) || error.log_stack) {
|
|
34
|
+
endLog.st = error.stack;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (prefs.logRequests) {
|
|
38
|
+
if (Buffer.isBuffer(req.body)) {
|
|
39
|
+
endLog.b = req.body.toString('base64');
|
|
40
|
+
}
|
|
41
|
+
else if (typeof req.body !== 'string') {
|
|
42
|
+
endLog.b = JSON.stringify(req.body);
|
|
43
|
+
}
|
|
44
|
+
else if (req.body) {
|
|
45
|
+
endLog.b = req.body;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (prefs.chunks?.length) {
|
|
49
|
+
const bodyString = Buffer.concat(prefs.chunks).toString('utf8');
|
|
50
|
+
if (bodyString) {
|
|
51
|
+
endLog.resBody = bodyString;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
service.getLogFields?.(req, endLog);
|
|
55
|
+
logger.info(endLog, 'req');
|
|
56
|
+
}
|
|
57
|
+
function loggerMiddleware(app, logRequests, logResponses) {
|
|
58
|
+
const { logger, service } = app.locals;
|
|
59
|
+
return function gblogger(req, res, next) {
|
|
60
|
+
const prefs = {
|
|
61
|
+
start: process.hrtime(),
|
|
62
|
+
logRequests,
|
|
63
|
+
chunks: logResponses ? [] : undefined,
|
|
64
|
+
logged: false,
|
|
65
|
+
};
|
|
66
|
+
res.locals[LOG_PREFS] = prefs;
|
|
67
|
+
if (logResponses) {
|
|
68
|
+
// res is a read-only stream, so the only way to intercept response
|
|
69
|
+
// data is to monkey-patch.
|
|
70
|
+
const oldWrite = res.write;
|
|
71
|
+
const oldEnd = res.end;
|
|
72
|
+
res.write = ((...args) => {
|
|
73
|
+
if (prefs.chunks) {
|
|
74
|
+
prefs.chunks.push(Buffer.isBuffer(args[0]) ? args[0] : Buffer.from(args[0]));
|
|
75
|
+
}
|
|
76
|
+
return oldWrite.apply(res, args);
|
|
77
|
+
});
|
|
78
|
+
res.end = ((...args) => {
|
|
79
|
+
if (args[0] && prefs.chunks) {
|
|
80
|
+
prefs.chunks.push(Buffer.isBuffer(args[0]) ? args[0] : Buffer.from(args[0]));
|
|
81
|
+
}
|
|
82
|
+
return oldEnd.apply(res, args);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
const preLog = {
|
|
86
|
+
...getBasicInfo(req),
|
|
87
|
+
ref: req.headers.referer || undefined,
|
|
88
|
+
sid: req.session?.id,
|
|
89
|
+
c: req.headers.correlationid || undefined,
|
|
90
|
+
};
|
|
91
|
+
service.getLogFields?.(req, preLog);
|
|
92
|
+
logger.info(preLog, 'pre');
|
|
93
|
+
const logWriter = () => finishLog(app, undefined, req, res);
|
|
94
|
+
res.on('finish', logWriter);
|
|
95
|
+
next();
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
exports.loggerMiddleware = loggerMiddleware;
|
|
99
|
+
function errorHandlerMiddleware(app, unnest, returnError) {
|
|
100
|
+
const gbErrorHandler = (error, req, res, next) => {
|
|
101
|
+
let loggable = error;
|
|
102
|
+
const body = error.response?.body || error.body;
|
|
103
|
+
if (unnest && body?.domain && body?.code && body?.message) {
|
|
104
|
+
loggable = {
|
|
105
|
+
status: error.status,
|
|
106
|
+
message: body.message,
|
|
107
|
+
domain: body.domain,
|
|
108
|
+
code: body.code,
|
|
109
|
+
display_message: body.display_message,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// Set the status to error, even if we aren't going to render the error.
|
|
113
|
+
res.status(loggable.status || 500);
|
|
114
|
+
if (returnError) {
|
|
115
|
+
finishLog(app, error, req, res);
|
|
116
|
+
const prefs = res.locals[LOG_PREFS];
|
|
117
|
+
prefs.logged = true;
|
|
118
|
+
res.json({
|
|
119
|
+
code: loggable.code,
|
|
120
|
+
message: loggable.message,
|
|
121
|
+
domain: loggable.domain,
|
|
122
|
+
display_message: loggable.display_message,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
next(error);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
return gbErrorHandler;
|
|
130
|
+
}
|
|
131
|
+
exports.errorHandlerMiddleware = errorHandlerMiddleware;
|
|
132
|
+
function notFoundMiddleware() {
|
|
133
|
+
const gbNotFoundHandler = (req, res, next) => {
|
|
134
|
+
const error = new error_1.ServiceError(req.app, `Cannot ${req.method} ${req.path}`, {
|
|
135
|
+
status: 404,
|
|
136
|
+
code: 'NotFound',
|
|
137
|
+
domain: 'http',
|
|
138
|
+
});
|
|
139
|
+
next(error);
|
|
140
|
+
};
|
|
141
|
+
return gbNotFoundHandler;
|
|
142
|
+
}
|
|
143
|
+
exports.notFoundMiddleware = notFoundMiddleware;
|
|
144
|
+
//# sourceMappingURL=requestLogger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requestLogger.js","sourceRoot":"","sources":["../../src/telemetry/requestLogger.ts"],"names":[],"mappings":"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"}
|