diff --git a/src/commons/logger/core/config.ts b/src/commons/logger/core/config.ts new file mode 100644 index 0000000..51264af --- /dev/null +++ b/src/commons/logger/core/config.ts @@ -0,0 +1,6 @@ +import { LoggerLevel } from './type'; + +export class LoggerConfig { + level: LoggerLevel; + serverLogLevel: LoggerLevel; +} diff --git a/src/commons/logger/core/index.ts b/src/commons/logger/core/index.ts new file mode 100644 index 0000000..40a47eb --- /dev/null +++ b/src/commons/logger/core/index.ts @@ -0,0 +1,3 @@ +export * from './config'; +export * from './token'; +export * from './type'; diff --git a/src/commons/logger/core/token.ts b/src/commons/logger/core/token.ts new file mode 100644 index 0000000..6d8f313 --- /dev/null +++ b/src/commons/logger/core/token.ts @@ -0,0 +1,4 @@ +import { Inject, Injectable, InjectionToken } from '@angular/core'; +import { LoggerLevel } from './type'; + +export const LOGGER_LEVEL = new InjectionToken('LoggerLevel'); diff --git a/src/commons/logger/core/type.ts b/src/commons/logger/core/type.ts new file mode 100644 index 0000000..72d4473 --- /dev/null +++ b/src/commons/logger/core/type.ts @@ -0,0 +1,26 @@ +export enum LoggerLevel { + TRACE = 0, + DEBUG, + INFO, + LOG, + WARN, + ERROR, + OFF, +} + +export const LoggerLevelName = [ + 'TRACE', + 'DEBUG', + 'INFO', + 'LOG', + 'WARN', + 'ERROR', + 'OFF' +]; + +export interface ServerLoggingParameter { + level: string; + message: string; + addtional?: string; + timestamp: Date; +} diff --git a/src/commons/logger/logger.module.ts b/src/commons/logger/logger.module.ts new file mode 100644 index 0000000..4918285 --- /dev/null +++ b/src/commons/logger/logger.module.ts @@ -0,0 +1,39 @@ +import { + NgModule, + ModuleWithProviders, +} from '@angular/core'; +import { CommonModule } from '@angular/common'; + + + + + + + +@NgModule({ +}) +export class LoggerRootModule { } + +@NgModule({ +}) +export class LoggerFeatureModule { } + +@NgModule({ +}) +export class LoggerModule { + static forRoot(reducers: any): ModuleWithProviders { + return { + ngModule: LoggerRootModule, + providers: [ + ], + }; + } + + static forFeature(featureName: string, reducers?: any): ModuleWithProviders { + return { + ngModule: LoggerFeatureModule, + providers: [ + ], + }; + } +} diff --git a/src/commons/logger/service/logger.service.ts b/src/commons/logger/service/logger.service.ts new file mode 100644 index 0000000..1081ea8 --- /dev/null +++ b/src/commons/logger/service/logger.service.ts @@ -0,0 +1,93 @@ +import { + LoggerConfig, + LoggerLevel, +} from '../core'; + + +export abstract class LoggerService { + + public constructor( + private readonly config: LoggerConfig + ) { + + } + + public trace(message, ...additional: any[]): void { + this._log(LoggerLevel.TRACE, message, additional); + } + + public debug(message, ...additional: any[]): void { + this._log(LoggerLevel.DEBUG, message, additional); + } + + public info(message, ...additional: any[]): void { + this._log(LoggerLevel.INFO, message, additional); + } + + public log(message, ...additional: any[]): void { + this._log(LoggerLevel.LOG, message, additional); + } + + public warn(message, ...additional: any[]): void { + this._log(LoggerLevel.WARN, message, additional); + } + + public error(message, ...additional: any[]): void { + this._log(LoggerLevel.ERROR, message, additional); + } + + private _timestamp(): string { + return new Date().toISOString(); + } + + private _log(level: LoggerLevel, logOnServer: boolean, message, additional: any[] = []): void { + if (!message) { + return; + } + + // Allow logging on server even if client log level is off + // if (logOnServer) { + // this._logOnServer(level, message, additional); + // } + + // if no message or the log level is less than the environ + if (level < this.config.level) { + return; + } + + try { + message = typeof message === 'string' ? message + : JSON.stringify(message, null, 2); + } catch (e) { + additional = [message, ...additional]; + message = 'The provided "message" value could not be parsed with JSON.stringify().'; + } + + // Coloring doesn't work in IE + // if (this._isIE) { + // return this._logIE(level, message, additional); + // } + + // const color = this._getColor(level); + + // console.log(`%c${this._timestamp()} [${Levels[level]}]`, `color:${color}`, message, ...additional); + } + + private _getColor(level: LoggerLevel): 'blue' | 'teal' | 'gray' | 'red' | undefined { + switch (level) { + case LoggerLevel.TRACE: + return 'blue'; + case LoggerLevel.DEBUG: + return 'teal'; + case LoggerLevel.INFO: + case LoggerLevel.LOG: + return 'gray'; + case LoggerLevel.WARN: + case LoggerLevel.ERROR: + return 'red'; + case LoggerLevel.OFF: + default: + return; + } + } +} diff --git a/src/commons/logger/store/logger.action.ts b/src/commons/logger/store/logger.action.ts new file mode 100644 index 0000000..15b419d --- /dev/null +++ b/src/commons/logger/store/logger.action.ts @@ -0,0 +1,20 @@ +import { Action } from '@ngrx/store'; + +import { + LoggerLevel, + ServerLoggingParameter, +} from '../core'; + +export enum ActionType { + ServerLogging = '[@@LOGGER] ServerLogging', +} + +export class ServerLogging implements Action { + readonly type = ActionType.ServerLogging; + + constructor(public payload: ServerLoggingParameter) {} +} + +export type Actions = + | ServerLogging +; diff --git a/src/packages/core/rpc/protocol/json/RPCClientJSONCodec.ts b/src/packages/core/rpc/protocol/json/RPCClientJSONCodec.ts index d6886a4..cb0ba5c 100644 --- a/src/packages/core/rpc/protocol/json/RPCClientJSONCodec.ts +++ b/src/packages/core/rpc/protocol/json/RPCClientJSONCodec.ts @@ -10,13 +10,13 @@ import { export interface ClientNotification { method: string; - params?: any[]; + params?: string[]; } export interface ClientRequest { jsonrpc: string; method: string; - params?: any[]; + params?: string[]; id?: number; } @@ -29,10 +29,12 @@ export interface ClientResponse { export class RPCClientJSONCodec extends RPCClientCodec { public request(method: string, args: any[], id?: number): any { + const params = convertParamsToStringArray(args); + const req: ClientRequest = { jsonrpc: '2.0', method: method, - params: args, + params: 0 === params.length ? null : params, id: id, }; return JSON.stringify(req); @@ -48,6 +50,35 @@ export class RPCClientJSONCodec extends RPCClientCodec { } } +function convertParamsToStringArray(args: any[]): string[] | undefined { + const values: string[] = []; + + if (undefined === args || null === args || 0 === args.length) { + return values; + } + + for (let indexI = 0; indexI < args.length; indexI++) { + const arg = args[indexI]; + + switch (typeof arg) { + case 'boolean': + case 'number': // enum + values.push(String(arg)); + break; + case 'string': + values.push(arg); + break; + case 'object': // array, map + values.push(JSON.stringify(arg)); + break; + default: + throw new Error(`Not supported type[${typeof arg}]`); + } + } + + return values; +} + export class RPCClientJSONResponseCodec extends RPCClientResponseCodec { public constructor(private _res: ClientResponse) { super();