timer-logs
Advanced tools
Comparing version 1.4.0 to 1.5.0
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const index_1 = require("../index"); | ||
const timer = new index_1.default({ filename: '/exemplar/index.ts', label: 'Exemplary!', omitStackTrace: true }); | ||
timer.customError('Hellp!'); | ||
const timer = new index_1.default({ | ||
filename: "/exemplar/index.ts", | ||
label: "Exemplar of how the logger can be used", | ||
omitStackTrace: true, | ||
environment: "development", | ||
}); | ||
timer.customError("Hellp!"); | ||
try { | ||
JSON.parse('i am not json'); | ||
JSON.parse("i am not json"); | ||
} | ||
@@ -12,20 +17,21 @@ catch (e) { | ||
} | ||
new Promise((resolve => setTimeout(resolve, 50))) | ||
new Promise((resolve) => setTimeout(resolve, 50)) | ||
.then(() => { | ||
throw new Error('Unexpected error occurred'); | ||
}).catch(timer.genericErrorCustomMessage('A better explanation for what caused this error')); | ||
throw new Error("Unexpected error occurred"); | ||
}) | ||
.catch(timer.genericErrorCustomMessage("A better explanation for what caused this error")); | ||
const postgresExample = async () => { | ||
const { rows } = await new Promise((resolve => setTimeout(resolve, 50))) | ||
const { rows } = await new Promise((resolve) => setTimeout(resolve, 50)) | ||
.then(() => { | ||
throw new Error('Unexpected error occurred'); | ||
return { rows: ['row1', 'row2'] }; | ||
throw new Error("Unexpected error occurred"); | ||
return { rows: ["row1", "row2"] }; | ||
}) | ||
.catch(timer.postgresErrorReturn({ rows: [] })); | ||
console.assert(rows instanceof Array, 'Rows should be an array even if an error is thrown'); | ||
console.assert(rows instanceof Array, "Rows should be an array even if an error is thrown"); | ||
}; | ||
postgresExample().then(() => { | ||
timer.info('Some information about the current state of the program:', false, 1, 2, 3, ['one', 'two', 'three']); | ||
timer.alert('Something has gone seriously wrong!'); | ||
timer.warn('This shouldn\'t happen under normal circumstances, but isn\'t a catastrophe'); | ||
timer.info("Some information about the current state of the program:", false, 1, 2, 3, ["one", "two", "three"]); | ||
timer.alert("Something has gone seriously wrong!"); | ||
timer.warn("This shouldn't happen under normal circumstances, but isn't a catastrophe"); | ||
timer.flush(); | ||
}); |
@@ -1,38 +0,59 @@ | ||
import Timer from '../index' | ||
import Timer from "../index"; | ||
// instantiate the logger with some config values. The bare minimum is the filename | ||
const timer = new Timer({filename: '/exemplar/index.ts', label: 'Exemplary!', omitStackTrace: true}) | ||
const timer = new Timer({ | ||
filename: "/exemplar/index.ts", | ||
label: "Exemplar of how the logger can be used", | ||
omitStackTrace: true, | ||
environment: "development", | ||
}); | ||
// log a custom error without actually throwing Error | ||
timer.customError('Hellp!') | ||
timer.customError("Hellp!"); | ||
// log any type of Error | ||
try{ | ||
JSON.parse('i am not json') | ||
}catch (e) { | ||
timer.genericError(e) | ||
try { | ||
JSON.parse("i am not json"); | ||
} catch (e) { | ||
timer.genericError(e); | ||
} | ||
// overriding the default error message in a promise .catch() | ||
new Promise((resolve => setTimeout(resolve, 50))) | ||
.then(()=> { | ||
throw new Error('Unexpected error occurred') | ||
}).catch(timer.genericErrorCustomMessage('A better explanation for what caused this error')) | ||
new Promise((resolve) => setTimeout(resolve, 50)) | ||
.then(() => { | ||
throw new Error("Unexpected error occurred"); | ||
}) | ||
.catch( | ||
timer.genericErrorCustomMessage( | ||
"A better explanation for what caused this error" | ||
) | ||
); | ||
const postgresExample = async () => { | ||
const { rows } = await new Promise((resolve => setTimeout(resolve, 50))) | ||
.then(()=> { | ||
throw new Error('Unexpected error occurred') | ||
return {rows: ['row1', 'row2']} | ||
}) | ||
.catch(timer.postgresErrorReturn({rows:[]})) | ||
console.assert(rows instanceof Array, 'Rows should be an array even if an error is thrown') | ||
} | ||
postgresExample().then(()=>{ | ||
timer.info('Some information about the current state of the program:', false, 1, 2, 3, ['one', 'two', 'three']) | ||
timer.alert('Something has gone seriously wrong!') | ||
timer.warn('This shouldn\'t happen under normal circumstances, but isn\'t a catastrophe') | ||
// always call flush at the end of the file (before the return statement) to print out the log | ||
timer.flush() | ||
}) | ||
const { rows } = await new Promise((resolve) => setTimeout(resolve, 50)) | ||
.then(() => { | ||
throw new Error("Unexpected error occurred"); | ||
return { rows: ["row1", "row2"] }; | ||
}) | ||
.catch(timer.postgresErrorReturn({ rows: [] })); | ||
console.assert( | ||
rows instanceof Array, | ||
"Rows should be an array even if an error is thrown" | ||
); | ||
}; | ||
postgresExample().then(() => { | ||
timer.info( | ||
"Some information about the current state of the program:", | ||
false, | ||
1, | ||
2, | ||
3, | ||
["one", "two", "three"] | ||
); | ||
timer.alert("Something has gone seriously wrong!"); | ||
timer.warn( | ||
"This shouldn't happen under normal circumstances, but isn't a catastrophe" | ||
); | ||
// always call flush at the end of the file (before the return statement) to print out the log | ||
timer.flush(); | ||
}); |
@@ -8,4 +8,4 @@ { | ||
"scripts": { | ||
"start": "ts-node index" | ||
"start": "ts-node index.ts" | ||
} | ||
} |
@@ -1,46 +0,4 @@ | ||
declare type LogDetails = { | ||
[key: string]: string | number | boolean; | ||
}; | ||
interface Config { | ||
/** | ||
* the severity of the log, defaults to DEFAULT | ||
*/ | ||
severity?: 'DEFAULT' | 'DEBUG' | 'INFO' | 'NOTICE' | 'WARNING' | 'ERROR' | 'CRITICAL' | 'ALERT' | 'EMERGENCY'; | ||
/** | ||
* the label of the log. gets printed in the google cloud summary message | ||
*/ | ||
label?: string; | ||
/** | ||
* any key-value pairs to include in the console log | ||
*/ | ||
details?: LogDetails; | ||
/** filename of the typescript source file where the log is coming from */ | ||
filename: string; | ||
/** | ||
* This will be printed on all log output, to distinguish logs output by this library from other logging in | ||
* your application. Its possible but not recommended to override it in the config. | ||
*/ | ||
loggerName?: string; | ||
/** | ||
* This will be printed on all log output from the instance configured with it, to help identify where a log has | ||
* come from, or what it relates to. This is mostly useful if you have | ||
* multiple instances of this class in a single file. Otherwise the file acts as an identifier. | ||
*/ | ||
logClass?: string; | ||
/** | ||
* Omit the stack trace from error logging. (still prints the provided file path) | ||
*/ | ||
omitStackTrace?: boolean; | ||
} | ||
export declare enum Severity { | ||
DEFAULT = "DEFAULT", | ||
DEBUG = "DEBUG", | ||
INFO = "INFO", | ||
NOTICE = "NOTICE", | ||
WARNING = "WARNING", | ||
ERROR = "ERROR", | ||
CRITICAL = "CRITICAL", | ||
ALERT = "ALERT", | ||
EMERGENCY = "EMERGENCY" | ||
} | ||
import { PostgresError } from "./types/dataStructures/Errors"; | ||
import { Config } from "./types/dataStructures/Config"; | ||
import { Severity } from "./types/enums/Severity"; | ||
export default class Timer { | ||
@@ -59,2 +17,3 @@ private readonly startTime; | ||
private readonly omitStackTrace; | ||
private readonly environment; | ||
/** | ||
@@ -68,3 +27,2 @@ * Create a new Timer object. Can have multiple timers within this object. | ||
set severity(value: Severity); | ||
private static consoleLog; | ||
/** | ||
@@ -195,2 +153,3 @@ * Start a new timer | ||
genericErrorCustomMessage(message: string): (e: Error) => void; | ||
private consoleLog; | ||
/** | ||
@@ -213,39 +172,1 @@ * Logs a postgres error and returns the value passed as the second parameter. | ||
} | ||
/** | ||
* Postgres error type thrown by pg library | ||
*/ | ||
declare type PostgresError = { | ||
message: string; | ||
errno: string; | ||
length: number; | ||
name: string; | ||
severity: string; | ||
code: string; | ||
detail?: string; | ||
hint?: string; | ||
position: string; | ||
internalPosition?: string; | ||
internalQuery?: string; | ||
where?: string; | ||
schema?: string; | ||
table?: string; | ||
column?: string; | ||
dataType?: string; | ||
constraint?: string; | ||
file: string; | ||
line: string; | ||
routine: string; | ||
}; | ||
/** | ||
* These are attributes that should be set on all log output, regardless of what triggered the log. | ||
*/ | ||
export declare type GenericLog = { | ||
severity: Severity; | ||
filename: string; | ||
logClass: string; | ||
loggerName: string; | ||
uniqueId: string; | ||
timestamp: string; | ||
[label: string]: string | number | boolean | null | undefined; | ||
}; | ||
export {}; |
188
index.js
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Severity = void 0; | ||
const crypto = require("crypto"); | ||
const logPresenter_1 = require("./logPresenter"); | ||
var Severity; | ||
(function (Severity) { | ||
Severity["DEFAULT"] = "DEFAULT"; | ||
Severity["DEBUG"] = "DEBUG"; | ||
Severity["INFO"] = "INFO"; | ||
Severity["NOTICE"] = "NOTICE"; | ||
Severity["WARNING"] = "WARNING"; | ||
Severity["ERROR"] = "ERROR"; | ||
Severity["CRITICAL"] = "CRITICAL"; | ||
Severity["ALERT"] = "ALERT"; | ||
Severity["EMERGENCY"] = "EMERGENCY"; | ||
})(Severity = exports.Severity || (exports.Severity = {})); | ||
var Environment; | ||
(function (Environment) { | ||
Environment[Environment["DEVELOPMENT"] = 0] = "DEVELOPMENT"; | ||
Environment[Environment["BROWSER"] = 1] = "BROWSER"; | ||
Environment[Environment["PRODUCTION"] = 2] = "PRODUCTION"; | ||
})(Environment || (Environment = {})); | ||
const Environment_1 = require("./types/enums/Environment"); | ||
const Severity_1 = require("./types/enums/Severity"); | ||
const BrowserPresenter_1 = require("./src/presenters/BrowserPresenter"); | ||
const DevelopmentPresenter_1 = require("./src/presenters/DevelopmentPresenter"); | ||
const ProductionPresenter_1 = require("./src/presenters/ProductionPresenter"); | ||
class Timer { | ||
@@ -29,13 +14,33 @@ constructor(config) { | ||
this.details = (_a = config.details) !== null && _a !== void 0 ? _a : {}; | ||
this.loggerName = (_b = config.loggerName) !== null && _b !== void 0 ? _b : 'timer-logs'; | ||
this.loggerName = (_b = config.loggerName) !== null && _b !== void 0 ? _b : "timer-logs"; | ||
this.filename = config.filename; | ||
this.splitFilePath = config.filename.split('/').filter(p => p.length > 0); | ||
this.label = (_c = config.label) !== null && _c !== void 0 ? _c : this.splitFilePath.slice(-1)[0].split('.')[0]; | ||
this.splitFilePath = config.filename.split("/").filter((p) => p.length > 0); | ||
this.label = (_c = config.label) !== null && _c !== void 0 ? _c : this.splitFilePath.slice(-1)[0].split(".")[0]; | ||
this.savedTimes = {}; | ||
this.logClass = (_d = config.logClass) !== null && _d !== void 0 ? _d : this.splitFilePath.slice(-1)[0].split('.')[0]; | ||
this.logClass = (_d = config.logClass) !== null && _d !== void 0 ? _d : this.splitFilePath.slice(-1)[0].split(".")[0]; | ||
this.omitStackTrace = (_e = config.omitStackTrace) !== null && _e !== void 0 ? _e : false; | ||
this._severity = Severity[(_f = config.severity) !== null && _f !== void 0 ? _f : Severity.DEFAULT]; | ||
this.uniqueId = crypto.randomBytes(8).toString('hex'); | ||
this.start('operationTime'); | ||
this._severity = Severity_1.Severity[(_f = config.severity) !== null && _f !== void 0 ? _f : Severity_1.Severity.DEFAULT]; | ||
this.uniqueId = crypto.randomBytes(8).toString("hex"); | ||
this.start("operationTime"); | ||
this.start(this.label); | ||
if (typeof window !== "undefined") | ||
this.environment = Environment_1.Environment.BROWSER; | ||
else if (process.env.NODE_ENV === "development") | ||
this.environment = Environment_1.Environment.DEVELOPMENT; | ||
else | ||
this.environment = Environment_1.Environment.PRODUCTION; | ||
if (config.environment !== undefined) { | ||
switch (config.environment) { | ||
case "browser": | ||
this.environment = Environment_1.Environment.BROWSER; | ||
break; | ||
case "development": | ||
this.environment = Environment_1.Environment.DEVELOPMENT; | ||
break; | ||
case "production": | ||
default: | ||
this.environment = Environment_1.Environment.PRODUCTION; | ||
break; | ||
} | ||
} | ||
} | ||
@@ -45,31 +50,6 @@ set severity(value) { | ||
} | ||
static consoleLog(logObject) { | ||
let environment; | ||
if (typeof window !== 'undefined') | ||
environment = Environment.BROWSER; | ||
else if (process.env.NODE_ENV === 'development') | ||
environment = Environment.DEVELOPMENT; | ||
else | ||
environment = Environment.PRODUCTION; | ||
let logPresenter; | ||
switch (environment) { | ||
case Environment.BROWSER: | ||
logPresenter = logPresenter_1.browserLogPresenter; | ||
break; | ||
case Environment.DEVELOPMENT: | ||
logPresenter = logPresenter_1.developerLogPresenter; | ||
break; | ||
case Environment.PRODUCTION: | ||
logPresenter = logPresenter_1.productionLogPresenter; | ||
break; | ||
default: | ||
logPresenter = logPresenter_1.productionLogPresenter; | ||
break; | ||
} | ||
logPresenter(logObject); | ||
} | ||
start(label) { | ||
console.assert(!this.savedTimes.hasOwnProperty(label), 'Timer started more than once for same label'); | ||
console.assert(label !== 'message', 'Label cannot be called message. Reserved by default'); | ||
console.assert(label !== 'severity', 'Label cannot be called severity. Reserved by default'); | ||
console.assert(!this.savedTimes.hasOwnProperty(label), "Timer started more than once for same label"); | ||
console.assert(label !== "message", "Label cannot be called message. Reserved by default"); | ||
console.assert(label !== "severity", "Label cannot be called severity. Reserved by default"); | ||
this.mostRecentlyStartedLabel = label; | ||
@@ -81,8 +61,8 @@ this.savedTimes[label] = { startTime: Date.now() }; | ||
return { | ||
stop: _stop | ||
stop: _stop, | ||
}; | ||
} | ||
stop(label) { | ||
console.assert(this.savedTimes.hasOwnProperty(label), 'Timer stopped for unstarted label. Missing timer.start()'); | ||
console.assert(this.savedTimes[label].finishTime === undefined, 'Stop called more than once for same label'); | ||
console.assert(this.savedTimes.hasOwnProperty(label), "Timer stopped for unstarted label. Missing timer.start()"); | ||
console.assert(this.savedTimes[label].finishTime === undefined, "Stop called more than once for same label"); | ||
const finishTime = Date.now(); | ||
@@ -95,3 +75,3 @@ this.savedTimes[label].finishTime = finishTime; | ||
if (!this.mostRecentlyStartedLabel) { | ||
console.error('Next called before a timer was started'); | ||
console.error("Next called before a timer was started"); | ||
return; | ||
@@ -108,12 +88,12 @@ } | ||
this.finishTime = Date.now(); | ||
this.stop('operationTime'); | ||
if (this.mostRecentlyStartedLabel && !this.savedTimes[this.mostRecentlyStartedLabel].finishTime) | ||
this.stop("operationTime"); | ||
if (this.mostRecentlyStartedLabel && | ||
!this.savedTimes[this.mostRecentlyStartedLabel].finishTime) | ||
this.end(); | ||
const printObject = { | ||
message: this.label + `: ${this.finishTime - this.startTime}ms` | ||
message: this.label + `: ${this.finishTime - this.startTime}ms`, | ||
}; | ||
const printMap = new Map(Object.entries(printObject)); | ||
Object.entries(this.savedTimes) | ||
.forEach(([label, times]) => { | ||
if (typeof times.time === 'number') | ||
Object.entries(this.savedTimes).forEach(([label, times]) => { | ||
if (typeof times.time === "number") | ||
printMap.set(label, times.time); | ||
@@ -138,22 +118,22 @@ }); | ||
info(message, ...messages) { | ||
const concatenatedMessage = [message].concat(messages === null || messages === void 0 ? void 0 : messages.map(m => m.toString())).join(' '); | ||
this.printLog(new Map([ | ||
['message', concatenatedMessage], | ||
]), Severity.INFO); | ||
const concatenatedMessage = [message] | ||
.concat(messages === null || messages === void 0 ? void 0 : messages.map((m) => m.toString())) | ||
.join(" "); | ||
this.printLog(new Map([["message", concatenatedMessage]]), Severity_1.Severity.INFO); | ||
} | ||
warn(message, ...messages) { | ||
const concatenatedMessage = [message].concat(messages === null || messages === void 0 ? void 0 : messages.map(m => m.toString())).join(' '); | ||
this.printLog(new Map([ | ||
['message', concatenatedMessage], | ||
]), Severity.WARNING); | ||
const concatenatedMessage = [message] | ||
.concat(messages === null || messages === void 0 ? void 0 : messages.map((m) => m.toString())) | ||
.join(" "); | ||
this.printLog(new Map([["message", concatenatedMessage]]), Severity_1.Severity.WARNING); | ||
} | ||
alert(message, ...messages) { | ||
const concatenatedMessage = [message].concat(messages === null || messages === void 0 ? void 0 : messages.map(m => m.toString())).join(' '); | ||
this.printLog(new Map([ | ||
['message', concatenatedMessage], | ||
]), Severity.ALERT); | ||
const concatenatedMessage = [message] | ||
.concat(messages === null || messages === void 0 ? void 0 : messages.map((m) => m.toString())) | ||
.join(" "); | ||
this.printLog(new Map([["message", concatenatedMessage]]), Severity_1.Severity.ALERT); | ||
} | ||
customError(message) { | ||
const errorDetails = new Map(Object.entries({ message })); | ||
this.printLog(errorDetails, Severity.ERROR); | ||
this.printLog(errorDetails, Severity_1.Severity.ERROR); | ||
} | ||
@@ -167,14 +147,12 @@ postgresError(e) { | ||
genericError(e, message) { | ||
const errorDetails = new Map([ | ||
['errorName', e.name] | ||
]); | ||
const errorDetails = new Map([["errorName", e.name]]); | ||
if (!this.omitStackTrace && e.stack) | ||
errorDetails.set('stackTrace', e.stack); | ||
errorDetails.set("stackTrace", e.stack); | ||
if (message) { | ||
errorDetails.set('message', message); | ||
errorDetails.set('errorMessage', e.message); | ||
errorDetails.set("message", message); | ||
errorDetails.set("errorMessage", e.message); | ||
} | ||
else | ||
errorDetails.set('message', e.message); | ||
this.printLog(errorDetails, Severity.ERROR); | ||
errorDetails.set("message", e.message); | ||
this.printLog(errorDetails, Severity_1.Severity.ERROR); | ||
} | ||
@@ -184,22 +162,42 @@ genericErrorCustomMessage(message) { | ||
} | ||
consoleLog(logObject) { | ||
let logPresenter; | ||
switch (this.environment) { | ||
case Environment_1.Environment.BROWSER: | ||
logPresenter = BrowserPresenter_1.BrowserPresenter; | ||
break; | ||
case Environment_1.Environment.DEVELOPMENT: | ||
logPresenter = DevelopmentPresenter_1.DevelopmentPresenter; | ||
break; | ||
case Environment_1.Environment.PRODUCTION: | ||
logPresenter = ProductionPresenter_1.ProductionPresenter; | ||
break; | ||
default: | ||
logPresenter = ProductionPresenter_1.ProductionPresenter; | ||
break; | ||
} | ||
logPresenter(logObject); | ||
} | ||
_postgresError(e, returnVal) { | ||
const errorDetails = new Map(Object.entries(e)); | ||
if (!errorDetails.has('message')) | ||
errorDetails.set('message', 'Postgres error code ' + e.code); | ||
if (!errorDetails.has("message")) | ||
errorDetails.set("message", "Postgres error code " + e.code); | ||
errorDetails.set("databaseType", "postgres"); | ||
this.printLog(errorDetails, Severity.ERROR); | ||
this.printLog(errorDetails, Severity_1.Severity.ERROR); | ||
return returnVal; | ||
} | ||
printLog(details, severity) { | ||
var _a; | ||
if (!details.has('message')) { | ||
details.set('message', 'timer-logs unset message in file ' + this.filename); | ||
} | ||
var _a, _b; | ||
let detailsMessage = (_a = details.get("message")) === null || _a === void 0 ? void 0 : _a.toString(); | ||
const message = details.has("message") && detailsMessage | ||
? detailsMessage | ||
: "timer-logs: message not set"; | ||
const log = { | ||
severity: severity, | ||
filename: this.filename, | ||
logClass: (_a = this.logClass) !== null && _a !== void 0 ? _a : this.splitFilePath.slice(-1)[0].split('.')[0], | ||
logClass: (_b = this.logClass) !== null && _b !== void 0 ? _b : this.splitFilePath.slice(-1)[0].split(".")[0], | ||
loggerName: this.loggerName, | ||
uniqueId: this.uniqueId, | ||
timestamp: new Date().toUTCString(), | ||
message, | ||
}; | ||
@@ -212,5 +210,5 @@ details.forEach((value, key) => { | ||
}); | ||
Timer.consoleLog(log); | ||
this.consoleLog(log); | ||
} | ||
} | ||
exports.default = Timer; |
780
index.ts
@@ -1,444 +0,396 @@ | ||
import * as crypto from 'crypto' | ||
import {browserLogPresenter, developerLogPresenter, productionLogPresenter} from "./logPresenter"; | ||
import * as crypto from "crypto"; | ||
import { PostgresError } from "./types/dataStructures/Errors"; | ||
import { Config } from "./types/dataStructures/Config"; | ||
import { Environment } from "./types/enums/Environment"; | ||
import { GenericLog, LogDetails } from "./types/dataStructures/Logs"; | ||
import { Severity } from "./types/enums/Severity"; | ||
import { BrowserPresenter } from "./src/presenters/BrowserPresenter"; | ||
import { DevelopmentPresenter } from "./src/presenters/DevelopmentPresenter"; | ||
import { ProductionPresenter } from "./src/presenters/ProductionPresenter"; | ||
type LogDetails = { [key: string]: string | number | boolean } | ||
interface Config { | ||
/** | ||
* the severity of the log, defaults to DEFAULT | ||
*/ | ||
severity?: 'DEFAULT' | 'DEBUG' | 'INFO' | 'NOTICE' | 'WARNING' | 'ERROR' | 'CRITICAL' | 'ALERT' | 'EMERGENCY' | ||
/** | ||
* the label of the log. gets printed in the google cloud summary message | ||
*/ | ||
label?: string | ||
/** | ||
* any key-value pairs to include in the console log | ||
*/ | ||
details?: LogDetails | ||
/** filename of the typescript source file where the log is coming from */ | ||
filename: string | ||
/** | ||
* This will be printed on all log output, to distinguish logs output by this library from other logging in | ||
* your application. Its possible but not recommended to override it in the config. | ||
*/ | ||
loggerName?: string | ||
/** | ||
* This will be printed on all log output from the instance configured with it, to help identify where a log has | ||
* come from, or what it relates to. This is mostly useful if you have | ||
* multiple instances of this class in a single file. Otherwise the file acts as an identifier. | ||
*/ | ||
logClass?: string | ||
/** | ||
* Omit the stack trace from error logging. (still prints the provided file path) | ||
*/ | ||
omitStackTrace?: boolean | ||
} | ||
/** | ||
* The same options that can be passed in, but not optional. By this point the default will be set if not passed in. | ||
*/ | ||
interface InternalConfig extends Config { | ||
severity: Severity | ||
label: string | ||
details: LogDetails | ||
filename: string | ||
loggerName: string | ||
logClass: string | ||
omitStackTrace: boolean | ||
} | ||
export enum Severity { | ||
DEFAULT = "DEFAULT", | ||
DEBUG = "DEBUG", | ||
INFO = "INFO", | ||
NOTICE = "NOTICE", | ||
WARNING = "WARNING", | ||
ERROR = "ERROR", | ||
CRITICAL = "CRITICAL", | ||
ALERT = "ALERT", | ||
EMERGENCY = "EMERGENCY" | ||
} | ||
enum Environment { | ||
DEVELOPMENT, | ||
BROWSER, | ||
PRODUCTION | ||
} | ||
export default class Timer { | ||
private readonly startTime: number | ||
private finishTime?: number | ||
private mostRecentlyStartedLabel?: string | ||
private readonly savedTimes: { [label: string]: { startTime: number; finishTime?: number; time?: number } } | ||
private readonly splitFilePath: string[] | ||
private readonly filename: string | ||
private readonly uniqueId: string | ||
private readonly label: string | ||
private readonly details: LogDetails | ||
private readonly loggerName: string | ||
private readonly logClass: string | ||
private readonly omitStackTrace: boolean | ||
private readonly startTime: number; | ||
private finishTime?: number; | ||
private mostRecentlyStartedLabel?: string; | ||
private readonly savedTimes: { | ||
[label: string]: { startTime: number; finishTime?: number; time?: number }; | ||
}; | ||
private readonly splitFilePath: string[]; | ||
private readonly filename: string; | ||
private readonly uniqueId: string; | ||
private readonly label: string; | ||
private readonly details: LogDetails; | ||
private readonly loggerName: string; | ||
private readonly logClass: string; | ||
private readonly omitStackTrace: boolean; | ||
private readonly environment: Environment; | ||
/** | ||
* Create a new Timer object. Can have multiple timers within this object. | ||
* Should only have one of these per file. Creating this object beings a timer automatically | ||
* @param config required configuration object, requires filename, others are optional | ||
*/ | ||
constructor(config: Config) { | ||
this.startTime = Date.now() | ||
this.details = config.details ?? {} | ||
this.loggerName = config.loggerName ?? 'timer-logs' | ||
this.filename = config.filename | ||
this.splitFilePath = config.filename.split('/').filter(p => p.length > 0) | ||
this.label = config.label ?? this.splitFilePath.slice(-1)[0].split('.')[0] | ||
this.savedTimes = {} | ||
this.logClass = config.logClass ?? this.splitFilePath.slice(-1)[0].split('.')[0] | ||
this.omitStackTrace = config.omitStackTrace ?? false | ||
this._severity = Severity[config.severity ?? Severity.DEFAULT] | ||
this.uniqueId = crypto.randomBytes(8).toString('hex') | ||
this.start('operationTime') | ||
this.start(this.label) | ||
/** | ||
* Create a new Timer object. Can have multiple timers within this object. | ||
* Should only have one of these per file. Creating this object beings a timer automatically | ||
* @param config required configuration object, requires filename, others are optional | ||
*/ | ||
constructor(config: Config) { | ||
this.startTime = Date.now(); | ||
this.details = config.details ?? {}; | ||
this.loggerName = config.loggerName ?? "timer-logs"; | ||
this.filename = config.filename; | ||
this.splitFilePath = config.filename.split("/").filter((p) => p.length > 0); | ||
this.label = config.label ?? this.splitFilePath.slice(-1)[0].split(".")[0]; | ||
this.savedTimes = {}; | ||
this.logClass = | ||
config.logClass ?? this.splitFilePath.slice(-1)[0].split(".")[0]; | ||
this.omitStackTrace = config.omitStackTrace ?? false; | ||
this._severity = Severity[config.severity ?? Severity.DEFAULT]; | ||
this.uniqueId = crypto.randomBytes(8).toString("hex"); | ||
this.start("operationTime"); | ||
this.start(this.label); | ||
// set the environment | ||
if (typeof window !== "undefined") this.environment = Environment.BROWSER; | ||
else if (process.env.NODE_ENV === "development") | ||
this.environment = Environment.DEVELOPMENT; | ||
else this.environment = Environment.PRODUCTION; | ||
if (config.environment !== undefined) { | ||
switch (config.environment) { | ||
case "browser": | ||
this.environment = Environment.BROWSER; | ||
break; | ||
case "development": | ||
this.environment = Environment.DEVELOPMENT; | ||
break; | ||
case "production": | ||
default: | ||
this.environment = Environment.PRODUCTION; | ||
break; | ||
} | ||
} | ||
} | ||
private _severity: Severity | ||
private _severity: Severity; | ||
set severity(value: Severity) { | ||
this._severity = value; | ||
} | ||
set severity(value: Severity) { | ||
this._severity = value; | ||
} | ||
private static consoleLog(logObject: GenericLog) { | ||
let environment: Environment | ||
if (typeof window !== 'undefined') | ||
environment = Environment.BROWSER | ||
else if (process.env.NODE_ENV === 'development') | ||
environment = Environment.DEVELOPMENT | ||
else | ||
environment = Environment.PRODUCTION | ||
let logPresenter: (logObject: GenericLog) => void | ||
switch (environment) { | ||
case Environment.BROWSER: | ||
logPresenter = browserLogPresenter | ||
break; | ||
case Environment.DEVELOPMENT: | ||
logPresenter = developerLogPresenter | ||
break; | ||
case Environment.PRODUCTION: | ||
logPresenter = productionLogPresenter | ||
break; | ||
default: | ||
logPresenter = productionLogPresenter | ||
break | ||
} | ||
logPresenter(logObject) | ||
} | ||
/** | ||
* Start a new timer | ||
* @param label the label of the timer. this will be console logged on flush() | ||
* @return object which can be used to stop the timer without its label | ||
*/ | ||
public start(label: string) { | ||
console.assert( | ||
!this.savedTimes.hasOwnProperty(label), | ||
"Timer started more than once for same label" | ||
); | ||
console.assert( | ||
label !== "message", | ||
"Label cannot be called message. Reserved by default" | ||
); | ||
console.assert( | ||
label !== "severity", | ||
"Label cannot be called severity. Reserved by default" | ||
); | ||
this.mostRecentlyStartedLabel = label; | ||
this.savedTimes[label] = { startTime: Date.now() }; | ||
/** | ||
* Start a new timer | ||
* @param label the label of the timer. this will be console logged on flush() | ||
* @return object which can be used to stop the timer without its label | ||
* Stops the timer and saves the time taken | ||
*/ | ||
public start(label: string) { | ||
console.assert(!this.savedTimes.hasOwnProperty(label), 'Timer started more than once for same label') | ||
console.assert(label !== 'message', 'Label cannot be called message. Reserved by default') | ||
console.assert(label !== 'severity', 'Label cannot be called severity. Reserved by default') | ||
this.mostRecentlyStartedLabel = label | ||
this.savedTimes[label] = {startTime: Date.now()} | ||
/** | ||
* Stops the timer and saves the time taken | ||
*/ | ||
const _stop = () => { | ||
return this.stop(label) | ||
} | ||
return { | ||
stop: _stop | ||
} | ||
} | ||
const _stop = () => { | ||
return this.stop(label); | ||
}; | ||
return { | ||
stop: _stop, | ||
}; | ||
} | ||
/** | ||
* Stops a timer and saves the time taken | ||
* @param label the label of the timer you wish to stop | ||
*/ | ||
public stop(label: string) { | ||
console.assert(this.savedTimes.hasOwnProperty(label), 'Timer stopped for unstarted label. Missing timer.start()') | ||
console.assert(this.savedTimes[label].finishTime === undefined, 'Stop called more than once for same label') | ||
const finishTime = Date.now() | ||
this.savedTimes[label].finishTime = finishTime | ||
this.savedTimes[label].time = finishTime - this.savedTimes[label].startTime | ||
return this.savedTimes[label].time | ||
} | ||
/** | ||
* Stops a timer and saves the time taken | ||
* @param label the label of the timer you wish to stop | ||
*/ | ||
public stop(label: string) { | ||
console.assert( | ||
this.savedTimes.hasOwnProperty(label), | ||
"Timer stopped for unstarted label. Missing timer.start()" | ||
); | ||
console.assert( | ||
this.savedTimes[label].finishTime === undefined, | ||
"Stop called more than once for same label" | ||
); | ||
const finishTime = Date.now(); | ||
this.savedTimes[label].finishTime = finishTime; | ||
this.savedTimes[label].time = finishTime - this.savedTimes[label].startTime; | ||
return this.savedTimes[label].time; | ||
} | ||
/** | ||
* Stops the most recently started timer, and starts a new one | ||
* @param label for new timer started | ||
* @example | ||
* timer.start('label1') | ||
* await new Promise() | ||
* timer.next('label2') | ||
* await new Promise() | ||
* timer.next('label3') | ||
* await new Promise() | ||
* timer.end() | ||
*/ | ||
public next(label: string) { | ||
if (!this.mostRecentlyStartedLabel) { | ||
console.error('Next called before a timer was started') | ||
return | ||
} | ||
this.stop(this.mostRecentlyStartedLabel) | ||
this.start(label) | ||
/** | ||
* Stops the most recently started timer, and starts a new one | ||
* @param label for new timer started | ||
* @example | ||
* timer.start('label1') | ||
* await new Promise() | ||
* timer.next('label2') | ||
* await new Promise() | ||
* timer.next('label3') | ||
* await new Promise() | ||
* timer.end() | ||
*/ | ||
public next(label: string) { | ||
if (!this.mostRecentlyStartedLabel) { | ||
console.error("Next called before a timer was started"); | ||
return; | ||
} | ||
this.stop(this.mostRecentlyStartedLabel); | ||
this.start(label); | ||
} | ||
/** | ||
* stops the most recently started timer | ||
*/ | ||
public end() { | ||
if (this.mostRecentlyStartedLabel) return this.stop(this.mostRecentlyStartedLabel) | ||
} | ||
/** | ||
* stops the most recently started timer | ||
*/ | ||
public end() { | ||
if (this.mostRecentlyStartedLabel) | ||
return this.stop(this.mostRecentlyStartedLabel); | ||
} | ||
/** | ||
* Prints times to the console in JSON format for Google Cloud Logging. | ||
* | ||
* Will end the most recently started timer if not already ended | ||
*/ | ||
public flush() { | ||
this.finishTime = Date.now() | ||
this.stop('operationTime') | ||
if (this.mostRecentlyStartedLabel && !this.savedTimes[this.mostRecentlyStartedLabel].finishTime) this.end() | ||
const printObject: { [label: string]: string | number | boolean } = { | ||
message: this.label + `: ${this.finishTime - this.startTime}ms` | ||
} | ||
const printMap = new Map(Object.entries(printObject)) | ||
Object.entries(this.savedTimes) | ||
.forEach(([label, times]) => { | ||
if (typeof times.time === 'number') printMap.set(label, times.time) | ||
}) | ||
if (this.details) | ||
Object.entries(this.details).forEach(([label, detail]) => { | ||
printMap.set(label, detail) | ||
}) | ||
this.printLog(printMap, this._severity) | ||
return this.finishTime - this.startTime | ||
} | ||
/** | ||
* Prints times to the console in JSON format for Google Cloud Logging. | ||
* | ||
* Will end the most recently started timer if not already ended | ||
*/ | ||
public flush() { | ||
this.finishTime = Date.now(); | ||
this.stop("operationTime"); | ||
if ( | ||
this.mostRecentlyStartedLabel && | ||
!this.savedTimes[this.mostRecentlyStartedLabel].finishTime | ||
) | ||
this.end(); | ||
const printObject: { [label: string]: string | number | boolean } = { | ||
message: this.label + `: ${this.finishTime - this.startTime}ms`, | ||
}; | ||
const printMap = new Map(Object.entries(printObject)); | ||
Object.entries(this.savedTimes).forEach(([label, times]) => { | ||
if (typeof times.time === "number") printMap.set(label, times.time); | ||
}); | ||
if (this.details) | ||
Object.entries(this.details).forEach(([label, detail]) => { | ||
printMap.set(label, detail); | ||
}); | ||
this.printLog(printMap, this._severity); | ||
return this.finishTime - this.startTime; | ||
} | ||
/** | ||
* Adds a detail to the JSON of the log. | ||
* | ||
* @param key the key to log in the JSON | ||
* @param value (optional) value for the key. Defaults to true | ||
*/ | ||
public addDetail(key: string, value: string | number | boolean = true) { | ||
Object.assign(this.details, {[key]: value}) | ||
} | ||
/** | ||
* Adds a detail to the JSON of the log. | ||
* | ||
* @param key the key to log in the JSON | ||
* @param value (optional) value for the key. Defaults to true | ||
*/ | ||
public addDetail(key: string, value: string | number | boolean = true) { | ||
Object.assign(this.details, { [key]: value }); | ||
} | ||
/** | ||
* Adds multiple details to the JSON of the log. | ||
* | ||
* @param details an object of key value pairs to log | ||
*/ | ||
public addDetails(details: { [key: string]: string | number | boolean }) { | ||
Object.assign(this.details, details) | ||
} | ||
/** | ||
* Adds multiple details to the JSON of the log. | ||
* | ||
* @param details an object of key value pairs to log | ||
*/ | ||
public addDetails(details: { [key: string]: string | number | boolean }) { | ||
Object.assign(this.details, details); | ||
} | ||
/** | ||
* Returns the time elapsed since creating this timer in milliseconds | ||
*/ | ||
public getTimeUntilNow() { | ||
return Date.now() - this.startTime | ||
} | ||
/** | ||
* Returns the time elapsed since creating this timer in milliseconds | ||
*/ | ||
public getTimeUntilNow() { | ||
return Date.now() - this.startTime; | ||
} | ||
/** | ||
* Log a message at INFO severity level. | ||
*/ | ||
public info(message: string, ...messages: any[]) { | ||
const concatenatedMessage = [message].concat(messages?.map(m => m.toString())).join(' ') | ||
this.printLog(new Map([ | ||
['message', concatenatedMessage], | ||
]), Severity.INFO) | ||
} | ||
/** | ||
* Log a message at INFO severity level. | ||
*/ | ||
public info(message: string, ...messages: any[]) { | ||
const concatenatedMessage = [message] | ||
.concat(messages?.map((m) => m.toString())) | ||
.join(" "); | ||
this.printLog(new Map([["message", concatenatedMessage]]), Severity.INFO); | ||
} | ||
/** | ||
* Log a message at WARNING severity level. | ||
*/ | ||
public warn(message: string, ...messages: any[]) { | ||
const concatenatedMessage = [message].concat(messages?.map(m => m.toString())).join(' ') | ||
this.printLog(new Map([ | ||
['message', concatenatedMessage], | ||
]), Severity.WARNING) | ||
} | ||
/** | ||
* Log a message at WARNING severity level. | ||
*/ | ||
public warn(message: string, ...messages: any[]) { | ||
const concatenatedMessage = [message] | ||
.concat(messages?.map((m) => m.toString())) | ||
.join(" "); | ||
this.printLog( | ||
new Map([["message", concatenatedMessage]]), | ||
Severity.WARNING | ||
); | ||
} | ||
/** | ||
* Log a message at ALERT severity level. | ||
*/ | ||
public alert(message: string, ...messages: any[]) { | ||
const concatenatedMessage = [message].concat(messages?.map(m => m.toString())).join(' ') | ||
this.printLog(new Map([ | ||
['message', concatenatedMessage], | ||
]), Severity.ALERT) | ||
} | ||
/** | ||
* Log a message at ALERT severity level. | ||
*/ | ||
public alert(message: string, ...messages: any[]) { | ||
const concatenatedMessage = [message] | ||
.concat(messages?.map((m) => m.toString())) | ||
.join(" "); | ||
this.printLog(new Map([["message", concatenatedMessage]]), Severity.ALERT); | ||
} | ||
/** | ||
* Logs a custom error message in a separate log to the main Timer | ||
* @param message the string to log | ||
*/ | ||
public customError(message: string) { | ||
const errorDetails = new Map(Object.entries({message})) | ||
this.printLog(errorDetails, Severity.ERROR) | ||
} | ||
/** | ||
* Logs a custom error message in a separate log to the main Timer | ||
* @param message the string to log | ||
*/ | ||
public customError(message: string) { | ||
const errorDetails = new Map(Object.entries({ message })); | ||
this.printLog(errorDetails, Severity.ERROR); | ||
} | ||
/** | ||
* Logs a postgres error message in a separate log to the main Timer. | ||
* | ||
* @param e the error object returned by postgres client | ||
* @return null so the promise resolves to a value | ||
* @example | ||
* const result = await pool.query('SELECT NOW()',[]) | ||
* .catch(e=>timer.postgresError(e)) | ||
*/ | ||
public postgresError(e: PostgresError): null { | ||
return this._postgresError(e, null) | ||
} | ||
/** | ||
* Logs a postgres error message in a separate log to the main Timer. | ||
* | ||
* @param e the error object returned by postgres client | ||
* @return null so the promise resolves to a value | ||
* @example | ||
* const result = await pool.query('SELECT NOW()',[]) | ||
* .catch(e=>timer.postgresError(e)) | ||
*/ | ||
public postgresError(e: PostgresError): null { | ||
return this._postgresError(e, null); | ||
} | ||
/** | ||
* Convenience wrapper for postgresError, to return a value. | ||
* By default it returns null, but can be overriden with this method. | ||
* This is useful if you want your promise to resolve to a default value | ||
* in case of an error. | ||
* @param returnValue the value to return | ||
* @example | ||
* const { rows } = await pool.query('SELECT NOW()',[]) | ||
* .catch(e=>timer.postgresErrorReturn({rows:[]})) | ||
*/ | ||
public postgresErrorReturn<ReturnType>(returnValue: ReturnType): (e: PostgresError) => ReturnType { | ||
return (e: PostgresError) => this._postgresError(e, returnValue) | ||
} | ||
/** | ||
* Convenience wrapper for postgresError, to return a value. | ||
* By default it returns null, but can be overriden with this method. | ||
* This is useful if you want your promise to resolve to a default value | ||
* in case of an error. | ||
* @param returnValue the value to return | ||
* @example | ||
* const { rows } = await pool.query('SELECT NOW()',[]) | ||
* .catch(e=>timer.postgresErrorReturn({rows:[]})) | ||
*/ | ||
public postgresErrorReturn<ReturnType>( | ||
returnValue: ReturnType | ||
): (e: PostgresError) => ReturnType { | ||
return (e: PostgresError) => this._postgresError(e, returnValue); | ||
} | ||
/** | ||
* Logs a generic error in a separate log to the main Timer. | ||
* | ||
* @param e the error that has been thrown | ||
* @param message an optional custom message giving context to the error | ||
* This can be called after any catching any error, like this: | ||
* @example | ||
* try{ | ||
* // code that could throw an error | ||
* }catch(e){ | ||
* timer.genericError(e) | ||
* } | ||
* @example | ||
* await asynchronousFunction() | ||
* .then() | ||
* .catch(timer.genericError) | ||
*/ | ||
public genericError(e: Error, message?: string) { | ||
const errorDetails = new Map([ | ||
['errorName', e.name] | ||
]) | ||
if (!this.omitStackTrace && e.stack) errorDetails.set('stackTrace', e.stack) | ||
if (message) { | ||
errorDetails.set('message', message) | ||
errorDetails.set('errorMessage', e.message) | ||
} else errorDetails.set('message', e.message) | ||
this.printLog(errorDetails, Severity.ERROR) | ||
} | ||
/** | ||
* Logs a generic error in a separate log to the main Timer. | ||
* | ||
* @param e the error that has been thrown | ||
* @param message an optional custom message giving context to the error | ||
* This can be called after any catching any error, like this: | ||
* @example | ||
* try{ | ||
* // code that could throw an error | ||
* }catch(e){ | ||
* timer.genericError(e) | ||
* } | ||
* @example | ||
* await asynchronousFunction() | ||
* .then() | ||
* .catch(timer.genericError) | ||
*/ | ||
public genericError(e: Error, message?: string) { | ||
const errorDetails = new Map([["errorName", e.name]]); | ||
if (!this.omitStackTrace && e.stack) | ||
errorDetails.set("stackTrace", e.stack); | ||
if (message) { | ||
errorDetails.set("message", message); | ||
errorDetails.set("errorMessage", e.message); | ||
} else errorDetails.set("message", e.message); | ||
this.printLog(errorDetails, Severity.ERROR); | ||
} | ||
/** | ||
* Logs any type of Error in a separate log to the main Timer. | ||
* | ||
* This is a convenience wrapper on `genericError` to allow you to add a custom message, | ||
* and still use in a promise catch clause. | ||
* @param message custom message to log with error. | ||
* | ||
* @example | ||
* await new Promise((resolve => setTimeout(resolve, 50))) | ||
* .then(()=> { | ||
* throw new Error('Unexpected error occured') | ||
* }).catch(timer.genericErrorCustomMessage('A better explanation for what caused this error')) | ||
*/ | ||
public genericErrorCustomMessage(message: string) { | ||
return (e: Error) => this.genericError(e, message) | ||
} | ||
/** | ||
* Logs any type of Error in a separate log to the main Timer. | ||
* | ||
* This is a convenience wrapper on `genericError` to allow you to add a custom message, | ||
* and still use in a promise catch clause. | ||
* @param message custom message to log with error. | ||
* | ||
* @example | ||
* await new Promise((resolve => setTimeout(resolve, 50))) | ||
* .then(()=> { | ||
* throw new Error('Unexpected error occured') | ||
* }).catch(timer.genericErrorCustomMessage('A better explanation for what caused this error')) | ||
*/ | ||
public genericErrorCustomMessage(message: string) { | ||
return (e: Error) => this.genericError(e, message); | ||
} | ||
/** | ||
* Logs a postgres error and returns the value passed as the second parameter. | ||
* | ||
* @param e the postgres error object | ||
* @param returnVal the value for this function to return after logging the error | ||
* @private | ||
*/ | ||
private _postgresError<ReturnType>(e: PostgresError, returnVal: ReturnType): ReturnType { | ||
const errorDetails = new Map(Object.entries(e)) | ||
if (!errorDetails.has('message')) errorDetails.set('message', 'Postgres error code ' + e.code) | ||
errorDetails.set("databaseType", "postgres") | ||
this.printLog(errorDetails, Severity.ERROR) | ||
return returnVal | ||
private consoleLog(logObject: GenericLog) { | ||
let logPresenter: (logObject: GenericLog) => void; | ||
switch (this.environment) { | ||
case Environment.BROWSER: | ||
logPresenter = BrowserPresenter; | ||
break; | ||
case Environment.DEVELOPMENT: | ||
logPresenter = DevelopmentPresenter; | ||
break; | ||
case Environment.PRODUCTION: | ||
logPresenter = ProductionPresenter; | ||
break; | ||
default: | ||
logPresenter = ProductionPresenter; | ||
break; | ||
} | ||
logPresenter(logObject); | ||
} | ||
/** | ||
* Internal printing method which makes sure all of the properties are printed with each log. | ||
* | ||
* @param details object of | ||
* @param severity | ||
* @private | ||
*/ | ||
private printLog(details: Map<string, string | number | boolean | null | undefined>, severity: Severity) { | ||
if (!details.has('message')) { | ||
// this should never be triggered. Always pass a message in the details map. Just a backup: | ||
details.set('message', 'timer-logs unset message in file ' + this.filename) | ||
} | ||
const log: GenericLog = { | ||
severity: severity, | ||
filename: this.filename, | ||
logClass: this.logClass ?? this.splitFilePath.slice(-1)[0].split('.')[0], | ||
loggerName: this.loggerName, | ||
uniqueId: this.uniqueId, | ||
timestamp: new Date().toUTCString(), | ||
} | ||
details.forEach((value, key) => { | ||
log[key] = value | ||
}) | ||
this.splitFilePath.forEach((filePath, level) => { | ||
log[`FilePathDepth${level + 1}`] = filePath | ||
}) | ||
Timer.consoleLog(log) | ||
} | ||
} | ||
/** | ||
* Postgres error type thrown by pg library | ||
*/ | ||
type PostgresError = { | ||
message: string | ||
errno: string | ||
length: number | ||
name: string | ||
severity: string | ||
code: string | ||
detail?: string | ||
hint?: string | ||
position: string | ||
internalPosition?: string | ||
internalQuery?: string | ||
where?: string | ||
schema?: string | ||
table?: string | ||
column?: string | ||
dataType?: string | ||
constraint?: string | ||
file: string | ||
line: string | ||
routine: string | ||
} | ||
/** | ||
* Logs a postgres error and returns the value passed as the second parameter. | ||
* | ||
* @param e the postgres error object | ||
* @param returnVal the value for this function to return after logging the error | ||
* @private | ||
*/ | ||
private _postgresError<ReturnType>( | ||
e: PostgresError, | ||
returnVal: ReturnType | ||
): ReturnType { | ||
const errorDetails = new Map(Object.entries(e)); | ||
if (!errorDetails.has("message")) | ||
errorDetails.set("message", "Postgres error code " + e.code); | ||
errorDetails.set("databaseType", "postgres"); | ||
this.printLog(errorDetails, Severity.ERROR); | ||
return returnVal; | ||
} | ||
/** | ||
* These are attributes that should be set on all log output, regardless of what triggered the log. | ||
*/ | ||
export type GenericLog = { | ||
severity: Severity, | ||
filename: string, | ||
logClass: string, | ||
loggerName: string, | ||
uniqueId: string, | ||
timestamp: string, | ||
[label: string]: string | number | boolean | null | undefined | ||
/** | ||
* Internal printing method which makes sure all of the properties are printed with each log. | ||
* | ||
* @param details object of | ||
* @param severity | ||
* @private | ||
*/ | ||
private printLog( | ||
details: Map<string, string | number | boolean | null | undefined>, | ||
severity: Severity | ||
) { | ||
let detailsMessage = details.get("message")?.toString(); | ||
// this should never be triggered. Always pass a message in the details map. Just a backup: | ||
const message = | ||
details.has("message") && detailsMessage | ||
? detailsMessage | ||
: "timer-logs: message not set"; | ||
const log: GenericLog = { | ||
severity: severity, | ||
filename: this.filename, | ||
logClass: this.logClass ?? this.splitFilePath.slice(-1)[0].split(".")[0], | ||
loggerName: this.loggerName, | ||
uniqueId: this.uniqueId, | ||
timestamp: new Date().toUTCString(), | ||
message, | ||
}; | ||
details.forEach((value, key) => { | ||
log[key] = value; | ||
}); | ||
this.splitFilePath.forEach((filePath, level) => { | ||
log[`FilePathDepth${level + 1}`] = filePath; | ||
}); | ||
this.consoleLog(log); | ||
} | ||
} |
{ | ||
"name": "timer-logs", | ||
"version": "1.4.0", | ||
"version": "1.5.0", | ||
"devDependencies": { | ||
"@types/node": "^15.00.0" | ||
"@types/node": "^15.00.0", | ||
"prettier": "^2.3.2" | ||
}, | ||
@@ -7,0 +8,0 @@ "author": { |
Sorry, the diff of this file is not supported yet
82398
52
1639
2