New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@jalik/logger

Package Overview
Dependencies
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@jalik/logger - npm Package Compare versions

Comparing version 2.2.9 to 3.0.0

dist/index.js

60

CHANGELOG.md
# 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

319

dist/Logger.js

@@ -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": {

# @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 @@ }

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc