@forklaunch/core 0.5.2 → 0.5.4
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/lib/cache/index.d.mts +5 -1
- package/lib/cache/index.d.ts +5 -1
- package/lib/cache/index.js +4 -3
- package/lib/cache/index.js.map +1 -1
- package/lib/cache/index.mjs +4 -3
- package/lib/cache/index.mjs.map +1 -1
- package/lib/http/index.d.mts +74 -68
- package/lib/http/index.d.ts +74 -68
- package/lib/http/index.js +277 -226
- package/lib/http/index.js.map +1 -1
- package/lib/http/index.mjs +279 -230
- package/lib/http/index.mjs.map +1 -1
- package/lib/openTelemetryCollector-CWrfzmmW.d.mts +44 -0
- package/lib/openTelemetryCollector-CWrfzmmW.d.ts +44 -0
- package/lib/services/index.d.mts +9 -3
- package/lib/services/index.d.ts +9 -3
- package/lib/services/index.js +32 -16
- package/lib/services/index.js.map +1 -1
- package/lib/services/index.mjs +32 -16
- package/lib/services/index.mjs.map +1 -1
- package/package.json +1 -1
package/lib/http/index.mjs
CHANGED
@@ -136,7 +136,7 @@ async function checkAuthorizationToken(authorizationMethod, authorizationToken,
|
|
136
136
|
}
|
137
137
|
resourceId = decodedJwt.payload.sub;
|
138
138
|
} catch (error) {
|
139
|
-
|
139
|
+
req.openTelemetryCollector.error(error);
|
140
140
|
return invalidAuthorizationToken;
|
141
141
|
}
|
142
142
|
break;
|
@@ -217,14 +217,271 @@ async function parseRequestAuth(req, res, next) {
|
|
217
217
|
next?.();
|
218
218
|
}
|
219
219
|
|
220
|
+
// src/services/getEnvVar.ts
|
221
|
+
function getEnvVar(name) {
|
222
|
+
const value = process.env[name];
|
223
|
+
return value;
|
224
|
+
}
|
225
|
+
|
226
|
+
// src/http/telemetry/openTelemetryCollector.ts
|
227
|
+
import { HyperExpressInstrumentation } from "@forklaunch/opentelemetry-instrumentation-hyper-express";
|
228
|
+
import {
|
229
|
+
metrics
|
230
|
+
} from "@opentelemetry/api";
|
231
|
+
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
|
232
|
+
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
|
233
|
+
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
234
|
+
import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";
|
235
|
+
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
|
236
|
+
import { Resource } from "@opentelemetry/resources";
|
237
|
+
import { BatchLogRecordProcessor } from "@opentelemetry/sdk-logs";
|
238
|
+
import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
|
239
|
+
import { NodeSDK } from "@opentelemetry/sdk-node";
|
240
|
+
import {
|
241
|
+
ATTR_SERVICE_NAME as ATTR_SERVICE_NAME2
|
242
|
+
} from "@opentelemetry/semantic-conventions";
|
243
|
+
import dotenv from "dotenv";
|
244
|
+
|
245
|
+
// src/http/guards/isForklaunchRequest.ts
|
246
|
+
function isForklaunchRequest(request) {
|
247
|
+
return request != null && typeof request === "object" && "contractDetails" in request;
|
248
|
+
}
|
249
|
+
|
250
|
+
// src/http/telemetry/pinoLogger.ts
|
251
|
+
import { isNever } from "@forklaunch/common";
|
252
|
+
import { trace as trace2 } from "@opentelemetry/api";
|
253
|
+
import { logs } from "@opentelemetry/api-logs";
|
254
|
+
import pino from "pino";
|
255
|
+
|
256
|
+
// src/http/guards/isLoggerMeta.ts
|
257
|
+
function isLoggerMeta(arg) {
|
258
|
+
return typeof arg === "object" && arg !== null && "_meta" in arg;
|
259
|
+
}
|
260
|
+
|
261
|
+
// src/http/telemetry/pinoLogger.ts
|
262
|
+
import PinoPretty from "pino-pretty";
|
263
|
+
function meta(meta2) {
|
264
|
+
return meta2;
|
265
|
+
}
|
266
|
+
function mapSeverity(level) {
|
267
|
+
switch (level) {
|
268
|
+
case "silent":
|
269
|
+
return 0;
|
270
|
+
case "trace":
|
271
|
+
return 1;
|
272
|
+
case "debug":
|
273
|
+
return 5;
|
274
|
+
case "info":
|
275
|
+
return 9;
|
276
|
+
case "warn":
|
277
|
+
return 13;
|
278
|
+
case "error":
|
279
|
+
return 17;
|
280
|
+
case "fatal":
|
281
|
+
return 21;
|
282
|
+
default:
|
283
|
+
isNever(level);
|
284
|
+
return 0;
|
285
|
+
}
|
286
|
+
}
|
287
|
+
var PinoLogger = class _PinoLogger {
|
288
|
+
pinoLogger;
|
289
|
+
meta;
|
290
|
+
prettyPrinter = PinoPretty.prettyFactory({
|
291
|
+
colorize: true
|
292
|
+
});
|
293
|
+
constructor(level, meta2 = {}) {
|
294
|
+
this.pinoLogger = pino({
|
295
|
+
level: level || "info",
|
296
|
+
formatters: {
|
297
|
+
level(label) {
|
298
|
+
return { level: label };
|
299
|
+
}
|
300
|
+
},
|
301
|
+
timestamp: pino.stdTimeFunctions.isoTime,
|
302
|
+
transport: {
|
303
|
+
target: "pino-pretty",
|
304
|
+
options: { colorize: true }
|
305
|
+
}
|
306
|
+
});
|
307
|
+
this.meta = meta2;
|
308
|
+
}
|
309
|
+
log(level, ...args) {
|
310
|
+
let meta2 = {};
|
311
|
+
const filteredArgs = args.filter((arg) => {
|
312
|
+
if (isLoggerMeta(arg)) {
|
313
|
+
Object.assign(meta2, arg);
|
314
|
+
return false;
|
315
|
+
}
|
316
|
+
return true;
|
317
|
+
});
|
318
|
+
const activeSpan = trace2.getActiveSpan();
|
319
|
+
if (activeSpan) {
|
320
|
+
const activeSpanContext = activeSpan.spanContext();
|
321
|
+
meta2.trace_id = activeSpanContext.traceId;
|
322
|
+
meta2.span_id = activeSpanContext.spanId;
|
323
|
+
meta2.trace_flags = activeSpanContext.traceFlags;
|
324
|
+
meta2 = {
|
325
|
+
// @ts-expect-error accessing private property
|
326
|
+
...activeSpan.attributes,
|
327
|
+
...meta2
|
328
|
+
};
|
329
|
+
}
|
330
|
+
meta2 = {
|
331
|
+
"api.name": "none",
|
332
|
+
"correlation.id": "none",
|
333
|
+
...meta2
|
334
|
+
};
|
335
|
+
this.pinoLogger[level](...filteredArgs);
|
336
|
+
logs.getLogger(process.env.OTEL_SERVICE_NAME ?? "unknown").emit({
|
337
|
+
severityText: level,
|
338
|
+
severityNumber: mapSeverity(level),
|
339
|
+
body: this.prettyPrinter(filteredArgs),
|
340
|
+
attributes: { ...this.meta, ...meta2 }
|
341
|
+
});
|
342
|
+
}
|
343
|
+
error = (msg, ...args) => this.log("error", msg, ...args);
|
344
|
+
info = (msg, ...args) => this.log("info", msg, ...args);
|
345
|
+
debug = (msg, ...args) => this.log("debug", msg, ...args);
|
346
|
+
warn = (msg, ...args) => this.log("warn", msg, ...args);
|
347
|
+
trace = (msg, ...args) => this.log("trace", msg, ...args);
|
348
|
+
child(meta2 = {}) {
|
349
|
+
return new _PinoLogger(this.pinoLogger.level, { ...this.meta, ...meta2 });
|
350
|
+
}
|
351
|
+
getBaseLogger() {
|
352
|
+
return this.pinoLogger;
|
353
|
+
}
|
354
|
+
};
|
355
|
+
function logger(level, meta2 = {}) {
|
356
|
+
return new PinoLogger(level, meta2);
|
357
|
+
}
|
358
|
+
|
359
|
+
// src/http/telemetry/openTelemetryCollector.ts
|
360
|
+
var OpenTelemetryCollector = class {
|
361
|
+
// scoped creation and create this in middleware when api execute. Also add correlation id
|
362
|
+
constructor(serviceName, level, metricDefinitions) {
|
363
|
+
this.serviceName = serviceName;
|
364
|
+
this.logger = logger(level || "info");
|
365
|
+
this.metrics = {};
|
366
|
+
for (const [metricId, metricType] of Object.entries(
|
367
|
+
metricDefinitions ?? {}
|
368
|
+
)) {
|
369
|
+
switch (metricType) {
|
370
|
+
case "counter":
|
371
|
+
this.metrics[metricId] = metrics.getMeter(this.serviceName).createCounter(metricId);
|
372
|
+
break;
|
373
|
+
case "gauge":
|
374
|
+
this.metrics[metricId] = metrics.getMeter(this.serviceName).createGauge(metricId);
|
375
|
+
break;
|
376
|
+
case "histogram":
|
377
|
+
this.metrics[metricId] = metrics.getMeter(this.serviceName).createHistogram(metricId);
|
378
|
+
break;
|
379
|
+
case "upDownCounter":
|
380
|
+
this.metrics[metricId] = metrics.getMeter(this.serviceName).createUpDownCounter(metricId);
|
381
|
+
break;
|
382
|
+
case "observableCounter":
|
383
|
+
this.metrics[metricId] = metrics.getMeter(this.serviceName).createObservableCounter(metricId);
|
384
|
+
break;
|
385
|
+
case "observableGauge":
|
386
|
+
this.metrics[metricId] = metrics.getMeter(this.serviceName).createObservableGauge(metricId);
|
387
|
+
break;
|
388
|
+
case "observableUpDownCounter":
|
389
|
+
this.metrics[metricId] = metrics.getMeter(this.serviceName).createObservableUpDownCounter(metricId);
|
390
|
+
break;
|
391
|
+
}
|
392
|
+
}
|
393
|
+
this.log("info", "OpenTelemetry (Traces + Logs + Metrics) started");
|
394
|
+
}
|
395
|
+
logger;
|
396
|
+
metrics;
|
397
|
+
log(level, ...args) {
|
398
|
+
this.logger.log(level, ...args);
|
399
|
+
}
|
400
|
+
info = (msg, ...args) => {
|
401
|
+
this.logger.log("info", msg, ...args);
|
402
|
+
};
|
403
|
+
error = (msg, ...args) => {
|
404
|
+
this.logger.log("error", msg, ...args);
|
405
|
+
};
|
406
|
+
warn = (msg, ...args) => {
|
407
|
+
this.logger.log("warn", msg, ...args);
|
408
|
+
};
|
409
|
+
debug = (msg, ...args) => {
|
410
|
+
this.logger.log("debug", msg, ...args);
|
411
|
+
};
|
412
|
+
trace = (msg, ...args) => {
|
413
|
+
this.logger.log("trace", msg, ...args);
|
414
|
+
};
|
415
|
+
getMetric(metricId) {
|
416
|
+
return this.metrics[metricId];
|
417
|
+
}
|
418
|
+
};
|
419
|
+
dotenv.config({ path: getEnvVar("ENV_FILE_PATH") });
|
420
|
+
new NodeSDK({
|
421
|
+
resource: new Resource({
|
422
|
+
[ATTR_SERVICE_NAME2]: getEnvVar("OTEL_SERVICE_NAME")
|
423
|
+
}),
|
424
|
+
traceExporter: new OTLPTraceExporter({
|
425
|
+
url: `${getEnvVar("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/traces`
|
426
|
+
}),
|
427
|
+
metricReader: new PeriodicExportingMetricReader({
|
428
|
+
exporter: new OTLPMetricExporter({
|
429
|
+
url: `${getEnvVar("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/metrics`
|
430
|
+
}),
|
431
|
+
exportIntervalMillis: 5e3
|
432
|
+
}),
|
433
|
+
logRecordProcessors: [
|
434
|
+
new BatchLogRecordProcessor(
|
435
|
+
new OTLPLogExporter({
|
436
|
+
url: `${getEnvVar("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/logs`
|
437
|
+
})
|
438
|
+
)
|
439
|
+
],
|
440
|
+
instrumentations: [
|
441
|
+
new HttpInstrumentation({
|
442
|
+
applyCustomAttributesOnSpan: (span, request) => {
|
443
|
+
span.setAttribute(
|
444
|
+
"service.name",
|
445
|
+
getEnvVar("OTEL_SERVICE_NAME") ?? "unknown"
|
446
|
+
);
|
447
|
+
if (isForklaunchRequest(request)) {
|
448
|
+
span.setAttribute("api.name", request.contractDetails?.name);
|
449
|
+
}
|
450
|
+
}
|
451
|
+
}),
|
452
|
+
new ExpressInstrumentation(),
|
453
|
+
new HyperExpressInstrumentation()
|
454
|
+
]
|
455
|
+
}).start();
|
456
|
+
var httpRequestsTotalCounter = metrics.getMeter(getEnvVar("OTEL_SERVICE_NAME") || "unknown").createCounter("http_requests_total", {
|
457
|
+
description: "Number of HTTP requests"
|
458
|
+
});
|
459
|
+
var httpServerDurationHistogram = metrics.getMeter(getEnvVar("OTEL_SERVICE_NAME") || "unknown").createHistogram("http_server_duration", {
|
460
|
+
description: "Duration of HTTP server requests",
|
461
|
+
unit: "s"
|
462
|
+
});
|
463
|
+
|
220
464
|
// src/http/middleware/request/enrichDetails.middleware.ts
|
221
|
-
function enrichDetails(path, contractDetails, requestSchema, responseSchemas) {
|
465
|
+
function enrichDetails(path, contractDetails, requestSchema, responseSchemas, openTelemetryCollector) {
|
222
466
|
return (req, res, next) => {
|
223
467
|
req.originalPath = path;
|
224
468
|
req.contractDetails = contractDetails;
|
225
469
|
req.requestSchema = requestSchema;
|
226
470
|
res.responseSchemas = responseSchemas;
|
471
|
+
req.openTelemetryCollector = openTelemetryCollector;
|
227
472
|
req.context.span?.setAttribute(ATTR_API_NAME, req.contractDetails?.name);
|
473
|
+
const startTime = process.hrtime();
|
474
|
+
res.on("finish", () => {
|
475
|
+
const [seconds, nanoseconds] = process.hrtime(startTime);
|
476
|
+
const durationMs = seconds + nanoseconds / 1e9;
|
477
|
+
httpServerDurationHistogram.record(durationMs, {
|
478
|
+
[ATTR_SERVICE_NAME]: getEnvVar("OTEL_SERVICE_NAME") || "unknown",
|
479
|
+
[ATTR_API_NAME]: req.contractDetails?.name || "unknown",
|
480
|
+
[ATTR_HTTP_REQUEST_METHOD]: req.method,
|
481
|
+
[ATTR_HTTP_ROUTE]: req.originalPath || "unknown",
|
482
|
+
[ATTR_HTTP_RESPONSE_STATUS_CODE]: res.statusCode
|
483
|
+
});
|
484
|
+
});
|
228
485
|
next?.();
|
229
486
|
};
|
230
487
|
}
|
@@ -266,7 +523,9 @@ function parse(req, _res, next) {
|
|
266
523
|
);
|
267
524
|
break;
|
268
525
|
case "warning":
|
269
|
-
|
526
|
+
req.openTelemetryCollector.warn(
|
527
|
+
prettyPrintParseErrors(parsedRequest.errors, "Request")
|
528
|
+
);
|
270
529
|
break;
|
271
530
|
case "none":
|
272
531
|
break;
|
@@ -277,9 +536,10 @@ function parse(req, _res, next) {
|
|
277
536
|
|
278
537
|
// src/http/router/expressLikeRouter.ts
|
279
538
|
var ForklaunchExpressLikeRouter = class {
|
280
|
-
constructor(basePath, schemaValidator, internal) {
|
539
|
+
constructor(basePath, schemaValidator, internal, openTelemetryCollector) {
|
281
540
|
this.schemaValidator = schemaValidator;
|
282
541
|
this.internal = internal;
|
542
|
+
this.openTelemetryCollector = openTelemetryCollector;
|
283
543
|
this.basePath = basePath;
|
284
544
|
}
|
285
545
|
requestHandler;
|
@@ -298,7 +558,8 @@ var ForklaunchExpressLikeRouter = class {
|
|
298
558
|
`${this.basePath}${path}`,
|
299
559
|
contractDetails,
|
300
560
|
requestSchema,
|
301
|
-
responseSchemas
|
561
|
+
responseSchemas,
|
562
|
+
this.openTelemetryCollector
|
302
563
|
),
|
303
564
|
parse,
|
304
565
|
parseRequestAuth
|
@@ -859,20 +1120,16 @@ var ForklaunchExpressLikeApplication = class extends ForklaunchExpressLikeRouter
|
|
859
1120
|
*
|
860
1121
|
* @param {SV} schemaValidator - The schema validator.
|
861
1122
|
*/
|
862
|
-
constructor(schemaValidator, internal) {
|
863
|
-
super("/", schemaValidator, internal);
|
1123
|
+
constructor(schemaValidator, internal, openTelemetryCollector) {
|
1124
|
+
super("/", schemaValidator, internal, openTelemetryCollector);
|
864
1125
|
this.schemaValidator = schemaValidator;
|
865
1126
|
this.internal = internal;
|
1127
|
+
this.openTelemetryCollector = openTelemetryCollector;
|
866
1128
|
this.internal.use(createContext(this.schemaValidator));
|
867
1129
|
this.internal.use(cors);
|
868
1130
|
}
|
869
1131
|
};
|
870
1132
|
|
871
|
-
// src/http/guards/isForklaunchRequest.ts
|
872
|
-
function isForklaunchRequest(request) {
|
873
|
-
return request != null && typeof request === "object" && "contractDetails" in request;
|
874
|
-
}
|
875
|
-
|
876
1133
|
// src/http/guards/isPath.ts
|
877
1134
|
function isPath(path) {
|
878
1135
|
return path.startsWith("/");
|
@@ -946,7 +1203,7 @@ var put = (_schemaValidator, path, contractDetails, ...handlers) => {
|
|
946
1203
|
};
|
947
1204
|
|
948
1205
|
// src/http/handlers/trace.ts
|
949
|
-
var
|
1206
|
+
var trace3 = (_schemaValidator, path, contractDetails, ...handlers) => {
|
950
1207
|
return typedHandler(_schemaValidator, path, "trace", contractDetails, ...handlers);
|
951
1208
|
};
|
952
1209
|
|
@@ -1971,8 +2228,10 @@ function parse2(req, res, next) {
|
|
1971
2228
|
${parseErrors.join("\n\n")}`));
|
1972
2229
|
break;
|
1973
2230
|
case "warning":
|
1974
|
-
|
1975
|
-
|
2231
|
+
req.openTelemetryCollector.warn(
|
2232
|
+
`Invalid response:
|
2233
|
+
${parseErrors.join("\n\n")}`
|
2234
|
+
);
|
1976
2235
|
break;
|
1977
2236
|
case "none":
|
1978
2237
|
break;
|
@@ -1981,96 +2240,6 @@ ${parseErrors.join("\n\n")}`);
|
|
1981
2240
|
next?.();
|
1982
2241
|
}
|
1983
2242
|
|
1984
|
-
// src/http/telemetry/pinoLogger.ts
|
1985
|
-
import { isNever } from "@forklaunch/common";
|
1986
|
-
import { trace as trace3 } from "@opentelemetry/api";
|
1987
|
-
import { logs } from "@opentelemetry/api-logs";
|
1988
|
-
import pino from "pino";
|
1989
|
-
function mapSeverity(level) {
|
1990
|
-
switch (level) {
|
1991
|
-
case "silent":
|
1992
|
-
return 0;
|
1993
|
-
case "trace":
|
1994
|
-
return 1;
|
1995
|
-
case "debug":
|
1996
|
-
return 5;
|
1997
|
-
case "info":
|
1998
|
-
return 9;
|
1999
|
-
case "warn":
|
2000
|
-
return 13;
|
2001
|
-
case "error":
|
2002
|
-
return 17;
|
2003
|
-
case "fatal":
|
2004
|
-
return 21;
|
2005
|
-
default:
|
2006
|
-
isNever(level);
|
2007
|
-
return 0;
|
2008
|
-
}
|
2009
|
-
}
|
2010
|
-
var PinoLogger = class _PinoLogger {
|
2011
|
-
pinoLogger;
|
2012
|
-
meta;
|
2013
|
-
constructor(level, meta = {}) {
|
2014
|
-
this.pinoLogger = pino({
|
2015
|
-
level: level || "info",
|
2016
|
-
formatters: {
|
2017
|
-
level(label) {
|
2018
|
-
return { level: label };
|
2019
|
-
}
|
2020
|
-
},
|
2021
|
-
timestamp: pino.stdTimeFunctions.isoTime,
|
2022
|
-
transport: {
|
2023
|
-
target: "pino-pretty",
|
2024
|
-
options: { colorize: true }
|
2025
|
-
}
|
2026
|
-
});
|
2027
|
-
this.meta = meta;
|
2028
|
-
}
|
2029
|
-
log(level, msg, meta = {}) {
|
2030
|
-
const activeSpan = trace3.getActiveSpan();
|
2031
|
-
if (activeSpan) {
|
2032
|
-
const activeSpanContext = activeSpan.spanContext();
|
2033
|
-
meta.trace_id = activeSpanContext.traceId;
|
2034
|
-
meta.span_id = activeSpanContext.spanId;
|
2035
|
-
meta.trace_flags = activeSpanContext.traceFlags;
|
2036
|
-
if (!meta.api_name) {
|
2037
|
-
meta = { ...meta, ...activeSpan?.attributes };
|
2038
|
-
}
|
2039
|
-
}
|
2040
|
-
this.pinoLogger[level](msg);
|
2041
|
-
logs.getLogger(process.env.OTEL_SERVICE_NAME ?? "unknown").emit({
|
2042
|
-
severityText: level,
|
2043
|
-
severityNumber: mapSeverity(level),
|
2044
|
-
body: msg,
|
2045
|
-
attributes: { ...this.meta, ...meta }
|
2046
|
-
});
|
2047
|
-
}
|
2048
|
-
error(msg, meta = {}) {
|
2049
|
-
this.log("error", msg, meta);
|
2050
|
-
}
|
2051
|
-
info(msg, meta = {}) {
|
2052
|
-
this.log("info", msg, meta);
|
2053
|
-
}
|
2054
|
-
debug(msg, meta = {}) {
|
2055
|
-
this.log("debug", msg, meta);
|
2056
|
-
}
|
2057
|
-
warn(msg, meta = {}) {
|
2058
|
-
this.log("warn", msg, meta);
|
2059
|
-
}
|
2060
|
-
trace(msg, meta = {}) {
|
2061
|
-
this.log("trace", msg, meta);
|
2062
|
-
}
|
2063
|
-
child(meta = {}) {
|
2064
|
-
return new _PinoLogger(this.pinoLogger.level, { ...this.meta, ...meta });
|
2065
|
-
}
|
2066
|
-
getBaseLogger() {
|
2067
|
-
return this.pinoLogger;
|
2068
|
-
}
|
2069
|
-
};
|
2070
|
-
function logger(level, meta = {}) {
|
2071
|
-
return new PinoLogger(level, meta);
|
2072
|
-
}
|
2073
|
-
|
2074
2243
|
// src/http/telemetry/recordMetric.ts
|
2075
2244
|
import {
|
2076
2245
|
ATTR_HTTP_REQUEST_METHOD as ATTR_HTTP_REQUEST_METHOD3,
|
@@ -2085,130 +2254,6 @@ import {
|
|
2085
2254
|
prettyPrintParseErrors as prettyPrintParseErrors3
|
2086
2255
|
} from "@forklaunch/validator";
|
2087
2256
|
|
2088
|
-
// src/services/getEnvVar.ts
|
2089
|
-
function getEnvVar(name) {
|
2090
|
-
const value = process.env[name];
|
2091
|
-
return value;
|
2092
|
-
}
|
2093
|
-
|
2094
|
-
// src/http/telemetry/openTelemetryCollector.ts
|
2095
|
-
import { HyperExpressInstrumentation } from "@forklaunch/opentelemetry-instrumentation-hyper-express";
|
2096
|
-
import {
|
2097
|
-
metrics
|
2098
|
-
} from "@opentelemetry/api";
|
2099
|
-
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
|
2100
|
-
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
|
2101
|
-
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
2102
|
-
import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";
|
2103
|
-
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
|
2104
|
-
import { Resource } from "@opentelemetry/resources";
|
2105
|
-
import { BatchLogRecordProcessor } from "@opentelemetry/sdk-logs";
|
2106
|
-
import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
|
2107
|
-
import { NodeSDK } from "@opentelemetry/sdk-node";
|
2108
|
-
import {
|
2109
|
-
ATTR_SERVICE_NAME as ATTR_SERVICE_NAME2
|
2110
|
-
} from "@opentelemetry/semantic-conventions";
|
2111
|
-
import dotenv from "dotenv";
|
2112
|
-
var OpenTelemetryCollector = class {
|
2113
|
-
// scoped creation and create this in middleware when api execute. Also add correlation id
|
2114
|
-
constructor(serviceName, level, metricDefinitions) {
|
2115
|
-
this.serviceName = serviceName;
|
2116
|
-
this.logger = logger(level ?? "info");
|
2117
|
-
this.metrics = {};
|
2118
|
-
for (const [metricId, metricType] of Object.entries(
|
2119
|
-
metricDefinitions ?? {}
|
2120
|
-
)) {
|
2121
|
-
switch (metricType) {
|
2122
|
-
case "counter":
|
2123
|
-
this.metrics[metricId] = metrics.getMeter(this.serviceName).createCounter(metricId);
|
2124
|
-
break;
|
2125
|
-
case "gauge":
|
2126
|
-
this.metrics[metricId] = metrics.getMeter(this.serviceName).createGauge(metricId);
|
2127
|
-
break;
|
2128
|
-
case "histogram":
|
2129
|
-
this.metrics[metricId] = metrics.getMeter(this.serviceName).createHistogram(metricId);
|
2130
|
-
break;
|
2131
|
-
case "upDownCounter":
|
2132
|
-
this.metrics[metricId] = metrics.getMeter(this.serviceName).createUpDownCounter(metricId);
|
2133
|
-
break;
|
2134
|
-
case "observableCounter":
|
2135
|
-
this.metrics[metricId] = metrics.getMeter(this.serviceName).createObservableCounter(metricId);
|
2136
|
-
break;
|
2137
|
-
case "observableGauge":
|
2138
|
-
this.metrics[metricId] = metrics.getMeter(this.serviceName).createObservableGauge(metricId);
|
2139
|
-
break;
|
2140
|
-
case "observableUpDownCounter":
|
2141
|
-
this.metrics[metricId] = metrics.getMeter(this.serviceName).createObservableUpDownCounter(metricId);
|
2142
|
-
break;
|
2143
|
-
}
|
2144
|
-
}
|
2145
|
-
this.log("info", "OpenTelemetry (Traces + Logs + Metrics) started");
|
2146
|
-
}
|
2147
|
-
logger;
|
2148
|
-
metrics;
|
2149
|
-
log(level, msg, meta = {}) {
|
2150
|
-
this.logger.log(level, msg, meta);
|
2151
|
-
}
|
2152
|
-
info(msg, meta = {}) {
|
2153
|
-
this.logger.info(msg, meta);
|
2154
|
-
}
|
2155
|
-
error(msg, meta = {}) {
|
2156
|
-
this.logger.error(msg, meta);
|
2157
|
-
}
|
2158
|
-
warn(msg, meta = {}) {
|
2159
|
-
this.logger.warn(msg, meta);
|
2160
|
-
}
|
2161
|
-
debug(msg, meta = {}) {
|
2162
|
-
this.logger.debug(msg, meta);
|
2163
|
-
}
|
2164
|
-
trace(msg, meta = {}) {
|
2165
|
-
this.logger.trace(msg, meta);
|
2166
|
-
}
|
2167
|
-
getMetric(metricId) {
|
2168
|
-
return this.metrics[metricId];
|
2169
|
-
}
|
2170
|
-
};
|
2171
|
-
dotenv.config({ path: getEnvVar("ENV_FILE_PATH") });
|
2172
|
-
new NodeSDK({
|
2173
|
-
resource: new Resource({
|
2174
|
-
[ATTR_SERVICE_NAME2]: getEnvVar("OTEL_SERVICE_NAME")
|
2175
|
-
}),
|
2176
|
-
traceExporter: new OTLPTraceExporter({
|
2177
|
-
url: `${getEnvVar("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/traces`
|
2178
|
-
}),
|
2179
|
-
metricReader: new PeriodicExportingMetricReader({
|
2180
|
-
exporter: new OTLPMetricExporter({
|
2181
|
-
url: `${getEnvVar("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/metrics`
|
2182
|
-
}),
|
2183
|
-
exportIntervalMillis: 5e3
|
2184
|
-
}),
|
2185
|
-
logRecordProcessors: [
|
2186
|
-
new BatchLogRecordProcessor(
|
2187
|
-
new OTLPLogExporter({
|
2188
|
-
url: `${getEnvVar("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/logs`
|
2189
|
-
})
|
2190
|
-
)
|
2191
|
-
],
|
2192
|
-
instrumentations: [
|
2193
|
-
new HttpInstrumentation({
|
2194
|
-
applyCustomAttributesOnSpan: (span, request) => {
|
2195
|
-
span.setAttribute(
|
2196
|
-
"service.name",
|
2197
|
-
getEnvVar("OTEL_SERVICE_NAME") ?? "unknown"
|
2198
|
-
);
|
2199
|
-
if (isForklaunchRequest(request)) {
|
2200
|
-
span.setAttribute("api.name", request.contractDetails?.name);
|
2201
|
-
}
|
2202
|
-
}
|
2203
|
-
}),
|
2204
|
-
new ExpressInstrumentation(),
|
2205
|
-
new HyperExpressInstrumentation()
|
2206
|
-
]
|
2207
|
-
}).start();
|
2208
|
-
var httpRequestsTotalCounter = metrics.getMeter(getEnvVar("OTEL_SERVICE_NAME") || "unknown").createCounter("http_requests_total", {
|
2209
|
-
description: "Number of HTTP requests"
|
2210
|
-
});
|
2211
|
-
|
2212
2257
|
// src/http/telemetry/recordMetric.ts
|
2213
2258
|
function recordMetric(req, res) {
|
2214
2259
|
httpRequestsTotalCounter.add(1, {
|
@@ -2227,6 +2272,7 @@ function enrichExpressLikeSend(instance, req, res, originalSend, data, shouldEnr
|
|
2227
2272
|
if (shouldEnrich) {
|
2228
2273
|
recordMetric(req, res);
|
2229
2274
|
if (res.statusCode === 404) {
|
2275
|
+
res.type("text/plain");
|
2230
2276
|
res.status(404);
|
2231
2277
|
logger("error").error("Not Found");
|
2232
2278
|
originalSend.call(instance, "Not Found");
|
@@ -2240,6 +2286,7 @@ function enrichExpressLikeSend(instance, req, res, originalSend, data, shouldEnr
|
|
2240
2286
|
${res.locals.errorMessage}`;
|
2241
2287
|
}
|
2242
2288
|
logger("error").error(errorString);
|
2289
|
+
res.type("text/plain");
|
2243
2290
|
res.status(500);
|
2244
2291
|
originalSend.call(instance, errorString);
|
2245
2292
|
parseErrorSent = true;
|
@@ -2416,6 +2463,7 @@ export {
|
|
2416
2463
|
getCodeForStatus,
|
2417
2464
|
head,
|
2418
2465
|
httpRequestsTotalCounter,
|
2466
|
+
httpServerDurationHistogram,
|
2419
2467
|
isClientError,
|
2420
2468
|
isForklaunchRequest,
|
2421
2469
|
isForklaunchRouter,
|
@@ -2425,6 +2473,7 @@ export {
|
|
2425
2473
|
isSuccessful,
|
2426
2474
|
isValidStatusCode,
|
2427
2475
|
logger,
|
2476
|
+
meta,
|
2428
2477
|
metricsDefinitions,
|
2429
2478
|
middleware,
|
2430
2479
|
options,
|
@@ -2432,7 +2481,7 @@ export {
|
|
2432
2481
|
post,
|
2433
2482
|
put,
|
2434
2483
|
recordMetric,
|
2435
|
-
|
2484
|
+
trace3 as trace,
|
2436
2485
|
typedHandler
|
2437
2486
|
};
|
2438
2487
|
//# sourceMappingURL=index.mjs.map
|