UNPKG

@loopback/logging

Version:

An extension exposes logging for Winston and Fluentd with LoopBack 4

128 lines (119 loc) 3.17 kB
// Copyright IBM Corp. and LoopBack contributors 2019. All Rights Reserved. // Node module: @loopback/logging // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT import { asGlobalInterceptor, BindingScope, config, ContextTags, inject, injectable, Interceptor, InvocationContext, Provider, ValueOrPromise, } from '@loopback/core'; import {Request, RequestContext, Response, RestBindings} from '@loopback/rest'; import morgan from 'morgan'; import {format} from 'util'; import {Logger} from 'winston'; import {LoggingBindings} from '../keys'; /** * A local interceptor that provides logging for method invocations. */ @injectable({ tags: {[ContextTags.KEY]: LoggingBindings.WINSTON_INVOCATION_LOGGER}, scope: BindingScope.SINGLETON, }) export class InvocationLoggingInterceptor implements Provider<Interceptor> { constructor( @inject(LoggingBindings.WINSTON_LOGGER) private logger: Logger, ) {} value() { return this.intercept.bind(this); } async intercept<T>( invocationCtx: InvocationContext, next: () => ValueOrPromise<T>, ) { try { this.logger.log( 'verbose', format( 'invoking %s with:', invocationCtx.targetName, invocationCtx.args, ), ); const result = await next(); this.logger.log( 'verbose', format('returned from %s:', invocationCtx.targetName, result), ); return result; } catch (err) { this.logger.log( 'error', format('error from %s', invocationCtx.targetName, err), ); throw err; } } } export interface AccessLogOptions extends morgan.Options<Request, Response> { format?: string | morgan.FormatFn; } /** * A global interceptor that provides logging for http requests/responses. */ @injectable(asGlobalInterceptor('logging'), { tags: { [ContextTags.KEY]: LoggingBindings.WINSTON_HTTP_ACCESS_LOGGER, // Only apply to invocations from REST routes [ContextTags.GLOBAL_INTERCEPTOR_SOURCE]: 'route', }, scope: BindingScope.SINGLETON, }) export class HttpAccessLogInterceptor implements Provider<Interceptor> { constructor( @inject(LoggingBindings.WINSTON_LOGGER) private logger: Logger, @config() private morganOptions: AccessLogOptions = {format: 'combined'}, ) {} value() { return this.intercept.bind(this); } async intercept<T>( invocationCtx: InvocationContext, next: () => ValueOrPromise<T>, ) { const reqCtx = await invocationCtx.get<RequestContext>( RestBindings.Http.CONTEXT, ); const options: AccessLogOptions = { ...this.morganOptions, stream: { write: (message: string) => { this.logger.info(message); }, }, }; if (typeof options.format === 'function') { morgan(options.format, options)( reqCtx.request, reqCtx.response, () => {}, ); } else { morgan(options.format ?? 'combined', options)( reqCtx.request, reqCtx.response, () => {}, ); } return next(); } }