core-native
Version:
A lightweight framework based on React Native + Redux + Redux Saga, in strict TypeScript.
138 lines (116 loc) • 4.8 kB
text/typescript
import {loggerContext} from "./platform/loggerContext";
import {app} from "./app";
import {APIException, Exception, NetworkConnectionException, ReactLifecycleException, RuntimeException} from "./Exception";
interface Log {
date: Date;
result: "OK" | "WARN" | "ERROR";
context: {[key: string]: string}; // To store indexed data (for Elastic Search)
info: {[key: string]: string}; // To store text data (no index)
elapsedTime: number;
action?: string;
errorCode?: string;
}
/**
* If eventLogger config is provided in non-DEV environment
* All collected logs will automatically sent to {serverURL} every {sendingFrequency} second
*
* The request will be PUT to the server in the following format
* {events: Log[]}
*/
export interface LoggerConfig {
serverURL: string;
sendingFrequency: number;
maskedKeywords?: RegExp[];
}
export interface Logger {
addContext(context: {[key: string]: string | (() => string)}): void;
/**
* Add a log item, whose result is OK
*/
info(action: string, info?: {[key: string]: string}): () => void;
/**
* Add a log item, whose result is WARN
* @errorCode: Naming in upper-case and underscore, e.g: SOME_DATA
*/
warn(errorCode: string, action?: string, info?: {[key: string]: string}): () => void;
/**
* Add a log item, whose result is ERROR
* @errorCode: Naming in upper-case and underscore, e.g: SOME_DATA
*/
error(errorCode: string, action?: string, info?: {[key: string]: string}): () => void;
/**
* This function can auto convert to ERROR/WARN level with exception information, according to type
*/
exception(exception: Exception): () => void;
}
export class LoggerImpl implements Logger {
private environmentContext: {[key: string]: string | (() => string)} = {};
private logQueue: Log[] = [];
constructor() {
this.environmentContext = loggerContext;
}
addContext(context: {[key: string]: string | (() => string)}): void {
this.environmentContext = {...this.environmentContext, ...context};
}
info(action: string, info?: {[key: string]: string}): () => void {
return this.appendLog("OK", action, undefined, info);
}
warn(errorCode: string, action?: string, info?: {[key: string]: string}): () => void {
return this.appendLog("WARN", action, errorCode, info);
}
error(errorCode: string, action?: string, info?: {[key: string]: string}): () => void {
return this.appendLog("ERROR", action, errorCode, info);
}
exception(exception: Exception): () => void {
if (exception instanceof NetworkConnectionException) {
return this.appendLog("WARN", undefined, "NETWORK_FAILURE", {errorMessage: exception.message});
} else {
const info: {[key: string]: string} = {errorMessage: exception.message};
let errorCode: string = "ERROR";
if (exception instanceof APIException) {
errorCode = `API_ERROR:${exception.statusCode}`;
info.requestURL = exception.requestURL;
if (exception.errorCode) {
info.errorCode = exception.errorCode;
}
if (exception.errorId) {
info.errorId = exception.errorId;
}
} else if (exception instanceof ReactLifecycleException) {
errorCode = "LIFECYCLE_ERROR";
info.stackTrace = exception.componentStack;
info.appState = JSON.stringify(app.store.getState().app);
} else if (exception instanceof RuntimeException) {
errorCode = "JS_ERROR";
info.stackTrace = JSON.stringify(exception.errorObject);
info.appState = JSON.stringify(app.store.getState().app);
}
return this.appendLog("ERROR", undefined, errorCode, info);
}
}
collect(): Log[] {
return this.logQueue;
}
empty(): void {
this.logQueue = [];
}
private appendLog(result: "OK" | "WARN" | "ERROR", action?: string, errorCode?: string, info?: {[key: string]: string}): () => void {
const completeContext = {};
Object.entries(this.environmentContext).map(([key, value]) => {
completeContext[key] = typeof value === "string" ? value : value();
});
const event: Log = {
date: new Date(),
result,
action,
errorCode,
info: info || {},
context: completeContext,
elapsedTime: 0,
};
this.logQueue.push(event);
return () => {
event.elapsedTime = new Date().getTime() - event.date.getTime();
};
}
}