feat: init

This commit is contained in:
Shinwoo PARK 2023-11-17 17:03:55 +09:00
commit 68c514ac50
19 changed files with 644 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.idea/
.vscode/
node_modules/

42
dist/functions.js vendored Normal file
View File

@ -0,0 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.includeOrExcludeObject = exports.notIncludedSymbol = void 0;
exports.notIncludedSymbol = Symbol('notIncluded');
async function includeOrExcludeObject(ocv, paths, currentPath = [], include) {
if (Array.isArray(ocv)) {
return (await Promise.all(ocv.map(async (v, i) => await includeOrExcludeObject(v, paths, [...currentPath, i.toString()], include)))).filter((e) => e !== exports.notIncludedSymbol);
}
if (typeof ocv === 'object') {
return Object.fromEntries((await Promise.all(Object.entries(ocv).map(async ([key, value]) => [
key,
await includeOrExcludeObject(value, paths, [...currentPath, key], include),
]))).filter((e) => e[1] !== exports.notIncludedSymbol));
}
const isIncluded = paths.includes(currentPath.join('.'));
return include
? isIncluded // include mode, path is in list
? ocv
: exports.notIncludedSymbol
: isIncluded // exclude mode, path is in list
? exports.notIncludedSymbol
: ocv;
}
exports.includeOrExcludeObject = includeOrExcludeObject;
async function objectContainedLogged(ocv, options) {
if (options && typeof ocv === 'object') {
if (options.include && options.include.length > 0) {
return JSON.stringify(await includeOrExcludeObject(ocv, options.include, [], true));
}
if (options.exclude && options.exclude.length > 0) {
return JSON.stringify(await includeOrExcludeObject(ocv, options.exclude, [], false));
}
}
if (typeof ocv === 'object') {
return JSON.stringify(ocv);
}
else {
return `${ocv}`;
}
}
exports.default = objectContainedLogged;
//# sourceMappingURL=functions.js.map

1
dist/functions.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"functions.js","sourceRoot":"","sources":["../src/functions.ts"],"names":[],"mappings":";;;AAAa,QAAA,iBAAiB,GAAG,MAAM,CAAC,aAAa,CAAC,CAAA;AAE/C,KAAK,UAAU,sBAAsB,CACxC,GAAQ,EACR,KAAe,EACf,cAAwB,EAAE,EAC1B,OAAgB;IAEhB,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;QACpB,OAAO,CACH,MAAM,OAAO,CAAC,GAAG,CACb,GAAG,CAAC,GAAG,CACH,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CACX,MAAM,sBAAsB,CACxB,CAAC,EACD,KAAK,EACL,CAAC,GAAG,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,EAC9B,OAAO,CACV,CACR,CACJ,CACJ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,yBAAiB,CAAC,CAAC;KAC5C;IAED,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;QACzB,OAAO,MAAM,CAAC,WAAW,CACrB,CACI,MAAM,OAAO,CAAC,GAAG,CACb,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC;YAC5C,GAAG;YACH,MAAM,sBAAsB,CACxB,KAAK,EACL,KAAK,EACL,CAAC,GAAG,WAAW,EAAE,GAAG,CAAC,EACrB,OAAO,CACV;SACJ,CAAC,CACL,CACJ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,yBAAiB,CAAC,CAC9C,CAAC;KACL;IAED,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAEzD,OAAO,OAAO;QACV,CAAC,CAAC,UAAU,CAAC,gCAAgC;YACzC,CAAC,CAAC,GAAG;YACL,CAAC,CAAC,yBAAiB;QACvB,CAAC,CAAC,UAAU,CAAC,gCAAgC;YACzC,CAAC,CAAC,yBAAiB;YACnB,CAAC,CAAC,GAAG,CAAA;AACjB,CAAC;AAjDD,wDAiDC;AAEc,KAAK,UAAU,qBAAqB,CAC/C,GAAQ,EACR,OAAiD;IAEjD,IAAI,OAAO,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;QACpC,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE;YAC/C,OAAO,IAAI,CAAC,SAAS,CACjB,MAAM,sBAAsB,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,CAC/D,CAAC;SACL;QACD,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE;YAC/C,OAAO,IAAI,CAAC,SAAS,CACjB,MAAM,sBAAsB,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,CAChE,CAAC;SACL;KACJ;IAED,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;QACzB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;KAC9B;SAAM;QACH,OAAO,GAAG,GAAG,EAAE,CAAC;KACnB;AACL,CAAC;AAtBD,wCAsBC"}

20
dist/index.js vendored Normal file
View File

@ -0,0 +1,20 @@
"use strict";
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 __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);
};
Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./logged"), exports);
__exportStar(require("./logger"), exports);
__exportStar(require("./reflected"), exports);
//# sourceMappingURL=index.js.map

1
dist/index.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,2CAAyB;AACzB,8CAA4B"}

98
dist/logged.js vendored Normal file
View File

@ -0,0 +1,98 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LoggedRoute = exports.LoggedFunction = void 0;
const common_1 = require("@nestjs/common");
const logger_1 = require("./logger");
const reflected_1 = require("./reflected");
const functions_1 = require("./functions");
function loggerInit(_target) {
if (!Object.getOwnPropertyNames(_target).includes('logger')) {
const newTargetLogger = new common_1.Logger(_target.constructor.name);
newTargetLogger.log('Logger Initialized.');
Object.defineProperty(_target, 'logger', {
writable: false,
enumerable: false,
configurable: false,
value: newTargetLogger,
});
}
}
function LoggedFunction(_target, key, descriptor) {
loggerInit(_target);
const logger = _target.logger;
const fn = descriptor.value;
if (!fn)
return;
descriptor.value = async function (...args) {
const scopedLoggerInjectableParam = Reflect.getOwnMetadata(reflected_1.scopedLogger, _target, key);
if (typeof scopedLoggerInjectableParam !== 'undefined' &&
(args.length <= scopedLoggerInjectableParam ||
!(args[scopedLoggerInjectableParam] instanceof logger_1.default))) {
args[scopedLoggerInjectableParam] = new logger_1.default(logger, key);
}
else if (typeof scopedLoggerInjectableParam !== 'undefined') {
args[scopedLoggerInjectableParam] = new logger_1.default(args[scopedLoggerInjectableParam], key);
}
const injectedLogger = typeof scopedLoggerInjectableParam !== 'undefined'
? args[scopedLoggerInjectableParam]
: logger;
const loggedParams = Reflect.getOwnMetadata(reflected_1.loggedParam, _target, key);
injectedLogger.log(`CALL ${key} ${loggedParams && loggedParams.length > 0
? 'WITH ' +
(await Promise.all(loggedParams.map(async ({ name, index, include, exclude }) => name + '=' + (await (0, functions_1.default)(args[index], {
include,
exclude,
}))))).join(', ')
: ''}`);
try {
const r = await fn.call(this, ...args);
injectedLogger.log(`RETURNED ${key}`);
return r;
}
catch (e) {
injectedLogger.error(`WHILE ${key} ERROR ${e}`);
throw e;
}
};
}
exports.LoggedFunction = LoggedFunction;
function LoggedRoute(route) {
return (_target, key, descriptor) => {
loggerInit(_target);
const logger = _target.logger;
const fullRoute = `${_target.constructor.name}/${route}`;
const fn = descriptor.value;
if (!fn)
return;
descriptor.value = async function (...args) {
const scopedLoggerInjectableParam = Reflect.getOwnMetadata(reflected_1.scopedLogger, _target, key);
if (typeof scopedLoggerInjectableParam !== 'undefined' &&
(args.length <= scopedLoggerInjectableParam ||
!(args[scopedLoggerInjectableParam] instanceof logger_1.default))) {
args[scopedLoggerInjectableParam] = new logger_1.default(logger, fullRoute);
}
const injectedLogger = typeof scopedLoggerInjectableParam !== 'undefined'
? args[scopedLoggerInjectableParam]
: logger;
const loggedParams = Reflect.getOwnMetadata(reflected_1.loggedParam, _target, key);
injectedLogger.log(`HIT HTTP ${fullRoute} (${key}) ${loggedParams && loggedParams.length > 0
? 'WITH ' +
(await Promise.all(loggedParams.map(async ({ name, index, include, exclude }) => name + '=' + (await (0, functions_1.default)(args[index], {
include,
exclude,
}))))).join(', ')
: ''}`);
try {
const r = await fn.call(this, ...args);
injectedLogger.log(`RETURNED RESPONSE ${fullRoute} (${key})`);
return r;
}
catch (e) {
injectedLogger.error(`WHILE HTTP ${fullRoute} (${key}) ERROR ${e}`);
throw e;
}
};
};
}
exports.LoggedRoute = LoggedRoute;
//# sourceMappingURL=logged.js.map

1
dist/logged.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"logged.js","sourceRoot":"","sources":["../src/logged.ts"],"names":[],"mappings":"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"}

24
dist/logger.js vendored Normal file
View File

@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const common_1 = require("@nestjs/common");
class ScopedLogger extends common_1.Logger {
constructor(logger, scope, scopeId) {
super();
this.logger = logger;
this.scope = scope;
this.scopeId = scopeId;
this.debug = this.scopedLog('debug');
this.log = this.scopedLog('log');
this.warn = this.scopedLog('warn');
this.verbose = this.scopedLog('verbose');
this.error = this.scopedLog('error');
this.fatal = this.scopedLog('fatal');
}
scopedLog(method) {
return (message) => {
this.logger[method](`-> ${this.scope}${this.scopeId ? `(${this.scopeId})` : ''}: ${message}`);
};
}
}
exports.default = ScopedLogger;
//# sourceMappingURL=logger.js.map

1
dist/logger.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":";;AAAA,2CAAsC;AAItC,MAAqB,YAAa,SAAQ,eAAM;IAC5C,YACY,MAAc,EACd,KAAa,EACb,OAAgB;QAExB,KAAK,EAAE,CAAC;QAJA,WAAM,GAAN,MAAM,CAAQ;QACd,UAAK,GAAL,KAAK,CAAQ;QACb,YAAO,GAAP,OAAO,CAAS;QAe5B,UAAK,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAChC,QAAG,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC5B,SAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC9B,YAAO,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACpC,UAAK,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAChC,UAAK,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAjBhC,CAAC;IAEO,SAAS,CAAC,MAAgB;QAC9B,OAAO,CAAC,OAAe,EAAE,EAAE;YACvB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CACf,MAAM,IAAI,CAAC,KAAK,GACZ,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EACzC,KAAK,OAAO,EAAE,CACjB,CAAC;QACN,CAAC,CAAC;IACN,CAAC;CAQJ;AAzBD,+BAyBC"}

27
dist/reflected.js vendored Normal file
View File

@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LoggedParam = exports.InjectLogger = exports.loggedParam = exports.scopedLogger = void 0;
exports.scopedLogger = Symbol('scopedLogger');
exports.loggedParam = Symbol('loggedParam');
function InjectLogger(target, propertyKey, parameterIndex) {
Reflect.defineMetadata(exports.scopedLogger, parameterIndex, target, propertyKey);
}
exports.InjectLogger = InjectLogger;
function LoggedParam(name, options) {
return (target, propertyKey, parameterIndex) => {
const existingLoggedParams = Reflect.getOwnMetadata(exports.loggedParam, target, propertyKey) || [];
existingLoggedParams.push({
name,
index: parameterIndex,
include: options &&
options.includePath &&
options.includePath.map((v) => (Array.isArray(v) ? v.join('.') : v)),
exclude: options &&
options.excludePath &&
options.excludePath.map((v) => (Array.isArray(v) ? v.join('.') : v)),
});
Reflect.defineMetadata(exports.loggedParam, existingLoggedParams, target, propertyKey);
};
}
exports.LoggedParam = LoggedParam;
//# sourceMappingURL=reflected.js.map

1
dist/reflected.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"reflected.js","sourceRoot":"","sources":["../src/reflected.ts"],"names":[],"mappings":";;;AAOa,QAAA,YAAY,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;AACtC,QAAA,WAAW,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;AAGjD,SAAgB,YAAY,CACxB,MAAW,EACX,WAA4B,EAC5B,cAAsB;IAEtB,OAAO,CAAC,cAAc,CAAC,oBAAY,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;AAC9E,CAAC;AAND,oCAMC;AAED,SAAgB,WAAW,CACvB,IAAY,EACZ,OAGC;IAED,OAAO,CACH,MAAW,EACX,WAA4B,EAC5B,cAAsB,EACxB,EAAE;QACA,MAAM,oBAAoB,GACtB,OAAO,CAAC,cAAc,CAAC,mBAAW,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC;QAEnE,oBAAoB,CAAC,IAAI,CAAC;YACtB,IAAI;YACJ,KAAK,EAAE,cAAc;YACrB,OAAO,EACH,OAAO;gBACP,OAAO,CAAC,WAAW;gBACnB,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACxE,OAAO,EACH,OAAO;gBACP,OAAO,CAAC,WAAW;gBACnB,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SAC3E,CAAC,CAAC;QAEH,OAAO,CAAC,cAAc,CAClB,mBAAW,EACX,oBAAoB,EACpB,MAAM,EACN,WAAW,CACd,CAAC;IACN,CAAC,CAAC;AACN,CAAC;AAnCD,kCAmCC"}

22
package.json Normal file
View File

@ -0,0 +1,22 @@
{
"name": "nestlogged",
"version": "1.0.0",
"description": "A NestJS Logger Decorator Library",
"main": "index.js",
"repository": "https://github.com/worplo/nestlogged",
"author": "Shinwoo PARK",
"license": "MIT",
"private": false,
"dependencies": {
"@nestjs/common": "^10.2.8",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1"
},
"devDependencies": {
"@types/node": "^20.9.1",
"typescript": "^5.2.2"
},
"scripts": {
"build": "tsc"
}
}

76
src/functions.ts Normal file
View File

@ -0,0 +1,76 @@
export const notIncludedSymbol = Symbol('notIncluded')
export async function includeOrExcludeObject(
ocv: any,
paths: string[],
currentPath: string[] = [],
include: boolean, // or exclude
) {
if (Array.isArray(ocv)) {
return (
await Promise.all(
ocv.map(
async (v, i) =>
await includeOrExcludeObject(
v,
paths,
[...currentPath, i.toString()],
include,
),
),
)
).filter((e) => e !== notIncludedSymbol);
}
if (typeof ocv === 'object') {
return Object.fromEntries(
(
await Promise.all(
Object.entries(ocv).map(async ([key, value]) => [
key,
await includeOrExcludeObject(
value,
paths,
[...currentPath, key],
include,
),
]),
)
).filter((e) => e[1] !== notIncludedSymbol),
);
}
const isIncluded = paths.includes(currentPath.join('.'));
return include
? isIncluded // include mode, path is in list
? ocv
: notIncludedSymbol
: isIncluded // exclude mode, path is in list
? notIncludedSymbol
: ocv
}
export default async function objectContainedLogged(
ocv: any,
options?: {include?: string[]; exclude: string[]},
): Promise<string> {
if (options && typeof ocv === 'object') {
if (options.include && options.include.length > 0) {
return JSON.stringify(
await includeOrExcludeObject(ocv, options.include, [], true),
);
}
if (options.exclude && options.exclude.length > 0) {
return JSON.stringify(
await includeOrExcludeObject(ocv, options.exclude, [], false),
);
}
}
if (typeof ocv === 'object') {
return JSON.stringify(ocv);
} else {
return `${ocv}`;
}
}

3
src/index.ts Normal file
View File

@ -0,0 +1,3 @@
export * from './logged';
export * from './logger';
export * from './reflected';

164
src/logged.ts Normal file
View File

@ -0,0 +1,164 @@
import {Logger} from "@nestjs/common";
import ScopedLogger from "./logger";
import {LoggedParamReflectData} from "./reflected";
import {loggedParam, scopedLogger} from "./reflected";
import objectContainedLogged from "./functions";
function loggerInit(_target: any) {
if (!Object.getOwnPropertyNames(_target).includes('logger')) {
const newTargetLogger = new Logger(_target.constructor.name);
newTargetLogger.log('Logger Initialized.');
Object.defineProperty(_target, 'logger', {
writable: false,
enumerable: false,
configurable: false,
value: newTargetLogger,
});
}
}
export function LoggedFunction<F extends Array<any>, R>(
_target: any,
key: string,
descriptor: TypedPropertyDescriptor<(...args: F) => Promise<R>>,
) {
loggerInit(_target);
const logger = _target.logger;
const fn = descriptor.value;
if (!fn) return;
descriptor.value = async function (...args: F) {
const scopedLoggerInjectableParam: number = Reflect.getOwnMetadata(
scopedLogger,
_target,
key,
);
if (
typeof scopedLoggerInjectableParam !== 'undefined' &&
(args.length <= scopedLoggerInjectableParam ||
!(args[scopedLoggerInjectableParam] instanceof ScopedLogger))
) {
args[scopedLoggerInjectableParam] = new ScopedLogger(logger, key);
} else if (typeof scopedLoggerInjectableParam !== 'undefined') {
args[scopedLoggerInjectableParam] = new ScopedLogger(
args[scopedLoggerInjectableParam],
key,
);
}
const injectedLogger=
typeof scopedLoggerInjectableParam !== 'undefined'
? args[scopedLoggerInjectableParam]
: logger;
const loggedParams: LoggedParamReflectData[] = Reflect.getOwnMetadata(
loggedParam,
_target,
key,
)
injectedLogger.log(
`CALL ${key} ${
loggedParams && loggedParams.length > 0
? 'WITH ' +
(
await Promise.all(
loggedParams.map(
async ({ name, index, include, exclude }) =>
name + '=' + (await objectContainedLogged(args[index], {
include,
exclude,
})),
),
)
).join(', ')
: ''
}`,
);
try {
const r: R = await fn.call(this, ...args);
injectedLogger.log(`RETURNED ${key}`);
return r;
} catch (e) {
injectedLogger.error(`WHILE ${key} ERROR ${e}`);
throw e;
}
};
}
export function LoggedRoute<F extends Array<any>, R>(route: string) {
return (
_target: any,
key: string,
descriptor: TypedPropertyDescriptor<(...args: F) => Promise<R>>,
) => {
loggerInit(_target);
const logger = _target.logger;
const fullRoute = `${_target.constructor.name}/${route}`;
const fn = descriptor.value;
if (!fn) return;
descriptor.value = async function (...args: F) {
const scopedLoggerInjectableParam: number = Reflect.getOwnMetadata(
scopedLogger,
_target,
key,
);
if (
typeof scopedLoggerInjectableParam !== 'undefined' &&
(args.length <= scopedLoggerInjectableParam ||
!(args[scopedLoggerInjectableParam] instanceof ScopedLogger))
) {
args[scopedLoggerInjectableParam] = new ScopedLogger(logger, fullRoute);
}
const injectedLogger=
typeof scopedLoggerInjectableParam !== 'undefined'
? args[scopedLoggerInjectableParam]
: logger;
const loggedParams: LoggedParamReflectData[] = Reflect.getOwnMetadata(
loggedParam,
_target,
key,
)
injectedLogger.log(
`HIT HTTP ${fullRoute} (${key}) ${
loggedParams && loggedParams.length > 0
? 'WITH ' +
(
await Promise.all(
loggedParams.map(
async ({ name, index, include, exclude }) =>
name + '=' + (await objectContainedLogged(args[index], {
include,
exclude,
})),
),
)
).join(', ')
: ''
}`,
);
try {
const r: R = await fn.call(this, ...args);
injectedLogger.log(`RETURNED RESPONSE ${fullRoute} (${key})`);
return r;
} catch (e) {
injectedLogger.error(`WHILE HTTP ${fullRoute} (${key}) ERROR ${e}`);
throw e;
}
};
}
}

30
src/logger.ts Normal file
View File

@ -0,0 +1,30 @@
import {Logger} from "@nestjs/common";
type LogLevel = 'debug' | 'log' | 'warn' | 'verbose' | 'error' | 'fatal';
export default class ScopedLogger extends Logger {
constructor(
private logger: Logger,
private scope: string,
private scopeId?: string,
) {
super();
}
private scopedLog(method: LogLevel) {
return (message: string) => {
this.logger[method](
`-> ${this.scope}${
this.scopeId ? `(${this.scopeId})` : ''
}: ${message}`,
);
};
}
debug = this.scopedLog('debug');
log = this.scopedLog('log');
warn = this.scopedLog('warn');
verbose = this.scopedLog('verbose');
error = this.scopedLog('error');
fatal = this.scopedLog('fatal');
}

55
src/reflected.ts Normal file
View File

@ -0,0 +1,55 @@
export interface LoggedParamReflectData {
name: string;
index: number;
include?: string[];
exclude?: string[];
}
export const scopedLogger = Symbol('scopedLogger');
export const loggedParam = Symbol('loggedParam');
export function InjectLogger(
target: any,
propertyKey: string | symbol,
parameterIndex: number,
) {
Reflect.defineMetadata(scopedLogger, parameterIndex, target, propertyKey);
}
export function LoggedParam(
name: string,
options?: {
includePath?: (string | string[])[];
excludePath?: (string | string[])[];
},
) {
return (
target: any,
propertyKey: string | symbol,
parameterIndex: number,
) => {
const existingLoggedParams: LoggedParamReflectData[] =
Reflect.getOwnMetadata(loggedParam, target, propertyKey) || [];
existingLoggedParams.push({
name,
index: parameterIndex,
include:
options &&
options.includePath &&
options.includePath.map((v) => (Array.isArray(v) ? v.join('.') : v)),
exclude:
options &&
options.excludePath &&
options.excludePath.map((v) => (Array.isArray(v) ? v.join('.') : v)),
});
Reflect.defineMetadata(
loggedParam,
existingLoggedParams,
target,
propertyKey
);
};
}

12
tsconfig.json Normal file
View File

@ -0,0 +1,12 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "ES2021",
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src"
},
"exclude": [
"node_modules"
],
}

63
yarn.lock Normal file
View File

@ -0,0 +1,63 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@lukeed/csprng@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@lukeed/csprng/-/csprng-1.1.0.tgz#1e3e4bd05c1cc7a0b2ddbd8a03f39f6e4b5e6cfe"
integrity sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==
"@nestjs/common@^10.2.8":
version "10.2.8"
resolved "https://registry.yarnpkg.com/@nestjs/common/-/common-10.2.8.tgz#f8934e6353440d6e51c89c0cf1b0f9aef54e8729"
integrity sha512-rmpwcdvq2IWMmsUVP8rsdKub6uDWk7dwCYo0aif50JTwcvcxzaP3iKVFKoSgvp0RKYu8h15+/AEOfaInmPpl0Q==
dependencies:
uid "2.0.2"
iterare "1.2.1"
tslib "2.6.2"
"@types/node@^20.9.1":
version "20.9.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.9.1.tgz#9d578c610ce1e984adda087f685ace940954fe19"
integrity sha512-HhmzZh5LSJNS5O8jQKpJ/3ZcrrlG6L70hpGqMIAoM9YVD0YBRNWYsfwcXq8VnSjlNpCpgLzMXdiPo+dxcvSmiA==
dependencies:
undici-types "~5.26.4"
iterare@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/iterare/-/iterare-1.2.1.tgz#139c400ff7363690e33abffa33cbba8920f00042"
integrity sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==
reflect-metadata@^0.1.13:
version "0.1.13"
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
rxjs@^7.8.1:
version "7.8.1"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543"
integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==
dependencies:
tslib "^2.1.0"
tslib@2.6.2, tslib@^2.1.0:
version "2.6.2"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
typescript@^5.2.2:
version "5.2.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78"
integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==
uid@2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/uid/-/uid-2.0.2.tgz#4b5782abf0f2feeefc00fa88006b2b3b7af3e3b9"
integrity sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==
dependencies:
"@lukeed/csprng" "^1.0.0"
undici-types@~5.26.4:
version "5.26.5"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==