Removing all Node specific stuff from NodeLogging.
This commit is contained in:
commit
e489a15892
5
.editorconfig
Normal file
5
.editorconfig
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 3
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
end_of_line = lf
|
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
node_modules/
|
||||||
|
logs/
|
||||||
|
yarn.lock
|
||||||
|
out/
|
3102
package-lock.json
generated
Normal file
3102
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
24
package.json
Normal file
24
package.json
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "@hibas123/logging",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "out/index.js",
|
||||||
|
"types": "out/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"prepublish": "tsc",
|
||||||
|
"build": "tsc",
|
||||||
|
"watch": "tsc --watch"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.stamm.me/OpenServer/Logging.git"
|
||||||
|
},
|
||||||
|
"author": "Fabian Stamm",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^3.3.4000"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@hibas123/utils": "^2.0.2"
|
||||||
|
}
|
||||||
|
}
|
94
readme.md
Normal file
94
readme.md
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
Simple logging module, that supports terminal coloring and different plugins
|
||||||
|
|
||||||
|
# Getting Started
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
const Logging = require("@hibas123/logging").Logging;
|
||||||
|
|
||||||
|
Logging.log("Hello there");
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
There are different Logging levels, that also apply terminal coloring:
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
Logging.debug("Debug message")
|
||||||
|
Logging.log("Log message")
|
||||||
|
Logging.warning("Warning")
|
||||||
|
Logging.error(new Error("To less creativity"))
|
||||||
|
Logging.error("Just an simple message as error")
|
||||||
|
Logging.errorMessage("Nearly the same as error")
|
||||||
|
```
|
||||||
|
|
||||||
|
All Logging types except the simple error take as many arguments as you want. These will be joined with spaces and serialized with the node util.inspect function.
|
||||||
|
|
||||||
|
# Setup
|
||||||
|
|
||||||
|
This logging module doesn't require any setup per default, but sometimes it makes sense to configure a few things.
|
||||||
|
|
||||||
|
For example can you disable the console output. This may be helpful, if you insert a custom adapters as described below.
|
||||||
|
|
||||||
|
Also you can set a name. All messages that are send with this instance are prefixed by this name.
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
const CustomLogging = new LoggingBase(name | {
|
||||||
|
name: "custom", // default undefined
|
||||||
|
console: false // default true
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# Plugins
|
||||||
|
|
||||||
|
There is a Plugin API available, that makes is possible to add custom Logging Adapter.
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
const Demo = new LoggingBase("Demo");
|
||||||
|
Demo.addAdapter(new DemoAdapter({ color: "rainbow" }));
|
||||||
|
```
|
||||||
|
|
||||||
|
The adapters need to provide a very simple Interface:
|
||||||
|
|
||||||
|
``` typescript
|
||||||
|
interface Adapter {
|
||||||
|
init(observable: ObservableInterface<Message>, name?: string): void | Promise<void>;
|
||||||
|
|
||||||
|
flush(sync: true): void;
|
||||||
|
flush(sync: false): void | Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Message {
|
||||||
|
type: LoggingTypes;
|
||||||
|
name?:string;
|
||||||
|
text: {
|
||||||
|
raw: string[],
|
||||||
|
formatted: string[]
|
||||||
|
};
|
||||||
|
date: Date;
|
||||||
|
file: string;
|
||||||
|
customColors?:string;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum LoggingTypes {
|
||||||
|
Log,
|
||||||
|
Warning,
|
||||||
|
Error,
|
||||||
|
Debug
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `ObservableInterface` comes from `@hibas123/utils`. It provides a very simple api for subscribing and unsubscribing from the message events.
|
||||||
|
|
||||||
|
More Details on Observable [git](https://git.stamm.me/OpenServer/Utils) or [npm](https://www.npmjs.com/package/@hibas123/utils)
|
||||||
|
|
||||||
|
# License
|
||||||
|
MIT
|
||||||
|
|
||||||
|
Copyright (c) 2018 Fabian Stamm
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
234
src/base.ts
Normal file
234
src/base.ts
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
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<void>[] = [];
|
||||||
|
|
||||||
|
private messageObservable = new Observable<Message>();
|
||||||
|
protected name: string;
|
||||||
|
|
||||||
|
constructor(options?: Partial<LoggingBaseOptions> | string) {
|
||||||
|
let opt: Partial<LoggingBaseOptions>;
|
||||||
|
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] = (<any>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<void>;
|
||||||
|
flush(sync: boolean): void | Promise<void> {
|
||||||
|
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 = (<any>Error).prepareStackTrace;
|
||||||
|
|
||||||
|
// Override with function that just returns `stack`
|
||||||
|
(<any>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[] = <any>err.stack;
|
||||||
|
|
||||||
|
// Restore original `Error.prepareStackTrace`
|
||||||
|
(<any>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();
|
||||||
|
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)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
src/consolewriter.ts
Normal file
39
src/consolewriter.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { ObservableInterface } from "@hibas123/utils";
|
||||||
|
import { Colors } from "./index";
|
||||||
|
import { Adapter, LoggingTypes, Message } from "./types";
|
||||||
|
|
||||||
|
|
||||||
|
export class ConsoleWriter implements Adapter {
|
||||||
|
init(observable: ObservableInterface<Message>) {
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
8
src/index.ts
Normal file
8
src/index.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { LoggingBase } from "./base";
|
||||||
|
export { Colors, LoggingBase } from "./base";
|
||||||
|
export { Adapter, LoggingTypes, Message } from "./types";
|
||||||
|
export { ObservableInterface } from "@hibas123/utils";
|
||||||
|
|
||||||
|
export let Logging: LoggingBase = undefined;
|
||||||
|
Logging = new LoggingBase();
|
||||||
|
export default Logging;
|
415
src/inspect.ts
Normal file
415
src/inspect.ts
Normal file
@ -0,0 +1,415 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* 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<InspectOptions>) {
|
||||||
|
// 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<T extends Y, Y>(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;
|
||||||
|
}
|
27
src/types.ts
Normal file
27
src/types.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
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<Message>, name?: string): void | Promise<void>;
|
||||||
|
|
||||||
|
flush(sync: true): void;
|
||||||
|
flush(sync: false): void | Promise<void>;
|
||||||
|
}
|
19
tsconfig.json
Normal file
19
tsconfig.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es2017",
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"sourceMap": true,
|
||||||
|
"outDir": "out",
|
||||||
|
"declaration": true,
|
||||||
|
"typeRoots": [
|
||||||
|
"node_modules/@types"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user