Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@boost/log

Package Overview
Dependencies
Maintainers
1
Versions
55
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@boost/log - npm Package Compare versions

Comparing version 2.0.1 to 2.1.0

20

CHANGELOG.md

@@ -6,2 +6,22 @@ # Change Log

## 2.1.0 - 2020-08-17
#### 🚀 Updates
- Build packages with Rollup to support web and node targets. ([38cdad9](https://github.com/milesj/boost/commit/38cdad9))
#### 📘 Docs
- Migrate to Docusaurus. (#105) ([24196b8](https://github.com/milesj/boost/commit/24196b8)), closes [#105](https://github.com/milesj/boost/issues/105)
#### 📦 Dependencies
- Update root dependencies. ([9c3203a](https://github.com/milesj/boost/commit/9c3203a))
**Note:** Version bump only for package @boost/log
### 2.0.1 - 2020-07-29

@@ -8,0 +28,0 @@

612

lib/index.js

@@ -1,50 +0,568 @@

"use strict";
/**
* @copyright 2020, Miles Johnson
* @license https://opensource.org/licenses/MIT
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var common = require('@boost/common');
var os = _interopDefault(require('os'));
var util = _interopDefault(require('util'));
var internal = require('@boost/internal');
var chalk = _interopDefault(require('chalk'));
var path = _interopDefault(require('path'));
var translate = require('@boost/translate');
var fs = _interopDefault(require('fs'));
var zlib = _interopDefault(require('zlib'));
function formatMetadata(metadata) {
const items = [];
const keys = Object.keys(metadata).sort();
keys.forEach(key => {
items.push(`${key}=${metadata[key]}`);
});
return `(${items.join(', ')})`;
}
function console$1(item) {
let output = item.message;
if (item.level !== 'log') {
output = `${item.label} ${output}`;
}
return output;
}
function debug(item) {
return `[${item.time.toISOString()}] ${item.level.toUpperCase()} ${item.message} ${formatMetadata({ ...item.metadata,
host: item.host,
name: item.name,
pid: item.pid
})}`;
}
function json(item) {
return JSON.stringify(item);
}
function message(item) {
return item.message;
}
var formats = /*#__PURE__*/Object.freeze({
__proto__: null,
console: console$1,
debug: debug,
json: json,
message: message
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
var msg = translate.createTranslator('log', path.join(__dirname, '../res'));
// In order of priority!
const LOG_LEVELS = ['log', 'trace', 'debug', 'info', 'warn', 'error'];
const DEFAULT_LABELS = {
debug: chalk.gray(msg('log:levelDebug')),
error: chalk.red(msg('log:levelError')),
info: chalk.cyan(msg('log:levelInfo')),
log: chalk.yellow(msg('log:levelLog')),
trace: chalk.magenta(msg('log:levelTrace')),
warn: chalk.yellow(msg('log:levelWarn'))
};
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.StreamTransport = exports.RotatingFileTransport = exports.FileTransport = exports.ConsoleTransport = exports.Transport = exports.Logger = exports.formats = exports.createLogger = void 0;
const createLogger_1 = __importDefault(require("./createLogger"));
exports.createLogger = createLogger_1.default;
const Logger_1 = __importDefault(require("./Logger"));
exports.Logger = Logger_1.default;
const Transport_1 = __importDefault(require("./Transport"));
exports.Transport = Transport_1.default;
const ConsoleTransport_1 = __importDefault(require("./transports/ConsoleTransport"));
exports.ConsoleTransport = ConsoleTransport_1.default;
const FileTransport_1 = __importDefault(require("./transports/FileTransport"));
exports.FileTransport = FileTransport_1.default;
const RotatingFileTransport_1 = __importDefault(require("./transports/RotatingFileTransport"));
exports.RotatingFileTransport = RotatingFileTransport_1.default;
const StreamTransport_1 = __importDefault(require("./transports/StreamTransport"));
exports.StreamTransport = StreamTransport_1.default;
const formats = __importStar(require("./formats"));
const MAX_LOG_SIZE = 10485760;
class Transport extends common.Contract {
constructor(options) {
super(options);
this.levels = [];
this.levels = this.options.levels;
}
blueprint({
array,
func,
string
}) {
return {
eol: string(os.EOL),
format: func().nullable(),
levels: array(string().oneOf(LOG_LEVELS))
};
}
/**
* Format the log item into a message string, and append a trailing newline if missing.
*/
format(item) {
const {
eol,
format
} = this.options;
let output = typeof format === 'function' ? format(item) : debug(item);
if (!output.endsWith(eol)) {
output += eol;
}
return output;
}
/**
* Write the formatted message according to the transport.
*/
}
class ConsoleTransport extends Transport {
constructor(options) {
super({
format: console$1,
levels: LOG_LEVELS,
...options
});
}
write(message, {
level
}) {
// eslint-disable-next-line no-console
console[level](message.trim());
}
}
var debug$1 = internal.createInternalDebugger('log');
class Logger extends common.Contract {
constructor(options) {
super(options);
this.silent = false;
const defaultLevel = internal.env('LOG_DEFAULT_LEVEL');
const maxLevel = internal.env('LOG_MAX_LEVEL');
debug$1('New logger "%s" created: %s %s', this.options.name, defaultLevel ? `${defaultLevel} level` : 'all levels', maxLevel ? `(max ${maxLevel})` : '');
}
blueprint({
array,
func,
object,
shape,
string
}) {
return {
labels: object(string()),
metadata: object(),
name: string().required().notEmpty(),
transports: array(shape({
format: func().notNullable(),
// eslint-disable-next-line react/forbid-prop-types
levels: array(string()),
write: func().notNullable()
}), [new ConsoleTransport()])
};
}
disable() {
debug$1('Logger %s disabled', this.options.name);
this.silent = true;
}
enable() {
debug$1('Logger %s enabled', this.options.name);
this.silent = false;
}
isAllowed(level, maxLevel) {
if (!maxLevel) {
return true;
} // eslint-disable-next-line no-restricted-syntax
for (const currentLevel of LOG_LEVELS) {
if (currentLevel === level) {
return true;
}
if (currentLevel === maxLevel) {
break;
}
}
return false;
}
log({
args = [],
level,
message,
metadata = {}
}) {
const logLevel = level || internal.env('LOG_DEFAULT_LEVEL') || 'log';
if (this.silent || !this.isAllowed(logLevel, internal.env('LOG_MAX_LEVEL'))) {
return;
}
const item = {
host: os.hostname(),
label: this.options.labels[logLevel] || DEFAULT_LABELS[logLevel] || '',
level: logLevel,
message: util.format(message, ...args),
metadata: { ...this.options.metadata,
...metadata
},
name: this.options.name,
pid: process.pid,
time: new Date()
};
this.options.transports.forEach(transport => {
if (transport.levels.includes(item.level)) {
void transport.write(transport.format(item), item);
}
});
}
}
function pipeLog(logger, level) {
return (...args) => {
let metadata = {};
let message = '';
if (common.isObject(args[0])) {
metadata = args.shift();
}
message = args.shift();
logger.log({
args,
level,
message,
metadata
});
};
}
function createLogger(options) {
const logger = new Logger(options);
const log = pipeLog(logger);
LOG_LEVELS.forEach(level => {
Object.defineProperty(log, level, {
value: pipeLog(logger, level)
});
});
Object.defineProperty(log, 'disable', {
value: () => logger.disable()
});
Object.defineProperty(log, 'enable', {
value: () => logger.enable()
});
return log;
}
class FileTransport extends Transport {
constructor(options) {
super(options);
this.path = void 0;
this.stream = void 0;
this.buffer = '';
this.draining = false;
this.lastSize = 0;
this.rotating = false;
this.path = common.Path.resolve(this.options.path);
this.checkFolderRequirements();
}
blueprint(preds) {
const {
bool,
instance,
union,
number,
string
} = preds;
return { ...super.blueprint(preds),
gzip: bool(),
maxSize: number(MAX_LOG_SIZE).positive(),
path: union([string(), instance(common.Path)], '').required()
};
}
/**
* Close the file stream and trigger the callback when finished.
*/
close(cb) {
const onClose = () => {
if (cb) {
cb();
}
this.stream = undefined;
};
if (this.stream) {
this.stream.once('finish', onClose).end();
} else {
onClose();
}
}
/**
* Open the file stream for writing.
*/
open() {
if (this.stream) {
return this.stream;
}
this.stream = this.createStream();
if (this.path.exists()) {
this.lastSize = fs.statSync(this.path.path()).size;
}
if (this.buffer) {
const message = this.buffer;
this.buffer = '';
this.write(message);
}
return this.stream;
}
/**
* Write a message to the file stream, and rotate files once written if necessary.
*/
write(message) {
if (this.rotating) {
this.buffer += message;
return;
}
const stream = this.open();
const written = stream.write(message, 'utf8', () => {
this.lastSize += Buffer.byteLength(message);
this.checkIfNeedsRotation();
}); // istanbul ignore next
if (!written) {
this.draining = true;
stream.once('drain', () => {
this.draining = false;
});
}
}
/**
* Check that the parent folder exists and has the correct permissions.
*/
checkFolderRequirements() {
fs.mkdirSync(this.path.parent().path(), {
recursive: true
});
}
/**
* Check if we should change and rotate files because of max size.
*/
checkIfNeedsRotation() {
if (this.lastSize > this.options.maxSize) {
this.closeStreamAndRotateFile();
}
}
/**
* Open and create a file stream for the defined path.
* Apply file size and gzip checks.
*/
createStream() {
const stream = fs.createWriteStream(this.path.path(), {
encoding: 'utf8',
flags: 'a'
}); // Apply gzip compression to the stream
if (this.options.gzip) {
const gzip = zlib.createGzip();
gzip.pipe(stream);
return gzip;
}
return stream;
}
/**
* Return the file name with extension, of the newly rotated file.
*/
getRotatedFileName() {
return this.path.name();
}
/**
* Count the number of files within path directory that matches the given file name.
*/
getNextIncrementCount(name) {
const files = fs.readdirSync(this.path.parent().path()); // eslint-disable-next-line security/detect-non-literal-regexp
const pattern = new RegExp(`^${name}.\\d+$`, 'u');
let count = 0;
files.forEach(file => {
if (file.match(pattern)) {
count += 1;
}
});
return count;
}
/**
* Close the open stream and attempt to rotate the file.
*/
closeStreamAndRotateFile() {
// istanbul ignore next
if (this.draining || this.rotating) {
return;
}
this.rotating = true;
this.close(() => {
this.rotateFile();
this.rotating = false;
});
}
/**
* Rotate the current file into a new file with an incremented name.
*/
rotateFile() {
let fileName = this.getRotatedFileName();
if (this.options.gzip) {
fileName += '.gz';
}
fileName += `.${this.getNextIncrementCount(fileName)}`;
fs.renameSync(this.path.path(), this.path.parent().append(fileName).path());
this.lastSize = 0;
}
}
const DAYS_IN_WEEK = 7;
class RotatingFileTransport extends FileTransport {
constructor(...args) {
super(...args);
this.lastTimestamp = this.formatTimestamp(Date.now());
}
blueprint(preds) {
const {
string
} = preds;
return { ...super.blueprint(preds),
rotation: string().oneOf(['hourly', 'daily', 'weekly', 'monthly'])
};
}
/**
* Format a `Date` object into a format used within the log file name.
*/
formatTimestamp(ms) {
const {
rotation
} = this.options;
const date = new Date(ms);
let timestamp = `${date.getFullYear()}${String(date.getMonth() + 1).padStart(2, '0')}`;
if (rotation === 'monthly') {
return timestamp;
} // Special case, calculate the week manually and return,
// but do not append so other rotations inherit!
if (rotation === 'weekly') {
const firstDay = new Date(date.getFullYear(), date.getMonth(), 1).getDay();
const offsetDate = date.getDate() + firstDay - 1;
timestamp += `.W${Math.floor(offsetDate / DAYS_IN_WEEK) + 1}`;
return timestamp;
}
timestamp += String(date.getDate()).padStart(2, '0');
if (rotation === 'daily') {
return timestamp;
}
timestamp += `.${String(date.getHours()).padStart(2, '0')}`;
return timestamp;
}
/**
* @inheritdoc
*/
checkIfNeedsRotation() {
if (this.lastSize > this.options.maxSize || this.formatTimestamp(Date.now()) !== this.lastTimestamp) {
this.closeStreamAndRotateFile();
}
}
/**
* @inheritdoc
*/
getRotatedFileName() {
const name = this.path.name(true);
const ext = this.path.ext(true);
return `${name}-${this.lastTimestamp}.${ext}`;
}
/**
* @inheritdoc
*/
rotateFile() {
super.rotateFile(); // Update timestamp to the new format
this.lastTimestamp = this.formatTimestamp(Date.now());
}
}
class StreamTransport extends Transport {
blueprint(preds) {
const {
func,
shape
} = preds;
return { ...super.blueprint(preds),
stream: shape({
write: func().required().notNullable()
})
};
}
write(message) {
this.options.stream.write(message);
}
}
exports.ConsoleTransport = ConsoleTransport;
exports.DEFAULT_LABELS = DEFAULT_LABELS;
exports.FileTransport = FileTransport;
exports.LOG_LEVELS = LOG_LEVELS;
exports.Logger = Logger;
exports.MAX_LOG_SIZE = MAX_LOG_SIZE;
exports.RotatingFileTransport = RotatingFileTransport;
exports.StreamTransport = StreamTransport;
exports.Transport = Transport;
exports.createLogger = createLogger;
exports.formats = formats;
__exportStar(require("./constants"), exports);
__exportStar(require("./types"), exports);

2

lib/testing.d.ts

@@ -1,3 +0,3 @@

import { LoggerFunction } from './types';
import type { LoggerFunction } from './index';
export declare function mockLogger(): LoggerFunction;
//# sourceMappingURL=testing.d.ts.map

@@ -1,17 +0,19 @@

"use strict";
/* eslint-disable jest/prefer-spy-on */
Object.defineProperty(exports, "__esModule", { value: true });
exports.mockLogger = void 0;
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
/* eslint-disable unicorn/import-index, jest/prefer-spy-on */
function mockLogger() {
const log = jest.fn();
log.disable = jest.fn();
log.enable = jest.fn();
log.debug = jest.fn();
log.error = jest.fn();
log.log = jest.fn();
log.info = jest.fn();
log.trace = jest.fn();
log.warn = jest.fn();
return log;
const log = jest.fn();
log.disable = jest.fn();
log.enable = jest.fn();
log.debug = jest.fn();
log.error = jest.fn();
log.log = jest.fn();
log.info = jest.fn();
log.trace = jest.fn();
log.warn = jest.fn();
return log;
}
exports.mockLogger = mockLogger;
{
"name": "@boost/log",
"version": "2.0.1",
"version": "2.1.0",
"release": "1594765247526",

@@ -24,5 +24,5 @@ "description": "Lightweight level based logging system.",

"dependencies": {
"@boost/common": "^2.1.0",
"@boost/internal": "^2.0.0",
"@boost/translate": "^2.0.1",
"@boost/common": "^2.2.0",
"@boost/internal": "^2.1.0",
"@boost/translate": "^2.1.0",
"chalk": "^4.1.0"

@@ -34,3 +34,3 @@ },

},
"gitHead": "fcbd70d657c873083d0c739128c0cc1b16978be2"
"gitHead": "7982950ce80d97d1815234ee0d66b5dc4ac3a843"
}

@@ -22,3 +22,3 @@ # Logging - Boost

- Handles default and max logging levels.
- Customizable colors, labels, and writable streams.
- Customizable transports with writable streams.
- Toggleable logging at runtime.

@@ -34,2 +34,2 @@

[https://milesj.gitbook.io/boost/log](https://milesj.gitbook.io/boost/log)
[https://boostlib.dev/docs/log](https://boostlib.dev/docs/log)

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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