diff --git a/projects/demo/src/app/app.component.html b/projects/demo/src/app/app.component.html index 0b81d29..d23b0de 100644 --- a/projects/demo/src/app/app.component.html +++ b/projects/demo/src/app/app.component.html @@ -2,5 +2,5 @@

Please open your console to see the output of the demo

- +
diff --git a/projects/demo/src/app/app.component.ts b/projects/demo/src/app/app.component.ts index 9dbd548..a36f571 100644 --- a/projects/demo/src/app/app.component.ts +++ b/projects/demo/src/app/app.component.ts @@ -19,6 +19,7 @@ export class AppComponent { handleLogLevelChange(newLevel: NgxLoggerLevel) { const updatedConfig = this.logger.getConfigSnapshot(); updatedConfig.level = newLevel; + updatedConfig.serverLogLevel = newLevel; this.logger.updateConfig(updatedConfig); } @@ -57,4 +58,10 @@ export class AppComponent { updatedConfig.disableFileDetails = disableFileDetails; this.logger.updateConfig(updatedConfig); } + + serverLogging(enabled: boolean) { + const updatedConfig = this.logger.getConfigSnapshot(); + updatedConfig.serverLoggingUrl = enabled ? '/dummyURL' : null; + this.logger.updateConfig(updatedConfig); + } } diff --git a/projects/demo/src/app/app.module.ts b/projects/demo/src/app/app.module.ts index 1651f65..7398920 100644 --- a/projects/demo/src/app/app.module.ts +++ b/projects/demo/src/app/app.module.ts @@ -13,7 +13,7 @@ import { MatSlideToggleModule, MatTooltipModule, } from '@angular/material'; -import { LoggerModule, NgxLoggerLevel } from 'ngx-logger'; +import { LoggerModule, NGXLogger, NgxLoggerLevel } from 'ngx-logger'; import { AppComponent } from './app.component'; import { LogConfigComponent } from './log-config/log-config.component'; @@ -29,6 +29,7 @@ import { HttpClientModule } from '@angular/common/http'; ReactiveFormsModule, LoggerModule.forRoot({ level: NgxLoggerLevel.DEBUG, + serverLogLevel: NgxLoggerLevel.DEBUG, }), MatButtonModule, MatCardModule, diff --git a/projects/demo/src/app/log-config/log-config.component.html b/projects/demo/src/app/log-config/log-config.component.html index 5fc43fb..1604f86 100644 --- a/projects/demo/src/app/log-config/log-config.component.html +++ b/projects/demo/src/app/log-config/log-config.component.html @@ -33,6 +33,7 @@

Logger Configuration


Disable file details + Server logging diff --git a/projects/demo/src/app/log-config/log-config.component.scss b/projects/demo/src/app/log-config/log-config.component.scss index bbf91f8..fdd41ac 100644 --- a/projects/demo/src/app/log-config/log-config.component.scss +++ b/projects/demo/src/app/log-config/log-config.component.scss @@ -10,3 +10,7 @@ button { display: flex; justify-content: center; } + +.server-logging { + margin-left: 16px; +} \ No newline at end of file diff --git a/projects/demo/src/app/log-config/log-config.component.ts b/projects/demo/src/app/log-config/log-config.component.ts index 053a0c0..27cd391 100644 --- a/projects/demo/src/app/log-config/log-config.component.ts +++ b/projects/demo/src/app/log-config/log-config.component.ts @@ -20,6 +20,9 @@ export class LogConfigComponent { @Output() disableFileDetails: EventEmitter = new EventEmitter(); + @Output() + serverLogging: EventEmitter = new EventEmitter(); + /** * Get the chip color based on the current logger level configuration */ @@ -56,4 +59,8 @@ export class LogConfigComponent { disableFileDetailsChange(change: MatSlideToggleChange) { this.disableFileDetails.emit(change.checked); } + + serverLoggingChange(change: MatSlideToggleChange) { + this.serverLogging.emit(change.checked); + } } diff --git a/projects/demo/src/app/logger-form/logger-form.component.html b/projects/demo/src/app/logger-form/logger-form.component.html index 2fad3fd..331b6eb 100644 --- a/projects/demo/src/app/logger-form/logger-form.component.html +++ b/projects/demo/src/app/logger-form/logger-form.component.html @@ -15,6 +15,7 @@ + diff --git a/projects/demo/src/app/logger-form/logger-form.component.ts b/projects/demo/src/app/logger-form/logger-form.component.ts index 8f21521..a47d288 100644 --- a/projects/demo/src/app/logger-form/logger-form.component.ts +++ b/projects/demo/src/app/logger-form/logger-form.component.ts @@ -1,6 +1,6 @@ import {Component, OnInit, Output, EventEmitter} from '@angular/core'; -import {Validators, FormBuilder} from '@angular/forms'; -import {NgxLoggerLevel} from 'ngx-logger'; +import {Validators, FormBuilder, FormGroup} from '@angular/forms'; +import {NGXLogger, NgxLoggerLevel} from 'ngx-logger'; import {LogEvent} from '../models/log-event.model'; @@ -36,7 +36,10 @@ export class LoggerFormComponent implements OnInit { {value: NgxLoggerLevel.ERROR, viewValue: 'Error'} ]; - constructor(private fb: FormBuilder) { + constructor( + private fb: FormBuilder, + private logger: NGXLogger + ) { } ngOnInit() { @@ -48,4 +51,11 @@ export class LoggerFormComponent implements OnInit { handleFormSubmission() { this.logToConsole.emit(this.loggerForm.value); } + + logComplex() { + const complexStructure = new FormGroup({ sub: new FormGroup({}) }); + this.logger.error('Test complex', complexStructure); + this.logger.error(complexStructure); + } + } diff --git a/src/lib/logger.service.spec.ts b/src/lib/logger.service.spec.ts index 700f3a9..d652d0c 100644 --- a/src/lib/logger.service.spec.ts +++ b/src/lib/logger.service.spec.ts @@ -10,6 +10,7 @@ import { NgxLoggerLevel } from './types/logger-level.enum'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { LogPosition } from 'dist/ngx-logger/lib/types/log-position'; import { of } from 'rxjs'; +import { FormGroup } from '@angular/forms'; describe('NGXLogger', () => { beforeEach(() => { @@ -45,6 +46,25 @@ describe('NGXLogger', () => { } )); + it('should handle complex circular structures', inject( + [NGXLogger], + (logger: NGXLogger) => { + // This structure is not "stringifyable" this make sure anything can be logged + // Before that we used JSON.stringify and it was not working + const complexStructure = new FormGroup({ sub: new FormGroup({}) }); + + spyOn(console, 'error'); + + logger.error('error', complexStructure); + + expect(console.error).toHaveBeenCalledWith(jasmine.anything(), jasmine.anything(), jasmine.anything(), complexStructure); + + logger.error(complexStructure); + + expect(console.error).toHaveBeenCalledWith(jasmine.anything(), jasmine.anything(), complexStructure); + } + )); + describe('trace', () => { it('should call _log with trace', inject( [NGXLogger], diff --git a/src/lib/logger.service.ts b/src/lib/logger.service.ts index 35eaeb8..7ee6ed8 100644 --- a/src/lib/logger.service.ts +++ b/src/lib/logger.service.ts @@ -176,7 +176,6 @@ export class NGXLogger { const logLevelString = Levels[level]; message = typeof message === 'function' ? message() : message; - message = NGXLoggerUtils.prepareMessage(message); // only use validated parameters for HTTP requests const validatedAdditionalParameters = NGXLoggerUtils.prepareAdditionalParameters(additional); @@ -187,7 +186,10 @@ export class NGXLogger { this.mapperService.getCallerDetails(config.enableSourceMaps, config.proxiedSteps).subscribe((callerDetails: LogPosition) => { const logObject: NGXLogInterface = { - message: message, + // prepareMessage is needed to match NGXLogInterface + // Even though I think message should be of type any (same as console.xxx signature) + // I'm not doing this right now as this would be a breaking change + message: NGXLoggerUtils.prepareMessage(message), additional: validatedAdditionalParameters, level: level, timestamp: timestamp, @@ -200,9 +202,9 @@ export class NGXLogger { } if (isLog2Server) { - // make sure the stack gets sent to the server - message = message instanceof Error ? message.stack : message; - logObject.message = message; + // make sure the stack gets sent to the server (without altering the message for console logging) + logObject.message = message instanceof Error ? message.stack : message; + logObject.message = NGXLoggerUtils.prepareMessage(logObject.message); const headers = this._customHttpHeaders || new HttpHeaders(); headers.set('Content-Type', 'application/json');