@vtex/api 7.3.0 → 7.3.1-beta.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.
@@ -7,6 +7,21 @@ import { Attributes } from '@opentelemetry/api';
7
7
  * Uses a single histogram for all latency measurements with attributes to differentiate.
8
8
  * This follows OpenTelemetry best practices and reduces metric cardinality.
9
9
  *
10
+ * ## Base Attributes (Request Context)
11
+ *
12
+ * DiagnosticsMetrics supports automatic merging of request-scoped "base attributes"
13
+ * with custom attributes provided in each metric call. This is useful for automatically
14
+ * including request context (account, status_code, route_id, etc.) in all metrics
15
+ * recorded during a request lifecycle.
16
+ *
17
+ * Use `runWithBaseAttributes()` to set base attributes for a scope. All metric calls
18
+ * within that scope will automatically include these base attributes, merged with
19
+ * any custom attributes provided.
20
+ *
21
+ * **Important:** Base attributes take precedence over custom attributes. If a custom
22
+ * attribute has the same key as a base attribute, the custom attribute is silently
23
+ * dropped and the base attribute value is used.
24
+ *
10
25
  * @example
11
26
  * ```typescript
12
27
  * const diagnosticsMetrics = new DiagnosticsMetrics()
@@ -25,6 +40,16 @@ import { Attributes } from '@opentelemetry/api';
25
40
  *
26
41
  * // Set a gauge value
27
42
  * diagnosticsMetrics.setGauge('cache_items_current', 1024, { cache: 'pages' })
43
+ *
44
+ * // Using base attributes for request context
45
+ * await diagnosticsMetrics.runWithBaseAttributes(
46
+ * { 'vtex.account.name': 'mystore', status_code: 200 },
47
+ * async () => {
48
+ * // All metrics recorded here will include the base attributes
49
+ * diagnosticsMetrics.recordLatency(100, { operation: 'custom-op' })
50
+ * // Result: { 'vtex.account.name': 'mystore', status_code: 200, operation: 'custom-op' }
51
+ * }
52
+ * )
28
53
  * ```
29
54
  */
30
55
  export declare class DiagnosticsMetrics {
@@ -44,13 +69,69 @@ export declare class DiagnosticsMetrics {
44
69
  * Called after metric client is initialized.
45
70
  */
46
71
  private createLatencyHistogram;
72
+ /**
73
+ * Execute a function with base attributes set in the OpenTelemetry context.
74
+ * All metric calls within the function will automatically include these base attributes,
75
+ * merged with any custom attributes provided in each call.
76
+ *
77
+ * Base attributes take precedence over custom attributes when there are key conflicts.
78
+ * Conflicting custom attributes are silently dropped.
79
+ *
80
+ * @param baseAttributes Base attributes to include in all metrics within the scope
81
+ * @param fn Function to execute with the base attributes context
82
+ * @returns The return value of the function
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * // In a request middleware
87
+ * await diagnosticsMetrics.runWithBaseAttributes(
88
+ * {
89
+ * 'vtex.account.name': ctx.vtex.account,
90
+ * status_code: ctx.status,
91
+ * route_id: ctx.vtex.route.id,
92
+ * },
93
+ * async () => {
94
+ * await next()
95
+ * }
96
+ * )
97
+ *
98
+ * // In app code (custom attributes are merged with base)
99
+ * diagnosticsMetrics.recordLatency(elapsed, { operation: 'my-operation', status: 'success' })
100
+ * // Result includes both base attributes AND custom attributes
101
+ * ```
102
+ */
103
+ runWithBaseAttributes<T>(baseAttributes: Attributes, fn: () => T): T;
104
+ /**
105
+ * Get the base attributes from the current OpenTelemetry context.
106
+ * Returns undefined if no base attributes are set.
107
+ */
108
+ private getBaseAttributes;
109
+ /**
110
+ * Merge base attributes from context with provided custom attributes.
111
+ * Base attributes take precedence over custom attributes when there are key conflicts.
112
+ *
113
+ * Custom attributes are limited to MAX_CUSTOM_ATTRIBUTES before merging.
114
+ * Custom attributes with keys that conflict with base attributes are silently dropped.
115
+ * Base attributes are not limited.
116
+ *
117
+ * @param customAttributes Custom attributes provided by the caller
118
+ * @returns Merged attributes (base + non-conflicting limited custom) or undefined if both are empty
119
+ */
120
+ private mergeAttributes;
47
121
  /**
48
122
  * Record a latency measurement using the single shared histogram.
49
123
  * Accepts either an hrtime tuple from process.hrtime() or milliseconds as a number.
50
124
  * Use attributes to differentiate between different operations.
51
125
  *
126
+ * Base attributes from the current context (set via `runWithBaseAttributes`) are
127
+ * automatically merged with the provided custom attributes. Base attributes take
128
+ * precedence - if a custom attribute key conflicts with a base attribute key,
129
+ * the custom attribute is silently dropped.
130
+ *
131
+ * Custom attributes are limited to MAX_CUSTOM_ATTRIBUTES (5). Base attributes are not limited.
132
+ *
52
133
  * @param value Either [seconds, nanoseconds] from process.hrtime() or milliseconds
53
- * @param attributes Attributes including 'operation' to identify the operation type (max of MAX_ATTRIBUTES attributes)
134
+ * @param attributes Custom attributes including 'operation' to identify the operation type (max 5 custom attributes)
54
135
  *
55
136
  * @example
56
137
  * ```typescript
@@ -67,9 +148,16 @@ export declare class DiagnosticsMetrics {
67
148
  * Increment a counter by a specific value.
68
149
  * Multiple counters are stored by name since counters represent different types of events.
69
150
  *
151
+ * Base attributes from the current context (set via `runWithBaseAttributes`) are
152
+ * automatically merged with the provided custom attributes. Base attributes take
153
+ * precedence - if a custom attribute key conflicts with a base attribute key,
154
+ * the custom attribute is silently dropped.
155
+ *
156
+ * Custom attributes are limited to MAX_CUSTOM_ATTRIBUTES (5). Base attributes are not limited.
157
+ *
70
158
  * @param name Counter name (e.g., 'http_requests_total', 'cache_hits_total')
71
159
  * @param value Amount to increment by (typically 1)
72
- * @param attributes Optional attributes for the counter (max of MAX_ATTRIBUTES attributes, e.g., { method: 'GET', status: '2xx' })
160
+ * @param attributes Optional custom attributes for the counter (max 5 custom attributes, e.g., { method: 'GET', status: '2xx' })
73
161
  *
74
162
  * @example
75
163
  * ```typescript
@@ -81,9 +169,16 @@ export declare class DiagnosticsMetrics {
81
169
  * Set a gauge to a specific value (current state).
82
170
  * Multiple gauges are stored by name since gauges represent different types of measurements.
83
171
  *
172
+ * Base attributes from the current context (set via `runWithBaseAttributes`) are
173
+ * automatically merged with the provided custom attributes. Base attributes take
174
+ * precedence - if a custom attribute key conflicts with a base attribute key,
175
+ * the custom attribute is silently dropped.
176
+ *
177
+ * Custom attributes are limited to MAX_CUSTOM_ATTRIBUTES (5). Base attributes are not limited.
178
+ *
84
179
  * @param name Gauge name (e.g., 'cache_items_current', 'memory_usage_bytes')
85
180
  * @param value Current value
86
- * @param attributes Optional attributes for the gauge (max of MAX_ATTRIBUTES attributes, e.g., { cache: 'pages' })
181
+ * @param attributes Optional custom attributes for the gauge (max 5 custom attributes, e.g., { cache: 'pages' })
87
182
  *
88
183
  * @example
89
184
  * ```typescript
@@ -1,13 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DiagnosticsMetrics = void 0;
4
+ const api_1 = require("@opentelemetry/api");
4
5
  const client_1 = require("../service/metrics/client");
5
6
  const constants_1 = require("../constants");
6
7
  /**
7
- * Maximum number of attributes allowed per metric to control cardinality.
8
- * This limit applies to external usage (VTEX IO Apps) to prevent unbounded metric dimensions.
8
+ * Maximum number of custom attributes allowed per metric call to control cardinality.
9
+ * This limit applies only to custom attributes provided by callers (VTEX IO Apps).
10
+ * Base attributes (set via runWithBaseAttributes) are not counted toward this limit.
11
+ *
12
+ * Total attributes sent = base attributes + custom attributes (up to MAX_CUSTOM_ATTRIBUTES)
13
+ */
14
+ const MAX_CUSTOM_ATTRIBUTES = 5;
15
+ /**
16
+ * Context key for storing base attributes in OpenTelemetry context.
17
+ * These attributes are automatically merged with custom attributes in all metric methods.
9
18
  */
10
- const MAX_ATTRIBUTES = 7;
19
+ const BASE_ATTRIBUTES_KEY = (0, api_1.createContextKey)('vtex.metrics.baseAttributes');
11
20
  /**
12
21
  * Converts an hrtime tuple [seconds, nanoseconds] to milliseconds.
13
22
  */
@@ -15,25 +24,27 @@ function hrtimeToMillis(hrtime) {
15
24
  return (hrtime[0] * 1e3) + (hrtime[1] / 1e6);
16
25
  }
17
26
  /**
18
- * Limits the number of attributes to prevent high cardinality.
19
- * Takes the first MAX_ATTRIBUTES entries if the limit is exceeded.
27
+ * Limits the number of custom attributes to prevent high cardinality.
28
+ * Takes the first MAX_CUSTOM_ATTRIBUTES entries if the limit is exceeded.
20
29
  *
21
- * @param attributes Optional attributes object
22
- * @returns Limited attributes object or undefined
30
+ * Note: This limit applies only to custom attributes. Base attributes are not limited.
31
+ *
32
+ * @param customAttributes Optional custom attributes object
33
+ * @returns Limited custom attributes object or undefined
23
34
  */
24
- function limitAttributes(attributes) {
25
- if (!attributes) {
35
+ function limitCustomAttributes(customAttributes) {
36
+ if (!customAttributes) {
26
37
  return undefined;
27
38
  }
28
- const entries = Object.entries(attributes);
29
- if (entries.length <= MAX_ATTRIBUTES) {
30
- return attributes;
39
+ const entries = Object.entries(customAttributes);
40
+ if (entries.length <= MAX_CUSTOM_ATTRIBUTES) {
41
+ return customAttributes;
31
42
  }
32
43
  if (constants_1.LINKED) {
33
- console.warn(`Attribute limit exceeded: ${entries.length} attributes provided, using only the first ${MAX_ATTRIBUTES}. ` +
34
- `Consider reducing the number of attributes to avoid high cardinality.`);
44
+ console.warn(`Custom attribute limit exceeded: ${entries.length} custom attributes provided, using only the first ${MAX_CUSTOM_ATTRIBUTES}. ` +
45
+ `Consider reducing the number of custom attributes to avoid high cardinality. `);
35
46
  }
36
- return Object.fromEntries(entries.slice(0, MAX_ATTRIBUTES));
47
+ return Object.fromEntries(entries.slice(0, MAX_CUSTOM_ATTRIBUTES));
37
48
  }
38
49
  /**
39
50
  * DiagnosticsMetrics provides a high-level API for recording metrics using
@@ -43,6 +54,21 @@ function limitAttributes(attributes) {
43
54
  * Uses a single histogram for all latency measurements with attributes to differentiate.
44
55
  * This follows OpenTelemetry best practices and reduces metric cardinality.
45
56
  *
57
+ * ## Base Attributes (Request Context)
58
+ *
59
+ * DiagnosticsMetrics supports automatic merging of request-scoped "base attributes"
60
+ * with custom attributes provided in each metric call. This is useful for automatically
61
+ * including request context (account, status_code, route_id, etc.) in all metrics
62
+ * recorded during a request lifecycle.
63
+ *
64
+ * Use `runWithBaseAttributes()` to set base attributes for a scope. All metric calls
65
+ * within that scope will automatically include these base attributes, merged with
66
+ * any custom attributes provided.
67
+ *
68
+ * **Important:** Base attributes take precedence over custom attributes. If a custom
69
+ * attribute has the same key as a base attribute, the custom attribute is silently
70
+ * dropped and the base attribute value is used.
71
+ *
46
72
  * @example
47
73
  * ```typescript
48
74
  * const diagnosticsMetrics = new DiagnosticsMetrics()
@@ -61,6 +87,16 @@ function limitAttributes(attributes) {
61
87
  *
62
88
  * // Set a gauge value
63
89
  * diagnosticsMetrics.setGauge('cache_items_current', 1024, { cache: 'pages' })
90
+ *
91
+ * // Using base attributes for request context
92
+ * await diagnosticsMetrics.runWithBaseAttributes(
93
+ * { 'vtex.account.name': 'mystore', status_code: 200 },
94
+ * async () => {
95
+ * // All metrics recorded here will include the base attributes
96
+ * diagnosticsMetrics.recordLatency(100, { operation: 'custom-op' })
97
+ * // Result: { 'vtex.account.name': 'mystore', status_code: 200, operation: 'custom-op' }
98
+ * }
99
+ * )
64
100
  * ```
65
101
  */
66
102
  class DiagnosticsMetrics {
@@ -110,13 +146,99 @@ class DiagnosticsMetrics {
110
146
  unit: 'ms',
111
147
  });
112
148
  }
149
+ /**
150
+ * Execute a function with base attributes set in the OpenTelemetry context.
151
+ * All metric calls within the function will automatically include these base attributes,
152
+ * merged with any custom attributes provided in each call.
153
+ *
154
+ * Base attributes take precedence over custom attributes when there are key conflicts.
155
+ * Conflicting custom attributes are silently dropped.
156
+ *
157
+ * @param baseAttributes Base attributes to include in all metrics within the scope
158
+ * @param fn Function to execute with the base attributes context
159
+ * @returns The return value of the function
160
+ *
161
+ * @example
162
+ * ```typescript
163
+ * // In a request middleware
164
+ * await diagnosticsMetrics.runWithBaseAttributes(
165
+ * {
166
+ * 'vtex.account.name': ctx.vtex.account,
167
+ * status_code: ctx.status,
168
+ * route_id: ctx.vtex.route.id,
169
+ * },
170
+ * async () => {
171
+ * await next()
172
+ * }
173
+ * )
174
+ *
175
+ * // In app code (custom attributes are merged with base)
176
+ * diagnosticsMetrics.recordLatency(elapsed, { operation: 'my-operation', status: 'success' })
177
+ * // Result includes both base attributes AND custom attributes
178
+ * ```
179
+ */
180
+ runWithBaseAttributes(baseAttributes, fn) {
181
+ const currentContext = api_1.context.active();
182
+ const newContext = currentContext.setValue(BASE_ATTRIBUTES_KEY, baseAttributes);
183
+ return api_1.context.with(newContext, fn);
184
+ }
185
+ /**
186
+ * Get the base attributes from the current OpenTelemetry context.
187
+ * Returns undefined if no base attributes are set.
188
+ */
189
+ getBaseAttributes() {
190
+ return api_1.context.active().getValue(BASE_ATTRIBUTES_KEY);
191
+ }
192
+ /**
193
+ * Merge base attributes from context with provided custom attributes.
194
+ * Base attributes take precedence over custom attributes when there are key conflicts.
195
+ *
196
+ * Custom attributes are limited to MAX_CUSTOM_ATTRIBUTES before merging.
197
+ * Custom attributes with keys that conflict with base attributes are silently dropped.
198
+ * Base attributes are not limited.
199
+ *
200
+ * @param customAttributes Custom attributes provided by the caller
201
+ * @returns Merged attributes (base + non-conflicting limited custom) or undefined if both are empty
202
+ */
203
+ mergeAttributes(customAttributes) {
204
+ const baseAttributes = this.getBaseAttributes();
205
+ // Limit custom attributes before merging
206
+ const limitedCustomAttributes = limitCustomAttributes(customAttributes);
207
+ if (!baseAttributes && !limitedCustomAttributes) {
208
+ return undefined;
209
+ }
210
+ if (!baseAttributes) {
211
+ return limitedCustomAttributes;
212
+ }
213
+ if (!limitedCustomAttributes) {
214
+ return baseAttributes;
215
+ }
216
+ // Filter out custom attributes that conflict with base attributes (base takes precedence)
217
+ const baseKeys = new Set(Object.keys(baseAttributes));
218
+ const nonConflictingCustomAttributes = {};
219
+ for (const [key, value] of Object.entries(limitedCustomAttributes)) {
220
+ if (!baseKeys.has(key)) {
221
+ nonConflictingCustomAttributes[key] = value;
222
+ }
223
+ // Silently drop conflicting custom attributes - base attributes take precedence
224
+ }
225
+ // Merge: base attributes + non-conflicting custom attributes
226
+ return { ...baseAttributes, ...nonConflictingCustomAttributes };
227
+ }
113
228
  /**
114
229
  * Record a latency measurement using the single shared histogram.
115
230
  * Accepts either an hrtime tuple from process.hrtime() or milliseconds as a number.
116
231
  * Use attributes to differentiate between different operations.
117
232
  *
233
+ * Base attributes from the current context (set via `runWithBaseAttributes`) are
234
+ * automatically merged with the provided custom attributes. Base attributes take
235
+ * precedence - if a custom attribute key conflicts with a base attribute key,
236
+ * the custom attribute is silently dropped.
237
+ *
238
+ * Custom attributes are limited to MAX_CUSTOM_ATTRIBUTES (5). Base attributes are not limited.
239
+ *
118
240
  * @param value Either [seconds, nanoseconds] from process.hrtime() or milliseconds
119
- * @param attributes Attributes including 'operation' to identify the operation type (max of MAX_ATTRIBUTES attributes)
241
+ * @param attributes Custom attributes including 'operation' to identify the operation type (max 5 custom attributes)
120
242
  *
121
243
  * @example
122
244
  * ```typescript
@@ -135,18 +257,25 @@ class DiagnosticsMetrics {
135
257
  }
136
258
  // Convert hrtime to milliseconds if needed
137
259
  const milliseconds = Array.isArray(value) ? hrtimeToMillis(value) : value;
138
- // Limit attributes to prevent high cardinality
139
- const limitedAttributes = limitAttributes(attributes);
140
- // Record to the single shared histogram with attributes
141
- this.latencyHistogram.record(milliseconds, limitedAttributes);
260
+ // Merge base attributes from context with custom attributes (custom attrs are limited internally)
261
+ const mergedAttributes = this.mergeAttributes(attributes);
262
+ // Record to the single shared histogram with merged attributes
263
+ this.latencyHistogram.record(milliseconds, mergedAttributes);
142
264
  }
143
265
  /**
144
266
  * Increment a counter by a specific value.
145
267
  * Multiple counters are stored by name since counters represent different types of events.
146
268
  *
269
+ * Base attributes from the current context (set via `runWithBaseAttributes`) are
270
+ * automatically merged with the provided custom attributes. Base attributes take
271
+ * precedence - if a custom attribute key conflicts with a base attribute key,
272
+ * the custom attribute is silently dropped.
273
+ *
274
+ * Custom attributes are limited to MAX_CUSTOM_ATTRIBUTES (5). Base attributes are not limited.
275
+ *
147
276
  * @param name Counter name (e.g., 'http_requests_total', 'cache_hits_total')
148
277
  * @param value Amount to increment by (typically 1)
149
- * @param attributes Optional attributes for the counter (max of MAX_ATTRIBUTES attributes, e.g., { method: 'GET', status: '2xx' })
278
+ * @param attributes Optional custom attributes for the counter (max 5 custom attributes, e.g., { method: 'GET', status: '2xx' })
150
279
  *
151
280
  * @example
152
281
  * ```typescript
@@ -166,18 +295,25 @@ class DiagnosticsMetrics {
166
295
  });
167
296
  this.counters.set(name, counter);
168
297
  }
169
- // Limit attributes to prevent high cardinality
170
- const limitedAttributes = limitAttributes(attributes);
298
+ // Merge base attributes from context with custom attributes (custom attrs are limited internally)
299
+ const mergedAttributes = this.mergeAttributes(attributes);
171
300
  // Increment the counter
172
- this.counters.get(name).add(value, limitedAttributes);
301
+ this.counters.get(name).add(value, mergedAttributes);
173
302
  }
174
303
  /**
175
304
  * Set a gauge to a specific value (current state).
176
305
  * Multiple gauges are stored by name since gauges represent different types of measurements.
177
306
  *
307
+ * Base attributes from the current context (set via `runWithBaseAttributes`) are
308
+ * automatically merged with the provided custom attributes. Base attributes take
309
+ * precedence - if a custom attribute key conflicts with a base attribute key,
310
+ * the custom attribute is silently dropped.
311
+ *
312
+ * Custom attributes are limited to MAX_CUSTOM_ATTRIBUTES (5). Base attributes are not limited.
313
+ *
178
314
  * @param name Gauge name (e.g., 'cache_items_current', 'memory_usage_bytes')
179
315
  * @param value Current value
180
- * @param attributes Optional attributes for the gauge (max of MAX_ATTRIBUTES attributes, e.g., { cache: 'pages' })
316
+ * @param attributes Optional custom attributes for the gauge (max 5 custom attributes, e.g., { cache: 'pages' })
181
317
  *
182
318
  * @example
183
319
  * ```typescript
@@ -197,10 +333,10 @@ class DiagnosticsMetrics {
197
333
  });
198
334
  this.gauges.set(name, gauge);
199
335
  }
200
- // Limit attributes to prevent high cardinality
201
- const limitedAttributes = limitAttributes(attributes);
336
+ // Merge base attributes from context with custom attributes (custom attrs are limited internally)
337
+ const mergedAttributes = this.mergeAttributes(attributes);
202
338
  // Set the gauge value
203
- this.gauges.get(name).set(value, limitedAttributes);
339
+ this.gauges.get(name).set(value, mergedAttributes);
204
340
  }
205
341
  }
206
342
  exports.DiagnosticsMetrics = DiagnosticsMetrics;
@@ -33,33 +33,53 @@ const logBillingInfo = ({ account, workspace, production, route: { id, type } },
33
33
  'workspace': workspace,
34
34
  });
35
35
  async function timings(ctx, next) {
36
- // Errors will be caught by the next middleware so we don't have to catch.
37
- await next();
38
- const { status: statusCode, vtex: { route: { id, type } }, timings: { total }, vtex } = ctx;
39
- const totalMillis = (0, time_1.hrToMillis)(total);
40
- console.log(log(ctx, totalMillis));
41
- console.log(logBillingInfo(vtex, totalMillis));
42
- const status = (0, status_1.statusLabel)(statusCode);
43
- // Legacy metrics (backward compatibility)
44
- // Only batch successful responses so metrics don't consider errors
45
- metrics.batch(`http-handler-${id}`, status === 'success' ? total : undefined, { [status]: 1 });
46
- // New diagnostics metrics with stable names and attributes
36
+ const { vtex: { route: { id, type } }, vtex } = ctx;
37
+ // Set base attributes for all metrics recorded during this request.
38
+ // This includes metrics recorded by VTEX IO apps during handler execution.
39
+ // These attributes will be automatically merged with custom attributes.
40
+ const baseAttributes = {
41
+ [constants_1.AttributeKeys.VTEX_ACCOUNT_NAME]: vtex.account,
42
+ component: 'http-handler',
43
+ route_id: id,
44
+ route_type: type,
45
+ };
46
+ // Wrap the request handling with base attributes context.
47
+ // All metrics recorded during next() will automatically include these attributes.
48
+ const executeWithBaseAttributes = async () => {
49
+ // Errors will be caught by the next middleware so we don't have to catch.
50
+ await next();
51
+ const { status: statusCode, timings: { total } } = ctx;
52
+ const totalMillis = (0, time_1.hrToMillis)(total);
53
+ console.log(log(ctx, totalMillis));
54
+ console.log(logBillingInfo(vtex, totalMillis));
55
+ const status = (0, status_1.statusLabel)(statusCode);
56
+ // Legacy metrics (backward compatibility)
57
+ // Only batch successful responses so metrics don't consider errors
58
+ metrics.batch(`http-handler-${id}`, status === 'success' ? total : undefined, { [status]: 1 });
59
+ // New diagnostics metrics with stable names and attributes
60
+ // Note: base attributes (account, route_id, route_type) are automatically merged
61
+ // We only need to provide the response-specific attributes here
62
+ if (global.diagnosticsMetrics) {
63
+ const responseAttributes = {
64
+ status_code: statusCode,
65
+ status,
66
+ };
67
+ // Record latency histogram (record all requests, not just successful ones)
68
+ global.diagnosticsMetrics.recordLatency(total, responseAttributes);
69
+ // Increment counter (status is an attribute, not in metric name)
70
+ global.diagnosticsMetrics.incrementCounter('http_handler_requests_total', 1, responseAttributes);
71
+ }
72
+ else {
73
+ console.warn('DiagnosticsMetrics not available. HTTP handler metrics not reported.');
74
+ }
75
+ };
76
+ // If diagnosticsMetrics is available, run with base attributes context
77
+ // Otherwise, run without context (fallback for graceful degradation)
47
78
  if (global.diagnosticsMetrics) {
48
- const attributes = {
49
- [constants_1.AttributeKeys.VTEX_ACCOUNT_NAME]: vtex.account,
50
- component: 'http-handler',
51
- route_id: id,
52
- route_type: type,
53
- status_code: statusCode,
54
- status,
55
- };
56
- // Record latency histogram (record all requests, not just successful ones)
57
- global.diagnosticsMetrics.recordLatency(total, attributes);
58
- // Increment counter (status is an attribute, not in metric name)
59
- global.diagnosticsMetrics.incrementCounter('http_handler_requests_total', 1, attributes);
79
+ await global.diagnosticsMetrics.runWithBaseAttributes(baseAttributes, executeWithBaseAttributes);
60
80
  }
61
81
  else {
62
- console.warn('DiagnosticsMetrics not available. HTTP handler metrics not reported.');
82
+ await executeWithBaseAttributes();
63
83
  }
64
84
  }
65
85
  exports.timings = timings;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vtex/api",
3
- "version": "7.3.0",
3
+ "version": "7.3.1-beta.0",
4
4
  "description": "VTEX I/O API client",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",