New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

timer-logs

Package Overview
Dependencies
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

timer-logs - npm Package Compare versions

Comparing version 1.4.0 to 1.5.0

.idea/prettier.xml

32

exemplar/index.js
"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 {};
"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;

@@ -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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc