@lokalise/prisma-utils 3.2.0 → 3.2.2

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.
@@ -12,8 +12,8 @@ class PromiseBasedCollectionScheduler {
12
12
  }
13
13
  async start() {
14
14
  while (this.active) {
15
- await this.collect();
16
15
  await (0, promises_1.setTimeout)(this.collectionIntervalInMs);
16
+ await this.collect();
17
17
  }
18
18
  }
19
19
  stop() {
@@ -5,7 +5,7 @@ export type PrometheusMetricsDefinitions = {
5
5
  counters: Record<string, prometheus.Counter<'prisma' | 'connection-pool'>>;
6
6
  gauges: Record<string, prometheus.Gauge<'prisma' | 'connection-pool'>>;
7
7
  histograms: Record<string, prometheus.Histogram<'prisma' | 'connection-pool'>>;
8
- names: string[];
8
+ keys: string[];
9
9
  };
10
10
  export type MetricCollectorOptions = {
11
11
  metricsPrefix: string;
@@ -15,17 +15,22 @@ export declare class MetricsCollector {
15
15
  private readonly options;
16
16
  private readonly registry;
17
17
  private readonly logger;
18
- private metrics?;
18
+ private metrics;
19
19
  constructor(prisma: PrismaClient, options: MetricCollectorOptions, registry: prometheus.Registry, logger: FastifyBaseLogger);
20
20
  /**
21
- * Updates metrics for prisma
21
+ * Updates metrics for prisma.
22
+ * If metric was not registered before it will be registered here.
22
23
  */
23
- collect(): Promise<void>;
24
+ collect(prefix: string): Promise<void>;
25
+ private registerNewMetrics;
24
26
  /**
25
27
  * Stops the metrics collection and cleans up resources
26
28
  */
27
29
  dispose(): Promise<void>;
28
30
  private registerMetrics;
31
+ /**
32
+ * If metrics are already registered, we just return them to avoid triggering a Prometheus error.
33
+ */
29
34
  private getRegisteredMetrics;
30
35
  private getJsonMetrics;
31
36
  }
@@ -8,7 +8,7 @@ function registerMetrics(_prefix, jsonMetrics) {
8
8
  counters: {},
9
9
  gauges: {},
10
10
  histograms: {},
11
- names: [],
11
+ keys: [],
12
12
  };
13
13
  for (const metric of jsonMetrics.counters) {
14
14
  metrics.counters[metric.key] = new prometheus.Counter({
@@ -16,7 +16,7 @@ function registerMetrics(_prefix, jsonMetrics) {
16
16
  help: metric.description,
17
17
  labelNames: ['prisma', 'connection_pool'],
18
18
  });
19
- metrics.names.push(metric.key);
19
+ metrics.keys.push(metric.key);
20
20
  }
21
21
  for (const metric of jsonMetrics.gauges) {
22
22
  metrics.gauges[metric.key] = new prometheus.Gauge({
@@ -24,7 +24,7 @@ function registerMetrics(_prefix, jsonMetrics) {
24
24
  help: metric.description,
25
25
  labelNames: ['prisma', 'connection_pool'],
26
26
  });
27
- metrics.names.push(metric.key);
27
+ metrics.keys.push(metric.key);
28
28
  }
29
29
  for (const metric of jsonMetrics.histograms) {
30
30
  metrics.histograms[metric.key] = new prometheus.Histogram({
@@ -33,7 +33,7 @@ function registerMetrics(_prefix, jsonMetrics) {
33
33
  buckets: metric.value.buckets.filter((bucket) => bucket[1] === 0).map((bucket) => bucket[0]),
34
34
  labelNames: ['prisma', 'connection_pool'],
35
35
  });
36
- metrics.names.push(metric.key);
36
+ metrics.keys.push(metric.key);
37
37
  }
38
38
  return metrics;
39
39
  }
@@ -55,30 +55,62 @@ class MetricsCollector {
55
55
  this.options = options;
56
56
  this.registry = registry;
57
57
  this.logger = logger;
58
+ this.metrics = {
59
+ counters: {},
60
+ gauges: {},
61
+ histograms: {},
62
+ keys: [],
63
+ };
58
64
  this.registerMetrics(this.registry, this.options).then((result) => {
59
65
  this.metrics = result;
66
+ this.logger.debug({}, `Prisma metrics registered ${result.keys}`);
60
67
  });
61
68
  }
62
69
  /**
63
- * Updates metrics for prisma
70
+ * Updates metrics for prisma.
71
+ * If metric was not registered before it will be registered here.
64
72
  */
65
- async collect() {
66
- if (!this.metrics) {
67
- return;
68
- }
73
+ async collect(prefix) {
69
74
  try {
75
+ const nonRegisteredMetrics = {
76
+ counters: [],
77
+ gauges: [],
78
+ histograms: [],
79
+ };
70
80
  const jsonMetrics = await this.getJsonMetrics();
71
81
  for (const counterMetric of jsonMetrics.counters) {
82
+ const existingMetric = this.metrics.counters[counterMetric.key];
83
+ /* c8 ignore start */
84
+ if (!existingMetric) {
85
+ nonRegisteredMetrics.counters.push(counterMetric);
86
+ continue;
87
+ }
88
+ /* c8 ignore stop */
72
89
  // we need to reset counter since prisma returns already the accumulated counter value
73
- this.metrics.counters[counterMetric.key].reset();
74
- this.metrics.counters[counterMetric.key].inc(counterMetric.value);
90
+ existingMetric.reset();
91
+ existingMetric.inc(counterMetric.value);
75
92
  }
76
93
  for (const gaugeMetric of jsonMetrics.gauges) {
77
- this.metrics.gauges[gaugeMetric.key].set(gaugeMetric.value);
94
+ const existingMetric = this.metrics.gauges[gaugeMetric.key];
95
+ /* c8 ignore start */
96
+ if (!existingMetric) {
97
+ nonRegisteredMetrics.gauges.push(gaugeMetric);
98
+ continue;
99
+ }
100
+ /* c8 ignore stop */
101
+ existingMetric.set(gaugeMetric.value);
78
102
  }
79
103
  for (const histogramMetric of jsonMetrics.histograms) {
80
- this.metrics.histograms[histogramMetric.key].observe(histogramMetric.value.count);
104
+ const existingMetric = this.metrics.histograms[histogramMetric.key];
105
+ /* c8 ignore start */
106
+ if (!existingMetric) {
107
+ nonRegisteredMetrics.histograms.push(histogramMetric);
108
+ continue;
109
+ }
110
+ /* c8 ignore stop */
111
+ existingMetric.observe(histogramMetric.value.count);
81
112
  }
113
+ this.registerNewMetrics(prefix, nonRegisteredMetrics);
82
114
  }
83
115
  catch (err) {
84
116
  /* c8 ignore start */
@@ -86,6 +118,26 @@ class MetricsCollector {
86
118
  }
87
119
  /* c8 ignore stop */
88
120
  }
121
+ registerNewMetrics(prefix, nonRegisteredMetrics) {
122
+ if (!nonRegisteredMetrics.counters.length &&
123
+ !nonRegisteredMetrics.gauges.length &&
124
+ !nonRegisteredMetrics.histograms.length) {
125
+ return;
126
+ }
127
+ /* c8 ignore start */
128
+ const newMetrics = registerMetrics(prefix, nonRegisteredMetrics);
129
+ for (const [key, value] of Object.entries(newMetrics.counters)) {
130
+ this.metrics.counters[key] = value;
131
+ }
132
+ for (const [key, value] of Object.entries(newMetrics.gauges)) {
133
+ this.metrics.gauges[key] = value;
134
+ }
135
+ for (const [key, value] of Object.entries(newMetrics.histograms)) {
136
+ this.metrics.histograms[key] = value;
137
+ }
138
+ this.logger.debug({}, `Prisma metrics registered ${newMetrics.keys}`);
139
+ /* c8 ignore stop */
140
+ }
89
141
  /**
90
142
  * Stops the metrics collection and cleans up resources
91
143
  */
@@ -93,7 +145,6 @@ class MetricsCollector {
93
145
  async registerMetrics(registry, { metricsPrefix }) {
94
146
  const jsonMetrics = await this.getJsonMetrics();
95
147
  const metricNames = getMetricKeys(metricsPrefix, jsonMetrics);
96
- // If metrics are already registered, just return them to avoid triggering a Prometheus error
97
148
  const existingMetrics = this.getRegisteredMetrics(registry, metricNames);
98
149
  if (existingMetrics) {
99
150
  /* c8 ignore start */
@@ -102,8 +153,10 @@ class MetricsCollector {
102
153
  /* c8 ignore stop */
103
154
  return registerMetrics(metricsPrefix, jsonMetrics);
104
155
  }
156
+ /**
157
+ * If metrics are already registered, we just return them to avoid triggering a Prometheus error.
158
+ */
105
159
  getRegisteredMetrics(registry, metricNames) {
106
- // If metrics are already registered, just return them to avoid triggering a Prometheus error
107
160
  if (!metricNames.length || !registry.getSingleMetric(metricNames[0])) {
108
161
  return;
109
162
  }
@@ -20,7 +20,7 @@ function plugin(fastify, pluginOptions, next) {
20
20
  };
21
21
  try {
22
22
  const collector = new MetricsCollector_1.MetricsCollector(options.prisma, options, fastify.metrics.client.register, fastify.log);
23
- const collectFn = async () => await collector.collect();
23
+ const collectFn = async () => await collector.collect(options.metricsPrefix);
24
24
  let scheduler;
25
25
  if (options.collectionOptions.type === 'interval') {
26
26
  scheduler = new CollectionScheduler_1.PromiseBasedCollectionScheduler(options.collectionOptions.intervalInMs, collectFn);
@@ -37,14 +37,14 @@ function plugin(fastify, pluginOptions, next) {
37
37
  collect: collectFn,
38
38
  });
39
39
  next();
40
+ /* c8 ignore start */
40
41
  }
41
42
  catch (err) {
42
- /* c8 ignore start */
43
43
  return next(err instanceof Error
44
44
  ? err
45
45
  : new Error('Unknown error in prisma-metrics-plugin', { cause: err }));
46
- /* c8 ignore stop */
47
46
  }
47
+ /* c8 ignore stop */
48
48
  }
49
49
  exports.prismaMetricsPlugin = (0, fastify_plugin_1.default)(plugin, {
50
50
  fastify: '5.x',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lokalise/prisma-utils",
3
- "version": "3.2.0",
3
+ "version": "3.2.2",
4
4
  "type": "commonjs",
5
5
  "license": "Apache-2.0",
6
6
  "files": ["dist", "README.md", "LICENSE.md"],
@@ -34,21 +34,21 @@
34
34
  "@lokalise/node-core": "^13.1.0"
35
35
  },
36
36
  "peerDependencies": {
37
- "@prisma/client": "^5.0.0",
38
- "prisma": "^5.0.0"
37
+ "@prisma/client": ">=5.0.0 <7.0.0",
38
+ "prisma": ">=5.0.0 <7.0.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@biomejs/biome": "^1.9.4",
42
42
  "@lokalise/biome-config": "^1.5.0",
43
43
  "@lokalise/backend-http-client": "^2.3.0",
44
44
  "@lokalise/fastify-extras": "^25.0.0",
45
- "@prisma/client": "^5.21.1",
45
+ "@prisma/client": "^6.0.1",
46
46
  "@vitest/coverage-v8": "^2.1.3",
47
47
  "cross-env": "^7.0.3",
48
48
  "dotenv-cli": "^7.4.1",
49
- "prisma": "^5.21.1",
49
+ "prisma": "^6.0.1",
50
50
  "rimraf": "^6.0.1",
51
- "typescript": "5.6.3",
51
+ "typescript": "5.7.2",
52
52
  "vitest": "^2.1.3"
53
53
  }
54
54
  }