Skip to content

Instantly share code, notes, and snippets.

@krishnathota
Created October 22, 2021 04:25
Show Gist options
  • Save krishnathota/b56014d1fc0d855e7d0e7b603f8980e1 to your computer and use it in GitHub Desktop.
Save krishnathota/b56014d1fc0d855e7d0e7b603f8980e1 to your computer and use it in GitHub Desktop.
Logger service
Logs to console, can be extended to localstorage, webapi
import { InjectionToken, ModuleWithProviders, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { LoggerService } from './services/logger.service';
// move these to new files to avoid circular dependency issues
const ENVIRONMENT = new InjectionToken<Environment>('environment');
export interface Environment {
production: boolean;
}
@NgModule({
imports: [CommonModule]
})
export class LoggerModule {
public static forRoot(environment: Environment): ModuleWithProviders<LoggerModule> {
return {
ngModule: CommonModule,
providers: [
{
provide: ENVIRONMENT,
useValue: environment
},
LoggerService
]
};
}
}
import { Inject, Injectable } from '@angular/core';
import { fromEvent } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import { TsUtilService } from 'mes-components/src/lib/util';
import { Entry } from '../models/entry';
import { Level } from '../models/level.enum';
import { ConsoleService } from './publishers/console.service';
import { LocalStorageService } from './publishers/local-storage.service';
import { WebApiService } from './publishers/web-api.service';
import { ENVIRONMENT } from '../environment.injector';
import { Environment } from '../models/environment';
@Injectable({
providedIn: 'root'
})
export class LoggerService {
constructor(
@Inject(ENVIRONMENT) private environment: Environment,
private console: ConsoleService,
private localStorage: LocalStorageService,
private webApi: WebApiService,
private tsUtil: TsUtilService
) {
this.fetchLevel();
}
private LOG_LEVEL = 'loglevel';
private WEB_API_LOG_LEVEL = 'webapiloglevel';
private API_LOG_LEVEL = 'apiloglevel';
private level: Level = Level.ERROR;
private apiLevel: Level = Level.OFF;
private logWithDate = false;
log(msg: string, ...params: any[]) {
this.writeToLog(msg, Level.LOG, params);
}
debug(msg: string, ...params: any[]) {
this.writeToLog(msg, Level.DEBUG, params);
}
info(msg: string, ...params: any[]) {
this.writeToLog(msg, Level.INFO, params);
}
warn(msg: string, ...params: any[]) {
this.writeToLog(msg, Level.WARN, params);
}
error(msg: string, ...params: any[]) {
this.writeToLog(msg, Level.ERROR, params);
}
private shouldLog = (level: Level, targetLevel?: Level) => {
if (!targetLevel) targetLevel = this.level;
return (level >= targetLevel && level !== Level.OFF) || targetLevel === Level.LOG;
};
private writeToLog(message: string, level: Level, params: any[]) {
const entry: Entry = {
message,
level,
params,
timeStamp: this.logWithDate ? new Date() : undefined
};
let loggers = [];
if (this.shouldLog(level, this.level)) {
loggers = [this.console, this.localStorage];
}
if (this.shouldLog(level, this.apiLevel)) {
loggers.push(this.webApi);
}
loggers.forEach((_) => _.log(entry));
}
private fetchLevel() {
this.level = this.environment.production ? Level.ERROR : Level.LOG;
this.apiLevel = this.environment.production ? Level.ERROR : Level.OFF;
Object.entries(sessionStorage).forEach(([key, value]) => {
if (
key.toLowerCase() === this.LOG_LEVEL ||
key.toLowerCase() === this.API_LOG_LEVEL ||
key.toLowerCase() === this.WEB_API_LOG_LEVEL
)
this.setLevel({ key: key.toLowerCase(), value });
});
fromEvent<StorageEvent>(window, 'storage')
.pipe(
filter((event) => event.storageArea === sessionStorage),
filter(
(event) =>
event.key.toLowerCase() === this.LOG_LEVEL ||
event.key.toLowerCase() === this.API_LOG_LEVEL ||
event.key.toLowerCase() === this.WEB_API_LOG_LEVEL
),
map((event: any) => ({ key: event.key, value: event.newValue }))
)
.subscribe(this.setLevel.bind(this));
}
private setLevel(level: { key; value }) {
const _level = this.tsUtil.enumKeys(Level).find((_) => _ === level?.value?.toUpperCase());
level.key === this.LOG_LEVEL ? (this.level = Level[_level]) : (this.apiLevel = Level[_level]);
}
}
import { Injectable } from '@angular/core';
import { Entry } from '../../models/entry';
import { Level } from '../../models/level.enum';
@Injectable({
providedIn: 'root'
})
export class ConsoleService {
private colors = {
[Level.LOG]: { background: 'DarkGrey', color: 'Black' },
[Level.DEBUG]: { background: 'Grey', color: 'White' },
[Level.INFO]: { background: 'DodgerBlue', color: 'White' },
[Level.WARN]: { background: 'Orange', color: 'White' },
[Level.ERROR]: { background: 'Red', color: 'White' }
};
constructor() {}
log(entry: Entry) {
// Append app name if needed
const { message, level, params, timeStamp } = entry;
const logger =
level === Level.ERROR
? console.error
: level === Level.WARN
? console.warn
: level === Level.INFO
? console.info
: console.log;
logger(
`%c ${Level[level]} `,
`background: ${this.colors[level].background}; color: ${this.colors[level].color}`,
timeStamp ? `${timeStamp} ${message}` : message,
...params
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment