@biorate/axios-prometheus
Version:
Axios-prometheus HTTP interface
195 lines • 8.77 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AxiosPrometheus = void 0;
const fs_1 = require("fs");
const tools_1 = require("@biorate/tools");
const inversion_1 = require("@biorate/inversion");
const axios_1 = require("@biorate/axios");
const prometheus_1 = require("@biorate/prometheus");
const opentelemetry_1 = require("@biorate/opentelemetry");
const lodash_1 = require("lodash");
__exportStar(require("@biorate/axios"), exports);
class AxiosPrometheus extends axios_1.Axios {
static mockFileName(name) {
return `Axios.${name}.snap`;
}
static checkMockDir(directory) {
try {
const dir = tools_1.path.create(process.cwd(), directory);
const stats = (0, fs_1.statSync)(dir);
if (!stats.isDirectory())
return null;
return dir;
}
catch (_a) {
return null;
}
}
static mockFilePath(filename) {
let directory = inversion_1.container.get(inversion_1.Types.Config).get('axios.mock.directory', null);
if (!directory)
directory = this.checkMockDir('test');
if (!directory)
directory = this.checkMockDir('tests');
if (!directory)
directory = process.cwd();
return tools_1.path.create(directory, '__snapshots__', filename !== null && filename !== void 0 ? filename : '');
}
static getMockData(instance, filename) {
return JSON.parse((0, fs_1.readFileSync)(this.mockFilePath(filename), 'utf8'));
}
static getMock(instance, options) {
const filename = this.mockFileName(instance.constructor.name);
try {
return (0, lodash_1.get)(this.getMockData(instance, filename), `${instance.constructor.name}.${JSON.stringify(options)}`);
}
catch (e) {
console.warn(`Axios mock snap file [${filename}] doesn't exists, or corrupted., because of [${e === null || e === void 0 ? void 0 : e.message}]`);
}
}
static setMock(instance, result, options) {
let data;
const filename = this.mockFileName(instance.constructor.name);
try {
data = this.getMockData(instance, filename);
}
catch (_a) {
data = {};
}
(0, lodash_1.set)(data, `${instance.constructor.name}.${JSON.stringify(options)}`, (0, lodash_1.pick)(result, ...this.mockFields));
try {
(0, fs_1.mkdirSync)(this.mockFilePath(), { recursive: true });
}
catch (_b) { }
try {
(0, fs_1.writeFileSync)(this.mockFilePath(filename), JSON.stringify(data, null, ' '), 'utf8');
}
catch (e) {
console.warn(`Can't write Axios mock snap file [${filename}], because of [${e === null || e === void 0 ? void 0 : e.message}]`);
}
}
get config() {
return inversion_1.container.get(inversion_1.Types.Config);
}
getStartTime() {
return process.hrtime();
}
log(statusCode, startTime) {
const diff = process.hrtime(startTime);
const time = diff[0] * 1e3 + diff[1] * 1e-6;
const msTo = tools_1.time.msTo;
this.counter
.labels({
method: this.method,
uri: this.baseURL + this.url,
status: statusCode,
})
.inc();
this.histogram
.labels({
method: this.method,
uri: this.baseURL + this.url,
status: statusCode,
})
.observe(msTo(time, 's'));
}
stringify(data) {
return typeof data === 'object' ? JSON.stringify(data) : String(data);
}
needTrace(url, span) {
if (!span)
return false;
const excluded = this.config.get('AxiosPrometheus.tracing.excluded', []);
for (const item of excluded) {
if (typeof item === 'string' && url.startsWith(item))
return false;
if (item instanceof RegExp && item.test(url))
return false;
}
return true;
}
fullUrl(params) {
var _a, _b;
return (_b = (_a = params === null || params === void 0 ? void 0 : params.baseURL) !== null && _a !== void 0 ? _a : '' + (params === null || params === void 0 ? void 0 : params.url)) !== null && _b !== void 0 ? _b : '';
}
async before(params) {
await super.before(params);
const span = opentelemetry_1.trace.getActiveSpan();
const url = this.fullUrl(params);
if (!this.needTrace(url, span))
return;
span.setAttribute('outgoing.request.url', this.stringify(url));
span.setAttribute('outgoing.request.body', this.stringify(params === null || params === void 0 ? void 0 : params.data));
span.setAttribute('outgoing.request.headers', this.stringify(params === null || params === void 0 ? void 0 : params.headers));
span.setAttribute('outgoing.request.method', this.stringify(params === null || params === void 0 ? void 0 : params.method));
span.setAttribute('outgoing.request.params', this.stringify(params === null || params === void 0 ? void 0 : params.path));
span.setAttribute('outgoing.request.query', this.stringify(params === null || params === void 0 ? void 0 : params.params));
}
async after(result, startTime, params) {
await super.after(result, startTime, params);
this.log(result.status, startTime);
const span = opentelemetry_1.trace.getActiveSpan();
const url = this.fullUrl(params);
if (!this.needTrace(url, span))
return;
span.setAttribute('outgoing.response.headers', this.stringify(result.headers));
span.setAttribute('outgoing.response.statusCode', this.stringify(result.status));
span.setAttribute('outgoing.response.data', this.stringify(result.data));
}
async catch(e, startTime, params) {
await super.catch(e, startTime, params);
if (!('response' in e))
return;
this.log(e.response.status, startTime);
const span = opentelemetry_1.trace.getActiveSpan();
const url = this.fullUrl(params);
if (!this.needTrace(url, span))
return;
span.setAttribute('outgoing.response.headers', this.stringify(e.response.headers));
span.setAttribute('outgoing.response.statusCode', this.stringify(e.response.status));
span.setAttribute('outgoing.response.data', this.stringify(e.response.data));
}
}
AxiosPrometheus.mockFields = ['data', 'status', 'statusText'];
__decorate([
(0, prometheus_1.counter)({
name: 'http_client_requests_seconds_count',
help: 'Http client requests count',
labelNames: ['method', 'uri', 'status'],
}),
__metadata("design:type", Object)
], AxiosPrometheus.prototype, "counter", void 0);
__decorate([
(0, prometheus_1.histogram)({
name: 'http_client_requests_seconds',
help: 'Http client requests seconds bucket',
labelNames: ['method', 'uri', 'status'],
buckets: [0.005, 0.01, 0.02, 0.05, 0.1, 0.3, 0.5, 1, 2, 3, 5, 10],
}),
__metadata("design:type", Object)
], AxiosPrometheus.prototype, "histogram", void 0);
exports.AxiosPrometheus = AxiosPrometheus;
//# sourceMappingURL=index.js.map