@forklaunch/core 0.5.3 → 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 +36 -35
- package/lib/http/index.d.ts +36 -35
- 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.js
CHANGED
@@ -47,6 +47,7 @@ __export(http_exports, {
|
|
47
47
|
getCodeForStatus: () => getCodeForStatus,
|
48
48
|
head: () => head,
|
49
49
|
httpRequestsTotalCounter: () => httpRequestsTotalCounter,
|
50
|
+
httpServerDurationHistogram: () => httpServerDurationHistogram,
|
50
51
|
isClientError: () => isClientError,
|
51
52
|
isForklaunchRequest: () => isForklaunchRequest,
|
52
53
|
isForklaunchRouter: () => isForklaunchRouter,
|
@@ -56,6 +57,7 @@ __export(http_exports, {
|
|
56
57
|
isSuccessful: () => isSuccessful,
|
57
58
|
isValidStatusCode: () => isValidStatusCode,
|
58
59
|
logger: () => logger,
|
60
|
+
meta: () => meta,
|
59
61
|
metricsDefinitions: () => metricsDefinitions,
|
60
62
|
middleware: () => middleware,
|
61
63
|
options: () => options,
|
@@ -63,7 +65,7 @@ __export(http_exports, {
|
|
63
65
|
post: () => post,
|
64
66
|
put: () => put,
|
65
67
|
recordMetric: () => recordMetric,
|
66
|
-
trace: () =>
|
68
|
+
trace: () => trace3,
|
67
69
|
typedHandler: () => typedHandler
|
68
70
|
});
|
69
71
|
module.exports = __toCommonJS(http_exports);
|
@@ -201,7 +203,7 @@ async function checkAuthorizationToken(authorizationMethod, authorizationToken,
|
|
201
203
|
}
|
202
204
|
resourceId = decodedJwt.payload.sub;
|
203
205
|
} catch (error) {
|
204
|
-
|
206
|
+
req.openTelemetryCollector.error(error);
|
205
207
|
return invalidAuthorizationToken;
|
206
208
|
}
|
207
209
|
break;
|
@@ -282,14 +284,267 @@ async function parseRequestAuth(req, res, next) {
|
|
282
284
|
next?.();
|
283
285
|
}
|
284
286
|
|
287
|
+
// src/services/getEnvVar.ts
|
288
|
+
function getEnvVar(name) {
|
289
|
+
const value = process.env[name];
|
290
|
+
return value;
|
291
|
+
}
|
292
|
+
|
293
|
+
// src/http/telemetry/openTelemetryCollector.ts
|
294
|
+
var import_opentelemetry_instrumentation_hyper_express = require("@forklaunch/opentelemetry-instrumentation-hyper-express");
|
295
|
+
var import_api3 = require("@opentelemetry/api");
|
296
|
+
var import_exporter_logs_otlp_http = require("@opentelemetry/exporter-logs-otlp-http");
|
297
|
+
var import_exporter_metrics_otlp_http = require("@opentelemetry/exporter-metrics-otlp-http");
|
298
|
+
var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
|
299
|
+
var import_instrumentation_express = require("@opentelemetry/instrumentation-express");
|
300
|
+
var import_instrumentation_http = require("@opentelemetry/instrumentation-http");
|
301
|
+
var import_resources = require("@opentelemetry/resources");
|
302
|
+
var import_sdk_logs = require("@opentelemetry/sdk-logs");
|
303
|
+
var import_sdk_metrics = require("@opentelemetry/sdk-metrics");
|
304
|
+
var import_sdk_node = require("@opentelemetry/sdk-node");
|
305
|
+
var import_semantic_conventions2 = require("@opentelemetry/semantic-conventions");
|
306
|
+
var import_dotenv = __toESM(require("dotenv"));
|
307
|
+
|
308
|
+
// src/http/guards/isForklaunchRequest.ts
|
309
|
+
function isForklaunchRequest(request) {
|
310
|
+
return request != null && typeof request === "object" && "contractDetails" in request;
|
311
|
+
}
|
312
|
+
|
313
|
+
// src/http/telemetry/pinoLogger.ts
|
314
|
+
var import_common2 = require("@forklaunch/common");
|
315
|
+
var import_api2 = require("@opentelemetry/api");
|
316
|
+
var import_api_logs = require("@opentelemetry/api-logs");
|
317
|
+
var import_pino = __toESM(require("pino"));
|
318
|
+
|
319
|
+
// src/http/guards/isLoggerMeta.ts
|
320
|
+
function isLoggerMeta(arg) {
|
321
|
+
return typeof arg === "object" && arg !== null && "_meta" in arg;
|
322
|
+
}
|
323
|
+
|
324
|
+
// src/http/telemetry/pinoLogger.ts
|
325
|
+
var import_pino_pretty = __toESM(require("pino-pretty"));
|
326
|
+
function meta(meta2) {
|
327
|
+
return meta2;
|
328
|
+
}
|
329
|
+
function mapSeverity(level) {
|
330
|
+
switch (level) {
|
331
|
+
case "silent":
|
332
|
+
return 0;
|
333
|
+
case "trace":
|
334
|
+
return 1;
|
335
|
+
case "debug":
|
336
|
+
return 5;
|
337
|
+
case "info":
|
338
|
+
return 9;
|
339
|
+
case "warn":
|
340
|
+
return 13;
|
341
|
+
case "error":
|
342
|
+
return 17;
|
343
|
+
case "fatal":
|
344
|
+
return 21;
|
345
|
+
default:
|
346
|
+
(0, import_common2.isNever)(level);
|
347
|
+
return 0;
|
348
|
+
}
|
349
|
+
}
|
350
|
+
var PinoLogger = class _PinoLogger {
|
351
|
+
pinoLogger;
|
352
|
+
meta;
|
353
|
+
prettyPrinter = import_pino_pretty.default.prettyFactory({
|
354
|
+
colorize: true
|
355
|
+
});
|
356
|
+
constructor(level, meta2 = {}) {
|
357
|
+
this.pinoLogger = (0, import_pino.default)({
|
358
|
+
level: level || "info",
|
359
|
+
formatters: {
|
360
|
+
level(label) {
|
361
|
+
return { level: label };
|
362
|
+
}
|
363
|
+
},
|
364
|
+
timestamp: import_pino.default.stdTimeFunctions.isoTime,
|
365
|
+
transport: {
|
366
|
+
target: "pino-pretty",
|
367
|
+
options: { colorize: true }
|
368
|
+
}
|
369
|
+
});
|
370
|
+
this.meta = meta2;
|
371
|
+
}
|
372
|
+
log(level, ...args) {
|
373
|
+
let meta2 = {};
|
374
|
+
const filteredArgs = args.filter((arg) => {
|
375
|
+
if (isLoggerMeta(arg)) {
|
376
|
+
Object.assign(meta2, arg);
|
377
|
+
return false;
|
378
|
+
}
|
379
|
+
return true;
|
380
|
+
});
|
381
|
+
const activeSpan = import_api2.trace.getActiveSpan();
|
382
|
+
if (activeSpan) {
|
383
|
+
const activeSpanContext = activeSpan.spanContext();
|
384
|
+
meta2.trace_id = activeSpanContext.traceId;
|
385
|
+
meta2.span_id = activeSpanContext.spanId;
|
386
|
+
meta2.trace_flags = activeSpanContext.traceFlags;
|
387
|
+
meta2 = {
|
388
|
+
// @ts-expect-error accessing private property
|
389
|
+
...activeSpan.attributes,
|
390
|
+
...meta2
|
391
|
+
};
|
392
|
+
}
|
393
|
+
meta2 = {
|
394
|
+
"api.name": "none",
|
395
|
+
"correlation.id": "none",
|
396
|
+
...meta2
|
397
|
+
};
|
398
|
+
this.pinoLogger[level](...filteredArgs);
|
399
|
+
import_api_logs.logs.getLogger(process.env.OTEL_SERVICE_NAME ?? "unknown").emit({
|
400
|
+
severityText: level,
|
401
|
+
severityNumber: mapSeverity(level),
|
402
|
+
body: this.prettyPrinter(filteredArgs),
|
403
|
+
attributes: { ...this.meta, ...meta2 }
|
404
|
+
});
|
405
|
+
}
|
406
|
+
error = (msg, ...args) => this.log("error", msg, ...args);
|
407
|
+
info = (msg, ...args) => this.log("info", msg, ...args);
|
408
|
+
debug = (msg, ...args) => this.log("debug", msg, ...args);
|
409
|
+
warn = (msg, ...args) => this.log("warn", msg, ...args);
|
410
|
+
trace = (msg, ...args) => this.log("trace", msg, ...args);
|
411
|
+
child(meta2 = {}) {
|
412
|
+
return new _PinoLogger(this.pinoLogger.level, { ...this.meta, ...meta2 });
|
413
|
+
}
|
414
|
+
getBaseLogger() {
|
415
|
+
return this.pinoLogger;
|
416
|
+
}
|
417
|
+
};
|
418
|
+
function logger(level, meta2 = {}) {
|
419
|
+
return new PinoLogger(level, meta2);
|
420
|
+
}
|
421
|
+
|
422
|
+
// src/http/telemetry/openTelemetryCollector.ts
|
423
|
+
var OpenTelemetryCollector = class {
|
424
|
+
// scoped creation and create this in middleware when api execute. Also add correlation id
|
425
|
+
constructor(serviceName, level, metricDefinitions) {
|
426
|
+
this.serviceName = serviceName;
|
427
|
+
this.logger = logger(level || "info");
|
428
|
+
this.metrics = {};
|
429
|
+
for (const [metricId, metricType] of Object.entries(
|
430
|
+
metricDefinitions ?? {}
|
431
|
+
)) {
|
432
|
+
switch (metricType) {
|
433
|
+
case "counter":
|
434
|
+
this.metrics[metricId] = import_api3.metrics.getMeter(this.serviceName).createCounter(metricId);
|
435
|
+
break;
|
436
|
+
case "gauge":
|
437
|
+
this.metrics[metricId] = import_api3.metrics.getMeter(this.serviceName).createGauge(metricId);
|
438
|
+
break;
|
439
|
+
case "histogram":
|
440
|
+
this.metrics[metricId] = import_api3.metrics.getMeter(this.serviceName).createHistogram(metricId);
|
441
|
+
break;
|
442
|
+
case "upDownCounter":
|
443
|
+
this.metrics[metricId] = import_api3.metrics.getMeter(this.serviceName).createUpDownCounter(metricId);
|
444
|
+
break;
|
445
|
+
case "observableCounter":
|
446
|
+
this.metrics[metricId] = import_api3.metrics.getMeter(this.serviceName).createObservableCounter(metricId);
|
447
|
+
break;
|
448
|
+
case "observableGauge":
|
449
|
+
this.metrics[metricId] = import_api3.metrics.getMeter(this.serviceName).createObservableGauge(metricId);
|
450
|
+
break;
|
451
|
+
case "observableUpDownCounter":
|
452
|
+
this.metrics[metricId] = import_api3.metrics.getMeter(this.serviceName).createObservableUpDownCounter(metricId);
|
453
|
+
break;
|
454
|
+
}
|
455
|
+
}
|
456
|
+
this.log("info", "OpenTelemetry (Traces + Logs + Metrics) started");
|
457
|
+
}
|
458
|
+
logger;
|
459
|
+
metrics;
|
460
|
+
log(level, ...args) {
|
461
|
+
this.logger.log(level, ...args);
|
462
|
+
}
|
463
|
+
info = (msg, ...args) => {
|
464
|
+
this.logger.log("info", msg, ...args);
|
465
|
+
};
|
466
|
+
error = (msg, ...args) => {
|
467
|
+
this.logger.log("error", msg, ...args);
|
468
|
+
};
|
469
|
+
warn = (msg, ...args) => {
|
470
|
+
this.logger.log("warn", msg, ...args);
|
471
|
+
};
|
472
|
+
debug = (msg, ...args) => {
|
473
|
+
this.logger.log("debug", msg, ...args);
|
474
|
+
};
|
475
|
+
trace = (msg, ...args) => {
|
476
|
+
this.logger.log("trace", msg, ...args);
|
477
|
+
};
|
478
|
+
getMetric(metricId) {
|
479
|
+
return this.metrics[metricId];
|
480
|
+
}
|
481
|
+
};
|
482
|
+
import_dotenv.default.config({ path: getEnvVar("ENV_FILE_PATH") });
|
483
|
+
new import_sdk_node.NodeSDK({
|
484
|
+
resource: new import_resources.Resource({
|
485
|
+
[import_semantic_conventions2.ATTR_SERVICE_NAME]: getEnvVar("OTEL_SERVICE_NAME")
|
486
|
+
}),
|
487
|
+
traceExporter: new import_exporter_trace_otlp_http.OTLPTraceExporter({
|
488
|
+
url: `${getEnvVar("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/traces`
|
489
|
+
}),
|
490
|
+
metricReader: new import_sdk_metrics.PeriodicExportingMetricReader({
|
491
|
+
exporter: new import_exporter_metrics_otlp_http.OTLPMetricExporter({
|
492
|
+
url: `${getEnvVar("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/metrics`
|
493
|
+
}),
|
494
|
+
exportIntervalMillis: 5e3
|
495
|
+
}),
|
496
|
+
logRecordProcessors: [
|
497
|
+
new import_sdk_logs.BatchLogRecordProcessor(
|
498
|
+
new import_exporter_logs_otlp_http.OTLPLogExporter({
|
499
|
+
url: `${getEnvVar("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/logs`
|
500
|
+
})
|
501
|
+
)
|
502
|
+
],
|
503
|
+
instrumentations: [
|
504
|
+
new import_instrumentation_http.HttpInstrumentation({
|
505
|
+
applyCustomAttributesOnSpan: (span, request) => {
|
506
|
+
span.setAttribute(
|
507
|
+
"service.name",
|
508
|
+
getEnvVar("OTEL_SERVICE_NAME") ?? "unknown"
|
509
|
+
);
|
510
|
+
if (isForklaunchRequest(request)) {
|
511
|
+
span.setAttribute("api.name", request.contractDetails?.name);
|
512
|
+
}
|
513
|
+
}
|
514
|
+
}),
|
515
|
+
new import_instrumentation_express.ExpressInstrumentation(),
|
516
|
+
new import_opentelemetry_instrumentation_hyper_express.HyperExpressInstrumentation()
|
517
|
+
]
|
518
|
+
}).start();
|
519
|
+
var httpRequestsTotalCounter = import_api3.metrics.getMeter(getEnvVar("OTEL_SERVICE_NAME") || "unknown").createCounter("http_requests_total", {
|
520
|
+
description: "Number of HTTP requests"
|
521
|
+
});
|
522
|
+
var httpServerDurationHistogram = import_api3.metrics.getMeter(getEnvVar("OTEL_SERVICE_NAME") || "unknown").createHistogram("http_server_duration", {
|
523
|
+
description: "Duration of HTTP server requests",
|
524
|
+
unit: "s"
|
525
|
+
});
|
526
|
+
|
285
527
|
// src/http/middleware/request/enrichDetails.middleware.ts
|
286
|
-
function enrichDetails(path, contractDetails, requestSchema, responseSchemas) {
|
528
|
+
function enrichDetails(path, contractDetails, requestSchema, responseSchemas, openTelemetryCollector) {
|
287
529
|
return (req, res, next) => {
|
288
530
|
req.originalPath = path;
|
289
531
|
req.contractDetails = contractDetails;
|
290
532
|
req.requestSchema = requestSchema;
|
291
533
|
res.responseSchemas = responseSchemas;
|
534
|
+
req.openTelemetryCollector = openTelemetryCollector;
|
292
535
|
req.context.span?.setAttribute(ATTR_API_NAME, req.contractDetails?.name);
|
536
|
+
const startTime = process.hrtime();
|
537
|
+
res.on("finish", () => {
|
538
|
+
const [seconds, nanoseconds] = process.hrtime(startTime);
|
539
|
+
const durationMs = seconds + nanoseconds / 1e9;
|
540
|
+
httpServerDurationHistogram.record(durationMs, {
|
541
|
+
[import_semantic_conventions.ATTR_SERVICE_NAME]: getEnvVar("OTEL_SERVICE_NAME") || "unknown",
|
542
|
+
[ATTR_API_NAME]: req.contractDetails?.name || "unknown",
|
543
|
+
[import_semantic_conventions.ATTR_HTTP_REQUEST_METHOD]: req.method,
|
544
|
+
[import_semantic_conventions.ATTR_HTTP_ROUTE]: req.originalPath || "unknown",
|
545
|
+
[import_semantic_conventions.ATTR_HTTP_RESPONSE_STATUS_CODE]: res.statusCode
|
546
|
+
});
|
547
|
+
});
|
293
548
|
next?.();
|
294
549
|
};
|
295
550
|
}
|
@@ -329,7 +584,9 @@ function parse(req, _res, next) {
|
|
329
584
|
);
|
330
585
|
break;
|
331
586
|
case "warning":
|
332
|
-
|
587
|
+
req.openTelemetryCollector.warn(
|
588
|
+
(0, import_validator.prettyPrintParseErrors)(parsedRequest.errors, "Request")
|
589
|
+
);
|
333
590
|
break;
|
334
591
|
case "none":
|
335
592
|
break;
|
@@ -340,9 +597,10 @@ function parse(req, _res, next) {
|
|
340
597
|
|
341
598
|
// src/http/router/expressLikeRouter.ts
|
342
599
|
var ForklaunchExpressLikeRouter = class {
|
343
|
-
constructor(basePath, schemaValidator, internal) {
|
600
|
+
constructor(basePath, schemaValidator, internal, openTelemetryCollector) {
|
344
601
|
this.schemaValidator = schemaValidator;
|
345
602
|
this.internal = internal;
|
603
|
+
this.openTelemetryCollector = openTelemetryCollector;
|
346
604
|
this.basePath = basePath;
|
347
605
|
}
|
348
606
|
requestHandler;
|
@@ -361,7 +619,8 @@ var ForklaunchExpressLikeRouter = class {
|
|
361
619
|
`${this.basePath}${path}`,
|
362
620
|
contractDetails,
|
363
621
|
requestSchema,
|
364
|
-
responseSchemas
|
622
|
+
responseSchemas,
|
623
|
+
this.openTelemetryCollector
|
365
624
|
),
|
366
625
|
parse,
|
367
626
|
parseRequestAuth
|
@@ -922,20 +1181,16 @@ var ForklaunchExpressLikeApplication = class extends ForklaunchExpressLikeRouter
|
|
922
1181
|
*
|
923
1182
|
* @param {SV} schemaValidator - The schema validator.
|
924
1183
|
*/
|
925
|
-
constructor(schemaValidator, internal) {
|
926
|
-
super("/", schemaValidator, internal);
|
1184
|
+
constructor(schemaValidator, internal, openTelemetryCollector) {
|
1185
|
+
super("/", schemaValidator, internal, openTelemetryCollector);
|
927
1186
|
this.schemaValidator = schemaValidator;
|
928
1187
|
this.internal = internal;
|
1188
|
+
this.openTelemetryCollector = openTelemetryCollector;
|
929
1189
|
this.internal.use(createContext(this.schemaValidator));
|
930
1190
|
this.internal.use(cors);
|
931
1191
|
}
|
932
1192
|
};
|
933
1193
|
|
934
|
-
// src/http/guards/isForklaunchRequest.ts
|
935
|
-
function isForklaunchRequest(request) {
|
936
|
-
return request != null && typeof request === "object" && "contractDetails" in request;
|
937
|
-
}
|
938
|
-
|
939
1194
|
// src/http/guards/isPath.ts
|
940
1195
|
function isPath(path) {
|
941
1196
|
return path.startsWith("/");
|
@@ -1009,7 +1264,7 @@ var put = (_schemaValidator, path, contractDetails, ...handlers) => {
|
|
1009
1264
|
};
|
1010
1265
|
|
1011
1266
|
// src/http/handlers/trace.ts
|
1012
|
-
var
|
1267
|
+
var trace3 = (_schemaValidator, path, contractDetails, ...handlers) => {
|
1013
1268
|
return typedHandler(_schemaValidator, path, "trace", contractDetails, ...handlers);
|
1014
1269
|
};
|
1015
1270
|
|
@@ -2032,8 +2287,10 @@ function parse2(req, res, next) {
|
|
2032
2287
|
${parseErrors.join("\n\n")}`));
|
2033
2288
|
break;
|
2034
2289
|
case "warning":
|
2035
|
-
|
2036
|
-
|
2290
|
+
req.openTelemetryCollector.warn(
|
2291
|
+
`Invalid response:
|
2292
|
+
${parseErrors.join("\n\n")}`
|
2293
|
+
);
|
2037
2294
|
break;
|
2038
2295
|
case "none":
|
2039
2296
|
break;
|
@@ -2042,96 +2299,6 @@ ${parseErrors.join("\n\n")}`);
|
|
2042
2299
|
next?.();
|
2043
2300
|
}
|
2044
2301
|
|
2045
|
-
// src/http/telemetry/pinoLogger.ts
|
2046
|
-
var import_common2 = require("@forklaunch/common");
|
2047
|
-
var import_api2 = require("@opentelemetry/api");
|
2048
|
-
var import_api_logs = require("@opentelemetry/api-logs");
|
2049
|
-
var import_pino = __toESM(require("pino"));
|
2050
|
-
function mapSeverity(level) {
|
2051
|
-
switch (level) {
|
2052
|
-
case "silent":
|
2053
|
-
return 0;
|
2054
|
-
case "trace":
|
2055
|
-
return 1;
|
2056
|
-
case "debug":
|
2057
|
-
return 5;
|
2058
|
-
case "info":
|
2059
|
-
return 9;
|
2060
|
-
case "warn":
|
2061
|
-
return 13;
|
2062
|
-
case "error":
|
2063
|
-
return 17;
|
2064
|
-
case "fatal":
|
2065
|
-
return 21;
|
2066
|
-
default:
|
2067
|
-
(0, import_common2.isNever)(level);
|
2068
|
-
return 0;
|
2069
|
-
}
|
2070
|
-
}
|
2071
|
-
var PinoLogger = class _PinoLogger {
|
2072
|
-
pinoLogger;
|
2073
|
-
meta;
|
2074
|
-
constructor(level, meta = {}) {
|
2075
|
-
this.pinoLogger = (0, import_pino.default)({
|
2076
|
-
level: level || "info",
|
2077
|
-
formatters: {
|
2078
|
-
level(label) {
|
2079
|
-
return { level: label };
|
2080
|
-
}
|
2081
|
-
},
|
2082
|
-
timestamp: import_pino.default.stdTimeFunctions.isoTime,
|
2083
|
-
transport: {
|
2084
|
-
target: "pino-pretty",
|
2085
|
-
options: { colorize: true }
|
2086
|
-
}
|
2087
|
-
});
|
2088
|
-
this.meta = meta;
|
2089
|
-
}
|
2090
|
-
log(level, msg, meta = {}) {
|
2091
|
-
const activeSpan = import_api2.trace.getActiveSpan();
|
2092
|
-
if (activeSpan) {
|
2093
|
-
const activeSpanContext = activeSpan.spanContext();
|
2094
|
-
meta.trace_id = activeSpanContext.traceId;
|
2095
|
-
meta.span_id = activeSpanContext.spanId;
|
2096
|
-
meta.trace_flags = activeSpanContext.traceFlags;
|
2097
|
-
if (!meta.api_name) {
|
2098
|
-
meta = { ...meta, ...activeSpan?.attributes };
|
2099
|
-
}
|
2100
|
-
}
|
2101
|
-
this.pinoLogger[level](msg);
|
2102
|
-
import_api_logs.logs.getLogger(process.env.OTEL_SERVICE_NAME ?? "unknown").emit({
|
2103
|
-
severityText: level,
|
2104
|
-
severityNumber: mapSeverity(level),
|
2105
|
-
body: msg,
|
2106
|
-
attributes: { ...this.meta, ...meta }
|
2107
|
-
});
|
2108
|
-
}
|
2109
|
-
error(msg, meta = {}) {
|
2110
|
-
this.log("error", msg, meta);
|
2111
|
-
}
|
2112
|
-
info(msg, meta = {}) {
|
2113
|
-
this.log("info", msg, meta);
|
2114
|
-
}
|
2115
|
-
debug(msg, meta = {}) {
|
2116
|
-
this.log("debug", msg, meta);
|
2117
|
-
}
|
2118
|
-
warn(msg, meta = {}) {
|
2119
|
-
this.log("warn", msg, meta);
|
2120
|
-
}
|
2121
|
-
trace(msg, meta = {}) {
|
2122
|
-
this.log("trace", msg, meta);
|
2123
|
-
}
|
2124
|
-
child(meta = {}) {
|
2125
|
-
return new _PinoLogger(this.pinoLogger.level, { ...this.meta, ...meta });
|
2126
|
-
}
|
2127
|
-
getBaseLogger() {
|
2128
|
-
return this.pinoLogger;
|
2129
|
-
}
|
2130
|
-
};
|
2131
|
-
function logger(level, meta = {}) {
|
2132
|
-
return new PinoLogger(level, meta);
|
2133
|
-
}
|
2134
|
-
|
2135
2302
|
// src/http/telemetry/recordMetric.ts
|
2136
2303
|
var import_semantic_conventions3 = require("@opentelemetry/semantic-conventions");
|
2137
2304
|
|
@@ -2139,126 +2306,6 @@ var import_semantic_conventions3 = require("@opentelemetry/semantic-conventions"
|
|
2139
2306
|
var import_common3 = require("@forklaunch/common");
|
2140
2307
|
var import_validator3 = require("@forklaunch/validator");
|
2141
2308
|
|
2142
|
-
// src/services/getEnvVar.ts
|
2143
|
-
function getEnvVar(name) {
|
2144
|
-
const value = process.env[name];
|
2145
|
-
return value;
|
2146
|
-
}
|
2147
|
-
|
2148
|
-
// src/http/telemetry/openTelemetryCollector.ts
|
2149
|
-
var import_opentelemetry_instrumentation_hyper_express = require("@forklaunch/opentelemetry-instrumentation-hyper-express");
|
2150
|
-
var import_api3 = require("@opentelemetry/api");
|
2151
|
-
var import_exporter_logs_otlp_http = require("@opentelemetry/exporter-logs-otlp-http");
|
2152
|
-
var import_exporter_metrics_otlp_http = require("@opentelemetry/exporter-metrics-otlp-http");
|
2153
|
-
var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
|
2154
|
-
var import_instrumentation_express = require("@opentelemetry/instrumentation-express");
|
2155
|
-
var import_instrumentation_http = require("@opentelemetry/instrumentation-http");
|
2156
|
-
var import_resources = require("@opentelemetry/resources");
|
2157
|
-
var import_sdk_logs = require("@opentelemetry/sdk-logs");
|
2158
|
-
var import_sdk_metrics = require("@opentelemetry/sdk-metrics");
|
2159
|
-
var import_sdk_node = require("@opentelemetry/sdk-node");
|
2160
|
-
var import_semantic_conventions2 = require("@opentelemetry/semantic-conventions");
|
2161
|
-
var import_dotenv = __toESM(require("dotenv"));
|
2162
|
-
var OpenTelemetryCollector = class {
|
2163
|
-
// scoped creation and create this in middleware when api execute. Also add correlation id
|
2164
|
-
constructor(serviceName, level, metricDefinitions) {
|
2165
|
-
this.serviceName = serviceName;
|
2166
|
-
this.logger = logger(level ?? "info");
|
2167
|
-
this.metrics = {};
|
2168
|
-
for (const [metricId, metricType] of Object.entries(
|
2169
|
-
metricDefinitions ?? {}
|
2170
|
-
)) {
|
2171
|
-
switch (metricType) {
|
2172
|
-
case "counter":
|
2173
|
-
this.metrics[metricId] = import_api3.metrics.getMeter(this.serviceName).createCounter(metricId);
|
2174
|
-
break;
|
2175
|
-
case "gauge":
|
2176
|
-
this.metrics[metricId] = import_api3.metrics.getMeter(this.serviceName).createGauge(metricId);
|
2177
|
-
break;
|
2178
|
-
case "histogram":
|
2179
|
-
this.metrics[metricId] = import_api3.metrics.getMeter(this.serviceName).createHistogram(metricId);
|
2180
|
-
break;
|
2181
|
-
case "upDownCounter":
|
2182
|
-
this.metrics[metricId] = import_api3.metrics.getMeter(this.serviceName).createUpDownCounter(metricId);
|
2183
|
-
break;
|
2184
|
-
case "observableCounter":
|
2185
|
-
this.metrics[metricId] = import_api3.metrics.getMeter(this.serviceName).createObservableCounter(metricId);
|
2186
|
-
break;
|
2187
|
-
case "observableGauge":
|
2188
|
-
this.metrics[metricId] = import_api3.metrics.getMeter(this.serviceName).createObservableGauge(metricId);
|
2189
|
-
break;
|
2190
|
-
case "observableUpDownCounter":
|
2191
|
-
this.metrics[metricId] = import_api3.metrics.getMeter(this.serviceName).createObservableUpDownCounter(metricId);
|
2192
|
-
break;
|
2193
|
-
}
|
2194
|
-
}
|
2195
|
-
this.log("info", "OpenTelemetry (Traces + Logs + Metrics) started");
|
2196
|
-
}
|
2197
|
-
logger;
|
2198
|
-
metrics;
|
2199
|
-
log(level, msg, meta = {}) {
|
2200
|
-
this.logger.log(level, msg, meta);
|
2201
|
-
}
|
2202
|
-
info(msg, meta = {}) {
|
2203
|
-
this.logger.info(msg, meta);
|
2204
|
-
}
|
2205
|
-
error(msg, meta = {}) {
|
2206
|
-
this.logger.error(msg, meta);
|
2207
|
-
}
|
2208
|
-
warn(msg, meta = {}) {
|
2209
|
-
this.logger.warn(msg, meta);
|
2210
|
-
}
|
2211
|
-
debug(msg, meta = {}) {
|
2212
|
-
this.logger.debug(msg, meta);
|
2213
|
-
}
|
2214
|
-
trace(msg, meta = {}) {
|
2215
|
-
this.logger.trace(msg, meta);
|
2216
|
-
}
|
2217
|
-
getMetric(metricId) {
|
2218
|
-
return this.metrics[metricId];
|
2219
|
-
}
|
2220
|
-
};
|
2221
|
-
import_dotenv.default.config({ path: getEnvVar("ENV_FILE_PATH") });
|
2222
|
-
new import_sdk_node.NodeSDK({
|
2223
|
-
resource: new import_resources.Resource({
|
2224
|
-
[import_semantic_conventions2.ATTR_SERVICE_NAME]: getEnvVar("OTEL_SERVICE_NAME")
|
2225
|
-
}),
|
2226
|
-
traceExporter: new import_exporter_trace_otlp_http.OTLPTraceExporter({
|
2227
|
-
url: `${getEnvVar("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/traces`
|
2228
|
-
}),
|
2229
|
-
metricReader: new import_sdk_metrics.PeriodicExportingMetricReader({
|
2230
|
-
exporter: new import_exporter_metrics_otlp_http.OTLPMetricExporter({
|
2231
|
-
url: `${getEnvVar("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/metrics`
|
2232
|
-
}),
|
2233
|
-
exportIntervalMillis: 5e3
|
2234
|
-
}),
|
2235
|
-
logRecordProcessors: [
|
2236
|
-
new import_sdk_logs.BatchLogRecordProcessor(
|
2237
|
-
new import_exporter_logs_otlp_http.OTLPLogExporter({
|
2238
|
-
url: `${getEnvVar("OTEL_EXPORTER_OTLP_ENDPOINT") ?? "http://localhost:4318"}/v1/logs`
|
2239
|
-
})
|
2240
|
-
)
|
2241
|
-
],
|
2242
|
-
instrumentations: [
|
2243
|
-
new import_instrumentation_http.HttpInstrumentation({
|
2244
|
-
applyCustomAttributesOnSpan: (span, request) => {
|
2245
|
-
span.setAttribute(
|
2246
|
-
"service.name",
|
2247
|
-
getEnvVar("OTEL_SERVICE_NAME") ?? "unknown"
|
2248
|
-
);
|
2249
|
-
if (isForklaunchRequest(request)) {
|
2250
|
-
span.setAttribute("api.name", request.contractDetails?.name);
|
2251
|
-
}
|
2252
|
-
}
|
2253
|
-
}),
|
2254
|
-
new import_instrumentation_express.ExpressInstrumentation(),
|
2255
|
-
new import_opentelemetry_instrumentation_hyper_express.HyperExpressInstrumentation()
|
2256
|
-
]
|
2257
|
-
}).start();
|
2258
|
-
var httpRequestsTotalCounter = import_api3.metrics.getMeter(getEnvVar("OTEL_SERVICE_NAME") || "unknown").createCounter("http_requests_total", {
|
2259
|
-
description: "Number of HTTP requests"
|
2260
|
-
});
|
2261
|
-
|
2262
2309
|
// src/http/telemetry/recordMetric.ts
|
2263
2310
|
function recordMetric(req, res) {
|
2264
2311
|
httpRequestsTotalCounter.add(1, {
|
@@ -2277,6 +2324,7 @@ function enrichExpressLikeSend(instance, req, res, originalSend, data, shouldEnr
|
|
2277
2324
|
if (shouldEnrich) {
|
2278
2325
|
recordMetric(req, res);
|
2279
2326
|
if (res.statusCode === 404) {
|
2327
|
+
res.type("text/plain");
|
2280
2328
|
res.status(404);
|
2281
2329
|
logger("error").error("Not Found");
|
2282
2330
|
originalSend.call(instance, "Not Found");
|
@@ -2290,6 +2338,7 @@ function enrichExpressLikeSend(instance, req, res, originalSend, data, shouldEnr
|
|
2290
2338
|
${res.locals.errorMessage}`;
|
2291
2339
|
}
|
2292
2340
|
logger("error").error(errorString);
|
2341
|
+
res.type("text/plain");
|
2293
2342
|
res.status(500);
|
2294
2343
|
originalSend.call(instance, errorString);
|
2295
2344
|
parseErrorSent = true;
|
@@ -2467,6 +2516,7 @@ function metricsDefinitions(metrics2) {
|
|
2467
2516
|
getCodeForStatus,
|
2468
2517
|
head,
|
2469
2518
|
httpRequestsTotalCounter,
|
2519
|
+
httpServerDurationHistogram,
|
2470
2520
|
isClientError,
|
2471
2521
|
isForklaunchRequest,
|
2472
2522
|
isForklaunchRouter,
|
@@ -2476,6 +2526,7 @@ function metricsDefinitions(metrics2) {
|
|
2476
2526
|
isSuccessful,
|
2477
2527
|
isValidStatusCode,
|
2478
2528
|
logger,
|
2529
|
+
meta,
|
2479
2530
|
metricsDefinitions,
|
2480
2531
|
middleware,
|
2481
2532
|
options,
|