@gravity-ui/gateway 4.11.0 → 4.12.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.
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { ApiActionConfig, ApiByScope, ApiServiceMixedActionConfig, GatewayConfig, GatewayRequest, GatewayResponse, SchemasByScope } from '../models/common';
|
|
1
|
+
import { ApiActionConfig, ApiByScope, ApiServiceMixedActionConfig, GatewayConfig, GatewayRequest, GatewayResponse, SchemasByScope, SendStats } from '../models/common';
|
|
2
2
|
import { GatewayContext } from '../models/context';
|
|
3
3
|
import { AppErrorConstructor } from '../models/error';
|
|
4
4
|
import type { GrpcContext } from './grpc';
|
|
5
5
|
export declare function createMixedAction<TSchema extends SchemasByScope, Context extends GatewayContext, Req extends GatewayRequest<Context>, Res extends GatewayResponse>(config: ApiServiceMixedActionConfig<Context, Req, Res, any, any, any>, api: ApiByScope<TSchema, Context, Req, Res>, serviceName: string, actionName: string, extra: {
|
|
6
6
|
config: GatewayConfig<Context, Req, Res>;
|
|
7
7
|
grpcContext: GrpcContext;
|
|
8
|
+
sendStats?: SendStats<Context>;
|
|
8
9
|
}, ErrorConstructor: AppErrorConstructor): (actionConfig: ApiActionConfig<Context, any>) => Promise<{
|
|
9
10
|
responseData: any;
|
|
10
11
|
debugHeaders: {};
|
|
@@ -16,9 +16,23 @@ const constants_1 = require("../constants");
|
|
|
16
16
|
const common_1 = require("../utils/common");
|
|
17
17
|
const create_context_api_1 = require("../utils/create-context-api");
|
|
18
18
|
const parse_error_1 = require("../utils/parse-error");
|
|
19
|
+
const redact_sensitive_headers_1 = require("../utils/redact-sensitive-headers");
|
|
20
|
+
function getMixedResponseSize(data, ctx, ErrorConstructor) {
|
|
21
|
+
var _a;
|
|
22
|
+
let responseSize = 0;
|
|
23
|
+
try {
|
|
24
|
+
responseSize = constants_1.ECMA_STRING_SIZE * ((_a = JSON.stringify(data)) === null || _a === void 0 ? void 0 : _a.length);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
(0, common_1.handleError)(ErrorConstructor, error, ctx, 'Calculate response size failed');
|
|
28
|
+
}
|
|
29
|
+
return responseSize;
|
|
30
|
+
}
|
|
19
31
|
function createMixedAction(config, api, serviceName, actionName, extra, ErrorConstructor) {
|
|
20
32
|
return async (actionConfig) => {
|
|
33
|
+
var _a, _b, _c;
|
|
21
34
|
const { args } = actionConfig, context = __rest(actionConfig, ["args"]);
|
|
35
|
+
const { requestId, headers: requestHeaders, ctx: parentCtx, userId } = actionConfig;
|
|
22
36
|
const ctx = actionConfig.ctx.create(`Gateway ${serviceName} ${actionName} [mixed]`, {
|
|
23
37
|
tags: {
|
|
24
38
|
action: actionName,
|
|
@@ -27,15 +41,30 @@ function createMixedAction(config, api, serviceName, actionName, extra, ErrorCon
|
|
|
27
41
|
},
|
|
28
42
|
});
|
|
29
43
|
const contextApi = (0, create_context_api_1.generateContextApi)(api, Object.assign(Object.assign({}, context), { ctx }));
|
|
44
|
+
const startRequestTime = Date.now();
|
|
45
|
+
const requestData = {
|
|
46
|
+
timestamp: startRequestTime,
|
|
47
|
+
service: serviceName,
|
|
48
|
+
action: actionName,
|
|
49
|
+
requestId: requestId || '',
|
|
50
|
+
requestMethod: '',
|
|
51
|
+
requestUrl: '',
|
|
52
|
+
traceId: ((_a = ctx.getTraceId) === null || _a === void 0 ? void 0 : _a.call(ctx)) || '',
|
|
53
|
+
userId: userId || '',
|
|
54
|
+
};
|
|
30
55
|
try {
|
|
31
56
|
const responseData = await config(contextApi, args, Object.assign(Object.assign({ headers: actionConfig.headers, lang: actionConfig.headers[constants_1.DEFAULT_LANG_HEADER] || constants_1.Lang.Ru, ctx }, extra), { abortSignal: actionConfig.abortSignal }));
|
|
32
57
|
ctx.log('Request completed');
|
|
58
|
+
(_b = extra.sendStats) === null || _b === void 0 ? void 0 : _b.call(extra, Object.assign(Object.assign({}, requestData), { requestTime: Date.now() - startRequestTime, responseSize: getMixedResponseSize(responseData, ctx, ErrorConstructor), restStatus: 200 }), (0, redact_sensitive_headers_1.redactSensitiveHeaders)(parentCtx, requestHeaders), parentCtx, { debugHeaders: {} });
|
|
33
59
|
return {
|
|
34
60
|
responseData,
|
|
35
61
|
debugHeaders: {},
|
|
36
62
|
};
|
|
37
63
|
}
|
|
38
64
|
catch (e) {
|
|
65
|
+
const errorData = e instanceof Object && 'error' in e ? e.error : e;
|
|
66
|
+
const restStatus = (errorData === null || errorData === void 0 ? void 0 : errorData.status) || 500;
|
|
67
|
+
(_c = extra.sendStats) === null || _c === void 0 ? void 0 : _c.call(extra, Object.assign(Object.assign({}, requestData), { requestTime: Date.now() - startRequestTime, responseSize: getMixedResponseSize(errorData, ctx, ErrorConstructor), restStatus }), (0, redact_sensitive_headers_1.redactSensitiveHeaders)(parentCtx, requestHeaders), parentCtx, { debugHeaders: {} });
|
|
39
68
|
if (e instanceof Object && 'error' in e) {
|
|
40
69
|
(0, common_1.handleError)(ErrorConstructor, e, ctx, 'Request failed', {
|
|
41
70
|
actionName,
|
package/build/components/rest.js
CHANGED
|
@@ -11,6 +11,7 @@ const constants_1 = require("../constants");
|
|
|
11
11
|
const axios_1 = require("../utils/axios");
|
|
12
12
|
const common_1 = require("../utils/common");
|
|
13
13
|
const parse_error_1 = require("../utils/parse-error");
|
|
14
|
+
const pipe_through_byte_counter_1 = require("../utils/pipe-through-byte-counter");
|
|
14
15
|
const redact_sensitive_headers_1 = require("../utils/redact-sensitive-headers");
|
|
15
16
|
const validate_1 = require("../utils/validate");
|
|
16
17
|
function getRestResponseSize(data, ctx, ErrorConstructor) {
|
|
@@ -306,7 +307,16 @@ function createRestAction(endpoints, config, serviceKey, actionName, options, Er
|
|
|
306
307
|
}
|
|
307
308
|
}
|
|
308
309
|
if (options === null || options === void 0 ? void 0 : options.sendStats) {
|
|
309
|
-
|
|
310
|
+
const emitStats = (responseSize, restStatus) => {
|
|
311
|
+
var _a;
|
|
312
|
+
return (_a = options.sendStats) === null || _a === void 0 ? void 0 : _a.call(options, Object.assign(Object.assign({}, requestData), { responseSize, restStatus }), (0, redact_sensitive_headers_1.redactSensitiveHeaders)(parentCtx, headers), parentCtx, { debugHeaders: (0, common_1.sanitizeDebugHeaders)(debugHeaders) });
|
|
313
|
+
};
|
|
314
|
+
if (response.data && typeof response.data.pipe === 'function') {
|
|
315
|
+
response.data = (0, pipe_through_byte_counter_1.pipeThroughByteCounter)(response.data, (streamedBytes) => emitStats(streamedBytes, 200));
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
emitStats(getRestResponseSize(response === null || response === void 0 ? void 0 : response.data, ctx, ErrorConstructor), 200);
|
|
319
|
+
}
|
|
310
320
|
}
|
|
311
321
|
else {
|
|
312
322
|
ctx.stats(Object.assign(Object.assign({}, requestData), { responseStatus: 200 }));
|
package/build/index.js
CHANGED
|
@@ -69,7 +69,7 @@ function createApiAction(schema, config, serviceKey, actionName, api, grpcContex
|
|
|
69
69
|
const env = config.env || '';
|
|
70
70
|
if (isMixedActionConfig(action)) {
|
|
71
71
|
const resultServiceName = serviceName || serviceKey;
|
|
72
|
-
return (0, mixed_1.createMixedAction)(action, api, resultServiceName, actionName, { config, grpcContext }, config.ErrorConstructor);
|
|
72
|
+
return (0, mixed_1.createMixedAction)(action, api, resultServiceName, actionName, { config, grpcContext, sendStats: config.sendStats }, config.ErrorConstructor);
|
|
73
73
|
}
|
|
74
74
|
const endpointsConfig = lodash_1.default.get(serviceSchema.endpoints, [installation, env]);
|
|
75
75
|
if (isRestActionConfig(action)) {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pipeThroughByteCounter = void 0;
|
|
4
|
+
const stream_1 = require("stream");
|
|
5
|
+
function pipeThroughByteCounter(source, onFlush) {
|
|
6
|
+
let streamedBytes = 0;
|
|
7
|
+
const counter = new stream_1.Transform({
|
|
8
|
+
transform(chunk, encoding, cb) {
|
|
9
|
+
if (Buffer.isBuffer(chunk) || chunk instanceof Uint8Array) {
|
|
10
|
+
streamedBytes += chunk.length;
|
|
11
|
+
}
|
|
12
|
+
else if (typeof chunk === 'string') {
|
|
13
|
+
streamedBytes += Buffer.byteLength(chunk, typeof encoding === 'string' ? encoding : undefined);
|
|
14
|
+
}
|
|
15
|
+
cb(null, chunk);
|
|
16
|
+
},
|
|
17
|
+
flush(cb) {
|
|
18
|
+
onFlush(streamedBytes);
|
|
19
|
+
cb();
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
return source.pipe(counter);
|
|
23
|
+
}
|
|
24
|
+
exports.pipeThroughByteCounter = pipeThroughByteCounter;
|