@ozmap/logger
Version:
DevOZ logger module.
234 lines (233 loc) • 7.24 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.host = exports.datetime = exports.output = exports.color = exports.level = exports.isJsonArray = exports.isJsonObject = exports.typeOf = exports.colorized = exports.normalize = exports.getCircularReplacer = exports.stringify = void 0;
const util_1 = require("util");
const LogLevels_1 = require("./enum/LogLevels");
const Colors_1 = require("./enum/Colors");
const Outputs_1 = require("./enum/Outputs");
/**
* Outputs the stringified version of the input data.
*
* @param data The data to stringify.
* @returns The stringified data.
*/
function stringify(data) {
if (typeof data === 'string')
return data;
if (isJsonObject(data) || isJsonArray(data)) {
return JSON.stringify(data, null, 2);
}
return (0, util_1.format)('%O', data);
}
exports.stringify = stringify;
/**
* Creates a replacer function for JSON.stringify to handle circular references.
* This version tracks parent objects (ancestors) to detect cycles.
* When a circular reference is detected, it returns the string "[Circular]" for that property.
*
* @returns A replacer function that handles circular objects by returning "[Circular]".
*/
function getCircularReplacer() {
const ancestors = [];
/**
* The replacer function to be used with JSON.stringify.
* It checks for circular references by comparing the current value against its ancestors.
*
* @param key The key of the property being stringified.
* @param value The value of the property being stringified.
* @returns The original value if it's not part of a circular reference,
* or the string "[Circular]" if a circular reference is detected.
*/
return function (key, value) {
if (typeof value !== 'object' || value === null) {
return value;
}
while (ancestors.length > 0 &&
ancestors[ancestors.length - 1] !== this) {
ancestors.pop();
}
if (ancestors.includes(value)) {
return '[Circular]';
}
ancestors.push(value);
return value;
};
}
exports.getCircularReplacer = getCircularReplacer;
/**
* Outputs the normalized version of the input data.
*
* @param data The data to normalize.
* @returns The normalized data.
*/
function normalize(data) {
const t = typeof data;
if (t === 'string' ||
t === 'number' ||
t === 'boolean' ||
isJsonObject(data) ||
isJsonArray(data)) {
return data;
}
return (0, util_1.format)('%O', data);
}
exports.normalize = normalize;
/**
* Factory function to create painter for log output coloring.
*
* @returns Readonly object with level tags as painter methods.
*/
function colorized() {
const output = (c) => color()
? (text) => Colors_1.Colors[c] + text + '\x1b[0m'
: (text) => text;
return Object.freeze({
SILLY: output('magenta') /** @deprecated */,
DEBUG: output('magenta'),
AUDIT: output('blue'),
HTTP: output('green') /** @deprecated */,
INFO: output('green'),
WARNING: output('yellow'),
ERROR: output('red'),
CRITICAL: output('red') /** @deprecated */
});
}
exports.colorized = colorized;
/**
* Function for checking the data type without relying on
* the generic typeof functionality.
*
* @param data The data being checked for its type.
* @returns The internal tag that represents the data type.
*/
function typeOf(data) {
var _a;
let internalTag = `Unknown`;
try {
internalTag = (_a = Object.prototype.toString.call(data)) === null || _a === void 0 ? void 0 : _a.slice(8, -1);
}
catch (e) {
internalTag = `Unknown`;
}
return internalTag;
}
exports.typeOf = typeOf;
/**
* Function for checking if data is a key/value pair object.
*
* @param data The data being checked.
* @returns Whether or not the data is an object.
*/
function isJsonObject(data) {
return typeOf(data) === 'Object';
}
exports.isJsonObject = isJsonObject;
/**
* Function for checking if data is an array object.
*
* @param data The data being checked.
* @returns Whether or not the data is an array.
*/
function isJsonArray(data) {
return typeOf(data) === 'Array';
}
exports.isJsonArray = isJsonArray;
/**
* Retrieve the current log level name.
*
* @returns The level name.
*/
function level() {
var _a;
const input = (((_a = process.env.OZLOGGER_LEVEL) === null || _a === void 0 ? void 0 : _a.toLowerCase()) ||
'debug');
return input in LogLevels_1.LogLevels ? input : 'audit';
}
exports.level = level;
/**
* Check if the log outputs should be colorized.
*
* @returns Whether or not the output can be colorized.
*/
function color() {
var _a;
return !!((_a = process.env.OZLOGGER_COLORS) === null || _a === void 0 ? void 0 : _a.match(/true/i));
}
exports.color = color;
/**
* Check which output should be used for logging.
*
* @returns Output name to be used.
*/
function output() {
var _a;
const input = (((_a = process.env.OZLOGGER_OUTPUT) === null || _a === void 0 ? void 0 : _a.toLowerCase()) ||
'json');
return Outputs_1.Outputs.indexOf(input) < 0 ? 'json' : input;
}
exports.output = output;
/**
* Return the current date and time closure.
*
* @returns The current datetime closure.
*/
function datetime() {
var _a;
const withDatetime = !!((_a = process.env.OZLOGGER_DATETIME) === null || _a === void 0 ? void 0 : _a.match(/true/i));
switch (output()) {
case 'text':
return withDatetime
? () => `${new Date().toISOString()} `
: () => '';
case 'json':
return withDatetime
? () => ({ timestamp: new Date().toISOString() })
: () => ({});
}
}
exports.datetime = datetime;
/**
* Parse the log server port and interface to bind to.
*
* @returns The port number and interface address.
*/
function host() {
const input = process.env.OZLOGGER_SERVER || '9898';
let port = 9898;
let hostname = 'localhost';
// Format: '9898'
if (/^\d+$/.test(input)) {
port = parseInt(input);
return [port, hostname];
}
// Format: ':9898'
if (/^:\d+$/.test(input)) {
port = parseInt(input.slice(1));
return [port, hostname];
}
// Format: '[::1]:9898'
if (/^\[.*\]:\d+$/.test(input)) {
const [ipv6, p] = input.slice(1, -1).split(']:');
hostname = ipv6;
port = parseInt(p);
return [port, hostname];
}
// Format: '127.0.0.1:9898'
if (/^\d+\.\d+\.\d+\.\d+:\d+$/.test(input)) {
const [ipv4, p] = input.split(':');
hostname = ipv4;
port = parseInt(p);
return [port, hostname];
}
// Format: 'localhost' or 'localhost:9898'
if (/^[^\s:]+(:\d+)?$/.test(input)) {
const [domain, p] = input.split(':');
if (domain)
hostname = domain;
if (p)
port = parseInt(p);
return [port, hostname];
}
throw new Error(`Unsupported HTTP server address (${input})`);
}
exports.host = host;