@forklaunch/core 0.5.3 → 0.5.5

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.
@@ -136,7 +136,7 @@ async function checkAuthorizationToken(authorizationMethod, authorizationToken,
136
136
  }
137
137
  resourceId = decodedJwt.payload.sub;
138
138
  } catch (error) {
139
- console.error(error);
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
  }
@@ -234,13 +491,18 @@ import {
234
491
  prettyPrintParseErrors
235
492
  } from "@forklaunch/validator";
236
493
 
494
+ // src/http/guards/hasSend.ts
495
+ function hasSend(res) {
496
+ return typeof res === "object" && res !== null && "send" in res;
497
+ }
498
+
237
499
  // src/http/guards/isResponseShape.ts
238
500
  function isResponseShape(maybeResponseShape) {
239
501
  return maybeResponseShape != null && "body" in maybeResponseShape && "query" in maybeResponseShape && "params" in maybeResponseShape && "headers" in maybeResponseShape;
240
502
  }
241
503
 
242
504
  // src/http/middleware/request/parse.middleware.ts
243
- function parse(req, _res, next) {
505
+ function parse(req, res, next) {
244
506
  const request = {
245
507
  params: req.params,
246
508
  query: req.query,
@@ -261,12 +523,22 @@ function parse(req, _res, next) {
261
523
  switch (req.contractDetails.options?.requestValidation) {
262
524
  default:
263
525
  case "error":
264
- next?.(
265
- new Error(prettyPrintParseErrors(parsedRequest.errors, "Request"))
266
- );
267
- break;
526
+ res.type("application/json");
527
+ res.status(400);
528
+ if (hasSend(res)) {
529
+ res.send(
530
+ `${prettyPrintParseErrors(parsedRequest.errors, "Request")}
531
+
532
+ Correlation id: ${req.context.correlationId ?? "No correlation ID"}`
533
+ );
534
+ } else {
535
+ next?.(new Error("Request is not sendable."));
536
+ }
537
+ return;
268
538
  case "warning":
269
- console.warn(prettyPrintParseErrors(parsedRequest.errors, "Request"));
539
+ req.openTelemetryCollector.warn(
540
+ prettyPrintParseErrors(parsedRequest.errors, "Request")
541
+ );
270
542
  break;
271
543
  case "none":
272
544
  break;
@@ -277,9 +549,10 @@ function parse(req, _res, next) {
277
549
 
278
550
  // src/http/router/expressLikeRouter.ts
279
551
  var ForklaunchExpressLikeRouter = class {
280
- constructor(basePath, schemaValidator, internal) {
552
+ constructor(basePath, schemaValidator, internal, openTelemetryCollector) {
281
553
  this.schemaValidator = schemaValidator;
282
554
  this.internal = internal;
555
+ this.openTelemetryCollector = openTelemetryCollector;
283
556
  this.basePath = basePath;
284
557
  }
285
558
  requestHandler;
@@ -298,7 +571,8 @@ var ForklaunchExpressLikeRouter = class {
298
571
  `${this.basePath}${path}`,
299
572
  contractDetails,
300
573
  requestSchema,
301
- responseSchemas
574
+ responseSchemas,
575
+ this.openTelemetryCollector
302
576
  ),
303
577
  parse,
304
578
  parseRequestAuth
@@ -859,20 +1133,16 @@ var ForklaunchExpressLikeApplication = class extends ForklaunchExpressLikeRouter
859
1133
  *
860
1134
  * @param {SV} schemaValidator - The schema validator.
861
1135
  */
862
- constructor(schemaValidator, internal) {
863
- super("/", schemaValidator, internal);
1136
+ constructor(schemaValidator, internal, openTelemetryCollector) {
1137
+ super("/", schemaValidator, internal, openTelemetryCollector);
864
1138
  this.schemaValidator = schemaValidator;
865
1139
  this.internal = internal;
1140
+ this.openTelemetryCollector = openTelemetryCollector;
866
1141
  this.internal.use(createContext(this.schemaValidator));
867
1142
  this.internal.use(cors);
868
1143
  }
869
1144
  };
870
1145
 
871
- // src/http/guards/isForklaunchRequest.ts
872
- function isForklaunchRequest(request) {
873
- return request != null && typeof request === "object" && "contractDetails" in request;
874
- }
875
-
876
1146
  // src/http/guards/isPath.ts
877
1147
  function isPath(path) {
878
1148
  return path.startsWith("/");
@@ -946,7 +1216,7 @@ var put = (_schemaValidator, path, contractDetails, ...handlers) => {
946
1216
  };
947
1217
 
948
1218
  // src/http/handlers/trace.ts
949
- var trace2 = (_schemaValidator, path, contractDetails, ...handlers) => {
1219
+ var trace3 = (_schemaValidator, path, contractDetails, ...handlers) => {
950
1220
  return typedHandler(_schemaValidator, path, "trace", contractDetails, ...handlers);
951
1221
  };
952
1222
 
@@ -1967,12 +2237,24 @@ function parse2(req, res, next) {
1967
2237
  switch (req.contractDetails.options?.responseValidation) {
1968
2238
  default:
1969
2239
  case "error":
1970
- next?.(new Error(`Invalid response:
1971
- ${parseErrors.join("\n\n")}`));
1972
- break;
2240
+ res.type("text/plain");
2241
+ res.status(400);
2242
+ if (hasSend(res)) {
2243
+ res.send(
2244
+ `Invalid response:
2245
+ ${parseErrors.join("\n\n")}
2246
+
2247
+ Correlation id: ${req.context.correlationId ?? "No correlation ID"}`
2248
+ );
2249
+ } else {
2250
+ next?.(new Error("Response is not sendable."));
2251
+ }
2252
+ return;
1973
2253
  case "warning":
1974
- console.warn(`Invalid response:
1975
- ${parseErrors.join("\n\n")}`);
2254
+ req.openTelemetryCollector.warn(
2255
+ `Invalid response:
2256
+ ${parseErrors.join("\n\n")}`
2257
+ );
1976
2258
  break;
1977
2259
  case "none":
1978
2260
  break;
@@ -1981,96 +2263,6 @@ ${parseErrors.join("\n\n")}`);
1981
2263
  next?.();
1982
2264
  }
1983
2265
 
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
2266
  // src/http/telemetry/recordMetric.ts
2075
2267
  import {
2076
2268
  ATTR_HTTP_REQUEST_METHOD as ATTR_HTTP_REQUEST_METHOD3,
@@ -2085,130 +2277,6 @@ import {
2085
2277
  prettyPrintParseErrors as prettyPrintParseErrors3
2086
2278
  } from "@forklaunch/validator";
2087
2279
 
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
2280
  // src/http/telemetry/recordMetric.ts
2213
2281
  function recordMetric(req, res) {
2214
2282
  httpRequestsTotalCounter.add(1, {
@@ -2227,6 +2295,7 @@ function enrichExpressLikeSend(instance, req, res, originalSend, data, shouldEnr
2227
2295
  if (shouldEnrich) {
2228
2296
  recordMetric(req, res);
2229
2297
  if (res.statusCode === 404) {
2298
+ res.type("text/plain");
2230
2299
  res.status(404);
2231
2300
  logger("error").error("Not Found");
2232
2301
  originalSend.call(instance, "Not Found");
@@ -2240,6 +2309,7 @@ function enrichExpressLikeSend(instance, req, res, originalSend, data, shouldEnr
2240
2309
  ${res.locals.errorMessage}`;
2241
2310
  }
2242
2311
  logger("error").error(errorString);
2312
+ res.type("text/plain");
2243
2313
  res.status(500);
2244
2314
  originalSend.call(instance, errorString);
2245
2315
  parseErrorSent = true;
@@ -2416,6 +2486,7 @@ export {
2416
2486
  getCodeForStatus,
2417
2487
  head,
2418
2488
  httpRequestsTotalCounter,
2489
+ httpServerDurationHistogram,
2419
2490
  isClientError,
2420
2491
  isForklaunchRequest,
2421
2492
  isForklaunchRouter,
@@ -2425,6 +2496,7 @@ export {
2425
2496
  isSuccessful,
2426
2497
  isValidStatusCode,
2427
2498
  logger,
2499
+ meta,
2428
2500
  metricsDefinitions,
2429
2501
  middleware,
2430
2502
  options,
@@ -2432,7 +2504,7 @@ export {
2432
2504
  post,
2433
2505
  put,
2434
2506
  recordMetric,
2435
- trace2 as trace,
2507
+ trace3 as trace,
2436
2508
  typedHandler
2437
2509
  };
2438
2510
  //# sourceMappingURL=index.mjs.map