/* * MIT License * * Copyright (c) 2019 nest-mods * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /* * Created by Diluka on 2018/6/20. * * * ----------- 神 兽 佑 我 ----------- * ┏┓ ┏┓+ + * ┏┛┻━━━━━━┛┻┓ + + * ┃ ┃ * ┣ ━ ┃ ++ + + + * ████━████ ┃+ * ┃ ┃ + * ┃ ┴ ┃ * ┃ ┃ + + * ┗━┓ ┏━┛ Code is far away from bug * ┃ ┃ with the animal protecting * ┃ ┃ + + + + * ┃ ┃ * ┃ ┃ + * ┃ ┃ + + * ┃ ┃ + * ┃ ┗━━━┓ + + * ┃ ┣┓ * ┃ ┏┛ * ┗┓┓┏━━━━┳┓┏┛ + + + + * ┃┫┫ ┃┫┫ * ┗┻┛ ┗┻┛+ + + + * ----------- 永 无 BUG ------------ */ import { Logger, LogLevel } from '@nestjs/common'; import * as _ from 'lodash'; import { Helpers } from './helpers.util'; import { InjectLoggerOptions } from './log.decorator'; // interface LogOptionsBase { /** * print notify message */ notify?: false | LogLevel; /** * using custom notify message */ notifyMessage?: string; } export interface LogCallingOptions extends LogOptionsBase { /** * print method parameters */ parameters?: false | LogLevel; } export interface LogCalledOptions extends LogOptionsBase { /** * print method result when success */ result?: false | LogLevel; } export interface LogThrowingOptions extends LogOptionsBase { /** * print error message */ message?: false | LogLevel; /** * print error stack */ stack?: false | LogLevel; /** * print error */ raw?: false | LogLevel; } // tslint:disable-next-line:no-empty-interface export interface LogCompletedOptions extends LogOptionsBase {} export interface LogInvokeOptions extends InjectLoggerOptions { /** * before calling method */ calling?: false | LogCallingOptions; /** * call method succeed */ called?: false | LogCalledOptions; /** * method throwing an error */ throwing?: false | LogThrowingOptions; /** * when method called, no matter it is success */ completed?: false | LogCompletedOptions; } // export const LogInvokeDefaultOptions: LogInvokeOptions = { calling: { notify: 'log', parameters: false }, called: false, throwing: { notify: 'log', message: 'warn', stack: false, raw: false }, completed: false, }; export function LogInvoke(options?: LogInvokeOptions); export function LogInvoke(prefix?: string, options?: LogInvokeOptions); export function LogInvoke( prefixOrOptions?: string | LogInvokeOptions, options: LogInvokeOptions = {}, ): MethodDecorator { let prefix; if (_.isString(prefixOrOptions)) { prefix = prefixOrOptions; } else { prefix = Helpers.DEFAULT_PREFIX; options = prefixOrOptions || options; } options = _.defaultsDeep(options, LogInvokeDefaultOptions); return ( target: object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor, ) => { const className = Helpers.getClassName(target); const context = options.context || className; const logger = new Logger(`${prefix}:${context}`, { timestamp: options.isTimeDiffEnabled, }); const methodSign = `${className}#${propertyKey as any}`; const method = descriptor.value; descriptor.value = async function (...args: any[]) { const { calling, called, throwing, completed } = options; if (calling) { const { notify, notifyMessage, parameters } = calling; if (notify) { Helpers.logWithLevel( logger, notify, )(notifyMessage || `calling ${methodSign}`); } if (parameters) { Helpers.logWithLevel(logger, parameters)('parameters:'); Helpers.logWithLevel(logger, parameters)(args); } } try { const calledResult = await method.apply(this, args); if (called) { const { result, notify, notifyMessage } = called; if (notify) { Helpers.logWithLevel( logger, notify, )(notifyMessage || `${methodSign} called`); } if (result) { Helpers.logWithLevel(logger, result)('result:'); Helpers.logWithLevel(logger, result)(calledResult); } } return calledResult; } catch (e) { if (throwing) { const { message, stack, raw, notify, notifyMessage } = throwing; if (notify) { Helpers.logWithLevel( logger, notify, )(notifyMessage || `${methodSign} failed`); } if (e instanceof Error) { if (message) { Helpers.logWithLevel(logger, message)('error message:'); Helpers.logWithLevel(logger, message)(e?.message); } if (stack) { Helpers.logWithLevel(logger, stack)('error stack:'); Helpers.logWithLevel(logger, stack)(e?.stack); } } if (raw) { Helpers.logWithLevel(logger, raw)('error:'); Helpers.logWithLevel(logger, raw)(e); } } throw e; } finally { if (completed) { const { notify, notifyMessage } = completed; if (notify) { Helpers.logWithLevel( logger, notify, )(notifyMessage || `call ${methodSign} completed`); } } } }; return descriptor; }; }