@promster/metrics 10.0.0 → 12.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.
Files changed (30) hide show
  1. package/dist/declarations/src/client/client.d.ts +5 -2
  2. package/dist/declarations/src/client/index.d.ts +1 -1
  3. package/dist/declarations/src/create-gc-metrics/create-gc-metrics.d.ts +2 -2
  4. package/dist/declarations/src/create-gc-metrics/index.d.ts +1 -1
  5. package/dist/declarations/src/create-gc-observer/create-gc-observer.d.ts +2 -1
  6. package/dist/declarations/src/create-gc-observer/index.d.ts +1 -1
  7. package/dist/declarations/src/create-graphql-metrics/create-graphql-metrics.d.ts +9 -2
  8. package/dist/declarations/src/create-graphql-metrics/index.d.ts +1 -1
  9. package/dist/declarations/src/create-http-metrics/create-http-metrics.d.ts +10 -2
  10. package/dist/declarations/src/create-http-metrics/index.d.ts +1 -1
  11. package/dist/declarations/src/create-request-recorder/create-request-recorder.d.ts +7 -7
  12. package/dist/declarations/src/create-request-recorder/index.d.ts +2 -2
  13. package/dist/declarations/src/end-measurement-from/index.d.ts +1 -1
  14. package/dist/declarations/src/environment/index.d.ts +2 -2
  15. package/dist/declarations/src/environment/skip-metrics-in-environment.d.ts +2 -2
  16. package/dist/declarations/src/index.d.ts +15 -14
  17. package/dist/declarations/src/normalizers/index.d.ts +3 -3
  18. package/dist/declarations/src/normalizers/method/index.d.ts +1 -1
  19. package/dist/declarations/src/normalizers/path/index.d.ts +1 -1
  20. package/dist/declarations/src/normalizers/status-code/index.d.ts +1 -1
  21. package/dist/declarations/src/sort-labels/index.d.ts +1 -1
  22. package/dist/declarations/src/sort-labels/sort-labels.d.ts +1 -1
  23. package/dist/declarations/src/summary/index.d.ts +1 -1
  24. package/dist/declarations/src/summary/summary.d.ts +1 -1
  25. package/dist/declarations/src/timing/index.d.ts +1 -1
  26. package/dist/promster-metrics.cjs.d.ts +1 -0
  27. package/dist/promster-metrics.cjs.d.ts.map +1 -0
  28. package/dist/promster-metrics.cjs.dev.js +102 -50
  29. package/dist/promster-metrics.cjs.prod.js +102 -50
  30. package/package.json +9 -9
@@ -1,4 +1,7 @@
1
1
  import * as Prometheus from 'prom-client';
2
- declare const defaultRegister: Prometheus.Registry;
3
- declare const configure: any;
2
+ declare const defaultRegister: Prometheus.Registry<"text/plain; version=0.0.4; charset=utf-8">;
3
+ interface TClientOptions extends Prometheus.DefaultMetricsCollectorConfiguration {
4
+ detectKubernetes?: boolean;
5
+ }
6
+ declare const configure: (options: TClientOptions) => void;
4
7
  export { Prometheus, defaultRegister, configure };
@@ -1,2 +1,2 @@
1
- import { Prometheus, defaultRegister, configure } from './client';
1
+ import { Prometheus, defaultRegister, configure } from "./client.js";
2
2
  export { Prometheus, defaultRegister, configure };
@@ -1,6 +1,6 @@
1
- import type { TGcMetrics } from '@promster/types';
1
+ import { type TDefaultedPromsterOptions, type TGcMetrics } from '@promster/types';
2
2
  declare const createGcMetrics: {
3
- (options: DeepRequired<import("@promster/types").TPromsterOptions>): TGcMetrics;
3
+ (options: TDefaultedPromsterOptions): TGcMetrics;
4
4
  defaultOptions: {
5
5
  getLabelValues: () => {};
6
6
  labels: never[];
@@ -1,2 +1,2 @@
1
- import { createGcMetrics } from './create-gc-metrics';
1
+ import { createGcMetrics } from "./create-gc-metrics.js";
2
2
  export { createGcMetrics };
@@ -1,2 +1,3 @@
1
- declare const createGcObserver: any;
1
+ import { type TOptionalPromsterOptions, type TGcMetrics } from '@promster/types';
2
+ declare const createGcObserver: (metrics: TGcMetrics, options: TOptionalPromsterOptions) => () => void;
2
3
  export { createGcObserver };
@@ -1,2 +1,2 @@
1
- import { createGcObserver } from './create-gc-observer';
1
+ import { createGcObserver } from "./create-gc-observer.js";
2
2
  export { createGcObserver };
@@ -1,6 +1,6 @@
1
- import type { TGraphQlMetrics } from '@promster/types';
1
+ import { type TDefaultedPromsterOptions, type TGraphQlMetrics } from '@promster/types';
2
2
  declare const createGraphQlMetrics: {
3
- (options: DeepRequired<import("@promster/types").TPromsterOptions>): TGraphQlMetrics;
3
+ (options: TDefaultedPromsterOptions): TGraphQlMetrics;
4
4
  defaultOptions: {
5
5
  getLabelValues: () => {};
6
6
  labels: never[];
@@ -13,6 +13,13 @@ declare const createGraphQlMetrics: {
13
13
  graphQlRequestDuration: string[];
14
14
  graphQlErrorsTotal: string[];
15
15
  };
16
+ metricPercentiles: {
17
+ graphQlParseDuration: number[];
18
+ graphQlValidationDuration: number[];
19
+ graphQlResolveFieldDuration: number[];
20
+ graphQlRequestDuration: number[];
21
+ graphQlErrorsTotal: number[];
22
+ };
16
23
  };
17
24
  };
18
25
  export { createGraphQlMetrics };
@@ -1,2 +1,2 @@
1
- import { createGraphQlMetrics } from './create-graphql-metrics';
1
+ import { createGraphQlMetrics } from "./create-graphql-metrics.js";
2
2
  export { createGraphQlMetrics };
@@ -1,6 +1,6 @@
1
- import type { THttpMetrics } from '@promster/types';
1
+ import { type TDefaultedPromsterOptions, type THttpMetrics } from '@promster/types';
2
2
  declare const createHttpMetrics: {
3
- (options: DeepRequired<import("@promster/types").TPromsterOptions>): THttpMetrics;
3
+ (options: TDefaultedPromsterOptions): THttpMetrics;
4
4
  defaultOptions: {
5
5
  getLabelValues: () => {};
6
6
  labels: never[];
@@ -13,6 +13,14 @@ declare const createHttpMetrics: {
13
13
  httpRequestContentLengthInBytes: string[];
14
14
  httpResponseContentLengthInBytes: string[];
15
15
  };
16
+ metricBuckets: {
17
+ httpRequestContentLengthInBytes: number[];
18
+ httpRequestDurationInSeconds: number[];
19
+ };
20
+ metricPercentiles: {
21
+ httpRequestDurationPerPercentileInSeconds: number[];
22
+ httpResponseContentLengthInBytes: number[];
23
+ };
16
24
  };
17
25
  };
18
26
  export { createHttpMetrics };
@@ -1,2 +1,2 @@
1
- import { createHttpMetrics } from './create-http-metrics';
1
+ import { createHttpMetrics } from "./create-http-metrics.js";
2
2
  export { createHttpMetrics };
@@ -1,16 +1,16 @@
1
- import type { TPromsterOptions, TLabelValues, THttpMetrics } from '@promster/types';
2
- import type { Timing } from '../timing';
3
- import { sortLabels } from '../sort-labels';
4
- import { endMeasurementFrom } from '../end-measurement-from';
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";
4
+ import { endMeasurementFrom } from "../end-measurement-from/index.js";
5
5
  type TRecordingOptions = {
6
6
  labels: TLabelValues;
7
7
  requestContentLength?: number;
8
8
  responseContentLength?: number;
9
9
  };
10
10
  type TLegacyTiming = [number, number];
11
- export type TRequestRecorder = (timing: Timing | TLegacyTiming, recordingOptions: TRecordingOptions) => void;
11
+ export type TRequestRecorder = (_timing: Timing | TLegacyTiming, _recordingOptions: TRecordingOptions) => void;
12
12
  declare const createRequestRecorder: {
13
- (metrics: THttpMetrics, options?: TPromsterOptions): TRequestRecorder;
14
- defaultOptions: TPromsterOptions;
13
+ (metrics: THttpMetrics, options?: TOptionalPromsterOptions): TRequestRecorder;
14
+ defaultOptions: TOptionalPromsterOptions;
15
15
  };
16
16
  export { createRequestRecorder, sortLabels, endMeasurementFrom };
@@ -1,3 +1,3 @@
1
- import { createRequestRecorder } from './create-request-recorder';
2
- export type { TRequestRecorder } from './create-request-recorder';
1
+ import { createRequestRecorder } from "./create-request-recorder.js";
2
+ export type { TRequestRecorder } from "./create-request-recorder.js";
3
3
  export { createRequestRecorder };
@@ -1,2 +1,2 @@
1
- import { endMeasurementFrom } from './end-measurement-from';
1
+ import { endMeasurementFrom } from "./end-measurement-from.js";
2
2
  export { endMeasurementFrom };
@@ -1,3 +1,3 @@
1
- import { isRunningInKubernetes } from './kubernetes';
2
- import { skipMetricsInEnvironment } from './skip-metrics-in-environment';
1
+ import { isRunningInKubernetes } from "./kubernetes.js";
2
+ import { skipMetricsInEnvironment } from "./skip-metrics-in-environment.js";
3
3
  export { isRunningInKubernetes, skipMetricsInEnvironment };
@@ -1,6 +1,6 @@
1
- import type { TPromsterOptions } from '@promster/types';
1
+ import { type TOptionalPromsterOptions } from '@promster/types';
2
2
  type TSkipMetricsInEnvironmentOptions = {
3
- detectKubernetes?: TPromsterOptions['detectKubernetes'];
3
+ detectKubernetes?: TOptionalPromsterOptions['detectKubernetes'];
4
4
  };
5
5
  declare const skipMetricsInEnvironment: (options: TSkipMetricsInEnvironmentOptions) => boolean;
6
6
  export { skipMetricsInEnvironment };
@@ -1,15 +1,16 @@
1
- import { Prometheus, defaultRegister } from './client';
2
- import { createHttpMetrics } from './create-http-metrics';
3
- import { createGraphQlMetrics } from './create-graphql-metrics';
4
- import { createGcMetrics } from './create-gc-metrics';
5
- import { getSummary, getContentType } from './summary';
6
- import { createRequestRecorder } from './create-request-recorder';
7
- import { createGcObserver } from './create-gc-observer';
8
- import { defaultNormalizers, normalizeStatusCode, normalizePath, normalizeMethod } from './normalizers';
9
- import { isRunningInKubernetes, skipMetricsInEnvironment } from './environment';
10
- import { endMeasurementFrom } from './end-measurement-from';
11
- import { sortLabels } from './sort-labels';
12
- import { timing } from './timing';
13
- export type { TRequestRecorder } from './create-request-recorder';
14
- export type { Timing as TPromsterTiming } from './timing';
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
+ 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
+ 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";
10
+ import { endMeasurementFrom } from "./end-measurement-from/index.js";
11
+ import { sortLabels } from "./sort-labels/index.js";
12
+ import { timing } from "./timing/index.js";
13
+ export type { TRequestRecorder } from "./create-request-recorder/index.js";
14
+ export type { Timing as TPromsterTiming } from "./timing/index.js";
15
15
  export { Prometheus, defaultRegister, createHttpMetrics, createGraphQlMetrics, createGcMetrics, getSummary, getContentType, createRequestRecorder, createGcObserver, defaultNormalizers, normalizeStatusCode, normalizePath, normalizeMethod, isRunningInKubernetes, skipMetricsInEnvironment, endMeasurementFrom, sortLabels, timing, };
16
+ export * from '@promster/types';
@@ -1,6 +1,6 @@
1
- import { normalizeStatusCode } from './status-code';
2
- import { normalizePath } from './path';
3
- import { normalizeMethod } from './method';
1
+ import { normalizeStatusCode } from "./status-code/index.js";
2
+ import { normalizePath } from "./path/index.js";
3
+ import { normalizeMethod } from "./method/index.js";
4
4
  declare const defaultNormalizers: {
5
5
  normalizeStatusCode: (statusCode: number) => number;
6
6
  normalizePath: (path: string) => string;
@@ -1,2 +1,2 @@
1
- import { normalizeMethod } from './method';
1
+ import { normalizeMethod } from "./method.js";
2
2
  export { normalizeMethod };
@@ -1,2 +1,2 @@
1
- import { normalizePath } from './path';
1
+ import { normalizePath } from "./path.js";
2
2
  export { normalizePath };
@@ -1,2 +1,2 @@
1
- import { normalizeStatusCode } from './status-code';
1
+ import { normalizeStatusCode } from "./status-code.js";
2
2
  export { normalizeStatusCode };
@@ -1,2 +1,2 @@
1
- import { sortLabels } from './sort-labels';
1
+ import { sortLabels } from "./sort-labels.js";
2
2
  export { sortLabels };
@@ -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';
1
+ import { getSummary, getContentType } from "./summary.js";
2
2
  export { getSummary, getContentType };
@@ -1,3 +1,3 @@
1
1
  declare const getSummary: () => Promise<string>;
2
- declare const getContentType: () => string;
2
+ declare const getContentType: () => "text/plain; version=0.0.4; charset=utf-8";
3
3
  export { getSummary, getContentType };
@@ -1,2 +1,2 @@
1
- import timing, { Timing } from './timing';
1
+ import timing, { Timing } from "./timing.js";
2
2
  export { timing, Timing };
@@ -1 +1,2 @@
1
1
  export * from "./declarations/src/index";
2
+ //# sourceMappingURL=promster-metrics.cjs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promster-metrics.cjs.d.ts","sourceRoot":"","sources":["./declarations/src/index.d.ts"],"names":[],"mappings":"AAAA"}
@@ -8,6 +8,7 @@ var merge = require('merge-options');
8
8
  var requireOptional = require('optional');
9
9
  var url = require('url');
10
10
  var UrlValueParser = require('url-value-parser');
11
+ var types = require('@promster/types');
11
12
 
12
13
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
13
14
 
@@ -74,35 +75,55 @@ const defaultOptions$4 = {
74
75
  httpRequestDurationInSeconds: ['http_request_duration_seconds'],
75
76
  httpRequestContentLengthInBytes: ['http_request_content_length_bytes'],
76
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
77
86
  }
78
87
  };
79
88
  const getMetrics$2 = options => ({
80
- httpRequestContentLengthInBytes: shouldObserveHttpContentLengthAsHistogram(options) ? asArray$2(options.metricNames.httpRequestContentLengthInBytes).map(nameOfHttpContentLengthMetric => new Prometheus__namespace.Histogram({
81
- name: `${options.metricPrefix}${nameOfHttpContentLengthMetric}`,
82
- help: 'The HTTP request content length in bytes.',
83
- labelNames: defaultLabels$2.concat(options.labels).sort(),
84
- buckets: options.buckets || defaultHttpContentLengthInBytes
85
- })) : undefined,
86
- httpResponseContentLengthInBytes: shouldObserveHttpContentLengthAsHistogram(options) ? asArray$2(options.metricNames.httpResponseContentLengthInBytes).map(nameOfHttpContentLengthMetric => new Prometheus__namespace.Histogram({
87
- name: `${options.metricPrefix}${nameOfHttpContentLengthMetric}`,
88
- help: 'The HTTP response content length in bytes.',
89
- labelNames: defaultLabels$2.concat(options.labels).sort(),
90
- buckets: options.buckets || defaultHttpContentLengthInBytes
91
- })) : undefined
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$2.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$2.concat(options.labels).sort(),
104
+ buckets: ((_options$metricBucket2 = options.metricBuckets) === null || _options$metricBucket2 === void 0 ? void 0 : _options$metricBucket2.httpResponseContentLengthInBytes) || defaultHttpContentLengthInBytes
105
+ });
106
+ }) : undefined
92
107
  });
93
108
  const getHttpRequestLatencyMetricsInSeconds = options => ({
94
- httpRequestDurationPerPercentileInSeconds: shouldObserveHttpRequestsAsSummary(options) ? asArray$2(options.metricNames.httpRequestDurationPerPercentileInSeconds).map(nameOfHttpRequestDurationPerPercentileInSeconds => new Prometheus__namespace.Summary({
95
- name: `${options.metricPrefix}${nameOfHttpRequestDurationPerPercentileInSeconds}`,
96
- help: 'The HTTP request latencies in seconds.',
97
- labelNames: defaultLabels$2.concat(options.labels).sort(),
98
- percentiles: options.percentiles || defaultHttpRequestDurationPercentileInSeconds
99
- })) : undefined,
100
- httpRequestDurationInSeconds: shouldObserveHttpRequestsAsHistogram(options) ? asArray$2(options.metricNames.httpRequestDurationInSeconds).map(nameOfHttpRequestDurationInSecondsMetric => new Prometheus__namespace.Histogram({
101
- name: `${options.metricPrefix}${nameOfHttpRequestDurationInSecondsMetric}`,
102
- help: 'The HTTP request latencies in seconds.',
103
- labelNames: defaultLabels$2.concat(options.labels).sort(),
104
- buckets: options.buckets || defaultHttpRequestDurationInSeconds
105
- })) : undefined
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$2.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$2.concat(options.labels).sort(),
124
+ buckets: ((_options$metricBucket3 = options.metricBuckets) === null || _options$metricBucket3 === void 0 ? void 0 : _options$metricBucket3.httpRequestDurationInSeconds) || defaultHttpRequestDurationInSeconds
125
+ });
126
+ }) : undefined
106
127
  });
107
128
  const getHttpRequestCounterMetric = options => ({
108
129
  httpRequestsTotal: shouldObserveHttpRequestsAsCounter(options) ? asArray$2(options.metricNames.httpRequestsTotal).map(nameOfHttpRequestsTotalMetric => new Prometheus__namespace.Counter({
@@ -142,33 +163,52 @@ const defaultOptions$3 = {
142
163
  graphQlResolveFieldDuration: ['graphql_resolve_field_duration_seconds'],
143
164
  graphQlRequestDuration: ['graphql_request_duration_seconds'],
144
165
  graphQlErrorsTotal: ['graphql_errors_total']
166
+ },
167
+ metricPercentiles: {
168
+ graphQlParseDuration: defaultGraphQlPercentiles,
169
+ graphQlValidationDuration: defaultGraphQlPercentiles,
170
+ graphQlResolveFieldDuration: defaultGraphQlPercentiles,
171
+ graphQlRequestDuration: defaultGraphQlPercentiles,
172
+ graphQlErrorsTotal: defaultGraphQlPercentiles
145
173
  }
146
174
  };
147
175
  const getMetrics$1 = options => ({
148
- graphQlParseDuration: shouldObserveGraphQlParseDurationAsHistogram(options) ? asArray$1(options.metricNames.graphQlParseDuration).map(nameOfGraphQlParseDuration => new Prometheus__namespace.Histogram({
149
- name: `${options.metricPrefix}${nameOfGraphQlParseDuration}`,
150
- help: 'The GraphQL request parse time in seconds.',
151
- labelNames: defaultLabels$1.concat(options.labels).sort(),
152
- buckets: options.buckets || defaultGraphQlPercentiles
153
- })) : undefined,
154
- graphQlValidationDuration: shouldObserveGraphQlValidationDurationAsHistogram(options) ? asArray$1(options.metricNames.graphQlValidationDuration).map(nameOfGraphQlValidationDuration => new Prometheus__namespace.Histogram({
155
- name: `${options.metricPrefix}${nameOfGraphQlValidationDuration}`,
156
- help: 'The GraphQL request validation time in seconds.',
157
- labelNames: defaultLabels$1.concat(options.labels).sort(),
158
- buckets: options.buckets || defaultGraphQlPercentiles
159
- })) : undefined,
160
- graphQlResolveFieldDuration: shouldObserveGraphQlResolveFieldDurationAsHistogram(options) ? asArray$1(options.metricNames.graphQlResolveFieldDuration).map(nameOfGraphQlResolveFieldDuration => new Prometheus__namespace.Histogram({
161
- name: `${options.metricPrefix}${nameOfGraphQlResolveFieldDuration}`,
162
- help: 'The GraphQL field resolving time in seconds.',
163
- labelNames: defaultLabels$1.concat(['field_name']).concat(options.labels).sort(),
164
- buckets: options.buckets || defaultGraphQlPercentiles
165
- })) : undefined,
166
- graphQlRequestDuration: shouldObserveGraphQlRequestDurationAsHistogram(options) ? asArray$1(options.metricNames.graphQlRequestDuration).map(nameOfGraphQlRequestDuration => new Prometheus__namespace.Histogram({
167
- name: `${options.metricPrefix}${nameOfGraphQlRequestDuration}`,
168
- help: 'The GraphQL request duration time in seconds.',
169
- labelNames: defaultLabels$1.concat(options.labels).sort(),
170
- buckets: options.buckets || defaultGraphQlPercentiles
171
- })) : undefined,
176
+ graphQlParseDuration: shouldObserveGraphQlParseDurationAsHistogram(options) ? asArray$1(options.metricNames.graphQlParseDuration).map(nameOfGraphQlParseDuration => {
177
+ var _options$metricPercen;
178
+ return new Prometheus__namespace.Histogram({
179
+ name: `${options.metricPrefix}${nameOfGraphQlParseDuration}`,
180
+ help: 'The GraphQL request parse time in seconds.',
181
+ labelNames: defaultLabels$1.concat(options.labels).sort(),
182
+ buckets: ((_options$metricPercen = options.metricPercentiles) === null || _options$metricPercen === void 0 ? void 0 : _options$metricPercen.graphQlParseDuration) || defaultGraphQlPercentiles
183
+ });
184
+ }) : undefined,
185
+ graphQlValidationDuration: shouldObserveGraphQlValidationDurationAsHistogram(options) ? asArray$1(options.metricNames.graphQlValidationDuration).map(nameOfGraphQlValidationDuration => {
186
+ var _options$metricPercen2;
187
+ return new Prometheus__namespace.Histogram({
188
+ name: `${options.metricPrefix}${nameOfGraphQlValidationDuration}`,
189
+ help: 'The GraphQL request validation time in seconds.',
190
+ labelNames: defaultLabels$1.concat(options.labels).sort(),
191
+ buckets: ((_options$metricPercen2 = options.metricPercentiles) === null || _options$metricPercen2 === void 0 ? void 0 : _options$metricPercen2.graphQlValidationDuration) || defaultGraphQlPercentiles
192
+ });
193
+ }) : undefined,
194
+ graphQlResolveFieldDuration: shouldObserveGraphQlResolveFieldDurationAsHistogram(options) ? asArray$1(options.metricNames.graphQlResolveFieldDuration).map(nameOfGraphQlResolveFieldDuration => {
195
+ var _options$metricPercen3;
196
+ return new Prometheus__namespace.Histogram({
197
+ name: `${options.metricPrefix}${nameOfGraphQlResolveFieldDuration}`,
198
+ help: 'The GraphQL field resolving time in seconds.',
199
+ labelNames: defaultLabels$1.concat(['field_name']).concat(options.labels).sort(),
200
+ buckets: ((_options$metricPercen3 = options.metricPercentiles) === null || _options$metricPercen3 === void 0 ? void 0 : _options$metricPercen3.graphQlResolveFieldDuration) || defaultGraphQlPercentiles
201
+ });
202
+ }) : undefined,
203
+ graphQlRequestDuration: shouldObserveGraphQlRequestDurationAsHistogram(options) ? asArray$1(options.metricNames.graphQlRequestDuration).map(nameOfGraphQlRequestDuration => {
204
+ var _options$metricPercen4;
205
+ return new Prometheus__namespace.Histogram({
206
+ name: `${options.metricPrefix}${nameOfGraphQlRequestDuration}`,
207
+ help: 'The GraphQL request duration time in seconds.',
208
+ labelNames: defaultLabels$1.concat(options.labels).sort(),
209
+ buckets: ((_options$metricPercen4 = options.metricPercentiles) === null || _options$metricPercen4 === void 0 ? void 0 : _options$metricPercen4.graphQlRequestDuration) || defaultGraphQlPercentiles
210
+ });
211
+ }) : undefined,
172
212
  graphQlErrorsTotal: shouldObserveGraphQlErrorsTotalAsCounter(options) ? asArray$1(options.metricNames.graphQlErrorsTotal).map(nameOfGraphQlErrorsCount => new Prometheus__namespace.Counter({
173
213
  name: `${options.metricPrefix}${nameOfGraphQlErrorsCount}`,
174
214
  help: 'Count of errors while parsing, validating, or executing a GraphQL operation.',
@@ -256,7 +296,6 @@ function endMeasurementFrom(start) {
256
296
  }
257
297
 
258
298
  const defaultOptions$1 = {
259
- skip: () => false,
260
299
  detectKubernetes: false
261
300
  };
262
301
  function isTiming(timing) {
@@ -325,6 +364,7 @@ const createGcObserver = once__default["default"]((metrics, options) => () => {
325
364
  }
326
365
  if (options.disableGcMetrics) return;
327
366
  gc().on('stats', stats => {
367
+ // @ts-expect-error
328
368
  const gcType = gcTypes[stats.gctype];
329
369
  metrics.countOfGcs.forEach(countOfGcMetricType => {
330
370
  countOfGcMetricType.labels(gcType).inc();
@@ -339,12 +379,18 @@ const createGcObserver = once__default["default"]((metrics, options) => () => {
339
379
  }
340
380
  });
341
381
  });
382
+
383
+ // @ts-expect-error
342
384
  createGcObserver.defaultOptions = defaultOptions;
343
385
 
344
386
  const normalizeStatusCode = statusCode => statusCode;
345
387
 
346
388
  const urlValueParser = new UrlValueParser__default["default"]();
347
- const normalizePath = path => urlValueParser.replacePathValues(url__default["default"].parse(path).pathname, '#val');
389
+ const normalizePath = path => {
390
+ const parsedPathname = url__default["default"].parse(path).pathname;
391
+ if (!parsedPathname) return '';
392
+ return urlValueParser.replacePathValues(parsedPathname, '#val');
393
+ };
348
394
 
349
395
  const normalizeMethod = method => method.toLowerCase();
350
396
 
@@ -405,3 +451,9 @@ exports.normalizeStatusCode = normalizeStatusCode;
405
451
  exports.skipMetricsInEnvironment = skipMetricsInEnvironment;
406
452
  exports.sortLabels = sortLabels;
407
453
  exports.timing = timing;
454
+ Object.keys(types).forEach(function (k) {
455
+ if (k !== 'default' && !exports.hasOwnProperty(k)) Object.defineProperty(exports, k, {
456
+ enumerable: true,
457
+ get: function () { return types[k]; }
458
+ });
459
+ });
@@ -8,6 +8,7 @@ var merge = require('merge-options');
8
8
  var requireOptional = require('optional');
9
9
  var url = require('url');
10
10
  var UrlValueParser = require('url-value-parser');
11
+ var types = require('@promster/types');
11
12
 
12
13
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
13
14
 
@@ -74,35 +75,55 @@ const defaultOptions$4 = {
74
75
  httpRequestDurationInSeconds: ['http_request_duration_seconds'],
75
76
  httpRequestContentLengthInBytes: ['http_request_content_length_bytes'],
76
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
77
86
  }
78
87
  };
79
88
  const getMetrics$2 = options => ({
80
- httpRequestContentLengthInBytes: shouldObserveHttpContentLengthAsHistogram(options) ? asArray$2(options.metricNames.httpRequestContentLengthInBytes).map(nameOfHttpContentLengthMetric => new Prometheus__namespace.Histogram({
81
- name: `${options.metricPrefix}${nameOfHttpContentLengthMetric}`,
82
- help: 'The HTTP request content length in bytes.',
83
- labelNames: defaultLabels$2.concat(options.labels).sort(),
84
- buckets: options.buckets || defaultHttpContentLengthInBytes
85
- })) : undefined,
86
- httpResponseContentLengthInBytes: shouldObserveHttpContentLengthAsHistogram(options) ? asArray$2(options.metricNames.httpResponseContentLengthInBytes).map(nameOfHttpContentLengthMetric => new Prometheus__namespace.Histogram({
87
- name: `${options.metricPrefix}${nameOfHttpContentLengthMetric}`,
88
- help: 'The HTTP response content length in bytes.',
89
- labelNames: defaultLabels$2.concat(options.labels).sort(),
90
- buckets: options.buckets || defaultHttpContentLengthInBytes
91
- })) : undefined
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$2.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$2.concat(options.labels).sort(),
104
+ buckets: ((_options$metricBucket2 = options.metricBuckets) === null || _options$metricBucket2 === void 0 ? void 0 : _options$metricBucket2.httpResponseContentLengthInBytes) || defaultHttpContentLengthInBytes
105
+ });
106
+ }) : undefined
92
107
  });
93
108
  const getHttpRequestLatencyMetricsInSeconds = options => ({
94
- httpRequestDurationPerPercentileInSeconds: shouldObserveHttpRequestsAsSummary(options) ? asArray$2(options.metricNames.httpRequestDurationPerPercentileInSeconds).map(nameOfHttpRequestDurationPerPercentileInSeconds => new Prometheus__namespace.Summary({
95
- name: `${options.metricPrefix}${nameOfHttpRequestDurationPerPercentileInSeconds}`,
96
- help: 'The HTTP request latencies in seconds.',
97
- labelNames: defaultLabels$2.concat(options.labels).sort(),
98
- percentiles: options.percentiles || defaultHttpRequestDurationPercentileInSeconds
99
- })) : undefined,
100
- httpRequestDurationInSeconds: shouldObserveHttpRequestsAsHistogram(options) ? asArray$2(options.metricNames.httpRequestDurationInSeconds).map(nameOfHttpRequestDurationInSecondsMetric => new Prometheus__namespace.Histogram({
101
- name: `${options.metricPrefix}${nameOfHttpRequestDurationInSecondsMetric}`,
102
- help: 'The HTTP request latencies in seconds.',
103
- labelNames: defaultLabels$2.concat(options.labels).sort(),
104
- buckets: options.buckets || defaultHttpRequestDurationInSeconds
105
- })) : undefined
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$2.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$2.concat(options.labels).sort(),
124
+ buckets: ((_options$metricBucket3 = options.metricBuckets) === null || _options$metricBucket3 === void 0 ? void 0 : _options$metricBucket3.httpRequestDurationInSeconds) || defaultHttpRequestDurationInSeconds
125
+ });
126
+ }) : undefined
106
127
  });
107
128
  const getHttpRequestCounterMetric = options => ({
108
129
  httpRequestsTotal: shouldObserveHttpRequestsAsCounter(options) ? asArray$2(options.metricNames.httpRequestsTotal).map(nameOfHttpRequestsTotalMetric => new Prometheus__namespace.Counter({
@@ -142,33 +163,52 @@ const defaultOptions$3 = {
142
163
  graphQlResolveFieldDuration: ['graphql_resolve_field_duration_seconds'],
143
164
  graphQlRequestDuration: ['graphql_request_duration_seconds'],
144
165
  graphQlErrorsTotal: ['graphql_errors_total']
166
+ },
167
+ metricPercentiles: {
168
+ graphQlParseDuration: defaultGraphQlPercentiles,
169
+ graphQlValidationDuration: defaultGraphQlPercentiles,
170
+ graphQlResolveFieldDuration: defaultGraphQlPercentiles,
171
+ graphQlRequestDuration: defaultGraphQlPercentiles,
172
+ graphQlErrorsTotal: defaultGraphQlPercentiles
145
173
  }
146
174
  };
147
175
  const getMetrics$1 = options => ({
148
- graphQlParseDuration: shouldObserveGraphQlParseDurationAsHistogram(options) ? asArray$1(options.metricNames.graphQlParseDuration).map(nameOfGraphQlParseDuration => new Prometheus__namespace.Histogram({
149
- name: `${options.metricPrefix}${nameOfGraphQlParseDuration}`,
150
- help: 'The GraphQL request parse time in seconds.',
151
- labelNames: defaultLabels$1.concat(options.labels).sort(),
152
- buckets: options.buckets || defaultGraphQlPercentiles
153
- })) : undefined,
154
- graphQlValidationDuration: shouldObserveGraphQlValidationDurationAsHistogram(options) ? asArray$1(options.metricNames.graphQlValidationDuration).map(nameOfGraphQlValidationDuration => new Prometheus__namespace.Histogram({
155
- name: `${options.metricPrefix}${nameOfGraphQlValidationDuration}`,
156
- help: 'The GraphQL request validation time in seconds.',
157
- labelNames: defaultLabels$1.concat(options.labels).sort(),
158
- buckets: options.buckets || defaultGraphQlPercentiles
159
- })) : undefined,
160
- graphQlResolveFieldDuration: shouldObserveGraphQlResolveFieldDurationAsHistogram(options) ? asArray$1(options.metricNames.graphQlResolveFieldDuration).map(nameOfGraphQlResolveFieldDuration => new Prometheus__namespace.Histogram({
161
- name: `${options.metricPrefix}${nameOfGraphQlResolveFieldDuration}`,
162
- help: 'The GraphQL field resolving time in seconds.',
163
- labelNames: defaultLabels$1.concat(['field_name']).concat(options.labels).sort(),
164
- buckets: options.buckets || defaultGraphQlPercentiles
165
- })) : undefined,
166
- graphQlRequestDuration: shouldObserveGraphQlRequestDurationAsHistogram(options) ? asArray$1(options.metricNames.graphQlRequestDuration).map(nameOfGraphQlRequestDuration => new Prometheus__namespace.Histogram({
167
- name: `${options.metricPrefix}${nameOfGraphQlRequestDuration}`,
168
- help: 'The GraphQL request duration time in seconds.',
169
- labelNames: defaultLabels$1.concat(options.labels).sort(),
170
- buckets: options.buckets || defaultGraphQlPercentiles
171
- })) : undefined,
176
+ graphQlParseDuration: shouldObserveGraphQlParseDurationAsHistogram(options) ? asArray$1(options.metricNames.graphQlParseDuration).map(nameOfGraphQlParseDuration => {
177
+ var _options$metricPercen;
178
+ return new Prometheus__namespace.Histogram({
179
+ name: `${options.metricPrefix}${nameOfGraphQlParseDuration}`,
180
+ help: 'The GraphQL request parse time in seconds.',
181
+ labelNames: defaultLabels$1.concat(options.labels).sort(),
182
+ buckets: ((_options$metricPercen = options.metricPercentiles) === null || _options$metricPercen === void 0 ? void 0 : _options$metricPercen.graphQlParseDuration) || defaultGraphQlPercentiles
183
+ });
184
+ }) : undefined,
185
+ graphQlValidationDuration: shouldObserveGraphQlValidationDurationAsHistogram(options) ? asArray$1(options.metricNames.graphQlValidationDuration).map(nameOfGraphQlValidationDuration => {
186
+ var _options$metricPercen2;
187
+ return new Prometheus__namespace.Histogram({
188
+ name: `${options.metricPrefix}${nameOfGraphQlValidationDuration}`,
189
+ help: 'The GraphQL request validation time in seconds.',
190
+ labelNames: defaultLabels$1.concat(options.labels).sort(),
191
+ buckets: ((_options$metricPercen2 = options.metricPercentiles) === null || _options$metricPercen2 === void 0 ? void 0 : _options$metricPercen2.graphQlValidationDuration) || defaultGraphQlPercentiles
192
+ });
193
+ }) : undefined,
194
+ graphQlResolveFieldDuration: shouldObserveGraphQlResolveFieldDurationAsHistogram(options) ? asArray$1(options.metricNames.graphQlResolveFieldDuration).map(nameOfGraphQlResolveFieldDuration => {
195
+ var _options$metricPercen3;
196
+ return new Prometheus__namespace.Histogram({
197
+ name: `${options.metricPrefix}${nameOfGraphQlResolveFieldDuration}`,
198
+ help: 'The GraphQL field resolving time in seconds.',
199
+ labelNames: defaultLabels$1.concat(['field_name']).concat(options.labels).sort(),
200
+ buckets: ((_options$metricPercen3 = options.metricPercentiles) === null || _options$metricPercen3 === void 0 ? void 0 : _options$metricPercen3.graphQlResolveFieldDuration) || defaultGraphQlPercentiles
201
+ });
202
+ }) : undefined,
203
+ graphQlRequestDuration: shouldObserveGraphQlRequestDurationAsHistogram(options) ? asArray$1(options.metricNames.graphQlRequestDuration).map(nameOfGraphQlRequestDuration => {
204
+ var _options$metricPercen4;
205
+ return new Prometheus__namespace.Histogram({
206
+ name: `${options.metricPrefix}${nameOfGraphQlRequestDuration}`,
207
+ help: 'The GraphQL request duration time in seconds.',
208
+ labelNames: defaultLabels$1.concat(options.labels).sort(),
209
+ buckets: ((_options$metricPercen4 = options.metricPercentiles) === null || _options$metricPercen4 === void 0 ? void 0 : _options$metricPercen4.graphQlRequestDuration) || defaultGraphQlPercentiles
210
+ });
211
+ }) : undefined,
172
212
  graphQlErrorsTotal: shouldObserveGraphQlErrorsTotalAsCounter(options) ? asArray$1(options.metricNames.graphQlErrorsTotal).map(nameOfGraphQlErrorsCount => new Prometheus__namespace.Counter({
173
213
  name: `${options.metricPrefix}${nameOfGraphQlErrorsCount}`,
174
214
  help: 'Count of errors while parsing, validating, or executing a GraphQL operation.',
@@ -256,7 +296,6 @@ function endMeasurementFrom(start) {
256
296
  }
257
297
 
258
298
  const defaultOptions$1 = {
259
- skip: () => false,
260
299
  detectKubernetes: false
261
300
  };
262
301
  function isTiming(timing) {
@@ -325,6 +364,7 @@ const createGcObserver = once__default["default"]((metrics, options) => () => {
325
364
  }
326
365
  if (options.disableGcMetrics) return;
327
366
  gc().on('stats', stats => {
367
+ // @ts-expect-error
328
368
  const gcType = gcTypes[stats.gctype];
329
369
  metrics.countOfGcs.forEach(countOfGcMetricType => {
330
370
  countOfGcMetricType.labels(gcType).inc();
@@ -339,12 +379,18 @@ const createGcObserver = once__default["default"]((metrics, options) => () => {
339
379
  }
340
380
  });
341
381
  });
382
+
383
+ // @ts-expect-error
342
384
  createGcObserver.defaultOptions = defaultOptions;
343
385
 
344
386
  const normalizeStatusCode = statusCode => statusCode;
345
387
 
346
388
  const urlValueParser = new UrlValueParser__default["default"]();
347
- const normalizePath = path => urlValueParser.replacePathValues(url__default["default"].parse(path).pathname, '#val');
389
+ const normalizePath = path => {
390
+ const parsedPathname = url__default["default"].parse(path).pathname;
391
+ if (!parsedPathname) return '';
392
+ return urlValueParser.replacePathValues(parsedPathname, '#val');
393
+ };
348
394
 
349
395
  const normalizeMethod = method => method.toLowerCase();
350
396
 
@@ -405,3 +451,9 @@ exports.normalizeStatusCode = normalizeStatusCode;
405
451
  exports.skipMetricsInEnvironment = skipMetricsInEnvironment;
406
452
  exports.sortLabels = sortLabels;
407
453
  exports.timing = timing;
454
+ Object.keys(types).forEach(function (k) {
455
+ if (k !== 'default' && !exports.hasOwnProperty(k)) Object.defineProperty(exports, k, {
456
+ enumerable: true,
457
+ get: function () { return types[k]; }
458
+ });
459
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promster/metrics",
3
- "version": "10.0.0",
3
+ "version": "12.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",
@@ -16,7 +16,7 @@
16
16
  "access": "public"
17
17
  },
18
18
  "engines": {
19
- "node": ">=16",
19
+ "node": ">=18",
20
20
  "npm": ">=8"
21
21
  },
22
22
  "repository": {
@@ -36,24 +36,24 @@
36
36
  "prometheus"
37
37
  ],
38
38
  "dependencies": {
39
+ "@promster/types": "^12.0.0",
39
40
  "lodash.memoize": "4.1.2",
40
41
  "lodash.once": "4.1.1",
41
42
  "merge-options": "3.0.4",
42
43
  "optional": "0.1.4",
43
- "ts-essentials": "9.3.2",
44
- "tslib": "2.4.1",
44
+ "tslib": "2.6.2",
45
45
  "url-value-parser": "2.2.0"
46
46
  },
47
47
  "devDependencies": {
48
- "@promster/types": "^4.0.0",
49
- "@types/lodash": "4.14.197",
50
- "prom-client": "14.2.0",
51
- "typescript": "4.9.5"
48
+ "prom-client": "15.0.0",
49
+ "typescript": "5.2.2",
50
+ "@types/node": "18.17.19",
51
+ "@types/lodash.once": "4.1.7"
52
52
  },
53
53
  "optionalDependencies": {
54
54
  "@sematext/gc-stats": "1.5.9"
55
55
  },
56
56
  "peerDependencies": {
57
- "prom-client": "13.x.x || 14.x"
57
+ "prom-client": "13.x.x || 14.x || 15.x"
58
58
  }
59
59
  }