diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 6e966e0..0000000 --- a/.editorconfig +++ /dev/null @@ -1,5 +0,0 @@ -charset = utf-8 -indent_style = space -indent_size = 3 -trim_trailing_whitespace = true -end_of_line = lf \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2ef46cc..56cf069 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules/ logs/ yarn.lock -out/ \ No newline at end of file +out/ +.history/ \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index ac3b5e4..bc7dd24 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,14 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@hibas123/logging": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@hibas123/logging/-/logging-1.0.1.tgz", + "integrity": "sha512-1yAq/Jjziot1tDbXZoi5TDuHkZxGB2hSlEuUkMnejvA60AfycNpTvzGd3ZLJC9fbKZFNxm2HfwW0pdIrecL0WQ==", + "requires": { + "@hibas123/utils": "^2.0.2" + } + }, "@hibas123/utils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@hibas123/utils/-/utils-2.0.2.tgz", @@ -1872,9 +1880,9 @@ "dev": true }, "nan": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.1.tgz", - "integrity": "sha512-I6YB/YEuDeUZMmhscXKxGgZlFnhsn5y0hgOZBadkzfTRrZBtJDZeg6eQf7PYMIEclwmorTKK8GztsyOUSVBREA==", + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", + "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==", "dev": true, "optional": true }, diff --git a/package.json b/package.json index 5410094..c6e430b 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,9 @@ { "name": "@hibas123/nodelogging", - "version": "1.5.0-alpha.2", + "version": "1.6.0-alpha.1", "description": "", "main": "out/index.js", "types": "out/index.d.ts", - "browser": "out/browser.js", "scripts": { "prepublish": "tsc", "build": "tsc", @@ -16,7 +15,7 @@ }, "repository": { "type": "git", - "url": "https://git.stamm.me/PerfCloud/nodelogging.git" + "url": "https://git.stamm.me/OpenServer/NodeLogging.git" }, "author": "Fabian Stamm", "license": "MIT", @@ -27,6 +26,7 @@ "typescript": "^3.3.4000" }, "dependencies": { + "@hibas123/logging": "^1.0.1", "@hibas123/utils": "^2.0.2" } -} +} \ No newline at end of file diff --git a/readme.md b/readme.md index 324c88a..9ec9860 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -Simple node logging module, that supports terminal coloring and writing to files +Simple logging module, that supports terminal coloring and writing to files # Getting Started diff --git a/src/base.ts b/src/base.ts deleted file mode 100644 index 9820f61..0000000 --- a/src/base.ts +++ /dev/null @@ -1,235 +0,0 @@ -import { Observable } from "@hibas123/utils"; -import { ConsoleWriter } from "./consolewriter"; -import inspect from "./inspect"; -import { Adapter, LoggingTypes, Message } from "./types"; - -export const Colors = { - Reset: "\x1b[0m", - Bright: "\x1b[1m", - Dim: "\x1b[2m", - Underscore: "\x1b[4m", - Blink: "\x1b[5m", - Reverse: "\x1b[7m", - Hidden: "\x1b[8m", - - FgBlack: "\x1b[30m", - FgRed: "\x1b[31m", - FgGreen: "\x1b[32m", - FgYellow: "\x1b[33m", - FgBlue: "\x1b[34m", - FgMagenta: "\x1b[35m", - FgCyan: "\x1b[36m", - FgWhite: "\x1b[37m", - - BgBlack: "\x1b[40m", - BgRed: "\x1b[41m", - BgGreen: "\x1b[42m", - BgYellow: "\x1b[43m", - BgBlue: "\x1b[44m", - BgMagenta: "\x1b[45m", - BgCyan: "\x1b[46m", - BgWhite: "\x1b[47m" -} - - -export interface LoggingBaseOptions { - /** - * Name will be prefixed on Console output and added to logfiles, if not specified here - */ - name: string, - /** - * Prints output to console - */ - console: boolean; -} - -export class LoggingBase { - private logFile: any; - private errorFile: any; - private adapter: Adapter[] = []; - private adapter_init: Promise[] = []; - - private messageObservable = new Observable(); - protected name: string; - - constructor(options?: Partial | string) { - let opt: Partial; - if (!options) opt = {} - else if (typeof options === "string") { - opt = { name: options }; - } else { - opt = options; - } - - let config = { - name: undefined, - console: true, - files: true, - ...opt - }; - - if (config.name) - this.name = config.name; - - for (let key in this) { - if (typeof this[key] === "function") this[key] = (this[key]).bind(this); - } - - if (config.console) { - this.addAdapter(new ConsoleWriter()); - } - } - - addAdapter(adapter: Adapter) { - this.adapter.push(adapter); - let prms = Promise.resolve(adapter.init(this.messageObservable.getPublicApi(), this.name)); - this.adapter_init.push(prms); - } - - flush(sync: true): void; - flush(sync: false): Promise; - flush(sync: boolean): void | Promise { - if (sync) { - this.adapter.forEach(elm => elm.flush(true)); - } else { - return Promise.all(this.adapter.map(elm => elm.flush(false))).then(() => { }); - } - } - - public waitForSetup() { - return Promise.all(this.adapter_init); - } - - debug(...message: any[]) { - this.message(LoggingTypes.Debug, message); - } - - log(...message: any[]) { - this.message(LoggingTypes.Log, message); - } - - warning(...message: any[]) { - this.message(LoggingTypes.Warning, message); - } - - logWithCustomColors(type: LoggingTypes, colors: string, ...message: any[]) { - this.message(type, message, colors); - } - - error(error: Error | string) { - if (!error) error = "Empty ERROR was passed, so no informations available"; - if (typeof error === "string") { - let e = new Error() - this.message(LoggingTypes.Error, [error, "\n", e.stack]); - } else { - this.message(LoggingTypes.Error, [error.message, "\n", error.stack], undefined, getCallerFromExisting(error)); - } - } - - errorMessage(...message: any[]) { - this.message(LoggingTypes.Error, message); - } - - private message(type: LoggingTypes, message: any[] | string, customColors?: string, caller?: { file: string, line: number }) { - let file_raw = caller || getCallerFile(); - let file = `${file_raw.file}:${String(file_raw.line).padEnd(3, " ")}`; - - let mb = ""; - if (typeof message === "string") { - mb = message; - } else { - message.forEach((e, i) => { - if (typeof e !== "string") e = inspect(e, { colors: true, showHidden: true, depth: 3 }); - if (e.endsWith("\n") || i === message.length - 1) { - mb += e; - } else { - mb += e + " "; - } - }); - } - - let lines = mb.split("\n"); - - let date = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, ''); - let prefix = `[ ${date} ][${LoggingTypes[type].toUpperCase().padEnd(5, " ")}][${file}]: `; - - let formatted = lines.map(line => prefix + line); - - let msg: Message = { - date: new Date(), - file, - name: this.name, - text: { - raw: lines, - formatted - }, - type, - customColors - } - - this.messageObservable.send(msg); - } -} - -function getStack() { - // Save original Error.prepareStackTrace - let origPrepareStackTrace = (Error).prepareStackTrace; - - // Override with function that just returns `stack` - (Error).prepareStackTrace = function (_, stack) { - return stack - } - - // Create a new `Error`, which automatically gets `stack` - let err = new Error(); - - // Evaluate `err.stack`, which calls our new `Error.prepareStackTrace` - let stack: any[] = err.stack; - - // Restore original `Error.prepareStackTrace` - (Error).prepareStackTrace = origPrepareStackTrace; - - // Remove superfluous function call on stack - stack.shift(); // getStack --> Error - - return stack -} - -function baseName(path) { - return path.split(/[\\/]/).pop(); -} - -function getCallerFile() { - try { - let stack = getStack() - - let current_file = stack.shift().getFileName(); - - while (stack.length) { - let caller_file = stack.shift(); - const util = require("util") - if (current_file !== caller_file.getFileName()) - return { - file: baseName(caller_file.getFileName()), - line: caller_file.getLineNumber() - }; - } - } catch (err) { } - return { file: undefined, line: 0 }; -} - -function getCallerFromExisting(err: Error): { file: string, line: number } { - if (!err || !err.stack) return { file: "NOFILE", line: 0 }; - let lines = err.stack.split("\n"); - lines.shift();// removing first line - while (lines.length > 0) { - let line = lines.shift(); - let matches = line.match(/[a-zA-Z_-]+[.][a-zA-Z_-]+[:][0-9]+/g) - if (matches && matches.length > 0) { - let [f, line] = matches[0].split(":") - return { - file: f, line: Number(line) - }; - } - } -} \ No newline at end of file diff --git a/src/browser.ts b/src/browser.ts deleted file mode 100644 index 822c65c..0000000 --- a/src/browser.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { LoggingBase } from "./base"; -export { Colors, LoggingBase } from "./base"; -export { Adapter, LoggingTypes, Message } from "./types"; - - -export let Logging: LoggingBase = undefined; -if (process.env.LOGGING_NO_DEFAULT !== "true") { - Logging = new LoggingBase(); -} -export default Logging; diff --git a/src/consolewriter.ts b/src/consolewriter.ts deleted file mode 100644 index 13556e2..0000000 --- a/src/consolewriter.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { ObservableInterface } from "@hibas123/utils"; -import { Colors } from "./index"; -import { Adapter, LoggingTypes, Message } from "./types"; - - -export class ConsoleWriter implements Adapter { - init(observable: ObservableInterface) { - observable.subscribe(this.onMessage.bind(this)); - } - - flush() { } - - onMessage(message: Message) { - let consoleLogFormat = Colors.Reset; - if (!message.customColors) { - switch (message.type) { - case LoggingTypes.Log: - //m += FgWhite + BgBlack; - break; - case LoggingTypes.Error: - consoleLogFormat += Colors.FgRed;//FgWhite + BgRed + FgWhite; - break; - case LoggingTypes.Debug: - consoleLogFormat += Colors.FgCyan; - break; - case LoggingTypes.Warning: - consoleLogFormat += Colors.FgYellow; - break; - } - } else { - consoleLogFormat += message.customColors; - } - - let lines = message.text.formatted; - let name = ""; - if (message.name) name = `[${message.name}]=>`; - lines.forEach(line => console.log(consoleLogFormat + name + line + Colors.Reset)) - } -} \ No newline at end of file diff --git a/src/filewriter.ts b/src/filewriter.ts index 11992f9..0b7fa0f 100644 --- a/src/filewriter.ts +++ b/src/filewriter.ts @@ -1,7 +1,8 @@ import { Lock, ObservableInterface } from "@hibas123/utils"; import * as fs from "fs"; import * as path from "path"; -import { Adapter, LoggingTypes, Message } from "./types"; +import { Adapter, Message, LoggingTypes } from "@hibas123/logging"; + const maxFileSize = 500000000; @@ -137,6 +138,7 @@ export class Files { this.size += data.byteLength; this.stream.write(data); } catch (err) { + // TODO: Better error handling! console.error(err); this.initializeFile(false); this.write_to_file(data); diff --git a/src/index.ts b/src/index.ts index 71e3a99..23113cb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,6 @@ -import { LoggingBase, LoggingBaseOptions } from "./base"; import { LoggingFiles } from "./filewriter"; +import { LoggingBase, LoggingBaseOptions } from "@hibas123/logging"; -export { Colors } from "./base"; -export { Adapter, LoggingTypes, Message } from "./types"; export interface LoggingOptions extends LoggingBaseOptions { files: boolean | { diff --git a/src/inspect.ts b/src/inspect.ts deleted file mode 100644 index 222df8d..0000000 --- a/src/inspect.ts +++ /dev/null @@ -1,415 +0,0 @@ - -/** - * Module exports. - */ - -interface InspectOptions { - depth: number; - colors: boolean; - showHidden: boolean; -} - -/** - * Echos the value of a value. Trys to print the value out - * in the best way possible given the different types. - * - * @param {Object} obj The object to print out. - * @param {Object} opts Optional options object that alters the output. - * @license MIT (© Joyent) - */ -/* legacy: obj, showHidden, depth, colors*/ -export default function inspect(obj: any, opts: Partial) { - // default options - let ctx = { - seen: [], - stylize: stylizeNoColor, - depth: undefined, - colors: undefined, - showHidden: undefined, - customInspect: undefined - }; - // legacy... - if (arguments.length >= 3) ctx.depth = arguments[2]; - if (arguments.length >= 4) ctx.colors = arguments[3]; - if (isBoolean(opts)) { - // legacy... - ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - _extend(ctx, opts); - } - // set default options - if (isUndefined(ctx.showHidden)) ctx.showHidden = false; - if (isUndefined(ctx.depth)) ctx.depth = 2; - if (isUndefined(ctx.colors)) ctx.colors = false; - if (isUndefined(ctx.customInspect)) ctx.customInspect = true; - if (ctx.colors) ctx.stylize = stylizeWithColor; - return formatValue(ctx, obj, ctx.depth); -} - -// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics -inspect.colors = { - 'bold': [1, 22], - 'italic': [3, 23], - 'underline': [4, 24], - 'inverse': [7, 27], - 'white': [37, 39], - 'grey': [90, 39], - 'black': [30, 39], - 'blue': [34, 39], - 'cyan': [36, 39], - 'green': [32, 39], - 'magenta': [35, 39], - 'red': [31, 39], - 'yellow': [33, 39] -}; - -// Don't use 'blue' not visible on cmd.exe -inspect.styles = { - 'special': 'cyan', - 'number': 'yellow', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' -}; - -function stylizeNoColor(str, styleType) { - return str; -} - -function isBoolean(arg) { - return typeof arg === 'boolean'; -} - -function isUndefined(arg) { - return arg === void 0; -} - -function stylizeWithColor(str, styleType) { - var style = inspect.styles[styleType]; - - if (style) { - return '\u001b[' + inspect.colors[style][0] + 'm' + str + - '\u001b[' + inspect.colors[style][1] + 'm'; - } else { - return str; - } -} - -function isFunction(arg) { - return typeof arg === 'function'; -} - -function isString(arg) { - return typeof arg === 'string'; -} - -function isNumber(arg) { - return typeof arg === 'number'; -} - -function isNull(arg) { - return arg === null; -} - -function hasOwn(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} - -function isRegExp(re) { - return isObject(re) && objectToString(re) === '[object RegExp]'; -} - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} - -function isError(e) { - return isObject(e) && - (objectToString(e) === '[object Error]' || e instanceof Error); -} - -function isDate(d) { - return isObject(d) && objectToString(d) === '[object Date]'; -} - -function objectToString(o) { - return Object.prototype.toString.call(o); -} - -function arrayToHash(array) { - var hash = {}; - - array.forEach(function (val, idx) { - hash[val] = true; - }); - - return hash; -} - -function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (hasOwn(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); - } - } - keys.forEach(function (key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); - } - }); - return output; -} - -function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; -} - -function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (ctx.customInspect && - value && - isFunction(value.inspect) && - // Filter out the util module, it's inspect function is special - value.inspect !== inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - var ret = value.inspect(recurseTimes, ctx); - if (!isString(ret)) { - ret = formatValue(ctx, ret, recurseTimes); - } - return ret; - } - - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; - } - - // Look up the keys of the object. - var keys = Object.keys(value); - var visibleKeys = arrayToHash(keys); - - try { - if (ctx.showHidden && Object.getOwnPropertyNames) { - keys = Object.getOwnPropertyNames(value); - } - } catch (e) { - // ignore - } - - // IE doesn't make error fields non-enumerable - // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx - if (isError(value) - && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { - return formatError(value); - } - - // Some type of object without properties can be shortcutted. - if (keys.length === 0) { - if (isFunction(value)) { - var name = value.name ? ': ' + value.name : ''; - return ctx.stylize('[Function' + name + ']', 'special'); - } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toString.call(value), 'date'); - } - if (isError(value)) { - return formatError(value); - } - } - - var base = '', array = false, braces = ['{', '}']; - - // Make Array say that they are Array - if (Array.isArray(value)) { - array = true; - braces = ['[', ']']; - } - - // Make functions say that they are functions - if (isFunction(value)) { - var n = value.name ? ': ' + value.name : ''; - base = ' [Function' + n + ']'; - } - - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); - } - - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); - } - - // Make error with message first say the error - if (isError(value)) { - base = ' ' + formatError(value); - } - - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; - } - - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } else { - return ctx.stylize('[Object]', 'special'); - } - } - - ctx.seen.push(value); - - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); - } else { - output = keys.map(function (key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); - } - - ctx.seen.pop(); - - return reduceToSingleString(output, base, braces); -} - -function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name, str, desc; - desc = { value: void 0 }; - try { - // ie6 › navigator.toString - // throws Error: Object doesn't support this property or method - desc.value = value[key]; - } catch (e) { - // ignore - } - try { - // ie10 › Object.getOwnPropertyDescriptor(window.location, 'hash') - // throws TypeError: Object doesn't support this action - if (Object.getOwnPropertyDescriptor) { - desc = Object.getOwnPropertyDescriptor(value, key) || desc; - } - } catch (e) { - // ignore - } - if (desc.get) { - if (desc.set) { - str = ctx.stylize('[Getter/Setter]', 'special'); - } else { - str = ctx.stylize('[Getter]', 'special'); - } - } else { - if (desc.set) { - str = ctx.stylize('[Setter]', 'special'); - } - } - if (!hasOwn(visibleKeys, key)) { - name = '[' + key + ']'; - } - if (!str) { - if (ctx.seen.indexOf(desc.value) < 0) { - if (isNull(recurseTimes)) { - str = formatValue(ctx, desc.value, null); - } else { - str = formatValue(ctx, desc.value, recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function (line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function (line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (isUndefined(name)) { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); - } - } - - return name + ': ' + str; -} - -function formatPrimitive(ctx, value) { - if (isUndefined(value)) - return ctx.stylize('undefined', 'undefined'); - if (isString(value)) { - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); - } - if (isNumber(value)) - return ctx.stylize('' + value, 'number'); - if (isBoolean(value)) - return ctx.stylize('' + value, 'boolean'); - // For some reason typeof null is "object", so special case here. - if (isNull(value)) - return ctx.stylize('null', 'null'); -} - -function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = output.reduce(function (prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; - }, 0); - - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; - } - - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; -} - -function _extend(origin: T, add: Y) { - // Don't do anything if add isn't an object - if (!add || !isObject(add)) return origin; - - var keys = Object.keys(add); - var i = keys.length; - while (i--) { - origin[keys[i]] = add[keys[i]]; - } - return origin; -} \ No newline at end of file diff --git a/src/test.ts b/src/test.ts index 0e22988..0c96d60 100644 --- a/src/test.ts +++ b/src/test.ts @@ -1,6 +1,7 @@ import { randomBytes } from "crypto"; import * as fs from "fs"; -import { Logging, LoggingExtended } from "./index"; +import { Logging, LoggingExtended } from "."; + const deleteFolderRecursive = function (path: string) { if (fs.existsSync(path)) { fs.readdirSync(path).forEach(function (file, index) { diff --git a/src/types.ts b/src/types.ts deleted file mode 100644 index d285d21..0000000 --- a/src/types.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ObservableInterface } from "@hibas123/utils"; - -export enum LoggingTypes { - Log, - Warning, - Error, - Debug -} - -export interface Message { - type: LoggingTypes; - name?: string; - text: { - raw: string[], - formatted: string[] - }; - date: Date; - file: string; - customColors?: string; -} - -export interface Adapter { - init(observable: ObservableInterface, name?: string): void | Promise; - - flush(sync: true): void; - flush(sync: false): void | Promise; -} \ No newline at end of file