mirror of
https://github.com/dzeiocom/libs.git
synced 2025-04-22 10:52:11 +00:00
Updated Logger implement Console
This commit is contained in:
parent
e0303a5abe
commit
70da3f2002
@ -1,8 +1,8 @@
|
||||
dist/*.d.ts.map
|
||||
node_modules
|
||||
src
|
||||
test
|
||||
.babelrc
|
||||
.eslintrc.js
|
||||
.gitignore
|
||||
webpack.config.js
|
||||
tsconfig.json
|
||||
.babelrc
|
||||
.eslintrc.js
|
||||
tsconfig.*
|
41
packages/logger/README.md
Normal file
41
packages/logger/README.md
Normal file
@ -0,0 +1,41 @@
|
||||
# @dzeio/logger
|
||||
|
||||
A Better logger for your test
|
||||
|
||||
## Install
|
||||
|
||||
For the browser via `unpkg` use it from Unpkg or download the file locally
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/@dzeio/logger/dist/browser.js"></script>
|
||||
<script>
|
||||
// Two Elements are available
|
||||
var logger = new Logger('prefix') // To initialize a new Logger
|
||||
// or
|
||||
initConsole() // this will repace the default console by the logger
|
||||
</script>
|
||||
```
|
||||
|
||||
Via Yarn/NPM
|
||||
|
||||
```bash
|
||||
yarn add @dzeio/logger
|
||||
# or
|
||||
npm i @dzeio/logger
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
As the Logger Implements the `console` the usage don't vary on their function BUT you have more control
|
||||
|
||||
ex:
|
||||
|
||||
```js
|
||||
import Logger from '@dzeio/logger' // Import the class
|
||||
const logger = new Logger('prefix') // initialize it
|
||||
// or
|
||||
import { logger } from '@dzeio/logger' // Import already initialized one
|
||||
|
||||
// You can block Logging for some time
|
||||
Logger.isBlocked(true) // false to unblock
|
||||
```
|
@ -13,7 +13,7 @@
|
||||
"browser": "./dist/browser.js",
|
||||
"types": "./dist/Logger.d.ts",
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.0"
|
||||
"ansi-colors": "^4.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.10.3",
|
||||
@ -29,6 +29,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"prepublishOnly": "yarn build",
|
||||
"build": "webpack --mode=\"production\" && tsc"
|
||||
"build": "webpack --mode=\"production\" && tsc",
|
||||
"test": "ts-node test"
|
||||
}
|
||||
}
|
||||
|
@ -1,54 +1,372 @@
|
||||
import { white, blue, yellow, green } from 'chalk'
|
||||
import colors, { black, white, blue, yellow, green } from 'ansi-colors'
|
||||
import { theme, logType, ObjectArray } from './types'
|
||||
|
||||
/**
|
||||
* Logger Class
|
||||
*/
|
||||
export default class Logger {
|
||||
export default class Logger implements Console {
|
||||
|
||||
/**
|
||||
* If it is set to true all message won't be shown until it is set to false
|
||||
* The maximun prefix length
|
||||
*/
|
||||
public static isBlocked = false
|
||||
private static queue: Array<Array<any>> = []
|
||||
private static prefixLen = 0
|
||||
|
||||
/**
|
||||
* Log a message into the console
|
||||
* @param prefix the prefix used
|
||||
* @param message the message to log
|
||||
* Current theme in use
|
||||
*
|
||||
* - undefined = detect theme
|
||||
* - light = theme for light background
|
||||
* - dark = theme for dark background
|
||||
*/
|
||||
public static log(prefix: string, ...message: Array<any>) {
|
||||
this.queue.push(this.formatMessage(prefix, ...message))
|
||||
while (this.queue.length > 0 && !this.isBlocked) {
|
||||
const item = this.queue.shift()
|
||||
if (!item) {
|
||||
continue
|
||||
}
|
||||
console.log(...item)
|
||||
private static theme: theme = undefined
|
||||
|
||||
/**
|
||||
* List of loggers currently in use
|
||||
*/
|
||||
private static loggers: Array<Logger> = []
|
||||
|
||||
/**
|
||||
* Console memory
|
||||
* (IDK what it is)
|
||||
*/
|
||||
public memory = console.memory
|
||||
|
||||
// NodeJS console (will be undefined on )
|
||||
/**
|
||||
* NODEJS ONLY
|
||||
* It will be undefined in Browser context
|
||||
*/
|
||||
// @ts-ignore
|
||||
public Console = console.Console
|
||||
/**
|
||||
* The messages queue
|
||||
*/
|
||||
private queue: Array<{type: logType, msg: Array<any>}> = []
|
||||
|
||||
/**
|
||||
* If true message won't be shown to console
|
||||
* (`urgent` message will still show)
|
||||
*/
|
||||
private blocked = false
|
||||
|
||||
/**
|
||||
* `count` function object value
|
||||
*/
|
||||
private countCount: ObjectArray<number> = {}
|
||||
|
||||
/**
|
||||
* `time` function object value
|
||||
*/
|
||||
private timeCount: ObjectArray<Date> = {}
|
||||
|
||||
/**
|
||||
* Construct a new Logger
|
||||
* @param prefix the prefix shown
|
||||
*/
|
||||
public constructor(
|
||||
public prefix: string = 'Logger'
|
||||
) {
|
||||
Logger.loggers.push(this)
|
||||
|
||||
// If Firefox disable colors
|
||||
// @ts-ignore
|
||||
if (typeof InstallTrigger !== 'undefined') {
|
||||
colors.enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a message into the console (passthrough the `Logger.isBlocked` boolean)
|
||||
* @param prefix The prefix used
|
||||
* @param message the message to log
|
||||
* STATIC FUNCTIONS
|
||||
*/
|
||||
public static urgent(prefix: string, ...message: Array<any>) {
|
||||
console.log(...this.formatMessage(prefix, ...message))
|
||||
|
||||
/**
|
||||
* Choose if every loggers should be blocked or not
|
||||
* @param value
|
||||
*/
|
||||
public static isBlocked(value: boolean) {
|
||||
for (const lgr of this.loggers) {
|
||||
lgr.blocked = value
|
||||
if (!value) {
|
||||
lgr.processQueue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static formatMessage(prefix: string, ...message: Array<any>): Array<any> {
|
||||
if (this.prefixLen < prefix.length) {
|
||||
this.prefixLen = prefix.length
|
||||
/**
|
||||
* Force a specific theme to be used
|
||||
*
|
||||
* (if undefined it will try to detect it)
|
||||
*
|
||||
* @param themeChosen The theme chosen to be overriden
|
||||
*/
|
||||
public static forceTheme(themeChosen: theme) {
|
||||
this.theme = themeChosen
|
||||
}
|
||||
|
||||
/**
|
||||
* INSTANCE FUNCTIONS
|
||||
*/
|
||||
|
||||
/**
|
||||
* return nothing if `condition` is `true`, log `data` if it is not
|
||||
* @param condition The value tested for being truthy
|
||||
* @param data The message to pass if `condition` is false
|
||||
*/
|
||||
public assert(condition?: boolean | undefined, ...data: Array<any>): void {
|
||||
if (!condition) {
|
||||
return this.error('Assertion failed:', ...data)
|
||||
}
|
||||
const els: Array<string> = ['', '']
|
||||
if (this.prefixLen > prefix.length) {
|
||||
const diff = this.prefixLen - prefix.length
|
||||
els[0] = this.buildSpace(diff / 2 - (diff % 2 !== 0 ? 1 : 0))
|
||||
els[1] = this.buildSpace(diff / 2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the console/terminal
|
||||
*/
|
||||
public clear(): void {
|
||||
console.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
* log the number of times `count` has been called
|
||||
* @param label Display label, default to `default`
|
||||
*/
|
||||
public count(label: string = 'default'): void {
|
||||
if (!Object.prototype.hasOwnProperty.call(this.countCount, label)) {
|
||||
this.countCount[label] = 0
|
||||
}
|
||||
this.log(`${label}:`, ++this.countCount[label])
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the count started with `count` function
|
||||
* @param label Display label, default to `default`
|
||||
*/
|
||||
public countReset(label: string = 'default'): void {
|
||||
delete this.countCount[label]
|
||||
}
|
||||
|
||||
/**
|
||||
* log as debug the `data`
|
||||
* (On browser like Chrome in the devtool you have to enable it beforehand)
|
||||
* @param data the data to log
|
||||
*/
|
||||
public debug(...data: Array<any>): void {
|
||||
this.process('debug', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: Method not fully implemented
|
||||
*
|
||||
* print a full object to the logger
|
||||
* @param item Object to log
|
||||
* @param options (NodeJS only) option for the display
|
||||
*/
|
||||
public dir(item?: any, options?: {showHidden?: boolean, depth?: number, colors?: boolean}): void {
|
||||
if (typeof item !== 'object') {
|
||||
return this.log(item)
|
||||
}
|
||||
this.log('Method not fully implemented')
|
||||
if (typeof window !== 'undefined') {
|
||||
console.dir(item)
|
||||
return
|
||||
}
|
||||
console.dir(item, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for `log` function
|
||||
* @param data data to log
|
||||
*/
|
||||
public dirxml(...data: Array<any>): void {
|
||||
this.process('dirxml', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* print to stderr on NodeJS, print with red coloring on browsers
|
||||
* @param data data to log
|
||||
*/
|
||||
public error(...data: Array<any>): void {
|
||||
this.process('error', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias to `error` function
|
||||
* @param data data to log
|
||||
*/
|
||||
public exception(...data: Array<any>): void { // NOT STANDARD / FIREFOX ONLY
|
||||
this.error(...data)
|
||||
}
|
||||
|
||||
/**
|
||||
* NodeJS -> Increase the indentation of future logs with `label` as header
|
||||
*
|
||||
* Browser -> Group futures logs
|
||||
* @param label labels to use as header
|
||||
*/
|
||||
public group(...label: Array<any>): void {
|
||||
console.group(...label)
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of `group` function
|
||||
* @param label label to use as header
|
||||
*/
|
||||
public groupCollapsed(...label: Array<any>): void {
|
||||
this.group(...label)
|
||||
}
|
||||
|
||||
/**
|
||||
* End the current group started with the `group` function
|
||||
*/
|
||||
public groupEnd(): void {
|
||||
console.groupEnd()
|
||||
}
|
||||
|
||||
/**
|
||||
* Log to console as Info
|
||||
* (Only Chrome else it is an alias of `log`)
|
||||
* @param data data to log
|
||||
*/
|
||||
public info(...data: Array<any>): void {
|
||||
this.process('info', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Log to console
|
||||
* @param data data to log
|
||||
*/
|
||||
public log(...data: Array<any>) {
|
||||
this.process('log', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* make a new profile in browsers or in NodeJS with `--inspect` flag
|
||||
* @param name Profile name
|
||||
*/
|
||||
public profile(name?: string) {
|
||||
// @ts-ignore
|
||||
if (console.profile) {
|
||||
// @ts-ignore
|
||||
console.profile(name)
|
||||
} else {
|
||||
throw new Error('profile don\'t exist in the current contexte')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* end the current running profile
|
||||
* @param name Profile name
|
||||
*/
|
||||
public profileEnd(name?: string) {
|
||||
// @ts-ignore
|
||||
console.profileEnd(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a Table to the console
|
||||
* @param tabularData Table data
|
||||
* @param properties Table properties
|
||||
*/
|
||||
public table(tabularData?: any, properties?: Array<string> | undefined): void {
|
||||
console.table(tabularData, properties)
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a timer
|
||||
* @param label Timer label
|
||||
*/
|
||||
public time(label: string = 'default'): void {
|
||||
if (!Object.prototype.hasOwnProperty.call(this.timeCount, label)) {
|
||||
this.timeCount[label] = new Date()
|
||||
return
|
||||
}
|
||||
this.warn(`Timer '${label}' already exists.`)
|
||||
}
|
||||
|
||||
/**
|
||||
* End a timer
|
||||
* @param label Timer label
|
||||
*/
|
||||
public timeEnd(label: string = 'default'): void {
|
||||
const diff = (new Date()).getTime() - this.timeCount[label].getTime()
|
||||
this.log(`${label}: ${diff}ms - Timer ended`)
|
||||
delete this.timeCount[label]
|
||||
}
|
||||
|
||||
/**
|
||||
* Log to the console with timer before it
|
||||
* @param label Timer label
|
||||
* @param data data to log next to the timer
|
||||
*/
|
||||
public timeLog(label: string = 'default', ...data: Array<any>): void {
|
||||
if (!this.timeCount[label]) {
|
||||
this.warn(`Timer '${label}' does not exist`)
|
||||
return
|
||||
}
|
||||
const diff = (new Date()).getTime() - this.timeCount[label].getTime()
|
||||
this.log(`${label}: ${diff}ms`, ...data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Browsers only, Add maker in the browser's Performance or Waterfall tool
|
||||
* @param label Label to use
|
||||
*/
|
||||
public timeStamp(label?: string): void {
|
||||
console.timeStamp(label)
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a stack trace to console
|
||||
* @param data data to trace
|
||||
*/
|
||||
public trace(...data: Array<any>): void {
|
||||
this.process('trace', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn in the console
|
||||
* (in NodeJS context it is an alias to the `error` function)
|
||||
* @param data data to log
|
||||
*/
|
||||
public warn(...data: Array<any>): void {
|
||||
this.process('warn', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Log to the console but skiping `isBlocked` check
|
||||
* @param data data to log
|
||||
*/
|
||||
public urgent(...data: Array<any>) {
|
||||
console.log(...this.formatMessage(data))
|
||||
}
|
||||
|
||||
/**
|
||||
* Precoess a message sent by one of the public functions
|
||||
* @param type logType
|
||||
* @param message message to log
|
||||
*/
|
||||
private process(type: logType, message: Array<any>) {
|
||||
this.queue.push({type, msg: this.formatMessage(message)})
|
||||
this.processQueue()
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a message for the console
|
||||
* @param message message to format
|
||||
*/
|
||||
private formatMessage(message: Array<any>): Array<any> {
|
||||
const prefix = this.prefix
|
||||
const prefixLen = prefix.length
|
||||
|
||||
if (Logger.prefixLen < prefixLen) {
|
||||
Logger.prefixLen = prefixLen
|
||||
}
|
||||
|
||||
const spacers: Array<string> = ['', '']
|
||||
if (Logger.prefixLen > prefixLen) {
|
||||
const diff = Logger.prefixLen - prefixLen
|
||||
const diff2 = diff /2
|
||||
spacers[0] = this.buildSpace(diff2 - (diff % 2 !== 0 ? 1 : 0))
|
||||
spacers[1] = this.buildSpace(diff2)
|
||||
}
|
||||
const res: Array<any> = [
|
||||
`${white('[ ')}${els[0]}${blue(prefix)}${els[1]}${white(' ]')}:` // prefix
|
||||
`${this.blackOrWhite('[ ')}${spacers[0]}${blue(prefix)}${spacers[1]}${this.blackOrWhite(' ]')}:`
|
||||
].concat(
|
||||
message.map((el) => {
|
||||
if (typeof el === 'object') {
|
||||
@ -60,11 +378,48 @@ export default class Logger {
|
||||
return res
|
||||
}
|
||||
|
||||
private static buildSpace(count: number): string {
|
||||
/**
|
||||
* Process Waiting queue
|
||||
*/
|
||||
private processQueue() {
|
||||
while (this.queue.length > 0 && !this.blocked) {
|
||||
const item = this.queue.shift()
|
||||
if (!item) {
|
||||
continue
|
||||
}
|
||||
if (item.type === 'trace') {
|
||||
console.log(item.msg.shift())
|
||||
}
|
||||
console[item.type](...item.msg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a new string of `count` spaces
|
||||
* @param count number of spaces to add
|
||||
*/
|
||||
private buildSpace(count: number): string {
|
||||
let str = ''
|
||||
for(let i = 0; i < count; i++) {
|
||||
str += ' '
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
/**
|
||||
* Color the text in black or white depending on `theme` variable or detection
|
||||
* @param text the text to color
|
||||
*/
|
||||
private blackOrWhite(text: string): string {
|
||||
if ((!Logger.theme && typeof window !== 'undefined') || Logger.theme === 'light') {
|
||||
return black(text)
|
||||
}
|
||||
return white(text)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Export a default Logger
|
||||
*/
|
||||
export const logger = new Logger()
|
||||
|
@ -2,5 +2,13 @@ import Logger from './Logger'
|
||||
|
||||
// Browser Import
|
||||
|
||||
/**
|
||||
* Init Logger in global context and add function to replace default console
|
||||
*/
|
||||
|
||||
// @ts-ignore
|
||||
window.Logger = Logger
|
||||
// @ts-ignore
|
||||
window.initConsole = function() {
|
||||
window.console = new Logger('Console')
|
||||
}
|
||||
|
17
packages/logger/src/types.ts
Normal file
17
packages/logger/src/types.ts
Normal file
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Object Array
|
||||
*/
|
||||
export interface ObjectArray<T = any> {
|
||||
[key: string]: T
|
||||
}
|
||||
|
||||
/**
|
||||
* used Internally,
|
||||
* the different types of logs
|
||||
*/
|
||||
export type logType = 'debug' | 'dir' | 'dirxml' | 'error' | 'info' | 'log' | 'trace' | 'warn'
|
||||
|
||||
/**
|
||||
* The possible themes
|
||||
*/
|
||||
export type theme = undefined | 'light' | 'dark'
|
54
packages/logger/test/index.ts
Normal file
54
packages/logger/test/index.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { logger as console } from '../src/Logger'
|
||||
|
||||
/**
|
||||
* This test file is simple :D
|
||||
*/
|
||||
|
||||
// Should remove the precedent line
|
||||
console.clear()
|
||||
|
||||
// Start a timer
|
||||
console.time()
|
||||
console.timeLog(undefined, 'Started Timer')
|
||||
|
||||
// Test assert
|
||||
console.log('Assert')
|
||||
console.assert(true, 'i am true') // should print nothing
|
||||
console.assert(false, 'i am false') // Should print 'i am false'
|
||||
|
||||
// all the different logs
|
||||
console.debug('debug')
|
||||
console.dir('dir')
|
||||
console.dirxml('dirxml')
|
||||
console.error('error')
|
||||
console.info('info')
|
||||
console.log('log')
|
||||
console.trace('trace')
|
||||
console.warn('warn')
|
||||
|
||||
// Timelog
|
||||
console.timeLog(undefined, 'timeLog')
|
||||
|
||||
console.group('New group')
|
||||
console.group('New group')
|
||||
console.group('New group')
|
||||
console.group('New group')
|
||||
console.group('New group')
|
||||
console.group('New group')
|
||||
console.group('New group')
|
||||
console.group('New group')
|
||||
console.log('Log in a group')
|
||||
console.groupEnd()
|
||||
console.groupEnd()
|
||||
console.groupEnd()
|
||||
console.groupEnd()
|
||||
console.groupEnd()
|
||||
console.groupEnd()
|
||||
console.groupEnd()
|
||||
console.groupEnd()
|
||||
console.groupEnd()
|
||||
|
||||
console.table([{ a: 1, b: 'Y' }, { a: 'Z', b: 2 }], ['a'])
|
||||
|
||||
// TimeEnd
|
||||
console.timeEnd()
|
6
packages/logger/tsconfig.test.json
Normal file
6
packages/logger/tsconfig.test.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"files": [
|
||||
"test/index.ts"
|
||||
]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user