Skip to content

Commit

Permalink
move to high order function
Browse files Browse the repository at this point in the history
  • Loading branch information
dawkaka committed Oct 29, 2024
1 parent 4316637 commit 03656e8
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 202 deletions.
28 changes: 9 additions & 19 deletions lib/apitoolkit.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Application, NextFunction, Request, Response } from 'express';
import { NextFunction, Request, Response } from 'express';
import { ReportError } from 'apitoolkit-js';
export { ReportError } from 'apitoolkit-js';
export type Config = {
type Config = {
serviceName: string;
debug?: boolean;
redactHeaders?: string[];
Expand All @@ -12,21 +12,11 @@ export type Config = {
tags?: string[];
serviceVersion?: string;
};
export declare class APIToolkit {
private config;
private apitoolkit_key?;
private captureRequestBody?;
private captureResponseBody?;
private serviceName;
constructor(config: Config);
expressErrorHandler(err: Error, _req: Request, _res: Response, next: NextFunction): void;
errorHandler(err: Error, req: Request, res: Response, next: NextFunction): void;
expressMiddleware(req: Request, res: Response, next: NextFunction): void;
ReportError: typeof ReportError;
static NewClient(config: Config): APIToolkit;
private setAttributes;
private getRequestBody;
private getUrlPath;
}
export declare const findMatchedRoute: (app: Application, method: string, url: string) => string;
export declare function expressMiddleware(config: Config): (req: Request, res: Response, next: NextFunction) => void;
export declare function expressErrorHandler(err: Error, _req: Request, _res: Response, next: NextFunction): void;
declare const APIToolkit: {
expressMiddleware: typeof expressMiddleware;
expressErrorHandler: typeof expressErrorHandler;
reportError: typeof ReportError;
};
export default APIToolkit;
167 changes: 79 additions & 88 deletions lib/apitoolkit.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.findMatchedRoute = exports.APIToolkit = exports.ReportError = void 0;
exports.ReportError = void 0;
exports.expressMiddleware = expressMiddleware;
exports.expressErrorHandler = expressErrorHandler;
const uuid_1 = require("uuid");
const api_1 = require("@opentelemetry/api");
const payload_1 = require("apitoolkit-js/lib/payload");
const apitoolkit_js_1 = require("apitoolkit-js");
var apitoolkit_js_2 = require("apitoolkit-js");
Object.defineProperty(exports, "ReportError", { enumerable: true, get: function () { return apitoolkit_js_2.ReportError; } });
class APIToolkit {
constructor(config) {
this.ReportError = apitoolkit_js_1.ReportError;
this.config = config;
this.captureRequestBody = config.captureRequestBody || false;
this.captureResponseBody = config.captureResponseBody || false;
this.serviceName = config.serviceName;
this.expressMiddleware = this.expressMiddleware.bind(this);
}
expressErrorHandler(err, _req, _res, next) {
(0, apitoolkit_js_1.ReportError)(err);
next(err);
}
errorHandler(err, req, res, next) {
return this.expressErrorHandler(err, req, res, next);
}
expressMiddleware(req, res, next) {
function expressMiddleware(config) {
return function expressMidd(req, res, next) {
apitoolkit_js_1.asyncLocalStorage.run(new Map(), () => {
const store = apitoolkit_js_1.asyncLocalStorage.getStore();
const msg_id = (0, uuid_1.v4)();
const span = api_1.trace.getTracer(this.serviceName).startSpan('apitoolkit-http-span');
const span = api_1.trace.getTracer(config.serviceName).startSpan('apitoolkit-http-span');
if (store) {
store.set('apitoolkit-span', span);
store.set('apitoolkit-msg-id', msg_id);
store.set('AT_errors', []);
}
if (this.config?.debug) {
if (config.debug) {
console.log('APIToolkit: expressMiddleware called');
}
let respBody = '';
const oldSend = res.send;
res.send = val => {
if (this.captureResponseBody) {
if (config.captureResponseBody) {
respBody = val;
}
return oldSend.apply(res, [val]);
Expand All @@ -49,12 +36,12 @@ class APIToolkit {
res.removeListener('error', onRespFinished(req, res));
res.removeListener('finish', onRespFinished(req, res));
try {
const reqBody = this.getRequestBody(req);
const url_path = this.getUrlPath(req);
this.setAttributes(span, req, res, msg_id, url_path, reqBody, respBody);
const reqBody = getRequestBody(req, config.captureRequestBody || false);
const url_path = getUrlPath(req);
setAttributes(span, req, res, msg_id, url_path, reqBody, respBody, config);
}
catch (error) {
if (this.config?.debug) {
if (config.debug) {
console.log(error);
}
}
Expand All @@ -66,79 +53,78 @@ class APIToolkit {
res.on('finish', onRespFinishedCB).on('error', onRespFinishedCB);
next();
});
}
static NewClient(config) {
return new APIToolkit(config);
}
setAttributes(span, req, res, msg_id, urlPath, reqBody, respBody) {
span.setAttributes({
'net.host.name': req.hostname,
'at-project-key': this.apitoolkit_key || '',
'apitoolkit.msg_id': msg_id,
'http.route': urlPath,
'http.request.method': req.method,
'http.response.status_code': res.statusCode,
'http.request.query_params': JSON.stringify(req.query),
'http.request.path_params': JSON.stringify(req.params),
'apitoolkit.sdk_type': 'JsExpress',
'http.request.body': Buffer.from((0, payload_1.redactFields)(reqBody, this.config.redactRequestBody || [])).toString('base64'),
'http.response.body': Buffer.from((0, payload_1.redactFields)(respBody, this.config.redactRequestBody || [])).toString('base64'),
'apitoolkit.errors': JSON.stringify(apitoolkit_js_1.asyncLocalStorage.getStore()?.get('AT_errors') || []),
'apitoolkit.service_version': this.config.serviceVersion || '',
'apitoolkit.tags': this.config.tags || []
});
const redactHeader = (header) => this.config.redactHeaders?.includes(header.toLowerCase()) || ['cookies', 'authorization'].includes(header.toLowerCase())
? '[CLIENT_REDACTED]'
: header;
Object.entries(req.headers).forEach(([header, value]) => span.setAttribute(`http.request.header.${header}`, redactHeader(String(value))));
Object.entries(res.getHeaders()).forEach(([header, value]) => span.setAttribute(`http.response.header.${header}`, redactHeader(String(value))));
}
getRequestBody(req) {
const reqBody = '';
if (req.body && this.captureRequestBody) {
try {
if (req.is('multipart/form-data')) {
if (req.file) {
req.body[req.file.fieldname] = `[${req.file.mimetype}_FILE]`;
}
else if (req.files) {
if (!Array.isArray(req.files)) {
for (const file in req.files) {
req.body[file] = req.files[file].map((f) => `[${f.mimetype}_FILE]`);
}
};
}
function setAttributes(span, req, res, msg_id, urlPath, reqBody, respBody, config) {
span.setAttributes({
'net.host.name': req.hostname,
'apitoolkit.msg_id': msg_id,
'http.route': urlPath,
'http.request.method': req.method,
'http.response.status_code': res.statusCode,
'http.request.query_params': JSON.stringify(req.query),
'http.request.path_params': JSON.stringify(req.params),
'apitoolkit.sdk_type': 'JsExpress',
'http.request.body': Buffer.from((0, payload_1.redactFields)(reqBody, config.redactRequestBody || [])).toString('base64'),
'http.response.body': Buffer.from((0, payload_1.redactFields)(respBody, config.redactRequestBody || [])).toString('base64'),
'apitoolkit.errors': JSON.stringify(apitoolkit_js_1.asyncLocalStorage.getStore()?.get('AT_errors') || []),
'apitoolkit.service_version': config.serviceVersion || '',
'apitoolkit.tags': config.tags || []
});
const redactHeader = (header) => config.redactHeaders?.includes(header.toLowerCase()) || ['cookies', 'authorization'].includes(header.toLowerCase())
? '[CLIENT_REDACTED]'
: header;
Object.entries(req.headers).forEach(([header, value]) => span.setAttribute(`http.request.header.${header}`, redactHeader(String(value))));
Object.entries(res.getHeaders()).forEach(([header, value]) => span.setAttribute(`http.response.header.${header}`, redactHeader(String(value))));
}
function expressErrorHandler(err, _req, _res, next) {
(0, apitoolkit_js_1.ReportError)(err);
next(err);
}
function getRequestBody(req, captureRequestBody) {
const reqBody = '';
if (req.body && captureRequestBody) {
try {
if (req.is('multipart/form-data')) {
if (req.file) {
req.body[req.file.fieldname] = `[${req.file.mimetype}_FILE]`;
}
else if (req.files) {
if (!Array.isArray(req.files)) {
for (const file in req.files) {
req.body[file] = req.files[file].map((f) => `[${f.mimetype}_FILE]`);
}
else {
for (const file of req.files) {
req.body[file.fieldname] = `[${file.mimetype}_FILE]`;
}
}
else {
for (const file of req.files) {
req.body[file.fieldname] = `[${file.mimetype}_FILE]`;
}
}
}
return JSON.stringify(req.body);
}
catch {
return String(req.body);
}
return JSON.stringify(req.body);
}
catch {
return String(req.body);
}
return reqBody;
}
getUrlPath(req) {
let url_path = req.route?.path || '';
if (url_path == '' && req.method.toLowerCase() !== 'head') {
url_path = (0, exports.findMatchedRoute)(req.app, req.method, req.originalUrl);
return reqBody;
}
function getUrlPath(req) {
let url_path = req.route?.path || '';
if (url_path == '' && req.method.toLowerCase() !== 'head') {
url_path = findMatchedRoute(req.app, req.method, req.originalUrl);
}
else if (req.baseUrl && req.baseUrl != '') {
if (req.originalUrl.startsWith(req.baseUrl)) {
url_path = req.baseUrl + url_path;
}
else if (req.baseUrl && req.baseUrl != '') {
if (req.originalUrl.startsWith(req.baseUrl)) {
url_path = req.baseUrl + url_path;
}
else {
url_path = (0, exports.findMatchedRoute)(req.app, req.method, req.originalUrl);
}
else {
url_path = findMatchedRoute(req.app, req.method, req.originalUrl);
}
return url_path;
}
return url_path;
}
exports.APIToolkit = APIToolkit;
const findMatchedRoute = (app, method, url) => {
try {
const path = url.split('?')[0];
Expand Down Expand Up @@ -169,7 +155,7 @@ const findMatchedRoute = (app, method, url) => {
return '';
}
};
exports.findMatchedRoute = findMatchedRoute;
const reportError = apitoolkit_js_1.ReportError;
function transformPath(params, path) {
let transformedPath = path;
for (const [key, value] of Object.entries(params)) {
Expand All @@ -178,4 +164,9 @@ function transformPath(params, path) {
}
return transformedPath;
}
const APIToolkit = {
expressMiddleware,
expressErrorHandler,
reportError
};
exports.default = APIToolkit;
Loading

0 comments on commit 03656e8

Please sign in to comment.