ngx-logger
Version:
[](https://www.npmjs.com/package/ngx-logger)
1 lines • 83.1 kB
Source Map (JSON)
{"version":3,"file":"ngx-logger.mjs","sources":["../../../src/lib/config/iconfig.ts","../../../src/lib/config/config-engine.ts","../../../src/lib/config/iconfig-engine-factory.ts","../../../src/lib/config/config-engine-factory.ts","../../../src/lib/mapper/imapper.service.ts","../../../src/lib/mapper/mapper.service.ts","../../../src/lib/metadata/imetadata.service.ts","../../../src/lib/metadata/metadata.service.ts","../../../src/lib/monitor/logger-monitor.ts","../../../src/lib/rules/irules.service.ts","../../../src/lib/rules/rules.service.ts","../../../src/lib/server/iserver.service.ts","../../../src/lib/server/server.service.ts","../../../src/lib/writer/iwriter.service.ts","../../../src/lib/types/logger-level.enum.ts","../../../src/lib/writer/color-scheme.ts","../../../src/lib/writer/writer.service.ts","../../../src/lib/logger.service.ts","../../../src/lib/custom-logger.service.ts","../../../src/lib/logger.module.ts","../../../src/public_api.ts","../../../src/ngx-logger.ts"],"sourcesContent":["import { HttpHeaders, HttpParams } from \"@angular/common/http\";\r\nimport { NgxLoggerLevel } from \"../types/logger-level.enum\";\r\nimport { NGXLoggerColorScheme } from \"../writer/color-scheme\";\r\n\r\n/**\r\n * Injection token of logger config\r\n */\r\nexport const TOKEN_LOGGER_CONFIG = 'TOKEN_LOGGER_CONFIG';\r\n\r\n/**\r\n * Interface that defines logger config data\r\n * You can use your own logger config as long as it implements this interface\r\n */\r\nexport interface INGXLoggerConfig {\r\n // Global config\r\n /** Minimum level to be written */\r\n level: NgxLoggerLevel;\r\n\r\n // metadata-service config\r\n /** Timestamp format: any format accepted by Angular DatePipe. Defaults to ISOString. If set you need to provide DatePipe from @angular/common */\r\n timestampFormat?: string;\r\n\r\n // rule-service config\r\n /** If true the console logging won't be called */\r\n disableConsoleLogging?: boolean;\r\n\r\n // mapper-service config\r\n /* If true, the logger will download sourcemaps to compute the file details */\r\n enableSourceMaps?: boolean;\r\n /** Number of calls that will be ignored when trying to get line of stacktrace */\r\n proxiedSteps?: number;\r\n\r\n // writer-service config\r\n /** Defines the color to use depending on log level */\r\n colorScheme?: NGXLoggerColorScheme;\r\n /** If true the console log won't include file details (filename, line number and column number) */\r\n disableFileDetails?: boolean;\r\n /** Adds context to the message that will be written to the log */\r\n context?: string;\r\n\r\n // server-service config\r\n /** Minimum level to be sent to server */\r\n serverLogLevel?: NgxLoggerLevel;\r\n /** URL used to send log to server */\r\n serverLoggingUrl?: string;\r\n /** If true, adds \"withCredentials\" options when sending log to server */\r\n withCredentials?: boolean;\r\n /** Http params that will be used when sending log to server */\r\n customHttpParams?: HttpParams,\r\n /** Http headers that will be used when sending log to server */\r\n customHttpHeaders?: HttpHeaders,\r\n /** Response type that will be used when sending log to server (defaults to json) */\r\n httpResponseType?: \"arraybuffer\" | \"blob\" | \"text\" | \"json\";\r\n /** Number of logs needed before it is sent to the server\r\n * This means your server will receive an array of INGXLoggerMetadata instead of just one object\r\n */\r\n serverCallsBatchSize?: number;\r\n /** Maximum time (in miliseconds) waited before performing a log call to the server if the number of logs was not reached\r\n * This means your server will receive an array of INGXLoggerMetadata instead of just one object\r\n */\r\n serverCallsTimer?: number;\r\n /** If true, logger calls to server will be performed outside NgZone */\r\n serverCallsOutsideNgZone?: boolean;\r\n}\r\n","import { NgxLoggerLevel } from './../types/logger-level.enum';\r\nimport { INGXLoggerConfigEngine } from './iconfig-engine';\r\nimport { INGXLoggerConfig } from './iconfig';\r\n\r\nexport class NGXLoggerConfigEngine implements INGXLoggerConfigEngine {\r\n\r\n private config: INGXLoggerConfig;\r\n\r\n constructor(\r\n config: INGXLoggerConfig,\r\n ) {\r\n this.config = this._clone(config);\r\n }\r\n\r\n /** Get a readonly access to the level configured for the NGXLogger */\r\n get level(): NgxLoggerLevel {\r\n return this.config.level;\r\n }\r\n\r\n /** Get a readonly access to the serverLogLevel configured for the NGXLogger */\r\n get serverLogLevel(): NgxLoggerLevel {\r\n return this.config.serverLogLevel;\r\n }\r\n\r\n updateConfig(config: INGXLoggerConfig) {\r\n this.config = this._clone(config);\r\n }\r\n\r\n /** Update the config partially\r\n * This is useful if you want to update only one parameter of the config\r\n */\r\n partialUpdateConfig(partialConfig: Partial<INGXLoggerConfig>): void {\r\n // avoid any error if the config is incorrect\r\n if (!partialConfig) {\r\n return;\r\n }\r\n\r\n Object.keys(partialConfig).forEach(configParamKey => {\r\n this.config[configParamKey] = partialConfig[configParamKey];\r\n });\r\n }\r\n\r\n getConfig(): INGXLoggerConfig {\r\n return this._clone(this.config);\r\n }\r\n\r\n // TODO: This is a shallow clone, If the config ever becomes hierarchical we must make this a deep clone\r\n private _clone(object: any) {\r\n const cloneConfig: INGXLoggerConfig = { level: null };\r\n\r\n Object.keys(object).forEach((key) => {\r\n cloneConfig[key] = object[key];\r\n });\r\n\r\n return cloneConfig;\r\n }\r\n}\r\n","import { INGXLoggerConfig } from \"./iconfig\";\r\nimport { INGXLoggerConfigEngine } from \"./iconfig-engine\";\r\n\r\n/**\r\n * Injection token of logger config engine factory\r\n */\r\nexport const TOKEN_LOGGER_CONFIG_ENGINE_FACTORY = 'TOKEN_LOGGER_CONFIG_ENGINE_FACTORY';\r\n\r\nexport interface INGXLoggerConfigEngineFactory {\r\n /** Create the instance of configEngine */\r\n provideConfigEngine(config: INGXLoggerConfig): INGXLoggerConfigEngine;\r\n}\r\n","import { INGXLoggerConfig } from \"./iconfig\";\r\nimport { NGXLoggerConfigEngine } from \"./config-engine\";\r\nimport { INGXLoggerConfigEngine } from \"./iconfig-engine\";\r\nimport { INGXLoggerConfigEngineFactory } from \"./iconfig-engine-factory\";\r\n\r\nexport class NGXLoggerConfigEngineFactory implements INGXLoggerConfigEngineFactory {\r\n\r\n provideConfigEngine(config: INGXLoggerConfig): INGXLoggerConfigEngine {\r\n return new NGXLoggerConfigEngine(config);\r\n }\r\n\r\n}\r\n","import { INGXLoggerConfig } from \"../config/iconfig\";\r\nimport { INGXLoggerMetadata } from \"../metadata/imetadata\";\r\nimport { INGXLoggerLogPosition } from \"./ilog-position\";\r\nimport { Observable } from \"rxjs\";\r\n\r\n/**\r\n * Injection token of logger mapper service\r\n */\r\nexport const TOKEN_LOGGER_MAPPER_SERVICE = 'TOKEN_LOGGER_MAPPER_SERVICE';\r\n\r\nexport interface INGXLoggerMapperService {\r\n /**\r\n * Returns the log position of the caller\r\n * If sourceMaps are enabled, it attemps to get the source map from the server, and use that to parse the position\r\n * @param config \r\n * @param metadata \r\n * @returns \r\n */\r\n getLogPosition(config: INGXLoggerConfig, metadata: INGXLoggerMetadata): Observable<INGXLoggerLogPosition>;\r\n}\r\n","import { HttpBackend, HttpRequest, HttpResponse } from '@angular/common/http';\r\nimport { SourceMap } from '@angular/compiler';\r\nimport { Injectable, Optional } from '@angular/core';\r\nimport { Observable, of } from 'rxjs';\r\nimport { catchError, filter, map, retry, shareReplay } from 'rxjs/operators';\r\nimport * as vlq from 'vlq';\r\nimport { INGXLoggerConfig } from '../config/iconfig';\r\nimport { INGXLoggerMetadata } from '../metadata/imetadata';\r\nimport { INGXLoggerLogPosition } from './ilog-position';\r\nimport { INGXLoggerMapperService } from './imapper.service';\r\n\r\n@Injectable()\r\nexport class NGXLoggerMapperService implements INGXLoggerMapperService {\r\n\r\n /** cache for source maps, key is source map location, ie. 'http://localhost:4200/main.js.map' */\r\n protected sourceMapCache: Map<string, Observable<SourceMap>> = new Map();\r\n\r\n /** cache for specific log position, key is the dist position, ie 'main.js:339:21' */\r\n protected logPositionCache: Map<string, Observable<INGXLoggerLogPosition>> = new Map();\r\n\r\n constructor(\r\n @Optional() private httpBackend: HttpBackend\r\n ) {\r\n }\r\n\r\n /**\r\n * Returns the log position of the caller\r\n * If sourceMaps are enabled, it attemps to get the source map from the server, and use that to parse the position\r\n * @param config \r\n * @param metadata \r\n * @returns \r\n */\r\n public getLogPosition(config: INGXLoggerConfig, metadata: INGXLoggerMetadata): Observable<INGXLoggerLogPosition> {\r\n const stackLine = this.getStackLine(config);\r\n\r\n // if we were not able to parse the stackLine, just return an empty Log Position\r\n if (!stackLine) {\r\n return of({ fileName: '', lineNumber: 0, columnNumber: 0 });\r\n }\r\n\r\n const logPosition = this.getLocalPosition(stackLine);\r\n\r\n if (!config.enableSourceMaps) {\r\n return of(logPosition);\r\n }\r\n\r\n const sourceMapLocation = this.getSourceMapLocation(stackLine);\r\n return this.getSourceMap(sourceMapLocation, logPosition);\r\n }\r\n\r\n /**\r\n * Get the stackline of the original caller\r\n * @param config \r\n * @returns null if stackline was not found\r\n */\r\n protected getStackLine(config: INGXLoggerConfig): string {\r\n const error = new Error();\r\n\r\n try {\r\n // noinspection ExceptionCaughtLocallyJS\r\n throw error;\r\n } catch (e) {\r\n\r\n try {\r\n // Here are different examples of stacktrace \r\n\r\n // Firefox (last line is the user code, the 4 first are ours):\r\n // getStackLine@http://localhost:4200/main.js:358:23\r\n // getCallerDetails@http://localhost:4200/main.js:557:44\r\n // _log@http://localhost:4200/main.js:830:28\r\n // debug@http://localhost:4200/main.js:652:14\r\n // handleLog@http://localhost:4200/main.js:1158:29\r\n\r\n // Chrome and Edge (last line is the user code):\r\n // Error\r\n // at Function.getStackLine (ngx-logger.js:329)\r\n // at NGXMapperService.getCallerDetails (ngx-logger.js:528)\r\n // at NGXLogger._log (ngx-logger.js:801)\r\n // at NGXLogger.info (ngx-logger.js:631)\r\n // at AppComponent.handleLog (app.component.ts:38)\r\n\r\n let defaultProxy = 4; // We make 4 functions call before getting here\r\n const firstStackLine = error.stack.split('\\n')[0];\r\n if (!firstStackLine.includes('.js:')) {\r\n // The stacktrace starts with no function call (example in Chrome or Edge)\r\n defaultProxy = defaultProxy + 1;\r\n }\r\n\r\n return error.stack.split('\\n')[(defaultProxy + (config.proxiedSteps || 0))];\r\n } catch (e) {\r\n return null;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Get position of caller without using sourceMaps\r\n * @param stackLine \r\n * @returns \r\n */\r\n protected getLocalPosition(stackLine: string): INGXLoggerLogPosition {\r\n // strip base path, then parse filename, line, and column, stackline looks like this :\r\n // Firefox\r\n // handleLog@http://localhost:4200/main.js:1158:29\r\n // Chrome and Edge\r\n // at AppComponent.handleLog (app.component.ts:38)\r\n\r\n const positionStartIndex = stackLine.lastIndexOf('\\/');\r\n let positionEndIndex = stackLine.indexOf(')');\r\n if (positionEndIndex < 0) {\r\n positionEndIndex = undefined;\r\n }\r\n\r\n const position = stackLine.substring(positionStartIndex + 1, positionEndIndex);\r\n const dataArray = position.split(':');\r\n if (dataArray.length === 3) {\r\n return { fileName: dataArray[0], lineNumber: +dataArray[1], columnNumber: +dataArray[2] };\r\n }\r\n return { fileName: 'unknown', lineNumber: 0, columnNumber: 0 };\r\n }\r\n\r\n private getTranspileLocation(stackLine: string): string {\r\n // Example stackLine:\r\n // Firefox : getStackLine@http://localhost:4200/main.js:358:23\r\n // Chrome and Edge : at Function.getStackLine (ngx-logger.js:329)\r\n let locationStartIndex = stackLine.indexOf('(');\r\n if (locationStartIndex < 0) {\r\n locationStartIndex = stackLine.lastIndexOf('@');\r\n if (locationStartIndex < 0) {\r\n locationStartIndex = stackLine.lastIndexOf(' ');\r\n }\r\n }\r\n\r\n let locationEndIndex = stackLine.indexOf(')');\r\n if (locationEndIndex < 0) {\r\n locationEndIndex = undefined;\r\n }\r\n\r\n return stackLine.substring(locationStartIndex + 1, locationEndIndex);\r\n }\r\n\r\n /**\r\n * Gets the URL of the sourcemap (the URL can be relative or absolute, it is browser dependant)\r\n * @param stackLine \r\n * @returns \r\n */\r\n protected getSourceMapLocation(stackLine: string): string {\r\n const file = this.getTranspileLocation(stackLine);\r\n const mapFullPath = file.substring(0, file.lastIndexOf(':'));\r\n return mapFullPath.substring(0, mapFullPath.lastIndexOf(':')) + '.map';\r\n }\r\n\r\n private getMapping(sourceMap: SourceMap, position: INGXLoggerLogPosition): INGXLoggerLogPosition {\r\n // => ';' indicates end of a line\r\n // => ',' separates mappings in a line\r\n // decoded mapping => [ generatedCodeColumn, sourceFileIndex, sourceCodeLine, sourceCodeColumn, nameIndex ]\r\n let sourceFileIndex = 0, // second field\r\n sourceCodeLine = 0, // third field\r\n sourceCodeColumn = 0; // fourth field\r\n\r\n const lines = sourceMap.mappings.split(';');\r\n\r\n for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {\r\n // reset column position to 0 after each line\r\n let generatedCodeColumn = 0;\r\n // decode sections in line\r\n const columns = lines[lineIndex].split(',');\r\n\r\n for (let columnIndex = 0; columnIndex < columns.length; columnIndex++) {\r\n const decodedSection = vlq.decode(columns[columnIndex]);\r\n if (decodedSection.length >= 4) {\r\n // update relative positions\r\n generatedCodeColumn += decodedSection[0];\r\n sourceFileIndex += decodedSection[1];\r\n sourceCodeLine += decodedSection[2];\r\n sourceCodeColumn += decodedSection[3];\r\n }\r\n\r\n // check if matching map\r\n if (lineIndex === position.lineNumber) {\r\n if (generatedCodeColumn === position.columnNumber) {\r\n // matching column and line found\r\n return { fileName: sourceMap.sources[sourceFileIndex], lineNumber: sourceCodeLine, columnNumber: sourceCodeColumn };\r\n } else if (columnIndex + 1 === columns.length) {\r\n // matching column not found, but line is correct\r\n return { fileName: sourceMap.sources[sourceFileIndex], lineNumber: sourceCodeLine, columnNumber: 0 };\r\n }\r\n }\r\n }\r\n }\r\n // failed if reached\r\n return { fileName: 'unknown', lineNumber: 0, columnNumber: 0 };\r\n }\r\n\r\n /**\r\n * does the http get request to get the source map\r\n * @param sourceMapLocation\r\n * @param distPosition\r\n */\r\n protected getSourceMap(sourceMapLocation: string, distPosition: INGXLoggerLogPosition): Observable<INGXLoggerLogPosition> {\r\n const req = new HttpRequest<SourceMap>('GET', sourceMapLocation);\r\n const distPositionKey = `${distPosition.fileName}:${distPosition.lineNumber}:${distPosition.columnNumber}`;\r\n\r\n // if the specific log position is already in cache return it\r\n if (this.logPositionCache.has(distPositionKey)) {\r\n return this.logPositionCache.get(distPositionKey);\r\n }\r\n\r\n // otherwise check if the source map is already cached for given source map location\r\n if (!this.sourceMapCache.has(sourceMapLocation)) {\r\n if (!this.httpBackend) {\r\n console.error('NGXLogger : Can\\'t get sourcemap because HttpBackend is not provided. You need to import HttpClientModule');\r\n this.sourceMapCache.set(sourceMapLocation, of(null));\r\n } else {\r\n // obtain the source map if not cached\r\n this.sourceMapCache.set(\r\n sourceMapLocation,\r\n this.httpBackend.handle(req).pipe(\r\n filter((e) => e instanceof HttpResponse),\r\n map<HttpResponse<SourceMap>, SourceMap>(\r\n (httpResponse: HttpResponse<SourceMap>) => httpResponse.body\r\n ),\r\n retry(3),\r\n shareReplay(1)\r\n )\r\n );\r\n }\r\n }\r\n\r\n // at this point the source map is cached, use it to get specific log position mapping\r\n const logPosition$ = this.sourceMapCache.get(sourceMapLocation).pipe(\r\n map<SourceMap, INGXLoggerLogPosition>((sourceMap) => {\r\n // sourceMap can be null if HttpBackend is not provided for example\r\n if (!sourceMap) {\r\n return distPosition;\r\n }\r\n // map generated position to source position\r\n return this.getMapping(sourceMap, distPosition)\r\n }),\r\n catchError(() => of(distPosition)),\r\n shareReplay(1)\r\n );\r\n\r\n // store specific log position in cache for given dest position and return it\r\n this.logPositionCache.set(distPositionKey, logPosition$);\r\n\r\n return logPosition$;\r\n }\r\n}\r\n","import { INGXLoggerConfig } from \"../config/iconfig\";\r\nimport { NgxLoggerLevel } from \"../types/logger-level.enum\";\r\nimport { INGXLoggerMetadata } from \"./imetadata\";\r\n\r\n/**\r\n * Injection token of logger metadata service\r\n */\r\nexport const TOKEN_LOGGER_METADATA_SERVICE = 'TOKEN_LOGGER_METADATA_SERVICE';\r\n\r\nexport interface INGXLoggerMetadataService {\r\n /**\r\n * Gets the content to be logged and some metadata around it\r\n * @param level \r\n * @param config \r\n * @param message \r\n * @param additional \r\n */\r\n getMetadata(level: NgxLoggerLevel, config: INGXLoggerConfig, message?: any | (() => any), additional?: any[]): INGXLoggerMetadata;\r\n}\r\n","import { DatePipe } from '@angular/common';\r\nimport { Injectable, Optional } from '@angular/core';\r\nimport { NgxLoggerLevel } from '../types/logger-level.enum';\r\nimport { INGXLoggerConfig } from '../config/iconfig';\r\nimport { INGXLoggerMetadata } from './imetadata';\r\nimport { INGXLoggerMetadataService } from './imetadata.service';\r\n\r\n@Injectable()\r\nexport class NGXLoggerMetadataService implements INGXLoggerMetadataService {\r\n\r\n constructor(\r\n @Optional() protected readonly datePipe: DatePipe,\r\n ) { }\r\n\r\n protected computeTimestamp(config: INGXLoggerConfig): string {\r\n const defaultTimestamp = () => new Date().toISOString();\r\n\r\n if (config.timestampFormat) {\r\n if (!this.datePipe) {\r\n console.error('NGXLogger : Can\\'t use timeStampFormat because DatePipe is not provided. You need to provide DatePipe');\r\n return defaultTimestamp();\r\n } else {\r\n return this.datePipe.transform(new Date(), config.timestampFormat);\r\n }\r\n }\r\n\r\n return defaultTimestamp();\r\n }\r\n\r\n public getMetadata(\r\n level: NgxLoggerLevel,\r\n config: INGXLoggerConfig,\r\n message?: any | (() => any),\r\n additional?: any[],\r\n ): INGXLoggerMetadata {\r\n const metadata: INGXLoggerMetadata = {\r\n level: level,\r\n additional: additional,\r\n };\r\n\r\n // The user can send a function\r\n // This is useful in order to compute string concatenation only when the log will actually be written\r\n if (message && typeof message === 'function') {\r\n metadata.message = message();\r\n } else {\r\n metadata.message = message;\r\n }\r\n\r\n metadata.timestamp = this.computeTimestamp(config);\r\n\r\n return metadata;\r\n }\r\n}\r\n","import { INGXLoggerConfig } from '../config/iconfig';\r\nimport { INGXLoggerMetadata } from '../metadata/imetadata';\r\nimport { INGXLoggerMonitor } from './ilogger-monitor';\r\n\r\n// I kept this class alive only to avoid a breaking change with the old version\r\n// This class does not implement anything so it is useless and the interface is enough\r\n\r\n/**\r\n * @deprecated this class does not implement anything thus being useless, you should rather implements @see INGXLoggerMonitor\r\n */\r\nexport abstract class NGXLoggerMonitor implements INGXLoggerMonitor {\r\n abstract onLog(logObject: INGXLoggerMetadata, config: INGXLoggerConfig): void;\r\n}\r\n","import { INGXLoggerConfig } from \"../config/iconfig\";\r\nimport { NgxLoggerLevel } from \"../types/logger-level.enum\";\r\n\r\n/**\r\n * Injection token of logger metadata service\r\n */\r\nexport const TOKEN_LOGGER_RULES_SERVICE = 'TOKEN_LOGGER_RULES_SERVICE';\r\n\r\n/**\r\n * Service used to know if some of the feature of the logger should be used or not\r\n */\r\nexport interface INGXLoggerRulesService {\r\n /**\r\n * If true the logger will write logs to console\r\n * @param level \r\n * @param config \r\n * @param message \r\n * @param additional \r\n */\r\n shouldCallWriter(level: NgxLoggerLevel, config: INGXLoggerConfig, message?: any | (() => any), additional?: any[]): boolean;\r\n /**\r\n * If true the logger will send logs to server\r\n * @param level \r\n * @param config \r\n * @param message \r\n * @param additional \r\n */\r\n shouldCallServer(level: NgxLoggerLevel, config: INGXLoggerConfig, message?: any | (() => any), additional?: any[]): boolean;\r\n /**\r\n * If true the logger will call the loggerMonitor\r\n * @param level \r\n * @param config \r\n * @param message \r\n * @param additional \r\n */\r\n shouldCallMonitor(level: NgxLoggerLevel, config: INGXLoggerConfig, message?: any | (() => any), additional?: any[]): boolean;\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { NgxLoggerLevel } from '../types/logger-level.enum';\r\nimport { INGXLoggerConfig } from '../config/iconfig';\r\nimport { INGXLoggerRulesService } from './irules.service';\r\n\r\n@Injectable()\r\nexport class NGXLoggerRulesService implements INGXLoggerRulesService {\r\n\r\n public shouldCallWriter(level: NgxLoggerLevel, config: INGXLoggerConfig, message?: any, additional?: any[]): boolean {\r\n return !config.disableConsoleLogging && level >= config.level;\r\n }\r\n\r\n public shouldCallServer(level: NgxLoggerLevel, config: INGXLoggerConfig, message?: any, additional?: any[]): boolean {\r\n return !!config.serverLoggingUrl && level >= config.serverLogLevel;\r\n }\r\n\r\n public shouldCallMonitor(level: NgxLoggerLevel, config: INGXLoggerConfig, message?: any, additional?: any[]): boolean {\r\n // The default behavior is to call the monitor only if the writer or the server is called\r\n return this.shouldCallWriter(level, config, message, additional) || this.shouldCallServer(level, config, message, additional);\r\n }\r\n}\r\n","import { INGXLoggerConfig } from \"../config/iconfig\";\r\nimport { INGXLoggerMetadata } from \"../metadata/imetadata\";\r\n\r\n/**\r\n * Injection token of logger server service\r\n */\r\nexport const TOKEN_LOGGER_SERVER_SERVICE = 'TOKEN_LOGGER_SERVER_SERVICE';\r\n\r\nexport interface INGXLoggerServerService {\r\n /**\r\n * Sends the content to be logged to the server according to the config\r\n * @param metadata \r\n * @param config \r\n */\r\n sendToServer(metadata: INGXLoggerMetadata, config: INGXLoggerConfig): void;\r\n\r\n /**\r\n * Flush the queue of the logger\r\n * @param config \r\n */\r\n flushQueue(config: INGXLoggerConfig): void;\r\n}\r\n","import { HttpBackend, HttpHeaders, HttpParams, HttpRequest, HttpResponse } from '@angular/common/http';\r\nimport { Injectable, NgZone, OnDestroy, Optional } from '@angular/core';\r\nimport { BehaviorSubject, Observable, Subscription, isObservable, of, throwError, timer } from 'rxjs';\r\nimport { catchError, concatMap, filter, map, take } from 'rxjs/operators';\r\nimport { INGXLoggerConfig } from '../config/iconfig';\r\nimport { INGXLoggerMetadata } from '../metadata/imetadata';\r\nimport { INGXLoggerServerService } from './iserver.service';\r\n\r\n@Injectable()\r\nexport class NGXLoggerServerService implements INGXLoggerServerService, OnDestroy {\r\n protected serverCallsQueue: INGXLoggerMetadata[] = [];\r\n protected flushingQueue: BehaviorSubject<boolean> = new BehaviorSubject(false);\r\n protected addToQueueTimer: Subscription;\r\n\r\n constructor(\r\n @Optional() protected readonly httpBackend: HttpBackend,\r\n @Optional() protected readonly ngZone: NgZone,\r\n ) { }\r\n\r\n ngOnDestroy(): void {\r\n if (this.flushingQueue) {\r\n this.flushingQueue.complete();\r\n this.flushingQueue = null;\r\n }\r\n if (this.addToQueueTimer) {\r\n this.addToQueueTimer.unsubscribe();\r\n this.addToQueueTimer = null;\r\n }\r\n }\r\n\r\n /**\r\n * Transforms an error object into a readable string (taking only the stack)\r\n * This is needed because JSON.stringify would return \"{}\"\r\n * @param err the error object\r\n * @returns The stack of the error\r\n */\r\n protected secureErrorObject(err: Error): string {\r\n return err?.stack;\r\n }\r\n\r\n /**\r\n * Transforms the additional parameters to avoid any json error when sending the data to the server\r\n * Basically it just replaces unstringifiable object to a string mentioning an error\r\n * @param additional The additional data to be sent\r\n * @returns The additional data secured\r\n */\r\n protected secureAdditionalParameters(additional: any[]): any[] {\r\n if (additional === null || additional === undefined) {\r\n return null;\r\n }\r\n\r\n return additional.map((next, idx) => {\r\n try {\r\n if (next instanceof Error) {\r\n return this.secureErrorObject(next);\r\n }\r\n // We just want to make sure the JSON can be parsed, we do not want to actually change the type\r\n if (typeof next === 'object') {\r\n JSON.stringify(next);\r\n }\r\n\r\n return next;\r\n } catch (e) {\r\n return `The additional[${idx}] value could not be parsed using JSON.stringify().`;\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Transforms the message so that it can be sent to the server\r\n * @param message the message to be sent\r\n * @returns the message secured\r\n */\r\n protected secureMessage(message: any): string {\r\n try {\r\n if (message instanceof Error) {\r\n return this.secureErrorObject(message);\r\n }\r\n\r\n if (typeof message !== 'string') {\r\n message = JSON.stringify(message, null, 2);\r\n }\r\n } catch (e) {\r\n message = 'The provided \"message\" value could not be parsed with JSON.stringify().';\r\n }\r\n\r\n return message;\r\n }\r\n\r\n /**\r\n * Edits HttpRequest object before sending request to server\r\n * @param httpRequest default request object\r\n * @returns altered httprequest\r\n */\r\n protected alterHttpRequest(httpRequest: HttpRequest<any>): HttpRequest<any> | Observable<HttpRequest<any>> {\r\n return httpRequest;\r\n }\r\n\r\n /**\r\n * Sends request to server\r\n * @param url \r\n * @param logContent \r\n * @param options \r\n * @returns \r\n */\r\n protected logOnServer(\r\n url: string,\r\n logContent: any,\r\n options: {\r\n headers?: HttpHeaders;\r\n reportProgress?: boolean;\r\n params?: HttpParams;\r\n responseType?: 'arraybuffer' | 'blob' | 'json' | 'text';\r\n withCredentials?: boolean;\r\n },\r\n ): Observable<any> {\r\n\r\n if (!this.httpBackend) {\r\n console.error('NGXLogger : Can\\'t log on server because HttpBackend is not provided. You need to import HttpClientModule');\r\n return of(null);\r\n }\r\n\r\n // HttpBackend skips all HttpInterceptors\r\n // They may log errors using this service causing circular calls\r\n let defaultRequest = new HttpRequest<any>('POST', url, logContent, options || {});\r\n let finalRequest: Observable<HttpRequest<any>> = of(defaultRequest);\r\n\r\n const alteredRequest = this.alterHttpRequest(defaultRequest);\r\n\r\n if (isObservable(alteredRequest)) {\r\n finalRequest = alteredRequest;\r\n } else if (alteredRequest) {\r\n finalRequest = of(alteredRequest);\r\n } else {\r\n console.warn('NGXLogger : alterHttpRequest returned an invalid request. Using default one instead');\r\n }\r\n\r\n return finalRequest.pipe(\r\n concatMap(req => {\r\n if (!req) {\r\n console.warn('NGXLogger : alterHttpRequest returned an invalid request (observable). Using default one instead');\r\n return this.httpBackend.handle(defaultRequest)\r\n }\r\n return this.httpBackend.handle(req);\r\n }),\r\n filter(e => e instanceof HttpResponse),\r\n map<HttpResponse<any>, any>((httpResponse: HttpResponse<any>) => httpResponse.body)\r\n );\r\n }\r\n\r\n /**\r\n * Customise the data sent to the API\r\n * @param metadata the data provided by NGXLogger\r\n * @returns the data that will be sent to the API in the body\r\n */\r\n protected customiseRequestBody(metadata: INGXLoggerMetadata | INGXLoggerMetadata[]): any {\r\n // In our API the body is not customised\r\n return metadata;\r\n }\r\n\r\n /**\r\n * Flush the queue of the logger\r\n * @param config \r\n */\r\n public flushQueue(config: INGXLoggerConfig): void {\r\n this.flushingQueue.next(true);\r\n\r\n // If a timer was set, we cancel it because the queue is flushed\r\n if (this.addToQueueTimer) {\r\n this.addToQueueTimer.unsubscribe();\r\n this.addToQueueTimer = null;\r\n }\r\n\r\n if (!!this.serverCallsQueue && this.serverCallsQueue.length > 0) {\r\n this.sendToServerAction(this.serverCallsQueue, config);\r\n }\r\n this.serverCallsQueue = [];\r\n\r\n this.flushingQueue.next(false);\r\n }\r\n\r\n protected sendToServerAction(metadata: INGXLoggerMetadata | INGXLoggerMetadata[], config: INGXLoggerConfig): void {\r\n let requestBody: any;\r\n\r\n const secureMetadata = (pMetadata: INGXLoggerMetadata) => {\r\n // Copying metadata locally because we don't want to change the object for the caller\r\n const securedMetadata: INGXLoggerMetadata = { ...pMetadata };\r\n securedMetadata.additional = this.secureAdditionalParameters(securedMetadata.additional);\r\n securedMetadata.message = this.secureMessage(securedMetadata.message);\r\n return securedMetadata;\r\n }\r\n\r\n if (Array.isArray(metadata)) {\r\n requestBody = [];\r\n metadata.forEach(m => {\r\n requestBody.push(secureMetadata(m));\r\n })\r\n } else {\r\n requestBody = secureMetadata(metadata);\r\n }\r\n\r\n // Allow users to customise the data sent to the API\r\n requestBody = this.customiseRequestBody(requestBody);\r\n\r\n const headers = config.customHttpHeaders || new HttpHeaders();\r\n if (!headers.has('Content-Type')) {\r\n headers.set('Content-Type', 'application/json');\r\n }\r\n\r\n const logOnServerAction = () => {\r\n this.logOnServer(\r\n config.serverLoggingUrl,\r\n requestBody,\r\n {\r\n headers,\r\n params: config.customHttpParams || new HttpParams(),\r\n responseType: config.httpResponseType || 'json',\r\n withCredentials: config.withCredentials || false,\r\n },\r\n ).pipe(catchError(err => {\r\n // Do not use NGXLogger here because this could cause an infinite loop \r\n console.error('NGXLogger: Failed to log on server', err);\r\n return throwError(err);\r\n })).subscribe();\r\n };\r\n\r\n if (config.serverCallsOutsideNgZone === true) {\r\n if (!this.ngZone) {\r\n console.error('NGXLogger: NgZone is not provided and serverCallsOutsideNgZone is set to true');\r\n return;\r\n }\r\n this.ngZone.runOutsideAngular(logOnServerAction);\r\n } else {\r\n logOnServerAction();\r\n }\r\n }\r\n\r\n /**\r\n * Sends the content to be logged to the server according to the config\r\n * @param metadata \r\n * @param config \r\n */\r\n public sendToServer(metadata: INGXLoggerMetadata, config: INGXLoggerConfig): void {\r\n // If there is no batch mode in the config, we send the log call straight to the server as usual\r\n if ((!config.serverCallsBatchSize || config.serverCallsBatchSize <= 0) &&\r\n (!config.serverCallsTimer || config.serverCallsTimer <= 0)) {\r\n this.sendToServerAction(metadata, config);\r\n return;\r\n }\r\n\r\n const addLogToQueueAction = () => {\r\n this.serverCallsQueue.push({ ...metadata });\r\n\r\n // Flush queue when size is reached\r\n if (!!config.serverCallsBatchSize && this.serverCallsQueue.length > config.serverCallsBatchSize) {\r\n this.flushQueue(config);\r\n }\r\n // Call timer only if it is in the config and timer is not already running\r\n if (config.serverCallsTimer > 0 && !this.addToQueueTimer) {\r\n this.addToQueueTimer = timer(config.serverCallsTimer).subscribe(_ => {\r\n this.flushQueue(config);\r\n });\r\n }\r\n };\r\n\r\n // If queue is being flushed, we need to wait for it to finish before adding other calls\r\n if (this.flushingQueue.value === true) {\r\n this.flushingQueue.pipe(\r\n filter(fq => fq === false),\r\n take(1),\r\n ).subscribe(_ => {\r\n addLogToQueueAction();\r\n });\r\n } else {\r\n addLogToQueueAction();\r\n }\r\n }\r\n}\r\n","import { INGXLoggerConfig } from \"../config/iconfig\";\r\nimport { INGXLoggerMetadata } from \"../metadata/imetadata\";\r\n\r\n/**\r\n * Injection token of logger writer service\r\n */\r\nexport const TOKEN_LOGGER_WRITER_SERVICE = 'TOKEN_LOGGER_WRITER_SERVICE';\r\n\r\nexport interface INGXLoggerWriterService {\r\n /**\r\n * Write content to the console\r\n * @param metadata \r\n * @param config \r\n */\r\n writeMessage(metadata: INGXLoggerMetadata, config: INGXLoggerConfig): void;\r\n}\r\n","export enum NgxLoggerLevel {\r\n TRACE = 0,\r\n DEBUG = 1,\r\n INFO = 2,\r\n LOG = 3,\r\n WARN = 4,\r\n ERROR = 5,\r\n FATAL = 6,\r\n OFF = 7\r\n}\r\n","export type NGXLoggerColorScheme = [string, string, string, string, string, string, string];\r\n\r\nexport const DEFAULT_COLOR_SCHEME: NGXLoggerColorScheme = [\r\n 'purple',\r\n 'teal',\r\n 'gray',\r\n 'gray',\r\n 'red',\r\n 'red',\r\n 'red'\r\n];\r\n","import { Inject, Injectable, PLATFORM_ID } from '@angular/core';\r\nimport { INGXLoggerMetadata } from '../metadata/imetadata';\r\nimport { INGXLoggerConfig } from '../config/iconfig';\r\nimport { INGXLoggerWriterService } from './iwriter.service';\r\nimport { isPlatformBrowser } from '@angular/common';\r\nimport { NgxLoggerLevel } from '../types/logger-level.enum';\r\nimport { DEFAULT_COLOR_SCHEME } from './color-scheme';\r\n\r\n@Injectable()\r\nexport class NGXLoggerWriterService implements INGXLoggerWriterService {\r\n\r\n protected readonly isIE: boolean;\r\n protected readonly logFunc: (metadata: INGXLoggerMetadata, config: INGXLoggerConfig, metaString: string) => void;\r\n\r\n /** List of functions called when preparing meta string */\r\n protected prepareMetaStringFuncs: ((metadata: INGXLoggerMetadata, config: INGXLoggerConfig) => string)[] = [\r\n this.getTimestampToWrite,\r\n this.getLevelToWrite,\r\n this.getFileDetailsToWrite,\r\n this.getContextToWrite,\r\n ];\r\n\r\n constructor(\r\n @Inject(PLATFORM_ID) protected platformId,\r\n ) {\r\n this.isIE = isPlatformBrowser(platformId) && navigator && navigator.userAgent &&\r\n !!(navigator.userAgent.indexOf('MSIE') !== -1 || navigator.userAgent.match(/Trident\\//) || navigator.userAgent.match(/Edge\\//));\r\n\r\n this.logFunc = this.isIE ? this.logIE.bind(this) : this.logModern.bind(this);\r\n }\r\n\r\n protected getTimestampToWrite(metadata: INGXLoggerMetadata, config: INGXLoggerConfig): string {\r\n return metadata.timestamp;\r\n }\r\n\r\n protected getLevelToWrite(metadata: INGXLoggerMetadata, config: INGXLoggerConfig): string {\r\n return NgxLoggerLevel[metadata.level];\r\n }\r\n\r\n protected getFileDetailsToWrite(metadata: INGXLoggerMetadata, config: INGXLoggerConfig): string {\r\n return config.disableFileDetails === true ? '' : `[${metadata.fileName}:${metadata.lineNumber}:${metadata.columnNumber}]`;\r\n }\r\n\r\n protected getContextToWrite(metadata: INGXLoggerMetadata, config: INGXLoggerConfig): string {\r\n return config.context ? `{${config.context}}` : '';\r\n }\r\n\r\n /** Generate a \"meta\" string that is displayed before the content sent to the log function */\r\n protected prepareMetaString(metadata: INGXLoggerMetadata, config: INGXLoggerConfig): string {\r\n let metaString = '';\r\n this.prepareMetaStringFuncs.forEach(prepareMetaStringFunc => {\r\n const metaItem = prepareMetaStringFunc(metadata, config);\r\n if (metaItem) {\r\n metaString = metaString + ' ' + metaItem;\r\n }\r\n })\r\n return metaString.trim();\r\n }\r\n\r\n /** Get the color to use when writing to console */\r\n protected getColor(metadata: INGXLoggerMetadata, config: INGXLoggerConfig): string | undefined {\r\n const configColorScheme = config.colorScheme ?? DEFAULT_COLOR_SCHEME;\r\n\r\n // this is needed to avoid a build error\r\n if (metadata.level === NgxLoggerLevel.OFF) {\r\n return undefined;\r\n }\r\n return configColorScheme[metadata.level];\r\n }\r\n\r\n /** Log to the console specifically for IE */\r\n protected logIE(metadata: INGXLoggerMetadata, config: INGXLoggerConfig, metaString: string): void {\r\n\r\n // Coloring doesn't work in IE\r\n\r\n // make sure additional isn't null or undefined so that ...additional doesn't error\r\n const additional = metadata.additional || [];\r\n\r\n switch (metadata.level) {\r\n case NgxLoggerLevel.WARN:\r\n console.warn(`${metaString} `, metadata.message, ...additional);\r\n break;\r\n case NgxLoggerLevel.ERROR:\r\n case NgxLoggerLevel.FATAL:\r\n console.error(`${metaString} `, metadata.message, ...additional);\r\n break;\r\n case NgxLoggerLevel.INFO:\r\n console.info(`${metaString} `, metadata.message, ...additional);\r\n break;\r\n default:\r\n console.log(`${metaString} `, metadata.message, ...additional);\r\n }\r\n }\r\n\r\n /** Log to the console */\r\n protected logModern(metadata: INGXLoggerMetadata, config: INGXLoggerConfig, metaString: string): void {\r\n const color = this.getColor(metadata, config);\r\n\r\n // make sure additional isn't null or undefined so that ...additional doesn't error\r\n const additional = metadata.additional || [];\r\n\r\n switch (metadata.level) {\r\n case NgxLoggerLevel.WARN:\r\n console.warn(`%c${metaString}`, `color:${color}`, metadata.message, ...additional);\r\n break;\r\n case NgxLoggerLevel.ERROR:\r\n case NgxLoggerLevel.FATAL:\r\n console.error(`%c${metaString}`, `color:${color}`, metadata.message, ...additional);\r\n break;\r\n case NgxLoggerLevel.INFO:\r\n console.info(`%c${metaString}`, `color:${color}`, metadata.message, ...additional);\r\n break;\r\n // Disabling console.trace since the stack trace is not helpful. it is showing the stack trace of\r\n // the console.trace statement\r\n // case NgxLoggerLevel.TRACE:\r\n // console.trace(`%c${metaString}`, `color:${color}`, message, ...additional);\r\n // break;\r\n\r\n case NgxLoggerLevel.DEBUG:\r\n console.debug(`%c${metaString}`, `color:${color}`, metadata.message, ...additional);\r\n break;\r\n default:\r\n console.log(`%c${metaString}`, `color:${color}`, metadata.message, ...additional);\r\n }\r\n }\r\n\r\n /** Write the content sent to the log function to the console */\r\n public writeMessage(metadata: INGXLoggerMetadata, config: INGXLoggerConfig): void {\r\n const metaString = this.prepareMetaString(metadata, config);\r\n\r\n this.logFunc(metadata, config, metaString);\r\n }\r\n}\r\n","import { Inject, Injectable } from '@angular/core';\r\nimport { HttpHeaders, HttpParams } from '@angular/common/http';\r\nimport { NgxLoggerLevel } from './types/logger-level.enum';\r\nimport { INGXLoggerConfigEngine } from './config/iconfig-engine';\r\nimport { INGXLoggerConfig, TOKEN_LOGGER_CONFIG } from './config/iconfig';\r\nimport { INGXLoggerMetadataService, TOKEN_LOGGER_METADATA_SERVICE } from './metadata/imetadata.service';\r\nimport { INGXLoggerRulesService, TOKEN_LOGGER_RULES_SERVICE } from './rules/irules.service';\r\nimport { INGXLoggerMapperService, TOKEN_LOGGER_MAPPER_SERVICE } from './mapper/imapper.service';\r\nimport { INGXLoggerMonitor } from './monitor/ilogger-monitor';\r\nimport { INGXLoggerWriterService, TOKEN_LOGGER_WRITER_SERVICE } from './writer/iwriter.service';\r\nimport { INGXLoggerServerService, TOKEN_LOGGER_SERVER_SERVICE } from './server/iserver.service';\r\nimport { take } from 'rxjs/operators';\r\nimport { INGXLoggerConfigEngineFactory, TOKEN_LOGGER_CONFIG_ENGINE_FACTORY } from './config/iconfig-engine-factory';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class NGXLogger {\r\n private _loggerMonitor: INGXLoggerMonitor;\r\n private configEngine: INGXLoggerConfigEngine;\r\n\r\n constructor(\r\n @Inject(TOKEN_LOGGER_CONFIG) config: INGXLoggerConfig,\r\n @Inject(TOKEN_LOGGER_CONFIG_ENGINE_FACTORY) configEngineFactory: INGXLoggerConfigEngineFactory,\r\n @Inject(TOKEN_LOGGER_METADATA_SERVICE) private metadataService: INGXLoggerMetadataService,\r\n @Inject(TOKEN_LOGGER_RULES_SERVICE) private ruleService: INGXLoggerRulesService,\r\n @Inject(TOKEN_LOGGER_MAPPER_SERVICE) private mapperService: INGXLoggerMapperService,\r\n @Inject(TOKEN_LOGGER_WRITER_SERVICE) private writerService: INGXLoggerWriterService,\r\n @Inject(TOKEN_LOGGER_SERVER_SERVICE) private serverService: INGXLoggerServerService,\r\n ) {\r\n this.configEngine = configEngineFactory.provideConfigEngine(config);\r\n }\r\n\r\n /** Get a readonly access to the level configured for the NGXLogger */\r\n get level(): NgxLoggerLevel {\r\n return this.configEngine.level;\r\n }\r\n\r\n /** Get a readonly access to the serverLogLevel configured for the NGXLogger */\r\n get serverLogLevel(): NgxLoggerLevel {\r\n return this.configEngine.serverLogLevel;\r\n }\r\n\r\n public trace(message?: any | (() => any), ...additional: any[]): void {\r\n this._log(NgxLoggerLevel.TRACE, message, additional);\r\n }\r\n\r\n public debug(message?: any | (() => any), ...additional: any[]): void {\r\n this._log(NgxLoggerLevel.DEBUG, message, additional);\r\n }\r\n\r\n public info(message?: any | (() => any), ...additional: any[]): void {\r\n this._log(NgxLoggerLevel.INFO, message, additional);\r\n }\r\n\r\n public log(message?: any | (() => any), ...additional: any[]): void {\r\n this._log(NgxLoggerLevel.LOG, message, additional);\r\n }\r\n\r\n public warn(message?: any | (() => any), ...additional: any[]): void {\r\n this._log(NgxLoggerLevel.WARN, message, additional);\r\n }\r\n\r\n public error(message?: any | (() => any), ...additional: any[]): void {\r\n this._log(NgxLoggerLevel.ERROR, message, additional);\r\n }\r\n\r\n public fatal(message?: any | (() => any), ...additional: any[]): void {\r\n this._log(NgxLoggerLevel.FATAL, message, additional);\r\n }\r\n\r\n /** @deprecated customHttpHeaders is now part of the config, this should be updated via @see updateConfig */\r\n public setCustomHttpHeaders(headers: HttpHeaders) {\r\n const config = this.getConfigSnapshot();\r\n config.customHttpHeaders = headers;\r\n this.updateConfig(config);\r\n }\r\n\r\n /** @deprecated customHttpParams is now part of the config, this should be updated via @see updateConfig */\r\n public setCustomParams(params: HttpParams) {\r\n const config = this.getConfigSnapshot();\r\n config.customHttpParams = params;\r\n this.updateConfig(config);\r\n }\r\n\r\n /** @deprecated withCredentials is now part of the config, this should be updated via @see updateConfig */\r\n public setWithCredentialsOptionValue(withCredentials: boolean) {\r\n const config = this.getConfigSnapshot();\r\n config.withCredentials = withCredentials;\r\n this.updateConfig(config);\r\n }\r\n\r\n /**\r\n * Register a INGXLoggerMonitor that will be trigger when a log is either written or sent to server\r\n * \r\n * There is only one monitor, registering one will overwrite the last one if there was one\r\n * @param monitor \r\n */\r\n public registerMonitor(monitor: INGXLoggerMonitor) {\r\n this._loggerMonitor = monitor;\r\n }\r\n\r\n /** Set config of logger\r\n * \r\n * Warning : This overwrites all the config, if you want to update only one property, you should use @see getConfigSnapshot before\r\n */\r\n public updateConfig(config: INGXLoggerConfig) {\r\n this.configEngine.updateConfig(config);\r\n }\r\n\r\n public partialUpdateConfig(partialConfig: Partial<INGXLoggerConfig>): void {\r\n this.configEngine.partialUpdateConfig(partialConfig);\r\n }\r\n\r\n /** Get config of logger */\r\n public getConfigSnapshot(): INGXLoggerConfig {\r\n return this.configEngine.getConfig();\r\n }\r\n\r\n /**\r\n * Flush the serveur queue\r\n */\r\n public flushServerQueue(): void {\r\n this.serverService.flushQueue(this.getConfigSnapshot());\r\n }\r\n\r\n private _log(level: NgxLoggerLevel, message?: any | (() => any), additional: any[] = []): void {\r\n const config = this.configEngine.getConfig();\r\n\r\n const shouldCallWriter = this.ruleService.shouldCallWriter(level, config, message, additional);\r\n const shouldCallServer = this.ruleService.shouldCallServer(level, config, message, additional);\r\n const shouldCallMonitor = this.ruleService.shouldCallMonitor(level, config, message, additional);\r\n\r\n if (!shouldCallWriter && !shouldCallServer && !shouldCallMonitor) {\r\n // If nothing is to be called we return\r\n return;\r\n }\r\n\r\n const metadata = this.metadataService.getMetadata(level, config, message, additional);\r\n this.mapperService.getLogPosition(config, metadata).pipe(take(1)).subscribe(logPosition => {\r\n if (logPosition) {\r\n metadata.fileName = logPosition.fileName;\r\n metadata.lineNumber = logPosition.lineNumber;\r\n metadata.columnNumber = logPosition.columnNumber;\r\n }\r\n\r\n if (shouldCallMonitor && this._loggerMonitor) {\r\n this._loggerMonitor.onLog(metadata, config);\r\n }\r\n if (shouldCallWriter) {\r\n this.writerService.writeMessage(metadata, config);\r\n }\r\n if (shouldCallServer) {\r\n this.serverService.sendToServer(metadata, config);\r\n }\r\n });\r\n }\r\n}\r\n","import { Inject, Injectable } from '@angular/core';\r\nimport { INGXLoggerConfig } from './config/iconfig';\r\nimport { NGXLogger } from './logger.service';\r\nimport { TOKEN_LOGGER_MAPPER_SERVICE, INGXLoggerMapperService } from './mapper/imapper.service';\r\nimport { TOKEN_LOGGER_METADATA_SERVICE, INGXLoggerMetadataService } from './metadata/imetadata.service';\r\nimport { TOKEN_LOGGER_RULES_SERVICE, INGXLoggerRulesService } from './rules/irules.service';\r\nimport { TOKEN_LOGGER_SERVER_SERVICE, INGXLoggerServerService } from './server/iserver.service';\r\nimport { TOKEN_LOGGER_WRITER_SERVICE, INGXLoggerWriterService } from './writer/iwriter.service';\r\nimport { INGXLoggerMonitor } from './monitor/ilogger-monitor';\r\nimport { INGXLoggerConfigEngineFactory, TOKEN_LOGGER_CONFIG_ENGINE_FACTORY } from './config/iconfig-engine-factory';\r\n\r\n/**\r\n * CustomNGXLoggerService is designed to allow users to get a new instance of a logger\r\n */\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class CustomNGXLoggerService {\r\n\r\n constructor(\r\n private logger: NGXLogger,\r\n @Inject(TOKEN_LOGGER_CONFIG_ENGINE_FACTORY) private configEngineFactory: INGXLoggerConfigEngineFactory,\r\n @Inject(TOKEN_LOGGER_METADATA_SERVICE) private metadataService: INGXLoggerMetadataService,\r\n @Inject(TOKEN_LOGGER_RULES_SERVICE) private ruleService: INGXLoggerRulesService,\r\n @Inject(TOKEN_LOGGER_MAPPER_SERVICE) private mapperService: INGXLoggerMapperService,\r\n @Inject(TOKEN_LOGGER_WRITER_SERVICE) private writerService: INGXLoggerWriterService,\r\n @Inject(TOKEN_LOGGER_SERVER_SERVICE) private serverService: INGXLoggerServerService,\r\n ) { }\r\n\r\n\r\n /**\r\n * Create an instance of a logger\r\n * @deprecated this function does not have all the features, @see getNewInstance for every params available\r\n * @param config \r\n * @param serverService \r\n * @param logMonitor \r\n * @param mapperService \r\n * @returns \r\n */\r\n create(\r\n config: INGXLoggerConfig,\r\n serverService?: INGXLoggerServerService,\r\n logMonitor?: INGXLoggerMonitor,\r\n mapperService?: INGXLoggerMapperService,\r\n ): NGXLogger {\r\n return this.getNewInstance({\r\n config,\r\n serverService,\r\n logMonitor,\r\n mapperService\r\n });\r\n }\r\n\r\n /**\r\n * Get a new instance of NGXLogger\r\n * @param params list of optional params to use when creating an instance of NGXLo