@vtex/api 6.52.0 → 6.53.0-beta.1
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/CHANGELOG.md +11 -1
- package/lib/HttpClient/middlewares/metrics.js +52 -5
- package/lib/HttpClient/middlewares/request/HttpAgentSingleton.d.ts +5 -0
- package/lib/HttpClient/middlewares/request/HttpAgentSingleton.js +15 -0
- package/lib/constants.d.ts +15 -0
- package/lib/constants.js +18 -1
- package/lib/metrics/DiagnosticsMetrics.d.ts +189 -0
- package/lib/metrics/DiagnosticsMetrics.js +342 -0
- package/lib/service/index.d.ts +9 -1
- package/lib/service/index.js +5 -1
- package/lib/service/logger/client.js +0 -5
- package/lib/service/metrics/client.d.ts +2 -0
- package/lib/service/metrics/client.js +38 -0
- package/lib/service/metrics/instruments/hostMetrics.d.ts +14 -0
- package/lib/service/metrics/instruments/hostMetrics.js +33 -0
- package/lib/service/telemetry/client.d.ts +9 -1
- package/lib/service/telemetry/client.js +93 -27
- package/lib/service/telemetry/resourceAttributes.d.ts +1 -0
- package/lib/service/telemetry/resourceAttributes.js +21 -0
- package/lib/service/worker/runtime/graphql/schema/schemaDirectives/Metric.js +20 -2
- package/lib/service/worker/runtime/http/middlewares/requestStats.js +42 -2
- package/lib/service/worker/runtime/http/middlewares/timings.js +49 -9
- package/lib/service/worker/runtime/statusTrack.js +3 -0
- package/package.json +7 -2
|
@@ -21,11 +21,29 @@ class Metric extends graphql_tools_1.SchemaDirectiveVisitor {
|
|
|
21
21
|
result = error;
|
|
22
22
|
failedToResolve = true;
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
const status = failedToResolve ? 'error' : 'success';
|
|
25
|
+
ctx.graphql.status = status;
|
|
25
26
|
const payload = {
|
|
26
|
-
[
|
|
27
|
+
[status]: 1,
|
|
27
28
|
};
|
|
29
|
+
// Legacy metrics (backward compatibility)
|
|
28
30
|
metrics.batch(`graphql-metric-${name}`, failedToResolve ? undefined : ellapsed, payload);
|
|
31
|
+
// New diagnostics metrics with stable names and attributes
|
|
32
|
+
if (global.diagnosticsMetrics) {
|
|
33
|
+
const attributes = {
|
|
34
|
+
[__1.AttributeKeys.VTEX_ACCOUNT_NAME]: ctx.vtex.account,
|
|
35
|
+
component: 'graphql',
|
|
36
|
+
field_name: name,
|
|
37
|
+
status,
|
|
38
|
+
};
|
|
39
|
+
// Record latency histogram (record all requests, not just successful ones)
|
|
40
|
+
global.diagnosticsMetrics.recordLatency(ellapsed, attributes);
|
|
41
|
+
// Increment counter (status is an attribute, not in metric name)
|
|
42
|
+
global.diagnosticsMetrics.incrementCounter('graphql_field_requests_total', 1, attributes);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
console.warn('DiagnosticsMetrics not available. GraphQL field metrics not reported.');
|
|
46
|
+
}
|
|
29
47
|
if (failedToResolve) {
|
|
30
48
|
throw result;
|
|
31
49
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.trackIncomingRequestStats = exports.incomingRequestStats = exports.cancelMessage = void 0;
|
|
4
|
+
const constants_1 = require("../../../../../constants");
|
|
4
5
|
exports.cancelMessage = 'Request cancelled';
|
|
5
6
|
class IncomingRequestStats {
|
|
6
7
|
constructor() {
|
|
@@ -22,20 +23,59 @@ class IncomingRequestStats {
|
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
exports.incomingRequestStats = new IncomingRequestStats();
|
|
25
|
-
const requestClosed = () => {
|
|
26
|
+
const requestClosed = (ctx) => () => {
|
|
26
27
|
exports.incomingRequestStats.closed++;
|
|
28
|
+
// Report to diagnostics metrics (cumulative counter)
|
|
29
|
+
const { status: statusCode, vtex: { account, route: { id, type } } } = ctx;
|
|
30
|
+
if (global.diagnosticsMetrics) {
|
|
31
|
+
global.diagnosticsMetrics.incrementCounter('http_server_requests_closed_total', 1, {
|
|
32
|
+
[constants_1.AttributeKeys.VTEX_ACCOUNT_NAME]: account,
|
|
33
|
+
route_id: id,
|
|
34
|
+
route_type: type,
|
|
35
|
+
status_code: statusCode,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
console.warn('DiagnosticsMetrics not available. Request closed metric not reported.');
|
|
40
|
+
}
|
|
27
41
|
};
|
|
28
42
|
const requestAborted = (ctx) => () => {
|
|
29
43
|
exports.incomingRequestStats.aborted++;
|
|
44
|
+
// Report to diagnostics metrics (cumulative counter)
|
|
45
|
+
const { status: statusCode, vtex: { account, route: { id, type } } } = ctx;
|
|
46
|
+
if (global.diagnosticsMetrics) {
|
|
47
|
+
global.diagnosticsMetrics.incrementCounter('http_server_requests_aborted_total', 1, {
|
|
48
|
+
[constants_1.AttributeKeys.VTEX_ACCOUNT_NAME]: account,
|
|
49
|
+
route_id: id,
|
|
50
|
+
route_type: type,
|
|
51
|
+
status_code: statusCode,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
console.warn('DiagnosticsMetrics not available. Request aborted metric not reported.');
|
|
56
|
+
}
|
|
30
57
|
if (ctx.vtex.cancellation && ctx.vtex.cancellation.cancelable) {
|
|
31
58
|
ctx.vtex.cancellation.source.cancel(exports.cancelMessage);
|
|
32
59
|
ctx.vtex.cancellation.cancelled = true;
|
|
33
60
|
}
|
|
34
61
|
};
|
|
35
62
|
async function trackIncomingRequestStats(ctx, next) {
|
|
36
|
-
ctx.req.on('close', requestClosed);
|
|
63
|
+
ctx.req.on('close', requestClosed(ctx));
|
|
37
64
|
ctx.req.on('aborted', requestAborted(ctx));
|
|
38
65
|
exports.incomingRequestStats.total++;
|
|
66
|
+
// Report total requests to diagnostics metrics (cumulative counter)
|
|
67
|
+
const { status: statusCode, vtex: { account, route: { id, type } } } = ctx;
|
|
68
|
+
if (global.diagnosticsMetrics) {
|
|
69
|
+
global.diagnosticsMetrics.incrementCounter('http_server_requests_total', 1, {
|
|
70
|
+
[constants_1.AttributeKeys.VTEX_ACCOUNT_NAME]: account,
|
|
71
|
+
route_id: id,
|
|
72
|
+
route_type: type,
|
|
73
|
+
status_code: statusCode,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
console.warn('DiagnosticsMetrics not available. Request total metric not reported.');
|
|
78
|
+
}
|
|
39
79
|
await next();
|
|
40
80
|
}
|
|
41
81
|
exports.trackIncomingRequestStats = trackIncomingRequestStats;
|
|
@@ -33,14 +33,54 @@ const logBillingInfo = ({ account, workspace, production, route: { id, type } },
|
|
|
33
33
|
'workspace': workspace,
|
|
34
34
|
});
|
|
35
35
|
async function timings(ctx, next) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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,
|
|
65
|
+
status_code: statusCode,
|
|
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)
|
|
78
|
+
if (global.diagnosticsMetrics) {
|
|
79
|
+
await global.diagnosticsMetrics.runWithBaseAttributes(baseAttributes, executeWithBaseAttributes);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
console.warn('DiagnosticsMetrics not available. HTTP handler metrics not reported.');
|
|
83
|
+
await executeWithBaseAttributes();
|
|
84
|
+
}
|
|
45
85
|
}
|
|
46
86
|
exports.timings = timings;
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.broadcastStatusTrack = exports.trackStatus = exports.statusTrackHandler = exports.isStatusTrackBroadcast = exports.isStatusTrack = void 0;
|
|
7
7
|
const cluster_1 = __importDefault(require("cluster"));
|
|
8
|
+
const HttpAgentSingleton_1 = require("../../../HttpClient/middlewares/request/HttpAgentSingleton");
|
|
8
9
|
const constants_1 = require("../../../constants");
|
|
9
10
|
const BROADCAST_STATUS_TRACK = 'broadcastStatusTrack';
|
|
10
11
|
const STATUS_TRACK = 'statusTrack';
|
|
@@ -26,6 +27,8 @@ const statusTrackHandler = async (ctx) => {
|
|
|
26
27
|
};
|
|
27
28
|
exports.statusTrackHandler = statusTrackHandler;
|
|
28
29
|
const trackStatus = () => {
|
|
30
|
+
// Update diagnostics metrics (gauges for HTTP agent stats)
|
|
31
|
+
HttpAgentSingleton_1.HttpAgentSingleton.updateHttpAgentMetrics();
|
|
29
32
|
// Flushing resets the metric accumulators, the CPU usage baseline and the
|
|
30
33
|
// incoming request stats, so it must keep running even though nothing
|
|
31
34
|
// consumes the returned metrics anymore.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vtex/api",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.53.0-beta.1",
|
|
4
4
|
"description": "VTEX I/O API client",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
@@ -47,9 +47,14 @@
|
|
|
47
47
|
},
|
|
48
48
|
"license": "MIT",
|
|
49
49
|
"dependencies": {
|
|
50
|
+
"@opentelemetry/api": "^1.9.0",
|
|
51
|
+
"@opentelemetry/host-metrics": "0.35.5",
|
|
52
|
+
"@opentelemetry/instrumentation": "0.57.2",
|
|
53
|
+
"@opentelemetry/instrumentation-koa": "0.47.1",
|
|
50
54
|
"@types/koa": "^2.11.0",
|
|
51
55
|
"@types/koa-compose": "^3.2.3",
|
|
52
|
-
"@vtex/diagnostics-nodejs": "0.1.
|
|
56
|
+
"@vtex/diagnostics-nodejs": "0.1.8-io",
|
|
57
|
+
"@vtex/diagnostics-semconv": "5.5.2",
|
|
53
58
|
"@vtex/node-error-report": "^0.0.3",
|
|
54
59
|
"@wry/equality": "^0.1.9",
|
|
55
60
|
"agentkeepalive": "^4.0.2",
|