@promster/metrics 14.0.0 → 15.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2020 suǝʞǝǝpʇ
3
+ Copyright (c) 2025 suǝʞǝǝpʇ
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,2 +1,2 @@
1
- import { Prometheus, defaultRegister, configure } from "./client.js";
1
+ import { Prometheus, configure, defaultRegister } from "./client.js";
2
2
  export { Prometheus, defaultRegister, configure };
@@ -1,4 +1,4 @@
1
- import { type TDefaultedPromsterOptions, type TGcMetrics } from '@promster/types';
1
+ import type { TDefaultedPromsterOptions, TGcMetrics } from '@promster/types';
2
2
  declare const createGcMetrics: {
3
3
  (options: TDefaultedPromsterOptions): TGcMetrics;
4
4
  defaultOptions: {
@@ -1,3 +1,3 @@
1
- import { type TOptionalPromsterOptions, type TGcMetrics } from '@promster/types';
2
- declare const createGcObserver: (metrics: TGcMetrics, options: TOptionalPromsterOptions) => () => void;
1
+ import type { TGcMetrics, TOptionalPromsterOptions } from '@promster/types';
2
+ declare const createGcObserver: (_metrics: TGcMetrics, options: TOptionalPromsterOptions) => () => void;
3
3
  export { createGcObserver };
@@ -1,4 +1,4 @@
1
- import { type TDefaultedPromsterOptions, type TGraphQlMetrics } from '@promster/types';
1
+ import type { TDefaultedPromsterOptions, TGraphQlMetrics } from '@promster/types';
2
2
  declare const createGraphQlMetrics: {
3
3
  (options: TDefaultedPromsterOptions): TGraphQlMetrics;
4
4
  defaultOptions: {
@@ -1,4 +1,4 @@
1
- import { type TDefaultedPromsterOptions, type THttpMetrics } from '@promster/types';
1
+ import type { TDefaultedPromsterOptions, THttpMetrics } from '@promster/types';
2
2
  declare const createHttpMetrics: {
3
3
  (options: TDefaultedPromsterOptions): THttpMetrics;
4
4
  defaultOptions: {
@@ -1,7 +1,7 @@
1
- import { type TOptionalPromsterOptions, type TLabelValues, type THttpMetrics } from '@promster/types';
2
- import { type Timing } from "../timing/index.js";
3
- import { sortLabels } from "../sort-labels/index.js";
1
+ import type { THttpMetrics, TLabelValues, TOptionalPromsterOptions } from '@promster/types';
2
+ import type { Timing } from "../timing/index.js";
4
3
  import { endMeasurementFrom } from "../end-measurement-from/index.js";
4
+ import { sortLabels } from "../sort-labels/index.js";
5
5
  type TRecordingOptions = {
6
6
  labels: TLabelValues;
7
7
  requestContentLength?: number;
@@ -1,4 +1,4 @@
1
- import { type TOptionalPromsterOptions } from '@promster/types';
1
+ import type { TOptionalPromsterOptions } from '@promster/types';
2
2
  type TSkipMetricsInEnvironmentOptions = {
3
3
  detectKubernetes?: TOptionalPromsterOptions['detectKubernetes'];
4
4
  };
@@ -1,14 +1,14 @@
1
1
  import { Prometheus, defaultRegister } from "./client/index.js";
2
- import { createHttpMetrics } from "./create-http-metrics/index.js";
3
- import { createGraphQlMetrics } from "./create-graphql-metrics/index.js";
4
2
  import { createGcMetrics } from "./create-gc-metrics/index.js";
5
- import { getSummary, getContentType } from "./summary/index.js";
6
- import { createRequestRecorder } from "./create-request-recorder/index.js";
7
3
  import { createGcObserver } from "./create-gc-observer/index.js";
8
- import { defaultNormalizers, normalizeStatusCode, normalizePath, normalizeMethod } from "./normalizers/index.js";
9
- import { isRunningInKubernetes, skipMetricsInEnvironment } from "./environment/index.js";
4
+ import { createGraphQlMetrics } from "./create-graphql-metrics/index.js";
5
+ import { createHttpMetrics } from "./create-http-metrics/index.js";
6
+ import { createRequestRecorder } from "./create-request-recorder/index.js";
10
7
  import { endMeasurementFrom } from "./end-measurement-from/index.js";
8
+ import { isRunningInKubernetes, skipMetricsInEnvironment } from "./environment/index.js";
9
+ import { defaultNormalizers, normalizeMethod, normalizePath, normalizeStatusCode } from "./normalizers/index.js";
11
10
  import { sortLabels } from "./sort-labels/index.js";
11
+ import { getContentType, getSummary } from "./summary/index.js";
12
12
  import { timing } from "./timing/index.js";
13
13
  export type { TRequestRecorder } from "./create-request-recorder/index.js";
14
14
  export type { Timing as TPromsterTiming } from "./timing/index.js";
@@ -1,6 +1,6 @@
1
- import { normalizeStatusCode } from "./status-code/index.js";
2
- import { normalizePath } from "./path/index.js";
3
1
  import { normalizeMethod } from "./method/index.js";
2
+ import { normalizePath } from "./path/index.js";
3
+ import { normalizeStatusCode } from "./status-code/index.js";
4
4
  declare const defaultNormalizers: {
5
5
  normalizeStatusCode: (statusCode: number) => number;
6
6
  normalizePath: (path: string) => string;
@@ -1,3 +1,3 @@
1
- import { type TLabelValues } from '@promster/types';
1
+ import type { TLabelValues } from '@promster/types';
2
2
  declare function sortLabels(unsortedLabels: TLabelValues): TLabelValues;
3
3
  export { sortLabels };
@@ -1,2 +1,2 @@
1
- import { getSummary, getContentType } from "./summary.js";
1
+ import { getContentType, getSummary } from "./summary.js";
2
2
  export { getSummary, getContentType };
@@ -1,2 +1,2 @@
1
- export * from "./declarations/src/index";
1
+ export * from "./declarations/src/index.js";
2
2
  //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvbXN0ZXItbWV0cmljcy5janMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4vZGVjbGFyYXRpb25zL3NyYy9pbmRleC5kLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBIn0=
@@ -6,7 +6,7 @@ var once = require('lodash.once');
6
6
  var Prometheus = require('prom-client');
7
7
  var merge = require('merge-options');
8
8
  var gcStats = require('prometheus-gc-stats');
9
- var url = require('url');
9
+ var url = require('node:url');
10
10
  var UrlValueParser = require('url-value-parser');
11
11
  var types = require('@promster/types');
12
12
 
@@ -45,9 +45,6 @@ const skipMetricsInEnvironment = options => options.detectKubernetes === true &&
45
45
  // This is the `globalRegistry` provided by the `prom-client`
46
46
  // We could create multiple registries with `new Prometheus.registry()`.
47
47
  const defaultRegister = Prometheus__namespace.register;
48
-
49
- // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
50
-
51
48
  const configure = once__default["default"](options => {
52
49
  const shouldSkipMetricsInEnvironment = skipMetricsInEnvironment(options);
53
50
  if (!shouldSkipMetricsInEnvironment) {
@@ -55,104 +52,53 @@ const configure = once__default["default"](options => {
55
52
  }
56
53
  });
57
54
 
58
- const defaultHttpRequestDurationPercentileInSeconds = [0.5, 0.9, 0.95, 0.98, 0.99];
59
- const defaultHttpRequestDurationInSeconds = [0.05, 0.1, 0.3, 0.5, 0.8, 1, 1.5, 2, 3, 10];
60
- const defaultHttpContentLengthInBytes = [100000, 200000, 500000, 1000000, 1500000, 2000000, 3000000, 5000000, 10000000];
61
- const defaultLabels$1 = ['path', 'status_code', 'method'];
62
55
  const asArray$2 = maybeArray => Array.isArray(maybeArray) ? maybeArray : [maybeArray];
63
- const shouldObserveHttpRequestsAsSummary = options => options.metricTypes.includes('httpRequestsSummary');
64
- const shouldObserveHttpRequestsAsHistogram = options => options.metricTypes.includes('httpRequestsHistogram');
65
- const shouldObserveHttpRequestsAsCounter = options => options.metricTypes.includes('httpRequestsTotal');
66
- const shouldObserveHttpContentLengthAsHistogram = options => options.metricTypes.includes('httpContentLengthHistogram');
67
56
  const defaultOptions$4 = {
68
57
  getLabelValues: () => ({}),
69
58
  labels: [],
70
59
  metricPrefix: '',
71
- metricTypes: ['httpRequestsTotal', 'httpRequestsHistogram'],
72
60
  metricNames: {
73
- httpRequestsTotal: ['http_requests_total'],
74
- httpRequestDurationPerPercentileInSeconds: ['http_request_duration_per_percentile_seconds'],
75
- httpRequestDurationInSeconds: ['http_request_duration_seconds'],
76
- httpRequestContentLengthInBytes: ['http_request_content_length_bytes'],
77
- httpResponseContentLengthInBytes: ['http_response_content_length_bytes']
78
- },
79
- metricBuckets: {
80
- httpRequestContentLengthInBytes: defaultHttpContentLengthInBytes,
81
- httpRequestDurationInSeconds: defaultHttpRequestDurationInSeconds
82
- },
83
- metricPercentiles: {
84
- httpRequestDurationPerPercentileInSeconds: defaultHttpRequestDurationPercentileInSeconds,
85
- httpResponseContentLengthInBytes: defaultHttpContentLengthInBytes
61
+ up: ['nodejs_up']
86
62
  }
87
63
  };
88
64
  const getMetrics$2 = options => ({
89
- httpRequestContentLengthInBytes: shouldObserveHttpContentLengthAsHistogram(options) ? asArray$2(options.metricNames.httpRequestContentLengthInBytes).map(nameOfHttpContentLengthMetric => {
90
- var _options$metricBucket;
91
- return new Prometheus__namespace.Histogram({
92
- name: `${options.metricPrefix}${nameOfHttpContentLengthMetric}`,
93
- help: 'The HTTP request content length in bytes.',
94
- labelNames: defaultLabels$1.concat(options.labels).sort(),
95
- buckets: ((_options$metricBucket = options.metricBuckets) === null || _options$metricBucket === void 0 ? void 0 : _options$metricBucket.httpRequestContentLengthInBytes) || defaultHttpContentLengthInBytes
96
- });
97
- }) : undefined,
98
- httpResponseContentLengthInBytes: shouldObserveHttpContentLengthAsHistogram(options) ? asArray$2(options.metricNames.httpResponseContentLengthInBytes).map(nameOfHttpContentLengthMetric => {
99
- var _options$metricBucket2;
100
- return new Prometheus__namespace.Histogram({
101
- name: `${options.metricPrefix}${nameOfHttpContentLengthMetric}`,
102
- help: 'The HTTP response content length in bytes.',
103
- labelNames: defaultLabels$1.concat(options.labels).sort(),
104
- buckets: ((_options$metricBucket2 = options.metricBuckets) === null || _options$metricBucket2 === void 0 ? void 0 : _options$metricBucket2.httpResponseContentLengthInBytes) || defaultHttpContentLengthInBytes
105
- });
106
- }) : undefined
107
- });
108
- const getHttpRequestLatencyMetricsInSeconds = options => ({
109
- httpRequestDurationPerPercentileInSeconds: shouldObserveHttpRequestsAsSummary(options) ? asArray$2(options.metricNames.httpRequestDurationPerPercentileInSeconds).map(nameOfHttpRequestDurationPerPercentileInSeconds => {
110
- var _options$metricPercen;
111
- return new Prometheus__namespace.Summary({
112
- name: `${options.metricPrefix}${nameOfHttpRequestDurationPerPercentileInSeconds}`,
113
- help: 'The HTTP request latencies in seconds.',
114
- labelNames: defaultLabels$1.concat(options.labels).sort(),
115
- percentiles: ((_options$metricPercen = options.metricPercentiles) === null || _options$metricPercen === void 0 ? void 0 : _options$metricPercen.httpRequestDurationPerPercentileInSeconds) || defaultHttpRequestDurationPercentileInSeconds
116
- });
117
- }) : undefined,
118
- httpRequestDurationInSeconds: shouldObserveHttpRequestsAsHistogram(options) ? asArray$2(options.metricNames.httpRequestDurationInSeconds).map(nameOfHttpRequestDurationInSecondsMetric => {
119
- var _options$metricBucket3;
120
- return new Prometheus__namespace.Histogram({
121
- name: `${options.metricPrefix}${nameOfHttpRequestDurationInSecondsMetric}`,
122
- help: 'The HTTP request latencies in seconds.',
123
- labelNames: defaultLabels$1.concat(options.labels).sort(),
124
- buckets: ((_options$metricBucket3 = options.metricBuckets) === null || _options$metricBucket3 === void 0 ? void 0 : _options$metricBucket3.httpRequestDurationInSeconds) || defaultHttpRequestDurationInSeconds
125
- });
126
- }) : undefined
127
- });
128
- const getHttpRequestCounterMetric = options => ({
129
- httpRequestsTotal: shouldObserveHttpRequestsAsCounter(options) ? asArray$2(options.metricNames.httpRequestsTotal).map(nameOfHttpRequestsTotalMetric => new Prometheus__namespace.Counter({
130
- name: `${options.metricPrefix}${nameOfHttpRequestsTotalMetric}`,
131
- help: 'The total HTTP requests.',
132
- labelNames: defaultLabels$1.concat(options.labels).sort()
133
- })) : undefined
65
+ up: asArray$2(options.metricNames.up).map(nameOfUpMetric => new Prometheus__namespace.Gauge({
66
+ name: `${options.metricPrefix}${nameOfUpMetric}`,
67
+ help: '1 = nodejs server is up, 0 = nodejs server is not up'
68
+ }))
134
69
  });
135
- const createHttpMetrics = options => {
70
+ const createGcMetrics = options => {
136
71
  const defaultedOptions = merge__default["default"](defaultOptions$4, options);
137
72
  configure({
138
73
  prefix: defaultedOptions.metricPrefix
139
74
  });
140
- const metrics = getMetrics$2(defaultedOptions);
141
- const httpRequestLatencyMetricsInSeconds = getHttpRequestLatencyMetricsInSeconds(defaultedOptions);
142
- const httpRequestCounterMetric = getHttpRequestCounterMetric(defaultedOptions);
143
- return Object.assign({}, metrics, httpRequestLatencyMetricsInSeconds, httpRequestCounterMetric);
75
+ const gcMetrics = getMetrics$2(defaultedOptions);
76
+ return gcMetrics;
144
77
  };
145
- createHttpMetrics.defaultOptions = defaultOptions$4;
78
+ createGcMetrics.defaultOptions = defaultOptions$4;
79
+
80
+ const defaultOptions$3 = {
81
+ disableGcMetrics: false
82
+ };
83
+ const createGcObserver = once__default["default"]((_metrics, options) => () => {
84
+ const startGcStats = gcStats__default["default"](defaultRegister, {
85
+ prefix: options.metricPrefix
86
+ });
87
+ startGcStats();
88
+ });
89
+
90
+ // @ts-expect-error
91
+ createGcObserver.defaultOptions = defaultOptions$3;
146
92
 
147
93
  const defaultGraphQlPercentiles = [0.5, 0.9, 0.95, 0.98, 0.99];
148
- const defaultLabels = ['operation_name'];
94
+ const defaultLabels$1 = ['operation_name'];
149
95
  const asArray$1 = maybeArray => Array.isArray(maybeArray) ? maybeArray : [maybeArray];
150
96
  const shouldObserveGraphQlParseDurationAsHistogram = options => options.metricTypes.includes('graphQlParseDurationHistogram');
151
97
  const shouldObserveGraphQlValidationDurationAsHistogram = options => options.metricTypes.includes('graphQlValidationDurationHistogram');
152
98
  const shouldObserveGraphQlResolveFieldDurationAsHistogram = options => options.metricTypes.includes('graphQlResolveFieldDurationHistogram');
153
99
  const shouldObserveGraphQlRequestDurationAsHistogram = options => options.metricTypes.includes('graphQlRequestDurationHistogram');
154
100
  const shouldObserveGraphQlErrorsTotalAsCounter = options => options.metricTypes.includes('graphQlErrorsTotal');
155
- const defaultOptions$3 = {
101
+ const defaultOptions$2 = {
156
102
  getLabelValues: () => ({}),
157
103
  labels: [],
158
104
  metricPrefix: '',
@@ -178,7 +124,7 @@ const getMetrics$1 = options => ({
178
124
  return new Prometheus__namespace.Histogram({
179
125
  name: `${options.metricPrefix}${nameOfGraphQlParseDuration}`,
180
126
  help: 'The GraphQL request parse time in seconds.',
181
- labelNames: defaultLabels.concat(options.labels).sort(),
127
+ labelNames: defaultLabels$1.concat(options.labels).sort(),
182
128
  buckets: ((_options$metricPercen = options.metricPercentiles) === null || _options$metricPercen === void 0 ? void 0 : _options$metricPercen.graphQlParseDuration) || defaultGraphQlPercentiles
183
129
  });
184
130
  }) : undefined,
@@ -187,7 +133,7 @@ const getMetrics$1 = options => ({
187
133
  return new Prometheus__namespace.Histogram({
188
134
  name: `${options.metricPrefix}${nameOfGraphQlValidationDuration}`,
189
135
  help: 'The GraphQL request validation time in seconds.',
190
- labelNames: defaultLabels.concat(options.labels).sort(),
136
+ labelNames: defaultLabels$1.concat(options.labels).sort(),
191
137
  buckets: ((_options$metricPercen2 = options.metricPercentiles) === null || _options$metricPercen2 === void 0 ? void 0 : _options$metricPercen2.graphQlValidationDuration) || defaultGraphQlPercentiles
192
138
  });
193
139
  }) : undefined,
@@ -196,7 +142,7 @@ const getMetrics$1 = options => ({
196
142
  return new Prometheus__namespace.Histogram({
197
143
  name: `${options.metricPrefix}${nameOfGraphQlResolveFieldDuration}`,
198
144
  help: 'The GraphQL field resolving time in seconds.',
199
- labelNames: defaultLabels.concat(['field_name']).concat(options.labels).sort(),
145
+ labelNames: defaultLabels$1.concat(['field_name']).concat(options.labels).sort(),
200
146
  buckets: ((_options$metricPercen3 = options.metricPercentiles) === null || _options$metricPercen3 === void 0 ? void 0 : _options$metricPercen3.graphQlResolveFieldDuration) || defaultGraphQlPercentiles
201
147
  });
202
148
  }) : undefined,
@@ -205,53 +151,122 @@ const getMetrics$1 = options => ({
205
151
  return new Prometheus__namespace.Histogram({
206
152
  name: `${options.metricPrefix}${nameOfGraphQlRequestDuration}`,
207
153
  help: 'The GraphQL request duration time in seconds.',
208
- labelNames: defaultLabels.concat(options.labels).sort(),
154
+ labelNames: defaultLabels$1.concat(options.labels).sort(),
209
155
  buckets: ((_options$metricPercen4 = options.metricPercentiles) === null || _options$metricPercen4 === void 0 ? void 0 : _options$metricPercen4.graphQlRequestDuration) || defaultGraphQlPercentiles
210
156
  });
211
157
  }) : undefined,
212
158
  graphQlErrorsTotal: shouldObserveGraphQlErrorsTotalAsCounter(options) ? asArray$1(options.metricNames.graphQlErrorsTotal).map(nameOfGraphQlErrorsCount => new Prometheus__namespace.Counter({
213
159
  name: `${options.metricPrefix}${nameOfGraphQlErrorsCount}`,
214
160
  help: 'Count of errors while parsing, validating, or executing a GraphQL operation.',
215
- labelNames: defaultLabels.concat(['phase']).concat(options.labels).sort()
161
+ labelNames: defaultLabels$1.concat(['phase']).concat(options.labels).sort()
216
162
  })) : undefined
217
163
  });
218
164
  const createGraphQlMetrics = options => {
219
- const defaultedOptions = merge__default["default"](defaultOptions$3, options);
165
+ const defaultedOptions = merge__default["default"](defaultOptions$2, options);
220
166
  configure({
221
167
  prefix: defaultedOptions.metricPrefix
222
168
  });
223
169
  const metrics = getMetrics$1(defaultedOptions);
224
170
  return metrics;
225
171
  };
226
- createGraphQlMetrics.defaultOptions = defaultOptions$3;
172
+ createGraphQlMetrics.defaultOptions = defaultOptions$2;
227
173
 
174
+ const defaultHttpRequestDurationPercentileInSeconds = [0.5, 0.9, 0.95, 0.98, 0.99];
175
+ const defaultHttpRequestDurationInSeconds = [0.05, 0.1, 0.3, 0.5, 0.8, 1, 1.5, 2, 3, 10];
176
+ const defaultHttpContentLengthInBytes = [100000, 200000, 500000, 1000000, 1500000, 2000000, 3000000, 5000000, 10000000];
177
+ const defaultLabels = ['path', 'status_code', 'method'];
228
178
  const asArray = maybeArray => Array.isArray(maybeArray) ? maybeArray : [maybeArray];
229
- const defaultOptions$2 = {
179
+ const shouldObserveHttpRequestsAsSummary = options => options.metricTypes.includes('httpRequestsSummary');
180
+ const shouldObserveHttpRequestsAsHistogram = options => options.metricTypes.includes('httpRequestsHistogram');
181
+ const shouldObserveHttpRequestsAsCounter = options => options.metricTypes.includes('httpRequestsTotal');
182
+ const shouldObserveHttpContentLengthAsHistogram = options => options.metricTypes.includes('httpContentLengthHistogram');
183
+ const defaultOptions$1 = {
230
184
  getLabelValues: () => ({}),
231
185
  labels: [],
232
186
  metricPrefix: '',
187
+ metricTypes: ['httpRequestsTotal', 'httpRequestsHistogram'],
233
188
  metricNames: {
234
- up: ['nodejs_up']
189
+ httpRequestsTotal: ['http_requests_total'],
190
+ httpRequestDurationPerPercentileInSeconds: ['http_request_duration_per_percentile_seconds'],
191
+ httpRequestDurationInSeconds: ['http_request_duration_seconds'],
192
+ httpRequestContentLengthInBytes: ['http_request_content_length_bytes'],
193
+ httpResponseContentLengthInBytes: ['http_response_content_length_bytes']
194
+ },
195
+ metricBuckets: {
196
+ httpRequestContentLengthInBytes: defaultHttpContentLengthInBytes,
197
+ httpRequestDurationInSeconds: defaultHttpRequestDurationInSeconds
198
+ },
199
+ metricPercentiles: {
200
+ httpRequestDurationPerPercentileInSeconds: defaultHttpRequestDurationPercentileInSeconds,
201
+ httpResponseContentLengthInBytes: defaultHttpContentLengthInBytes
235
202
  }
236
203
  };
237
204
  const getMetrics = options => ({
238
- up: asArray(options.metricNames.up).map(nameOfUpMetric => new Prometheus__namespace.Gauge({
239
- name: `${options.metricPrefix}${nameOfUpMetric}`,
240
- help: '1 = nodejs server is up, 0 = nodejs server is not up'
241
- }))
205
+ httpRequestContentLengthInBytes: shouldObserveHttpContentLengthAsHistogram(options) ? asArray(options.metricNames.httpRequestContentLengthInBytes).map(nameOfHttpContentLengthMetric => {
206
+ var _options$metricBucket;
207
+ return new Prometheus__namespace.Histogram({
208
+ name: `${options.metricPrefix}${nameOfHttpContentLengthMetric}`,
209
+ help: 'The HTTP request content length in bytes.',
210
+ labelNames: defaultLabels.concat(options.labels).sort(),
211
+ buckets: ((_options$metricBucket = options.metricBuckets) === null || _options$metricBucket === void 0 ? void 0 : _options$metricBucket.httpRequestContentLengthInBytes) || defaultHttpContentLengthInBytes
212
+ });
213
+ }) : undefined,
214
+ httpResponseContentLengthInBytes: shouldObserveHttpContentLengthAsHistogram(options) ? asArray(options.metricNames.httpResponseContentLengthInBytes).map(nameOfHttpContentLengthMetric => {
215
+ var _options$metricBucket2;
216
+ return new Prometheus__namespace.Histogram({
217
+ name: `${options.metricPrefix}${nameOfHttpContentLengthMetric}`,
218
+ help: 'The HTTP response content length in bytes.',
219
+ labelNames: defaultLabels.concat(options.labels).sort(),
220
+ buckets: ((_options$metricBucket2 = options.metricBuckets) === null || _options$metricBucket2 === void 0 ? void 0 : _options$metricBucket2.httpResponseContentLengthInBytes) || defaultHttpContentLengthInBytes
221
+ });
222
+ }) : undefined
242
223
  });
243
- const createGcMetrics = options => {
244
- const defaultedOptions = merge__default["default"](defaultOptions$2, options);
224
+ const getHttpRequestLatencyMetricsInSeconds = options => ({
225
+ httpRequestDurationPerPercentileInSeconds: shouldObserveHttpRequestsAsSummary(options) ? asArray(options.metricNames.httpRequestDurationPerPercentileInSeconds).map(nameOfHttpRequestDurationPerPercentileInSeconds => {
226
+ var _options$metricPercen;
227
+ return new Prometheus__namespace.Summary({
228
+ name: `${options.metricPrefix}${nameOfHttpRequestDurationPerPercentileInSeconds}`,
229
+ help: 'The HTTP request latencies in seconds.',
230
+ labelNames: defaultLabels.concat(options.labels).sort(),
231
+ percentiles: ((_options$metricPercen = options.metricPercentiles) === null || _options$metricPercen === void 0 ? void 0 : _options$metricPercen.httpRequestDurationPerPercentileInSeconds) || defaultHttpRequestDurationPercentileInSeconds
232
+ });
233
+ }) : undefined,
234
+ httpRequestDurationInSeconds: shouldObserveHttpRequestsAsHistogram(options) ? asArray(options.metricNames.httpRequestDurationInSeconds).map(nameOfHttpRequestDurationInSecondsMetric => {
235
+ var _options$metricBucket3;
236
+ return new Prometheus__namespace.Histogram({
237
+ name: `${options.metricPrefix}${nameOfHttpRequestDurationInSecondsMetric}`,
238
+ help: 'The HTTP request latencies in seconds.',
239
+ labelNames: defaultLabels.concat(options.labels).sort(),
240
+ buckets: ((_options$metricBucket3 = options.metricBuckets) === null || _options$metricBucket3 === void 0 ? void 0 : _options$metricBucket3.httpRequestDurationInSeconds) || defaultHttpRequestDurationInSeconds
241
+ });
242
+ }) : undefined
243
+ });
244
+ const getHttpRequestCounterMetric = options => ({
245
+ httpRequestsTotal: shouldObserveHttpRequestsAsCounter(options) ? asArray(options.metricNames.httpRequestsTotal).map(nameOfHttpRequestsTotalMetric => new Prometheus__namespace.Counter({
246
+ name: `${options.metricPrefix}${nameOfHttpRequestsTotalMetric}`,
247
+ help: 'The total HTTP requests.',
248
+ labelNames: defaultLabels.concat(options.labels).sort()
249
+ })) : undefined
250
+ });
251
+ const createHttpMetrics = options => {
252
+ const defaultedOptions = merge__default["default"](defaultOptions$1, options);
245
253
  configure({
246
254
  prefix: defaultedOptions.metricPrefix
247
255
  });
248
- const gcMetrics = getMetrics(defaultedOptions);
249
- return gcMetrics;
256
+ const metrics = getMetrics(defaultedOptions);
257
+ const httpRequestLatencyMetricsInSeconds = getHttpRequestLatencyMetricsInSeconds(defaultedOptions);
258
+ const httpRequestCounterMetric = getHttpRequestCounterMetric(defaultedOptions);
259
+ return Object.assign({}, metrics, httpRequestLatencyMetricsInSeconds, httpRequestCounterMetric);
250
260
  };
251
- createGcMetrics.defaultOptions = defaultOptions$2;
261
+ createHttpMetrics.defaultOptions = defaultOptions$1;
252
262
 
253
- const getSummary = async () => defaultRegister.metrics();
254
- const getContentType = () => defaultRegister.contentType;
263
+ const NS_PER_SEC = 1e9;
264
+ function endMeasurementFrom(start) {
265
+ const [seconds, nanoseconds] = process.hrtime(start);
266
+ return {
267
+ durationS: (seconds * NS_PER_SEC + nanoseconds) / NS_PER_SEC
268
+ };
269
+ }
255
270
 
256
271
  function sortLabels(unsortedLabels) {
257
272
  return Object.keys(unsortedLabels).sort((a, b) => {
@@ -268,87 +283,73 @@ function sortLabels(unsortedLabels) {
268
283
  }, {});
269
284
  }
270
285
 
271
- const NS_PER_SEC = 1e9;
272
- function endMeasurementFrom(start) {
273
- const [seconds, nanoseconds] = process.hrtime(start);
274
- return {
275
- durationS: (seconds * NS_PER_SEC + nanoseconds) / NS_PER_SEC
276
- };
277
- }
278
-
279
- const defaultOptions$1 = {
286
+ const defaultOptions = {
280
287
  detectKubernetes: false
281
288
  };
282
289
  function isTiming(timing) {
283
290
  return !Array.isArray(timing);
284
291
  }
285
- const createRequestRecorder = (metrics, options = defaultOptions$1) => {
286
- const defaultedRecorderOptions = merge__default["default"](defaultOptions$1, options);
292
+ const createRequestRecorder = (metrics, options = defaultOptions) => {
293
+ const defaultedRecorderOptions = merge__default["default"](defaultOptions, options);
287
294
  const shouldSkipMetricsByEnvironment = skipMetricsInEnvironment(defaultedRecorderOptions);
288
295
  return (timing, recordingOptions) => {
289
296
  const durationS = isTiming(timing) ? timing.end().value().seconds : endMeasurementFrom(timing).durationS;
290
297
  const labels = sortLabels(recordingOptions.labels);
291
298
  if (!shouldSkipMetricsByEnvironment && durationS !== undefined) {
292
- var _metrics$httpRequestD;
293
- (_metrics$httpRequestD = metrics.httpRequestDurationInSeconds) === null || _metrics$httpRequestD === void 0 || _metrics$httpRequestD.forEach(httpRequestDurationInSecondsMetricType => {
294
- httpRequestDurationInSecondsMetricType.observe(labels, durationS);
295
- });
299
+ if (metrics.httpRequestDurationInSeconds) {
300
+ for (const httpRequestDurationInSecondsMetricType of metrics.httpRequestDurationInSeconds) {
301
+ httpRequestDurationInSecondsMetricType.observe(labels, durationS);
302
+ }
303
+ }
296
304
  }
297
305
  if (!shouldSkipMetricsByEnvironment && durationS !== undefined) {
298
- var _metrics$httpRequestD2;
299
- (_metrics$httpRequestD2 = metrics.httpRequestDurationPerPercentileInSeconds) === null || _metrics$httpRequestD2 === void 0 || _metrics$httpRequestD2.forEach(httpRequestDurationPerPercentileInSecondsMetricType => {
300
- httpRequestDurationPerPercentileInSecondsMetricType.observe(labels, durationS);
301
- });
306
+ if (metrics.httpRequestDurationPerPercentileInSeconds) {
307
+ for (const httpRequestDurationPerPercentileInSecondsMetricType of metrics.httpRequestDurationPerPercentileInSeconds) {
308
+ httpRequestDurationPerPercentileInSecondsMetricType.observe(labels, durationS);
309
+ }
310
+ }
302
311
  }
303
312
  if (!shouldSkipMetricsByEnvironment && durationS !== undefined) {
304
- var _metrics$httpRequests;
305
- (_metrics$httpRequests = metrics.httpRequestsTotal) === null || _metrics$httpRequests === void 0 || _metrics$httpRequests.forEach(httpRequestsTotalMetricType => {
306
- httpRequestsTotalMetricType.inc(labels);
307
- });
313
+ if (metrics.httpRequestsTotal) {
314
+ for (const httpRequestsTotalMetricType of metrics.httpRequestsTotal) {
315
+ httpRequestsTotalMetricType.inc(labels);
316
+ }
317
+ }
308
318
  }
309
319
  if (recordingOptions.requestContentLength) {
310
- var _metrics$httpRequestC;
311
- (_metrics$httpRequestC = metrics.httpRequestContentLengthInBytes) === null || _metrics$httpRequestC === void 0 || _metrics$httpRequestC.forEach(httpRequestContentLengthInBytesMetricType => {
312
- httpRequestContentLengthInBytesMetricType.observe(labels,
313
- // @ts-expect-error
314
- recordingOptions.requestContentLength);
315
- });
320
+ if (metrics.httpRequestContentLengthInBytes) {
321
+ for (const httpRequestContentLengthInBytesMetricType of metrics.httpRequestContentLengthInBytes) {
322
+ httpRequestContentLengthInBytesMetricType.observe(labels,
323
+ // @ts-expect-error
324
+ recordingOptions.requestContentLength);
325
+ }
326
+ }
316
327
  }
317
328
  if (recordingOptions.responseContentLength) {
318
- var _metrics$httpResponse;
319
- (_metrics$httpResponse = metrics.httpResponseContentLengthInBytes) === null || _metrics$httpResponse === void 0 || _metrics$httpResponse.forEach(httpResponseContentLengthInBytesMetricType => {
320
- httpResponseContentLengthInBytesMetricType.observe(labels,
321
- // @ts-expect-error
322
- recordingOptions.responseContentLength);
323
- });
329
+ if (metrics.httpResponseContentLengthInBytes) {
330
+ for (const httpResponseContentLengthInBytesMetricType of metrics.httpResponseContentLengthInBytes) {
331
+ httpResponseContentLengthInBytesMetricType.observe(labels,
332
+ // @ts-expect-error
333
+ recordingOptions.responseContentLength);
334
+ }
335
+ }
324
336
  }
325
337
  };
326
338
  };
327
- createRequestRecorder.defaultOptions = defaultOptions$1;
328
-
329
- const defaultOptions = {
330
- disableGcMetrics: false
331
- };
332
- const createGcObserver = once__default["default"]((metrics, options) => () => {
333
- const startGcStats = gcStats__default["default"](defaultRegister, {
334
- prefix: options.metricPrefix
335
- });
336
- startGcStats();
337
- });
338
-
339
- // @ts-expect-error
340
- createGcObserver.defaultOptions = defaultOptions;
339
+ createRequestRecorder.defaultOptions = defaultOptions;
341
340
 
342
- const normalizeStatusCode = statusCode => statusCode;
341
+ const normalizeMethod = method => method.toLowerCase();
343
342
 
344
343
  const urlValueParser = new UrlValueParser__default["default"]();
345
344
  const normalizePath = path => {
346
345
  const parsedPathname = url__default["default"].parse(path).pathname;
347
- if (!parsedPathname) return '';
346
+ if (!parsedPathname) {
347
+ return '';
348
+ }
348
349
  return urlValueParser.replacePathValues(parsedPathname, '#val');
349
350
  };
350
351
 
351
- const normalizeMethod = method => method.toLowerCase();
352
+ const normalizeStatusCode = statusCode => statusCode;
352
353
 
353
354
  const defaultNormalizers = {
354
355
  normalizeStatusCode,
@@ -356,6 +357,9 @@ const defaultNormalizers = {
356
357
  normalizeMethod
357
358
  };
358
359
 
360
+ const getSummary = async () => defaultRegister.metrics();
361
+ const getContentType = () => defaultRegister.contentType;
362
+
359
363
  class Timing {
360
364
  static NS_PER_SEC = BigInt(1e9);
361
365
  #startTime;
@@ -366,9 +370,11 @@ class Timing {
366
370
  value() {
367
371
  const startTime = this.#startTime;
368
372
  const endTime = this.#endTime;
369
- if (!endTime || !startTime) return {
370
- seconds: undefined
371
- };
373
+ if (!endTime || !startTime) {
374
+ return {
375
+ seconds: undefined
376
+ };
377
+ }
372
378
  return {
373
379
  seconds: Number(endTime - startTime) / Number(Timing.NS_PER_SEC)
374
380
  };
@@ -6,7 +6,7 @@ var once = require('lodash.once');
6
6
  var Prometheus = require('prom-client');
7
7
  var merge = require('merge-options');
8
8
  var gcStats = require('prometheus-gc-stats');
9
- var url = require('url');
9
+ var url = require('node:url');
10
10
  var UrlValueParser = require('url-value-parser');
11
11
  var types = require('@promster/types');
12
12
 
@@ -45,9 +45,6 @@ const skipMetricsInEnvironment = options => options.detectKubernetes === true &&
45
45
  // This is the `globalRegistry` provided by the `prom-client`
46
46
  // We could create multiple registries with `new Prometheus.registry()`.
47
47
  const defaultRegister = Prometheus__namespace.register;
48
-
49
- // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
50
-
51
48
  const configure = once__default["default"](options => {
52
49
  const shouldSkipMetricsInEnvironment = skipMetricsInEnvironment(options);
53
50
  if (!shouldSkipMetricsInEnvironment) {
@@ -55,104 +52,53 @@ const configure = once__default["default"](options => {
55
52
  }
56
53
  });
57
54
 
58
- const defaultHttpRequestDurationPercentileInSeconds = [0.5, 0.9, 0.95, 0.98, 0.99];
59
- const defaultHttpRequestDurationInSeconds = [0.05, 0.1, 0.3, 0.5, 0.8, 1, 1.5, 2, 3, 10];
60
- const defaultHttpContentLengthInBytes = [100000, 200000, 500000, 1000000, 1500000, 2000000, 3000000, 5000000, 10000000];
61
- const defaultLabels$1 = ['path', 'status_code', 'method'];
62
55
  const asArray$2 = maybeArray => Array.isArray(maybeArray) ? maybeArray : [maybeArray];
63
- const shouldObserveHttpRequestsAsSummary = options => options.metricTypes.includes('httpRequestsSummary');
64
- const shouldObserveHttpRequestsAsHistogram = options => options.metricTypes.includes('httpRequestsHistogram');
65
- const shouldObserveHttpRequestsAsCounter = options => options.metricTypes.includes('httpRequestsTotal');
66
- const shouldObserveHttpContentLengthAsHistogram = options => options.metricTypes.includes('httpContentLengthHistogram');
67
56
  const defaultOptions$4 = {
68
57
  getLabelValues: () => ({}),
69
58
  labels: [],
70
59
  metricPrefix: '',
71
- metricTypes: ['httpRequestsTotal', 'httpRequestsHistogram'],
72
60
  metricNames: {
73
- httpRequestsTotal: ['http_requests_total'],
74
- httpRequestDurationPerPercentileInSeconds: ['http_request_duration_per_percentile_seconds'],
75
- httpRequestDurationInSeconds: ['http_request_duration_seconds'],
76
- httpRequestContentLengthInBytes: ['http_request_content_length_bytes'],
77
- httpResponseContentLengthInBytes: ['http_response_content_length_bytes']
78
- },
79
- metricBuckets: {
80
- httpRequestContentLengthInBytes: defaultHttpContentLengthInBytes,
81
- httpRequestDurationInSeconds: defaultHttpRequestDurationInSeconds
82
- },
83
- metricPercentiles: {
84
- httpRequestDurationPerPercentileInSeconds: defaultHttpRequestDurationPercentileInSeconds,
85
- httpResponseContentLengthInBytes: defaultHttpContentLengthInBytes
61
+ up: ['nodejs_up']
86
62
  }
87
63
  };
88
64
  const getMetrics$2 = options => ({
89
- httpRequestContentLengthInBytes: shouldObserveHttpContentLengthAsHistogram(options) ? asArray$2(options.metricNames.httpRequestContentLengthInBytes).map(nameOfHttpContentLengthMetric => {
90
- var _options$metricBucket;
91
- return new Prometheus__namespace.Histogram({
92
- name: `${options.metricPrefix}${nameOfHttpContentLengthMetric}`,
93
- help: 'The HTTP request content length in bytes.',
94
- labelNames: defaultLabels$1.concat(options.labels).sort(),
95
- buckets: ((_options$metricBucket = options.metricBuckets) === null || _options$metricBucket === void 0 ? void 0 : _options$metricBucket.httpRequestContentLengthInBytes) || defaultHttpContentLengthInBytes
96
- });
97
- }) : undefined,
98
- httpResponseContentLengthInBytes: shouldObserveHttpContentLengthAsHistogram(options) ? asArray$2(options.metricNames.httpResponseContentLengthInBytes).map(nameOfHttpContentLengthMetric => {
99
- var _options$metricBucket2;
100
- return new Prometheus__namespace.Histogram({
101
- name: `${options.metricPrefix}${nameOfHttpContentLengthMetric}`,
102
- help: 'The HTTP response content length in bytes.',
103
- labelNames: defaultLabels$1.concat(options.labels).sort(),
104
- buckets: ((_options$metricBucket2 = options.metricBuckets) === null || _options$metricBucket2 === void 0 ? void 0 : _options$metricBucket2.httpResponseContentLengthInBytes) || defaultHttpContentLengthInBytes
105
- });
106
- }) : undefined
107
- });
108
- const getHttpRequestLatencyMetricsInSeconds = options => ({
109
- httpRequestDurationPerPercentileInSeconds: shouldObserveHttpRequestsAsSummary(options) ? asArray$2(options.metricNames.httpRequestDurationPerPercentileInSeconds).map(nameOfHttpRequestDurationPerPercentileInSeconds => {
110
- var _options$metricPercen;
111
- return new Prometheus__namespace.Summary({
112
- name: `${options.metricPrefix}${nameOfHttpRequestDurationPerPercentileInSeconds}`,
113
- help: 'The HTTP request latencies in seconds.',
114
- labelNames: defaultLabels$1.concat(options.labels).sort(),
115
- percentiles: ((_options$metricPercen = options.metricPercentiles) === null || _options$metricPercen === void 0 ? void 0 : _options$metricPercen.httpRequestDurationPerPercentileInSeconds) || defaultHttpRequestDurationPercentileInSeconds
116
- });
117
- }) : undefined,
118
- httpRequestDurationInSeconds: shouldObserveHttpRequestsAsHistogram(options) ? asArray$2(options.metricNames.httpRequestDurationInSeconds).map(nameOfHttpRequestDurationInSecondsMetric => {
119
- var _options$metricBucket3;
120
- return new Prometheus__namespace.Histogram({
121
- name: `${options.metricPrefix}${nameOfHttpRequestDurationInSecondsMetric}`,
122
- help: 'The HTTP request latencies in seconds.',
123
- labelNames: defaultLabels$1.concat(options.labels).sort(),
124
- buckets: ((_options$metricBucket3 = options.metricBuckets) === null || _options$metricBucket3 === void 0 ? void 0 : _options$metricBucket3.httpRequestDurationInSeconds) || defaultHttpRequestDurationInSeconds
125
- });
126
- }) : undefined
127
- });
128
- const getHttpRequestCounterMetric = options => ({
129
- httpRequestsTotal: shouldObserveHttpRequestsAsCounter(options) ? asArray$2(options.metricNames.httpRequestsTotal).map(nameOfHttpRequestsTotalMetric => new Prometheus__namespace.Counter({
130
- name: `${options.metricPrefix}${nameOfHttpRequestsTotalMetric}`,
131
- help: 'The total HTTP requests.',
132
- labelNames: defaultLabels$1.concat(options.labels).sort()
133
- })) : undefined
65
+ up: asArray$2(options.metricNames.up).map(nameOfUpMetric => new Prometheus__namespace.Gauge({
66
+ name: `${options.metricPrefix}${nameOfUpMetric}`,
67
+ help: '1 = nodejs server is up, 0 = nodejs server is not up'
68
+ }))
134
69
  });
135
- const createHttpMetrics = options => {
70
+ const createGcMetrics = options => {
136
71
  const defaultedOptions = merge__default["default"](defaultOptions$4, options);
137
72
  configure({
138
73
  prefix: defaultedOptions.metricPrefix
139
74
  });
140
- const metrics = getMetrics$2(defaultedOptions);
141
- const httpRequestLatencyMetricsInSeconds = getHttpRequestLatencyMetricsInSeconds(defaultedOptions);
142
- const httpRequestCounterMetric = getHttpRequestCounterMetric(defaultedOptions);
143
- return Object.assign({}, metrics, httpRequestLatencyMetricsInSeconds, httpRequestCounterMetric);
75
+ const gcMetrics = getMetrics$2(defaultedOptions);
76
+ return gcMetrics;
144
77
  };
145
- createHttpMetrics.defaultOptions = defaultOptions$4;
78
+ createGcMetrics.defaultOptions = defaultOptions$4;
79
+
80
+ const defaultOptions$3 = {
81
+ disableGcMetrics: false
82
+ };
83
+ const createGcObserver = once__default["default"]((_metrics, options) => () => {
84
+ const startGcStats = gcStats__default["default"](defaultRegister, {
85
+ prefix: options.metricPrefix
86
+ });
87
+ startGcStats();
88
+ });
89
+
90
+ // @ts-expect-error
91
+ createGcObserver.defaultOptions = defaultOptions$3;
146
92
 
147
93
  const defaultGraphQlPercentiles = [0.5, 0.9, 0.95, 0.98, 0.99];
148
- const defaultLabels = ['operation_name'];
94
+ const defaultLabels$1 = ['operation_name'];
149
95
  const asArray$1 = maybeArray => Array.isArray(maybeArray) ? maybeArray : [maybeArray];
150
96
  const shouldObserveGraphQlParseDurationAsHistogram = options => options.metricTypes.includes('graphQlParseDurationHistogram');
151
97
  const shouldObserveGraphQlValidationDurationAsHistogram = options => options.metricTypes.includes('graphQlValidationDurationHistogram');
152
98
  const shouldObserveGraphQlResolveFieldDurationAsHistogram = options => options.metricTypes.includes('graphQlResolveFieldDurationHistogram');
153
99
  const shouldObserveGraphQlRequestDurationAsHistogram = options => options.metricTypes.includes('graphQlRequestDurationHistogram');
154
100
  const shouldObserveGraphQlErrorsTotalAsCounter = options => options.metricTypes.includes('graphQlErrorsTotal');
155
- const defaultOptions$3 = {
101
+ const defaultOptions$2 = {
156
102
  getLabelValues: () => ({}),
157
103
  labels: [],
158
104
  metricPrefix: '',
@@ -178,7 +124,7 @@ const getMetrics$1 = options => ({
178
124
  return new Prometheus__namespace.Histogram({
179
125
  name: `${options.metricPrefix}${nameOfGraphQlParseDuration}`,
180
126
  help: 'The GraphQL request parse time in seconds.',
181
- labelNames: defaultLabels.concat(options.labels).sort(),
127
+ labelNames: defaultLabels$1.concat(options.labels).sort(),
182
128
  buckets: ((_options$metricPercen = options.metricPercentiles) === null || _options$metricPercen === void 0 ? void 0 : _options$metricPercen.graphQlParseDuration) || defaultGraphQlPercentiles
183
129
  });
184
130
  }) : undefined,
@@ -187,7 +133,7 @@ const getMetrics$1 = options => ({
187
133
  return new Prometheus__namespace.Histogram({
188
134
  name: `${options.metricPrefix}${nameOfGraphQlValidationDuration}`,
189
135
  help: 'The GraphQL request validation time in seconds.',
190
- labelNames: defaultLabels.concat(options.labels).sort(),
136
+ labelNames: defaultLabels$1.concat(options.labels).sort(),
191
137
  buckets: ((_options$metricPercen2 = options.metricPercentiles) === null || _options$metricPercen2 === void 0 ? void 0 : _options$metricPercen2.graphQlValidationDuration) || defaultGraphQlPercentiles
192
138
  });
193
139
  }) : undefined,
@@ -196,7 +142,7 @@ const getMetrics$1 = options => ({
196
142
  return new Prometheus__namespace.Histogram({
197
143
  name: `${options.metricPrefix}${nameOfGraphQlResolveFieldDuration}`,
198
144
  help: 'The GraphQL field resolving time in seconds.',
199
- labelNames: defaultLabels.concat(['field_name']).concat(options.labels).sort(),
145
+ labelNames: defaultLabels$1.concat(['field_name']).concat(options.labels).sort(),
200
146
  buckets: ((_options$metricPercen3 = options.metricPercentiles) === null || _options$metricPercen3 === void 0 ? void 0 : _options$metricPercen3.graphQlResolveFieldDuration) || defaultGraphQlPercentiles
201
147
  });
202
148
  }) : undefined,
@@ -205,53 +151,122 @@ const getMetrics$1 = options => ({
205
151
  return new Prometheus__namespace.Histogram({
206
152
  name: `${options.metricPrefix}${nameOfGraphQlRequestDuration}`,
207
153
  help: 'The GraphQL request duration time in seconds.',
208
- labelNames: defaultLabels.concat(options.labels).sort(),
154
+ labelNames: defaultLabels$1.concat(options.labels).sort(),
209
155
  buckets: ((_options$metricPercen4 = options.metricPercentiles) === null || _options$metricPercen4 === void 0 ? void 0 : _options$metricPercen4.graphQlRequestDuration) || defaultGraphQlPercentiles
210
156
  });
211
157
  }) : undefined,
212
158
  graphQlErrorsTotal: shouldObserveGraphQlErrorsTotalAsCounter(options) ? asArray$1(options.metricNames.graphQlErrorsTotal).map(nameOfGraphQlErrorsCount => new Prometheus__namespace.Counter({
213
159
  name: `${options.metricPrefix}${nameOfGraphQlErrorsCount}`,
214
160
  help: 'Count of errors while parsing, validating, or executing a GraphQL operation.',
215
- labelNames: defaultLabels.concat(['phase']).concat(options.labels).sort()
161
+ labelNames: defaultLabels$1.concat(['phase']).concat(options.labels).sort()
216
162
  })) : undefined
217
163
  });
218
164
  const createGraphQlMetrics = options => {
219
- const defaultedOptions = merge__default["default"](defaultOptions$3, options);
165
+ const defaultedOptions = merge__default["default"](defaultOptions$2, options);
220
166
  configure({
221
167
  prefix: defaultedOptions.metricPrefix
222
168
  });
223
169
  const metrics = getMetrics$1(defaultedOptions);
224
170
  return metrics;
225
171
  };
226
- createGraphQlMetrics.defaultOptions = defaultOptions$3;
172
+ createGraphQlMetrics.defaultOptions = defaultOptions$2;
227
173
 
174
+ const defaultHttpRequestDurationPercentileInSeconds = [0.5, 0.9, 0.95, 0.98, 0.99];
175
+ const defaultHttpRequestDurationInSeconds = [0.05, 0.1, 0.3, 0.5, 0.8, 1, 1.5, 2, 3, 10];
176
+ const defaultHttpContentLengthInBytes = [100000, 200000, 500000, 1000000, 1500000, 2000000, 3000000, 5000000, 10000000];
177
+ const defaultLabels = ['path', 'status_code', 'method'];
228
178
  const asArray = maybeArray => Array.isArray(maybeArray) ? maybeArray : [maybeArray];
229
- const defaultOptions$2 = {
179
+ const shouldObserveHttpRequestsAsSummary = options => options.metricTypes.includes('httpRequestsSummary');
180
+ const shouldObserveHttpRequestsAsHistogram = options => options.metricTypes.includes('httpRequestsHistogram');
181
+ const shouldObserveHttpRequestsAsCounter = options => options.metricTypes.includes('httpRequestsTotal');
182
+ const shouldObserveHttpContentLengthAsHistogram = options => options.metricTypes.includes('httpContentLengthHistogram');
183
+ const defaultOptions$1 = {
230
184
  getLabelValues: () => ({}),
231
185
  labels: [],
232
186
  metricPrefix: '',
187
+ metricTypes: ['httpRequestsTotal', 'httpRequestsHistogram'],
233
188
  metricNames: {
234
- up: ['nodejs_up']
189
+ httpRequestsTotal: ['http_requests_total'],
190
+ httpRequestDurationPerPercentileInSeconds: ['http_request_duration_per_percentile_seconds'],
191
+ httpRequestDurationInSeconds: ['http_request_duration_seconds'],
192
+ httpRequestContentLengthInBytes: ['http_request_content_length_bytes'],
193
+ httpResponseContentLengthInBytes: ['http_response_content_length_bytes']
194
+ },
195
+ metricBuckets: {
196
+ httpRequestContentLengthInBytes: defaultHttpContentLengthInBytes,
197
+ httpRequestDurationInSeconds: defaultHttpRequestDurationInSeconds
198
+ },
199
+ metricPercentiles: {
200
+ httpRequestDurationPerPercentileInSeconds: defaultHttpRequestDurationPercentileInSeconds,
201
+ httpResponseContentLengthInBytes: defaultHttpContentLengthInBytes
235
202
  }
236
203
  };
237
204
  const getMetrics = options => ({
238
- up: asArray(options.metricNames.up).map(nameOfUpMetric => new Prometheus__namespace.Gauge({
239
- name: `${options.metricPrefix}${nameOfUpMetric}`,
240
- help: '1 = nodejs server is up, 0 = nodejs server is not up'
241
- }))
205
+ httpRequestContentLengthInBytes: shouldObserveHttpContentLengthAsHistogram(options) ? asArray(options.metricNames.httpRequestContentLengthInBytes).map(nameOfHttpContentLengthMetric => {
206
+ var _options$metricBucket;
207
+ return new Prometheus__namespace.Histogram({
208
+ name: `${options.metricPrefix}${nameOfHttpContentLengthMetric}`,
209
+ help: 'The HTTP request content length in bytes.',
210
+ labelNames: defaultLabels.concat(options.labels).sort(),
211
+ buckets: ((_options$metricBucket = options.metricBuckets) === null || _options$metricBucket === void 0 ? void 0 : _options$metricBucket.httpRequestContentLengthInBytes) || defaultHttpContentLengthInBytes
212
+ });
213
+ }) : undefined,
214
+ httpResponseContentLengthInBytes: shouldObserveHttpContentLengthAsHistogram(options) ? asArray(options.metricNames.httpResponseContentLengthInBytes).map(nameOfHttpContentLengthMetric => {
215
+ var _options$metricBucket2;
216
+ return new Prometheus__namespace.Histogram({
217
+ name: `${options.metricPrefix}${nameOfHttpContentLengthMetric}`,
218
+ help: 'The HTTP response content length in bytes.',
219
+ labelNames: defaultLabels.concat(options.labels).sort(),
220
+ buckets: ((_options$metricBucket2 = options.metricBuckets) === null || _options$metricBucket2 === void 0 ? void 0 : _options$metricBucket2.httpResponseContentLengthInBytes) || defaultHttpContentLengthInBytes
221
+ });
222
+ }) : undefined
242
223
  });
243
- const createGcMetrics = options => {
244
- const defaultedOptions = merge__default["default"](defaultOptions$2, options);
224
+ const getHttpRequestLatencyMetricsInSeconds = options => ({
225
+ httpRequestDurationPerPercentileInSeconds: shouldObserveHttpRequestsAsSummary(options) ? asArray(options.metricNames.httpRequestDurationPerPercentileInSeconds).map(nameOfHttpRequestDurationPerPercentileInSeconds => {
226
+ var _options$metricPercen;
227
+ return new Prometheus__namespace.Summary({
228
+ name: `${options.metricPrefix}${nameOfHttpRequestDurationPerPercentileInSeconds}`,
229
+ help: 'The HTTP request latencies in seconds.',
230
+ labelNames: defaultLabels.concat(options.labels).sort(),
231
+ percentiles: ((_options$metricPercen = options.metricPercentiles) === null || _options$metricPercen === void 0 ? void 0 : _options$metricPercen.httpRequestDurationPerPercentileInSeconds) || defaultHttpRequestDurationPercentileInSeconds
232
+ });
233
+ }) : undefined,
234
+ httpRequestDurationInSeconds: shouldObserveHttpRequestsAsHistogram(options) ? asArray(options.metricNames.httpRequestDurationInSeconds).map(nameOfHttpRequestDurationInSecondsMetric => {
235
+ var _options$metricBucket3;
236
+ return new Prometheus__namespace.Histogram({
237
+ name: `${options.metricPrefix}${nameOfHttpRequestDurationInSecondsMetric}`,
238
+ help: 'The HTTP request latencies in seconds.',
239
+ labelNames: defaultLabels.concat(options.labels).sort(),
240
+ buckets: ((_options$metricBucket3 = options.metricBuckets) === null || _options$metricBucket3 === void 0 ? void 0 : _options$metricBucket3.httpRequestDurationInSeconds) || defaultHttpRequestDurationInSeconds
241
+ });
242
+ }) : undefined
243
+ });
244
+ const getHttpRequestCounterMetric = options => ({
245
+ httpRequestsTotal: shouldObserveHttpRequestsAsCounter(options) ? asArray(options.metricNames.httpRequestsTotal).map(nameOfHttpRequestsTotalMetric => new Prometheus__namespace.Counter({
246
+ name: `${options.metricPrefix}${nameOfHttpRequestsTotalMetric}`,
247
+ help: 'The total HTTP requests.',
248
+ labelNames: defaultLabels.concat(options.labels).sort()
249
+ })) : undefined
250
+ });
251
+ const createHttpMetrics = options => {
252
+ const defaultedOptions = merge__default["default"](defaultOptions$1, options);
245
253
  configure({
246
254
  prefix: defaultedOptions.metricPrefix
247
255
  });
248
- const gcMetrics = getMetrics(defaultedOptions);
249
- return gcMetrics;
256
+ const metrics = getMetrics(defaultedOptions);
257
+ const httpRequestLatencyMetricsInSeconds = getHttpRequestLatencyMetricsInSeconds(defaultedOptions);
258
+ const httpRequestCounterMetric = getHttpRequestCounterMetric(defaultedOptions);
259
+ return Object.assign({}, metrics, httpRequestLatencyMetricsInSeconds, httpRequestCounterMetric);
250
260
  };
251
- createGcMetrics.defaultOptions = defaultOptions$2;
261
+ createHttpMetrics.defaultOptions = defaultOptions$1;
252
262
 
253
- const getSummary = async () => defaultRegister.metrics();
254
- const getContentType = () => defaultRegister.contentType;
263
+ const NS_PER_SEC = 1e9;
264
+ function endMeasurementFrom(start) {
265
+ const [seconds, nanoseconds] = process.hrtime(start);
266
+ return {
267
+ durationS: (seconds * NS_PER_SEC + nanoseconds) / NS_PER_SEC
268
+ };
269
+ }
255
270
 
256
271
  function sortLabels(unsortedLabels) {
257
272
  return Object.keys(unsortedLabels).sort((a, b) => {
@@ -268,87 +283,73 @@ function sortLabels(unsortedLabels) {
268
283
  }, {});
269
284
  }
270
285
 
271
- const NS_PER_SEC = 1e9;
272
- function endMeasurementFrom(start) {
273
- const [seconds, nanoseconds] = process.hrtime(start);
274
- return {
275
- durationS: (seconds * NS_PER_SEC + nanoseconds) / NS_PER_SEC
276
- };
277
- }
278
-
279
- const defaultOptions$1 = {
286
+ const defaultOptions = {
280
287
  detectKubernetes: false
281
288
  };
282
289
  function isTiming(timing) {
283
290
  return !Array.isArray(timing);
284
291
  }
285
- const createRequestRecorder = (metrics, options = defaultOptions$1) => {
286
- const defaultedRecorderOptions = merge__default["default"](defaultOptions$1, options);
292
+ const createRequestRecorder = (metrics, options = defaultOptions) => {
293
+ const defaultedRecorderOptions = merge__default["default"](defaultOptions, options);
287
294
  const shouldSkipMetricsByEnvironment = skipMetricsInEnvironment(defaultedRecorderOptions);
288
295
  return (timing, recordingOptions) => {
289
296
  const durationS = isTiming(timing) ? timing.end().value().seconds : endMeasurementFrom(timing).durationS;
290
297
  const labels = sortLabels(recordingOptions.labels);
291
298
  if (!shouldSkipMetricsByEnvironment && durationS !== undefined) {
292
- var _metrics$httpRequestD;
293
- (_metrics$httpRequestD = metrics.httpRequestDurationInSeconds) === null || _metrics$httpRequestD === void 0 || _metrics$httpRequestD.forEach(httpRequestDurationInSecondsMetricType => {
294
- httpRequestDurationInSecondsMetricType.observe(labels, durationS);
295
- });
299
+ if (metrics.httpRequestDurationInSeconds) {
300
+ for (const httpRequestDurationInSecondsMetricType of metrics.httpRequestDurationInSeconds) {
301
+ httpRequestDurationInSecondsMetricType.observe(labels, durationS);
302
+ }
303
+ }
296
304
  }
297
305
  if (!shouldSkipMetricsByEnvironment && durationS !== undefined) {
298
- var _metrics$httpRequestD2;
299
- (_metrics$httpRequestD2 = metrics.httpRequestDurationPerPercentileInSeconds) === null || _metrics$httpRequestD2 === void 0 || _metrics$httpRequestD2.forEach(httpRequestDurationPerPercentileInSecondsMetricType => {
300
- httpRequestDurationPerPercentileInSecondsMetricType.observe(labels, durationS);
301
- });
306
+ if (metrics.httpRequestDurationPerPercentileInSeconds) {
307
+ for (const httpRequestDurationPerPercentileInSecondsMetricType of metrics.httpRequestDurationPerPercentileInSeconds) {
308
+ httpRequestDurationPerPercentileInSecondsMetricType.observe(labels, durationS);
309
+ }
310
+ }
302
311
  }
303
312
  if (!shouldSkipMetricsByEnvironment && durationS !== undefined) {
304
- var _metrics$httpRequests;
305
- (_metrics$httpRequests = metrics.httpRequestsTotal) === null || _metrics$httpRequests === void 0 || _metrics$httpRequests.forEach(httpRequestsTotalMetricType => {
306
- httpRequestsTotalMetricType.inc(labels);
307
- });
313
+ if (metrics.httpRequestsTotal) {
314
+ for (const httpRequestsTotalMetricType of metrics.httpRequestsTotal) {
315
+ httpRequestsTotalMetricType.inc(labels);
316
+ }
317
+ }
308
318
  }
309
319
  if (recordingOptions.requestContentLength) {
310
- var _metrics$httpRequestC;
311
- (_metrics$httpRequestC = metrics.httpRequestContentLengthInBytes) === null || _metrics$httpRequestC === void 0 || _metrics$httpRequestC.forEach(httpRequestContentLengthInBytesMetricType => {
312
- httpRequestContentLengthInBytesMetricType.observe(labels,
313
- // @ts-expect-error
314
- recordingOptions.requestContentLength);
315
- });
320
+ if (metrics.httpRequestContentLengthInBytes) {
321
+ for (const httpRequestContentLengthInBytesMetricType of metrics.httpRequestContentLengthInBytes) {
322
+ httpRequestContentLengthInBytesMetricType.observe(labels,
323
+ // @ts-expect-error
324
+ recordingOptions.requestContentLength);
325
+ }
326
+ }
316
327
  }
317
328
  if (recordingOptions.responseContentLength) {
318
- var _metrics$httpResponse;
319
- (_metrics$httpResponse = metrics.httpResponseContentLengthInBytes) === null || _metrics$httpResponse === void 0 || _metrics$httpResponse.forEach(httpResponseContentLengthInBytesMetricType => {
320
- httpResponseContentLengthInBytesMetricType.observe(labels,
321
- // @ts-expect-error
322
- recordingOptions.responseContentLength);
323
- });
329
+ if (metrics.httpResponseContentLengthInBytes) {
330
+ for (const httpResponseContentLengthInBytesMetricType of metrics.httpResponseContentLengthInBytes) {
331
+ httpResponseContentLengthInBytesMetricType.observe(labels,
332
+ // @ts-expect-error
333
+ recordingOptions.responseContentLength);
334
+ }
335
+ }
324
336
  }
325
337
  };
326
338
  };
327
- createRequestRecorder.defaultOptions = defaultOptions$1;
328
-
329
- const defaultOptions = {
330
- disableGcMetrics: false
331
- };
332
- const createGcObserver = once__default["default"]((metrics, options) => () => {
333
- const startGcStats = gcStats__default["default"](defaultRegister, {
334
- prefix: options.metricPrefix
335
- });
336
- startGcStats();
337
- });
338
-
339
- // @ts-expect-error
340
- createGcObserver.defaultOptions = defaultOptions;
339
+ createRequestRecorder.defaultOptions = defaultOptions;
341
340
 
342
- const normalizeStatusCode = statusCode => statusCode;
341
+ const normalizeMethod = method => method.toLowerCase();
343
342
 
344
343
  const urlValueParser = new UrlValueParser__default["default"]();
345
344
  const normalizePath = path => {
346
345
  const parsedPathname = url__default["default"].parse(path).pathname;
347
- if (!parsedPathname) return '';
346
+ if (!parsedPathname) {
347
+ return '';
348
+ }
348
349
  return urlValueParser.replacePathValues(parsedPathname, '#val');
349
350
  };
350
351
 
351
- const normalizeMethod = method => method.toLowerCase();
352
+ const normalizeStatusCode = statusCode => statusCode;
352
353
 
353
354
  const defaultNormalizers = {
354
355
  normalizeStatusCode,
@@ -356,6 +357,9 @@ const defaultNormalizers = {
356
357
  normalizeMethod
357
358
  };
358
359
 
360
+ const getSummary = async () => defaultRegister.metrics();
361
+ const getContentType = () => defaultRegister.contentType;
362
+
359
363
  class Timing {
360
364
  static NS_PER_SEC = BigInt(1e9);
361
365
  #startTime;
@@ -366,9 +370,11 @@ class Timing {
366
370
  value() {
367
371
  const startTime = this.#startTime;
368
372
  const endTime = this.#endTime;
369
- if (!endTime || !startTime) return {
370
- seconds: undefined
371
- };
373
+ if (!endTime || !startTime) {
374
+ return {
375
+ seconds: undefined
376
+ };
377
+ }
372
378
  return {
373
379
  seconds: Number(endTime - startTime) / Number(Timing.NS_PER_SEC)
374
380
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promster/metrics",
3
- "version": "14.0.0",
3
+ "version": "15.0.0",
4
4
  "description": "Metrics utilities used by all other server integrations",
5
5
  "main": "dist/promster-metrics.cjs.js",
6
6
  "typings": "dist/promster-metrics.cjs.d.ts",
@@ -36,19 +36,19 @@
36
36
  "prometheus"
37
37
  ],
38
38
  "dependencies": {
39
- "@promster/types": "^14.0.0",
40
39
  "lodash.memoize": "4.1.2",
41
- "prometheus-gc-stats": "1.1.0",
42
40
  "lodash.once": "4.1.1",
43
41
  "merge-options": "3.0.4",
44
- "tslib": "2.6.2",
45
- "url-value-parser": "2.2.0"
42
+ "prometheus-gc-stats": "1.1.0",
43
+ "tslib": "2.8.1",
44
+ "url-value-parser": "2.2.0",
45
+ "@promster/types": "15.0.0"
46
46
  },
47
47
  "devDependencies": {
48
- "prom-client": "15.1.1",
49
- "typescript": "5.3.3",
50
- "@types/node": "20.11.30",
51
- "@types/lodash.once": "4.1.9"
48
+ "@types/lodash.once": "4.1.9",
49
+ "@types/node": "22.14.0",
50
+ "prom-client": "15.1.3",
51
+ "typescript": "5.8.3"
52
52
  },
53
53
  "peerDependencies": {
54
54
  "prom-client": "13.x.x || 14.x || 15.x"