@jalik/logger
Advanced tools
Comparing version 2.2.9 to 3.0.0
# Changelog | ||
## v3.0.0 | ||
- **[BREAKING CHANGE]** Changed method signature of `log()` in Logger | ||
to `log(level: string, message: string, context: object)` | ||
- **[BREAKING CHANGE]** Removed methods `clone()`, `on()` and `off()` in Logger | ||
- **[BREAKING CHANGE]** Removed options `console`, `displayContext` and `displayName` from Logger | ||
constructor | ||
- **[BREAKING CHANGE]** Moved log level constants to levels.js | ||
- **[BREAKING CHANGE]** Logger must be imported using a named | ||
import (example: `import { Logger } from '@jalik/logger'`) | ||
- Added `FATAL` constant log level | ||
- Added method `fatal(string|Error, object)` in Logger | ||
- Added option `level: string` in Logger constructor (default: `info`), it can be one of `debug`, `info`, `warn`, `error` or `fatal` | ||
- Added option `outputs: Array<function>` in Logger constructor (default: `[consoleOutput()]`) | ||
- Added option `defaultContext: null|object` in Logger constructor (default: `null`) | ||
- Added option `filter: null|function` in Logger constructor (default: `null`) | ||
- Upgraded dependencies | ||
## v2.2.9 | ||
- Upgraded dependencies | ||
## v2.2.8 | ||
- Upgraded dependencies | ||
## v2.2.7 | ||
- Added `esnext` and `sideEffects` in package.json | ||
@@ -15,20 +36,27 @@ - Renamed logger.js to Logger.js | ||
## v2.2.6 | ||
- Upgraded dependencies | ||
## v2.2.5 | ||
- Upgraded dependencies | ||
## v2.2.4 | ||
- Upgraded dependencies | ||
## v2.2.3 | ||
- Upgraded dependencies | ||
## v2.2.2 | ||
- Upgraded dependencies | ||
## v2.2.1 | ||
- Upgraded dependencies | ||
## v2.2.0 | ||
- Upgraded dependencies | ||
@@ -39,11 +67,15 @@ - Lib available in ES6+ syntax (see `src` folder) to enable auto-completion in IDEs | ||
## v2.1.4 | ||
- Fixes compatibility error `'log' called on an object that does not implement interface Console` | ||
## v2.1.3 | ||
- Upgraded dependencies | ||
## v2.1.2 | ||
- Upgraded dependencies | ||
## v2.1.1 | ||
- Upgraded devDependencies | ||
@@ -53,25 +85,32 @@ - Changes package's repository URL | ||
## v2.1.0 | ||
- Adds `:` after the logger name (ex: `ClassLogger: test`) | ||
- Adds method `Logger.clone(name: String)` | ||
- Removes useless `return` instruction in the following methods: | ||
- `Logger.debug()` | ||
- `Logger.error()` | ||
- `Logger.info()` | ||
- `Logger.warn()` | ||
- `Logger.debug()` | ||
- `Logger.error()` | ||
- `Logger.info()` | ||
- `Logger.warn()` | ||
## v2.0.1 | ||
- Fixes example of `Logger.on(event: String, listener: Function)` in README | ||
## v2.0.0 | ||
- **BREAKING:** Method `Logger.on(event: String, listener: Function)` has changed to improve ease of use. Before you had to pass | ||
`debug`, `error`, `info` or `warning` as the first string argument, now use the `log` | ||
event instead. Also in the callback, the `type` of log is inserted as the second argument after `message`, thus `context` is now the third argument. | ||
- BEFORE: `Logger.on('error', (message, context) => {})` | ||
- NOW: `Logger.on('log', (message, type, context) => {})` | ||
- **BREAKING:** Method `Logger.on(event: String, listener: Function)` has changed to improve ease of | ||
use. Before you had to pass | ||
`debug`, `error`, `info` or `warning` as the first string argument, now use the `log` | ||
event instead. Also in the callback, the `type` of log is inserted as the second argument | ||
after `message`, thus `context` is now the third argument. | ||
- BEFORE: `Logger.on('error', (message, context) => {})` | ||
- NOW: `Logger.on('log', (message, type, context) => {})` | ||
- Fixes code examples in README | ||
## v1.0.5 | ||
- Upgraded dependencies | ||
## v1.0.4 | ||
- Adds constructor option `displayName: Boolean` | ||
@@ -82,5 +121,7 @@ - Adds constructor option `name: String` | ||
## v1.0.3 | ||
- Exports `Logger` using ES6 default export | ||
## v1.0.1 | ||
- Adds options to activate or deactivate console logging for a type of message | ||
@@ -95,2 +136,3 @@ - Adds option `Logger.options.console.debug = true` | ||
## v1.0.0 | ||
- First public release |
@@ -5,2 +5,4 @@ "use strict"; | ||
var _typeof3 = require("@babel/runtime/helpers/typeof"); | ||
Object.defineProperty(exports, "__esModule", { | ||
@@ -13,2 +15,4 @@ value: true | ||
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); | ||
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); | ||
@@ -18,76 +22,70 @@ | ||
var _deepExtend = _interopRequireDefault(require("@jalik/deep-extend")); | ||
var _levels = _interopRequireWildcard(require("./levels")); | ||
var _observer = _interopRequireDefault(require("@jalik/observer")); | ||
var _consoleOutput = _interopRequireDefault(require("./outputs/consoleOutput")); | ||
var _types = _interopRequireDefault(require("./types")); | ||
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } | ||
/* | ||
* The MIT License (MIT) | ||
* Copyright (c) 2020 Karl STEIN | ||
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof3(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } | ||
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } | ||
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } | ||
var defaultOptions = { | ||
active: true, | ||
defaultContext: null, | ||
filter: null, | ||
level: _levels.INFO, | ||
name: null, | ||
outputs: [(0, _consoleOutput["default"])()] | ||
}; | ||
/** | ||
* Returns details of an error. | ||
* @param {Error} error | ||
* @return {{message: string, name: string, reason: string, stack: string, type: string}} | ||
*/ | ||
var Logger = /*#__PURE__*/function () { | ||
function Logger(options) { | ||
(0, _classCallCheck2["default"])(this, Logger); | ||
// Set default options | ||
this.options = (0, _deepExtend["default"])({ | ||
active: true, | ||
console: { | ||
debug: true, | ||
error: true, | ||
info: true, | ||
other: true, | ||
warning: true | ||
}, | ||
displayContext: false, | ||
displayName: false, | ||
name: null | ||
}, options); // Create observer | ||
this.observer = new _observer["default"](this); // Check console availability | ||
function getErrorDetails(error) { | ||
var attributes = ['message', 'name', 'reason', 'stack', 'type']; | ||
var details = {}; | ||
if ((typeof console === "undefined" ? "undefined" : (0, _typeof2["default"])(console)) !== 'object' || console === null) { | ||
throw new Error('The console object is not available in this environment.'); | ||
} // Add polyfill methods to the console object | ||
// eslint-disable-next-line no-console | ||
for (var i = 0; i < attributes.length; i += 1) { | ||
if (attributes[i] in error) { | ||
details[attributes[i]] = error[attributes[i]]; | ||
} | ||
} | ||
return details; | ||
} | ||
if (typeof console.log === 'function') { | ||
// eslint-disable-next-line no-console | ||
if (typeof console.debug !== 'function') { | ||
// eslint-disable-next-line no-console | ||
console.debug = console.log.bind(console); | ||
} // eslint-disable-next-line no-console | ||
var Logger = /*#__PURE__*/function () { | ||
function Logger() { | ||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
(0, _classCallCheck2["default"])(this, Logger); | ||
// Use default options. | ||
var opts = _objectSpread(_objectSpread({}, defaultOptions), options); // Set logger status. | ||
if (typeof console.error !== 'function') { | ||
// eslint-disable-next-line no-console | ||
console.error = console.log.bind(console); | ||
} // eslint-disable-next-line no-console | ||
this.active = opts.active === true; // Set default log context. | ||
if (typeof console.info !== 'function') { | ||
// eslint-disable-next-line no-console | ||
console.info = console.log.bind(console); | ||
} // eslint-disable-next-line no-console | ||
this.defaultContext = opts.defaultContext; // Set logs filter. | ||
this.filter = opts.filter; // Set minimal log level. | ||
if (typeof console.warn !== 'function') { | ||
// eslint-disable-next-line no-console | ||
console.warn = console.log.bind(console); | ||
} | ||
} // Check logger name | ||
this.level = opts.level; // Set logger name. | ||
this.name = opts.name == null ? "logger_".concat(Date.now()) : String(opts.name); // Set log outputs. | ||
if (typeof this.options.name === 'undefined' || this.options.name === null) { | ||
// Generate a name | ||
this.name = "logger-".concat(Date.now()); | ||
} else { | ||
this.name = this.options.name; | ||
this.outputs = [].concat(opts.outputs || []); | ||
if ((0, _typeof2["default"])(this.outputs) !== 'object' || !(this.outputs instanceof Array) || this.outputs.length === 0) { | ||
throw new Error('Logger outputs cannot be empty.'); | ||
} | ||
} | ||
/** | ||
* Returns a clone of the current logger with a different name. | ||
* @param name | ||
* @return {Logger} | ||
* Logs a debug message. | ||
* @param {string} message | ||
* @param context | ||
*/ | ||
@@ -97,11 +95,10 @@ | ||
(0, _createClass2["default"])(Logger, [{ | ||
key: "clone", | ||
value: function clone(name) { | ||
return new Logger((0, _deepExtend["default"])({}, this.options, { | ||
name: name | ||
})); | ||
key: "debug", | ||
value: function debug(message) { | ||
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined; | ||
this.log(_levels.DEBUG, message, context); | ||
} | ||
/** | ||
* Logs a debug message | ||
* @param message | ||
* Logs an error message. | ||
* @param {string|Error} messageOrError | ||
* @param context | ||
@@ -111,9 +108,18 @@ */ | ||
}, { | ||
key: "debug", | ||
value: function debug(message, context) { | ||
this.log(message, _types["default"].debug, context); | ||
key: "error", | ||
value: function error(messageOrError) { | ||
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined; | ||
var ctx = context || {}; | ||
var message = messageOrError; | ||
if (messageOrError instanceof Error) { | ||
message = messageOrError.message; | ||
ctx.error = getErrorDetails(messageOrError); | ||
} | ||
this.log(_levels.ERROR, message, ctx); | ||
} | ||
/** | ||
* Logs an error message | ||
* @param messageOrError | ||
* Logs a fatal error message. | ||
* @param {string|Error} messageOrError | ||
* @param context | ||
@@ -123,25 +129,27 @@ */ | ||
}, { | ||
key: "error", | ||
value: function error(messageOrError, context) { | ||
key: "fatal", | ||
value: function fatal(messageOrError) { | ||
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined; | ||
var ctx = context || {}; | ||
var msg = messageOrError; | ||
var message = messageOrError; | ||
if (messageOrError instanceof Error) { | ||
ctx.error = {}; | ||
var attributes = ['name', 'message', 'reason', 'stack', 'type']; | ||
for (var i = 0; i < attributes.length; i += 1) { | ||
if (attributes[i] in messageOrError) { | ||
ctx.error[attributes[i]] = messageOrError[attributes[i]]; | ||
} | ||
} | ||
var message = messageOrError.message; | ||
msg = message; | ||
message = messageOrError.message; | ||
ctx.error = getErrorDetails(messageOrError); | ||
} | ||
this.log(msg, _types["default"].error, ctx); | ||
this.log(_levels.FATAL, message, ctx); | ||
} | ||
/** | ||
* Returns the logger name | ||
* Returns the log level. | ||
* @return {string} | ||
*/ | ||
}, { | ||
key: "getLevel", | ||
value: function getLevel() { | ||
return this.level; | ||
} | ||
/** | ||
* Returns the logger name. | ||
* @return {string|null} | ||
@@ -156,4 +164,4 @@ */ | ||
/** | ||
* Logs an information message | ||
* @param message | ||
* Logs an informational message. | ||
* @param {string} message | ||
* @param context | ||
@@ -164,7 +172,8 @@ */ | ||
key: "info", | ||
value: function info(message, context) { | ||
this.log(message, _types["default"].info, context); | ||
value: function info(message) { | ||
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined; | ||
this.log(_levels.INFO, message, context); | ||
} | ||
/** | ||
* Checks if the logger is active | ||
* Checks if the logging is active. | ||
* @return {boolean} | ||
@@ -176,8 +185,8 @@ */ | ||
value: function isActive() { | ||
return this.options.active === true; | ||
return this.active === true; | ||
} | ||
/** | ||
* Logs a message | ||
* @param message | ||
* @param type | ||
* Logs a message with a certain level. | ||
* @param {string} level | ||
* @param {string} message | ||
* @param context | ||
@@ -188,110 +197,51 @@ */ | ||
key: "log", | ||
value: function log(message, type, context) { | ||
var _this$observer; | ||
value: function log(level, message) { | ||
var context = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined; | ||
if (this.isActive()) { | ||
var args = []; // Display logger name in console | ||
// Ignore if logger is not active or if log level is higher. | ||
if (!this.isActive() || _levels["default"].indexOf(this.level) > _levels["default"].indexOf(level)) { | ||
return; | ||
} // Prepare log event. | ||
if (this.options.displayName === true) { | ||
args.push("".concat(this.name, ":")); | ||
} // Display message in console | ||
var event = { | ||
context: this.defaultContext ? _objectSpread(_objectSpread({}, this.defaultContext), context) : context, | ||
level: level, | ||
logger: this.name, | ||
message: message, | ||
timestamp: Date.now() | ||
}; // Filter log event. | ||
args.push(message); // Display context in console | ||
if (typeof this.filter === 'function' && this.filter(event) !== true) { | ||
return; | ||
} // Pass log event to outputs. | ||
if (typeof context !== 'undefined' && this.options.displayContext === true) { | ||
args.push(context); | ||
} // Displays the message in the console | ||
switch (type) { | ||
case _types["default"].debug: | ||
if (this.options.console.debug === true) { | ||
var _console; | ||
// eslint-disable-next-line no-console | ||
(_console = console).log.apply(_console, args); | ||
} | ||
break; | ||
case _types["default"].error: | ||
if (this.options.console.error === true) { | ||
var _console2; | ||
// eslint-disable-next-line no-console | ||
(_console2 = console).error.apply(_console2, args); | ||
} | ||
break; | ||
case _types["default"].info: | ||
if (this.options.console.info === true) { | ||
var _console3; | ||
// eslint-disable-next-line no-console | ||
(_console3 = console).info.apply(_console3, args); | ||
} | ||
break; | ||
case _types["default"].warning: | ||
if (this.options.console.warning === true) { | ||
var _console4; | ||
// eslint-disable-next-line no-console | ||
(_console4 = console).warn.apply(_console4, args); | ||
} | ||
break; | ||
default: | ||
if (typeof this.options.console[type] === 'boolean' && this.options.console[type] === true || typeof this.options.console[type] !== 'boolean' && this.options.console.other === true) { | ||
var _console5; | ||
// eslint-disable-next-line no-console | ||
(_console5 = console).log.apply(_console5, args); | ||
} | ||
} | ||
} // Notify all listeners | ||
(_this$observer = this.observer).notify.apply(_this$observer, ['log'].concat([message, type, context])); | ||
this.outputs.forEach(function (output) { | ||
output(event); | ||
}); | ||
} | ||
/** | ||
* Removes an event listener | ||
* @param event | ||
* @param listener | ||
* Enables or disables logging. | ||
* @param {boolean} active | ||
*/ | ||
}, { | ||
key: "off", | ||
value: function off(event, listener) { | ||
this.observer.detach(event, listener); | ||
key: "setActive", | ||
value: function setActive(active) { | ||
this.active = active === true; | ||
} | ||
/** | ||
* Adds an event listener | ||
* @param event | ||
* @param listener | ||
* Changes the log level. | ||
* @param {string} level | ||
*/ | ||
}, { | ||
key: "on", | ||
value: function on(event, listener) { | ||
this.observer.attach(event, listener); | ||
key: "setLevel", | ||
value: function setLevel(level) { | ||
this.level = level; | ||
} | ||
/** | ||
* Activates or deactivates the logger | ||
* @param active | ||
*/ | ||
}, { | ||
key: "setActive", | ||
value: function setActive(active) { | ||
this.options.active = active === true; | ||
} | ||
/** | ||
* Logs a warning message | ||
* @param message | ||
* Logs a warning message. | ||
* @param {string} message | ||
* @param context | ||
@@ -302,4 +252,5 @@ */ | ||
key: "warn", | ||
value: function warn(message, context) { | ||
this.log(message, _types["default"].warning, context); | ||
value: function warn(message) { | ||
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined; | ||
this.log(_levels.WARN, message, context); | ||
} | ||
@@ -306,0 +257,0 @@ }]); |
{ | ||
"name": "@jalik/logger", | ||
"version": "2.2.9", | ||
"version": "3.0.0", | ||
"description": "A logging utility to log messages to anywhere.", | ||
@@ -9,3 +9,5 @@ "license": "MIT", | ||
"error", | ||
"log", | ||
"logs", | ||
"logger", | ||
"logging" | ||
@@ -25,4 +27,5 @@ ], | ||
}, | ||
"main": "dist/Logger.js", | ||
"esnext": "src/Logger.js", | ||
"main": "./dist/index.js", | ||
"module": "./src/index.js", | ||
"esnext": "./src/index.js", | ||
"sideEffects": false, | ||
@@ -40,5 +43,3 @@ "scripts": { | ||
"dependencies": { | ||
"@babel/runtime": "^7.14.0", | ||
"@jalik/deep-extend": "^1.1.12", | ||
"@jalik/observer": "^1.1.11" | ||
"@babel/runtime": "^7.14.0" | ||
}, | ||
@@ -45,0 +46,0 @@ "devDependencies": { |
312
README.md
# @jalik/logger | ||
![GitHub package.json version](https://img.shields.io/github/package-json/v/jalik/js-logger.svg) | ||
@@ -9,7 +10,10 @@ [![Build Status](https://travis-ci.com/jalik/js-logger.svg?branch=master)](https://travis-ci.com/jalik/js-logger) | ||
A flexible logger to log messages to anything you want (console, file, database...), there's nothing more to say about it. | ||
A fast and handy logging library to send logs to anything you want (console, file, database, | ||
APIs...). | ||
## Introduction | ||
Logging is an important part of an application lifecycle, from development to production, we always need to log messages for debugging or tracing errors and warnings, this lib will hep you taking control of logging in your apps. | ||
Logging is an important part of an application lifecycle, from development to production, we always | ||
need to log messages for debugging and making error investigation easier, this is the purpose of | ||
this lib. | ||
@@ -21,3 +25,6 @@ ## Creating a logger | ||
```js | ||
import Logger from '@jalik/logger'; | ||
import { | ||
Logger, | ||
INFO | ||
} from '@jalik/logger'; | ||
@@ -27,40 +34,51 @@ const logger = new Logger({ | ||
active: true, | ||
// Display message of given types in the console | ||
console: { | ||
debug: true, | ||
error: true, | ||
info: true, | ||
other: true, | ||
warning: true | ||
}, | ||
// Display context in the console | ||
displayContext: false, | ||
// Display logger name in the console | ||
displayName: true, | ||
// Give a name to this logger | ||
name: 'main' | ||
// Set the minimal log level to log messages | ||
level: INFO, | ||
// Set the name of this logger | ||
name: 'main', | ||
// Set logging outputs | ||
outputs: [ | ||
// Output logs to the console | ||
consoleOutput() | ||
] | ||
}); | ||
``` | ||
Note that after creating the logger, you can still change the options via the public attribute | ||
`options`, like `logger.options.console.debug = false`. | ||
Or just use the code below to create a logger with the default config (`active: true`, `level: INFO` | ||
, | ||
`outputs: [consoleOutput()]`). | ||
## Logging types | ||
```js | ||
import { Logger } from '@jalik/logger'; | ||
Instead of levels, this lib refers to types of logging, this is useful to distinguish and filter | ||
messages, there are 4 well known types of logging : | ||
- debug : only used for debugging | ||
- error : only used for errors and exceptions | ||
- info : only used to display informative messages | ||
- warning : only used to display warnings | ||
const logger = new Logger({ name: 'main' }); | ||
``` | ||
You can get the string value of each types by importing the types list. | ||
## Levels of logging | ||
Several logging levels are available to differentiate important events. | ||
Below is the list of levels ordered from the **less important to the most important**. | ||
- `debug`: used for debugging messages | ||
- `info`: used for informational messages | ||
- `warn`: used for warning messages | ||
- `error`: used for error messages | ||
- `fatal`: used for fatal error messages | ||
All levels are defined with the following constants. | ||
```js | ||
import Types from '@jalik/logger/dist/types'; | ||
import { | ||
DEBUG, | ||
INFO, | ||
WARN, | ||
ERROR, | ||
FATAL | ||
} from '@jalik/logger'; | ||
``` | ||
Types.debug; // used by console.debug() | ||
Types.error; // used by console.error() | ||
Types.info; // used by console.info() | ||
Types.warning; // used by console.warn() | ||
The ordered levels list is also available as an array. | ||
```js | ||
import { levels } from '@jalik/logger'; | ||
``` | ||
@@ -70,89 +88,217 @@ | ||
When you log a message, you can also provide an optional context as extra information, you have a dedicated method for each type of logging. | ||
To log messages, you can use the method `log(level: string, message: string, context?: any)` or one | ||
of the shortcut methods `debug()` | ||
, `info()`, `warn()`, `error()` and `fatal()`. | ||
### `log(level, message, context)` | ||
```js | ||
import Logger from '@jalik/logger'; | ||
import { | ||
Logger, | ||
INFO | ||
} from '@jalik/logger'; | ||
const logger = new Logger(); | ||
const logger = new Logger({ name: 'main' }); | ||
// Logs a debug message | ||
// Note: you can use string templates available since ES6 | ||
// to have dynamic logs. | ||
const user = {name: 'karl'}; | ||
logger.debug(`user logged "${user.name}"`, user); | ||
// Logs a custom type message. | ||
const ipAddress = '6.6.6.6'; | ||
logger.log(INFO, `The IP address ${ipAddress} has failed to login 3 times`, 'suspicious', { ipAddress }); | ||
``` | ||
// Logs an error message | ||
logger.error('Forbidden', {error: new Error('forbidden')}); | ||
// You can directly pass an Error object | ||
logger.error(new Error('forbidden')); | ||
### `debug(message, context)` | ||
// Logs an info message | ||
logger.info('Application started', { | ||
date: new Date() | ||
}); | ||
```js | ||
import { Logger } from '@jalik/logger'; | ||
// Logs a warning message | ||
logger.warn('Disk usage is above 90%', { | ||
diskUsage: 92.6 | ||
}); | ||
const logger = new Logger({ name: 'main' }); | ||
const a = 2; | ||
const b = 4; | ||
const result = a + b; | ||
// Logs a custom type message | ||
const ipAddress = '6.6.6.6'; | ||
logger.log(`The IP address ${ipAddress} has failed to login 3 times`, 'suspicious', {ipAddress}); | ||
// Log the message with a context | ||
logger.debug(`result = ${result}`, { a, b }); | ||
// or without context | ||
logger.debug(`result = ${result}`); | ||
``` | ||
## Activating or deactivating a logger | ||
### `info(message, context)` | ||
By default a logger is activated, but you can deactivate it anytime you want by using the `setActive(Boolean)` method. | ||
```js | ||
import { Logger } from '@jalik/logger'; | ||
const logger = new Logger({ name: 'main' }); | ||
const bootTime = 1337; | ||
// Log the message with a context | ||
logger.info(`Application started in ${bootTime} ms`, { bootTime, tags: ['boot'] }); | ||
// or without context | ||
logger.info(`Application started in ${bootTime} ms`); | ||
``` | ||
### `warn(message, context)` | ||
```js | ||
import Logger from '@jalik/logger'; | ||
import { Logger } from '@jalik/logger'; | ||
const logger = new Logger(); | ||
const logger = new Logger({ name: 'main' }); | ||
const diskUsage = 93.6; | ||
// Activate logger on production environment only | ||
logger.setActive(process.env.NODE_ENV === 'PRODUCTION'); | ||
// Log the message with a context | ||
logger.warn('Disk usage is above 90%', { diskUsage }); | ||
// or without context | ||
logger.warn('Disk usage is above 90%'); | ||
``` | ||
// And to check if the logger is active | ||
### `error(message, context)` | ||
```js | ||
import { Logger } from '@jalik/logger'; | ||
const logger = new Logger({ name: 'main' }); | ||
const error = new Error('Forbidden'); | ||
// Log the message with a context | ||
logger.error('Forbidden', { error }); | ||
// or simply | ||
logger.error(error); | ||
// or without context | ||
logger.error('Forbidden'); | ||
``` | ||
### `fatal(message, context)` | ||
```js | ||
import { Logger } from '@jalik/logger'; | ||
const logger = new Logger({ name: 'main' }); | ||
const error = new Error('app crashed'); | ||
// Log the message with a context | ||
logger.fatal('app crashed', { error }); | ||
// or simply | ||
logger.fatal(error); | ||
// or without context | ||
logger.fatal('app crashed'); | ||
``` | ||
## Enabling or disabling a logger | ||
A logger is enabled by default if you don't set `active: false` in Logger options. However, you can | ||
change logging status at anytime the `setActive(Boolean)` method. | ||
### `setActive(boolean)` | ||
```js | ||
import { Logger } from '@jalik/logger'; | ||
const logger = new Logger({ | ||
// Enable logger on production environment only. | ||
active: process.env.NODE_ENV === 'PRODUCTION' | ||
}); | ||
// To check if the logger is active. | ||
logger.isActive(); | ||
// Disable logger after 30 seconds. | ||
setTimeout(() => { | ||
logger.setActive(false); | ||
// Anything that is logged after the line above will be ignored. | ||
logger.info('Sky is blue'); | ||
}, 30000) | ||
``` | ||
## Listening events | ||
### `isActive(): boolean` | ||
The logger is flexible enough in the way that you can execute callbacks when an event occurs (debug, error, info, warning), so you could save logs to a database, a file or whatever you want. | ||
This method tells you if the logger is enabled. | ||
## Setting a default context | ||
It is possible to define a `defaultContext` when creating the logger. | ||
This context will be passed to all log events and may be overwritten for each log. | ||
```js | ||
import Types from '@jalik/logger/dist/types'; | ||
import Logger from '@jalik/logger'; | ||
import { Logger } from '@jalik/logger'; | ||
const logger = new Logger(); | ||
// With this event listener, you can do something when an error happens | ||
logger.on('log', (message, type, context) => { | ||
if (type === Types.error) { | ||
// do whatever you want here... | ||
// save error to database, send an email... | ||
const logger = new Logger({ | ||
defaultContext: { | ||
host: process.env.HOST | ||
} | ||
}); | ||
// This will trigger the listener defined above | ||
logger.error('Cannot contact DNS server', { | ||
ipAddress: '8.8.8.8' | ||
// then logging a message will automatically use the default context. | ||
logger.info('Application started.'); | ||
// you can even add a context over a default context (attributes will be merged and/or replaced). | ||
logger.info('Something happened', { tag: 'something-event' }); | ||
``` | ||
## Filtering log events | ||
You can filter the logs that are processed by using the `filter` option when creating a logger. | ||
```js | ||
import { | ||
DEBUG, | ||
Logger | ||
} from '@jalik/logger'; | ||
const cronFilter = (event) => { | ||
return (event.context && event.context.tag === 'cron') || /cron/g.test(event.message) | ||
} | ||
const logger = new Logger({ | ||
level: DEBUG, | ||
filter: cronFilter | ||
}); | ||
// this will be logged. | ||
logger.info('Cron jobs executed.', { tag: 'cron' }); | ||
// this will not be logged. | ||
logger.info('Application started.'); | ||
``` | ||
## Cloning a logger | ||
## Logging outputs | ||
It can be useful to clone an existing logger, thus reusing the same configuration by calling the `clone()` method on a logger. | ||
Each logger can be configured with one or more `outputs`. | ||
By default, a logger will output messages to the console with the `consoleOutput` like in the code | ||
below. | ||
### `consoleOutput(options)` | ||
The console output allows you to display logs in the console (browser and nodejs), you can also | ||
provide your own formatter. | ||
```js | ||
import Logger from '@jalik/logger'; | ||
import { | ||
Logger, | ||
consoleOutput | ||
} from '@jalik/logger'; | ||
const loggerA = new Logger({name:'A', displayContext: true}); | ||
const loggerB = loggerA.clone('B'); | ||
function formatter(event) { | ||
return [ | ||
new Date(event.timestamp).toISOString(), | ||
event.level.toUpperCase(), | ||
`[${event.logger}]`, | ||
':', | ||
event.message, | ||
';', | ||
JSON.stringify(event.context) | ||
].join(' ') | ||
} | ||
// The logger B will display the given context since it has been enabled in the logger A. | ||
loggerB.debug('printed now', {date: new Date()}); | ||
const logger = new Logger({ | ||
name: 'main', | ||
outputs: [ | ||
consoleOutput({ formatter }), | ||
], | ||
}); | ||
logger.info('Hello World', { number: 42 }); | ||
// 2021-05-27T02:40:06.957Z DEBUG [main] : Hello World ; {"number":42} | ||
``` | ||
To create your own logger output, please see how [consoleOutput](src/outputs/consoleOutput.js) was | ||
created. | ||
## Changelog | ||
@@ -159,0 +305,0 @@ |
/* | ||
* The MIT License (MIT) | ||
* Copyright (c) 2020 Karl STEIN | ||
* Copyright (c) 2021 Karl STEIN | ||
*/ | ||
import deepExtend from '@jalik/deep-extend'; | ||
import Observer from '@jalik/observer'; | ||
import Types from './types'; | ||
import levels, { | ||
DEBUG, | ||
ERROR, | ||
FATAL, | ||
INFO, | ||
WARN, | ||
} from './levels'; | ||
import consoleOutput from './outputs/consoleOutput'; | ||
class Logger { | ||
constructor(options) { | ||
// Set default options | ||
this.options = deepExtend({ | ||
active: true, | ||
console: { | ||
debug: true, | ||
error: true, | ||
info: true, | ||
other: true, | ||
warning: true, | ||
}, | ||
displayContext: false, | ||
displayName: false, | ||
name: null, | ||
}, options); | ||
const defaultOptions = { | ||
active: true, | ||
defaultContext: null, | ||
filter: null, | ||
level: INFO, | ||
name: null, | ||
outputs: [consoleOutput()], | ||
}; | ||
// Create observer | ||
this.observer = new Observer(this); | ||
/** | ||
* Returns details of an error. | ||
* @param {Error} error | ||
* @return {{message: string, name: string, reason: string, stack: string, type: string}} | ||
*/ | ||
function getErrorDetails(error) { | ||
const attributes = ['message', 'name', 'reason', 'stack', 'type']; | ||
const details = {}; | ||
// Check console availability | ||
if (typeof console !== 'object' || console === null) { | ||
throw new Error('The console object is not available in this environment.'); | ||
for (let i = 0; i < attributes.length; i += 1) { | ||
if (attributes[i] in error) { | ||
details[attributes[i]] = error[attributes[i]]; | ||
} | ||
} | ||
return details; | ||
} | ||
// Add polyfill methods to the console object | ||
// eslint-disable-next-line no-console | ||
if (typeof console.log === 'function') { | ||
// eslint-disable-next-line no-console | ||
if (typeof console.debug !== 'function') { | ||
// eslint-disable-next-line no-console | ||
console.debug = console.log.bind(console); | ||
} | ||
// eslint-disable-next-line no-console | ||
if (typeof console.error !== 'function') { | ||
// eslint-disable-next-line no-console | ||
console.error = console.log.bind(console); | ||
} | ||
// eslint-disable-next-line no-console | ||
if (typeof console.info !== 'function') { | ||
// eslint-disable-next-line no-console | ||
console.info = console.log.bind(console); | ||
} | ||
// eslint-disable-next-line no-console | ||
if (typeof console.warn !== 'function') { | ||
// eslint-disable-next-line no-console | ||
console.warn = console.log.bind(console); | ||
} | ||
} | ||
class Logger { | ||
constructor(options = {}) { | ||
// Use default options. | ||
const opts = { ...defaultOptions, ...options }; | ||
// Check logger name | ||
if (typeof this.options.name === 'undefined' || this.options.name === null) { | ||
// Generate a name | ||
this.name = `logger-${Date.now()}`; | ||
} else { | ||
this.name = this.options.name; | ||
// Set logger status. | ||
this.active = opts.active === true; | ||
// Set default log context. | ||
this.defaultContext = opts.defaultContext; | ||
// Set logs filter. | ||
this.filter = opts.filter; | ||
// Set minimal log level. | ||
this.level = opts.level; | ||
// Set logger name. | ||
this.name = opts.name == null ? `logger_${Date.now()}` : String(opts.name); | ||
// Set log outputs. | ||
this.outputs = [].concat(opts.outputs || []); | ||
if (typeof this.outputs !== 'object' || !(this.outputs instanceof Array) || this.outputs.length === 0) { | ||
throw new Error('Logger outputs cannot be empty.'); | ||
} | ||
@@ -70,46 +70,52 @@ } | ||
/** | ||
* Returns a clone of the current logger with a different name. | ||
* @param name | ||
* @return {Logger} | ||
* Logs a debug message. | ||
* @param {string} message | ||
* @param context | ||
*/ | ||
clone(name) { | ||
return new Logger(deepExtend({}, this.options, { name })); | ||
debug(message, context = undefined) { | ||
this.log(DEBUG, message, context); | ||
} | ||
/** | ||
* Logs a debug message | ||
* @param message | ||
* Logs an error message. | ||
* @param {string|Error} messageOrError | ||
* @param context | ||
*/ | ||
debug(message, context) { | ||
this.log(message, Types.debug, context); | ||
error(messageOrError, context = undefined) { | ||
const ctx = context || {}; | ||
let message = messageOrError; | ||
if (messageOrError instanceof Error) { | ||
message = messageOrError.message; | ||
ctx.error = getErrorDetails(messageOrError); | ||
} | ||
this.log(ERROR, message, ctx); | ||
} | ||
/** | ||
* Logs an error message | ||
* @param messageOrError | ||
* Logs a fatal error message. | ||
* @param {string|Error} messageOrError | ||
* @param context | ||
*/ | ||
error(messageOrError, context) { | ||
fatal(messageOrError, context = undefined) { | ||
const ctx = context || {}; | ||
let msg = messageOrError; | ||
let message = messageOrError; | ||
if (messageOrError instanceof Error) { | ||
ctx.error = {}; | ||
const attributes = ['name', 'message', 'reason', 'stack', 'type']; | ||
for (let i = 0; i < attributes.length; i += 1) { | ||
if (attributes[i] in messageOrError) { | ||
ctx.error[attributes[i]] = messageOrError[attributes[i]]; | ||
} | ||
} | ||
const { message } = messageOrError; | ||
msg = message; | ||
message = messageOrError.message; | ||
ctx.error = getErrorDetails(messageOrError); | ||
} | ||
this.log(msg, Types.error, ctx); | ||
this.log(FATAL, message, ctx); | ||
} | ||
/** | ||
* Returns the logger name | ||
* Returns the log level. | ||
* @return {string} | ||
*/ | ||
getLevel() { | ||
return this.level; | ||
} | ||
/** | ||
* Returns the logger name. | ||
* @return {string|null} | ||
@@ -122,119 +128,73 @@ */ | ||
/** | ||
* Logs an information message | ||
* @param message | ||
* Logs an informational message. | ||
* @param {string} message | ||
* @param context | ||
*/ | ||
info(message, context) { | ||
this.log(message, Types.info, context); | ||
info(message, context = undefined) { | ||
this.log(INFO, message, context); | ||
} | ||
/** | ||
* Checks if the logger is active | ||
* Checks if the logging is active. | ||
* @return {boolean} | ||
*/ | ||
isActive() { | ||
return this.options.active === true; | ||
return this.active === true; | ||
} | ||
/** | ||
* Logs a message | ||
* @param message | ||
* @param type | ||
* Logs a message with a certain level. | ||
* @param {string} level | ||
* @param {string} message | ||
* @param context | ||
*/ | ||
log(message, type, context) { | ||
if (this.isActive()) { | ||
const args = []; | ||
log(level, message, context = undefined) { | ||
// Ignore if logger is not active or if log level is higher. | ||
if (!this.isActive() || levels.indexOf(this.level) > levels.indexOf(level)) { | ||
return; | ||
} | ||
// Display logger name in console | ||
if (this.options.displayName === true) { | ||
args.push(`${this.name}:`); | ||
} | ||
// Prepare log event. | ||
const event = { | ||
context: this.defaultContext ? { ...this.defaultContext, ...context } : context, | ||
level, | ||
logger: this.name, | ||
message, | ||
timestamp: Date.now(), | ||
}; | ||
// Display message in console | ||
args.push(message); | ||
// Display context in console | ||
if (typeof context !== 'undefined' && this.options.displayContext === true) { | ||
args.push(context); | ||
} | ||
// Displays the message in the console | ||
switch (type) { | ||
case Types.debug: | ||
if (this.options.console.debug === true) { | ||
// eslint-disable-next-line no-console | ||
console.log(...args); | ||
} | ||
break; | ||
case Types.error: | ||
if (this.options.console.error === true) { | ||
// eslint-disable-next-line no-console | ||
console.error(...args); | ||
} | ||
break; | ||
case Types.info: | ||
if (this.options.console.info === true) { | ||
// eslint-disable-next-line no-console | ||
console.info(...args); | ||
} | ||
break; | ||
case Types.warning: | ||
if (this.options.console.warning === true) { | ||
// eslint-disable-next-line no-console | ||
console.warn(...args); | ||
} | ||
break; | ||
default: | ||
if ((typeof this.options.console[type] === 'boolean' | ||
&& this.options.console[type] === true) | ||
|| (typeof this.options.console[type] !== 'boolean' | ||
&& this.options.console.other === true)) { | ||
// eslint-disable-next-line no-console | ||
console.log(...args); | ||
} | ||
} | ||
// Filter log event. | ||
if (typeof this.filter === 'function' && this.filter(event) !== true) { | ||
return; | ||
} | ||
// Notify all listeners | ||
this.observer.notify('log', ...[message, type, context]); | ||
// Pass log event to outputs. | ||
this.outputs.forEach((output) => { | ||
output(event); | ||
}); | ||
} | ||
/** | ||
* Removes an event listener | ||
* @param event | ||
* @param listener | ||
* Enables or disables logging. | ||
* @param {boolean} active | ||
*/ | ||
off(event, listener) { | ||
this.observer.detach(event, listener); | ||
setActive(active) { | ||
this.active = active === true; | ||
} | ||
/** | ||
* Adds an event listener | ||
* @param event | ||
* @param listener | ||
* Changes the log level. | ||
* @param {string} level | ||
*/ | ||
on(event, listener) { | ||
this.observer.attach(event, listener); | ||
setLevel(level) { | ||
this.level = level; | ||
} | ||
/** | ||
* Activates or deactivates the logger | ||
* @param active | ||
*/ | ||
setActive(active) { | ||
this.options.active = (active === true); | ||
} | ||
/** | ||
* Logs a warning message | ||
* @param message | ||
* Logs a warning message. | ||
* @param {string} message | ||
* @param context | ||
*/ | ||
warn(message, context) { | ||
this.log(message, Types.warning, context); | ||
warn(message, context = undefined) { | ||
this.log(WARN, message, context); | ||
} | ||
@@ -241,0 +201,0 @@ } |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
36672
1
15
662
311
1
- Removed@jalik/deep-extend@^1.1.12
- Removed@jalik/observer@^1.1.11
- Removed@jalik/deep-extend@1.2.2(transitive)
- Removed@jalik/observer@1.2.1(transitive)