1455 lines
55 KiB
JavaScript
1455 lines
55 KiB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.jiboLog = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
|
"use strict";
|
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
});
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const output_handlers_1 = require("./output-handlers");
|
|
const defaultConfig_1 = require("./defaultConfig");
|
|
const utils_1 = require("./utils");
|
|
const getPlatformVersion_1 = require("./utils/getPlatformVersion");
|
|
const types_1 = require("./types");
|
|
const Level_1 = require("./types/Level");
|
|
const LogOutputs_1 = require("./LogOutputs");
|
|
const utils_2 = require("./utils");
|
|
const PromiseUtils_1 = require("./utils/PromiseUtils");
|
|
const fs = require("fs");
|
|
const fsx = require("fs-extra");
|
|
const os = require("os");
|
|
const osHomedir = require("os-homedir");
|
|
const path = require("path");
|
|
const NAMESPACE_DELIMITER = '.';
|
|
const prify = PromiseUtils_1.PromiseUtils.promisify;
|
|
/**
|
|
* Log class - centralized logging facility
|
|
* @class Log
|
|
* @param {string} [namespace=''] The namespace to log to
|
|
* @param {Log} [parent] The log parent (prepended to the namespace)
|
|
*/
|
|
class Log {
|
|
constructor(namespace = '', parent) {
|
|
/**
|
|
* The robot ID, defaulting to the hostname of the current machine
|
|
* It is useful to have this public, so a cloud process can set the
|
|
* robot ID based on the robot credentials provided upon connection
|
|
* @name Log#robotID
|
|
* @type {string}
|
|
*/
|
|
this.robotID = os.hostname();
|
|
// In the Pegasus environment, we need to support a separate configuration
|
|
// per robot
|
|
this._outputPerNamespace = {};
|
|
this.namespace =
|
|
(parent && parent.namespace)
|
|
? `${parent.namespace}${NAMESPACE_DELIMITER}${namespace}`
|
|
: namespace;
|
|
if (!Log._staticNamespaceLevels) {
|
|
this.outputPerNamespace =
|
|
parent
|
|
? parent._outputPerNamespace
|
|
: Log._outputPerNamespace;
|
|
}
|
|
}
|
|
/**
|
|
* The level of each output channel of the global logger
|
|
* @static
|
|
* @readonly
|
|
* @name Log.outputs
|
|
* @type {LogOutputs}
|
|
*/
|
|
static get outputs() {
|
|
return Log.global.outputs;
|
|
}
|
|
/**
|
|
* Load the default logging configuration statically
|
|
* @static
|
|
* @method Log.initialize
|
|
* @return {Promise<void>}
|
|
*/
|
|
static initialize() {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
if (!Log._initialized) {
|
|
Log._outputPerNamespace = {};
|
|
// Set up the output handlers
|
|
Log._outputHandlers = output_handlers_1.outputHandlers;
|
|
// Load the default logging configuration
|
|
Log._loadConfig(defaultConfig_1.default);
|
|
// See if there's a local config file, and load it up if so
|
|
Log._localConfigPath = process.env.JIBO_LOG_CONFIG ||
|
|
(Log._onRobot
|
|
? '/var/jibo/t.logging.json'
|
|
: path.resolve(osHomedir(), '.jibo', 't.logging.json'));
|
|
yield Log._loadLocalConfig();
|
|
if (Log._onRobot) {
|
|
// By this point, globally uncaught exception and unhandled
|
|
// promise rejection handlers have been attached, so stifle
|
|
// stdout and stderr to avoid System Manager from logging
|
|
// console output from Node processes to syslog (and thus
|
|
// double-logging). This allows use of DevTools Console to
|
|
// monitor logs in real time
|
|
const nullStream = new utils_2.NullStream();
|
|
process.stdout.write = nullStream.write.bind(nullStream);
|
|
process.stderr.write = nullStream.write.bind(nullStream);
|
|
}
|
|
// Don't set the initialized flag until after we've tried loading a
|
|
// local config file
|
|
Log._initialized = true;
|
|
}
|
|
});
|
|
}
|
|
/**
|
|
* Add an output handler to jibo-log
|
|
* @method Log.addOutputHandler
|
|
* @param {string} name The name of the output channel
|
|
* @param {OutputHandler<Config extends Object>} handler The handler to add
|
|
*/
|
|
static addOutputHandler(name, handler) {
|
|
Log._outputHandlers[name] = handler;
|
|
}
|
|
/**
|
|
* Set the logging configuration from input (e.g. parsed from JSON file)
|
|
* @static
|
|
* @method Log.loadConfig
|
|
* @param {LoggingConfig} loggingConfig The configuration to load
|
|
* @return {Promise<void>}
|
|
*/
|
|
// Load local configuration (on- or off-robot) after processes load their
|
|
// own configuration, so that local configuration takes precedence
|
|
static loadConfig(loggingConfig) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
// Wait for Log to finish its initialization, to avoid race condition
|
|
// for its own loading of the local config file
|
|
while (!Log._initialized) {
|
|
yield prify((cb) => setImmediate(cb));
|
|
}
|
|
// If integration tests indicate that local config should be ignored,
|
|
// we need to clear the already-loaded local config, and reload the
|
|
// jibo-log defaults
|
|
if (loggingConfig.skipLocalConfig) {
|
|
Log._outputPerNamespace = {};
|
|
Log._loadConfig(defaultConfig_1.default);
|
|
}
|
|
Log._loadConfig(loggingConfig);
|
|
// If there's a local config file, load it afterwards so it takes
|
|
// precedence. _skipLocalConfig check is so integration tests can
|
|
// ensure local config is ignored, so results are consistent
|
|
if (!Log._skipLocalConfig) {
|
|
yield Log._loadLocalConfig();
|
|
}
|
|
});
|
|
}
|
|
/**
|
|
* Generate LoggingConfig for output (e.g. to stringify to JSON file)
|
|
* @static
|
|
* @method Log.getConfig
|
|
* @return {LoggingConfig}
|
|
*/
|
|
static getConfig() {
|
|
const logUncaughtExceptions = Log._globalErrorHandler.logUncaughtExceptions;
|
|
const logUnhandledRejections = Log._globalErrorHandler.logUnhandledRejections;
|
|
const namespaces = Object.keys(Log._outputPerNamespace).reduce((namespaces, namespace) => {
|
|
return Object.assign({}, namespaces, { [namespace]: Log._outputPerNamespace[namespace] });
|
|
}, {});
|
|
const outputs = Object.keys(Log._outputHandlers).reduce((outputs, name) => {
|
|
return Object.assign({}, outputs, { [name]: Log._outputHandlers[name].config });
|
|
}, {});
|
|
// Don't save out the skipLocalConfig value - it's just for tests
|
|
const stackTraceLimit = Error.stackTraceLimit;
|
|
const staticNamespaceLevels = Log._staticNamespaceLevels;
|
|
return {
|
|
logUncaughtExceptions,
|
|
logUnhandledRejections,
|
|
namespaces,
|
|
outputs,
|
|
stackTraceLimit,
|
|
staticNamespaceLevels,
|
|
};
|
|
}
|
|
/**
|
|
* Save the current log configuration file to a local logging config file
|
|
* If process.env.JIBO_LOG_CONFIG: use that; else...
|
|
* On-robot: /var/jibo/t.logging.json
|
|
* Off-robot: ~/.jibo/t.logging.json
|
|
* @static
|
|
* @method Log.saveConfig
|
|
* @return {Promise<void>}
|
|
*/
|
|
static saveConfig() {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
try {
|
|
yield prify((cb) => {
|
|
fsx.ensureDir(path.dirname(Log._localConfigPath), cb);
|
|
});
|
|
}
|
|
catch (err) {
|
|
Log._jiboLog.warn(`Error creating directory for ${Log._localConfigPath}`, err);
|
|
return;
|
|
}
|
|
try {
|
|
const stringConfig = JSON.stringify(Log.getConfig(), null, 4);
|
|
yield prify((cb) => {
|
|
fs.writeFile(Log._localConfigPath, stringConfig, cb);
|
|
});
|
|
}
|
|
catch (err) {
|
|
Log._jiboLog.warn(`Error writing local config to ${Log._localConfigPath}`, err);
|
|
return;
|
|
}
|
|
Log._jiboLog.info(`Wrote local config to ${Log._localConfigPath}`);
|
|
});
|
|
}
|
|
/**
|
|
* Set up listener for log-level update notifications
|
|
* @static
|
|
* @method Log.handleLogLevelNotifications
|
|
* @param {events.EventEmitter} notificationsDispatcher Event emitter that emits 'LevelChanged' events
|
|
* @param {boolean} [save = false] Whether to save the configuration to disk or not
|
|
* @return {Promise<void>}
|
|
*/
|
|
static handleLogLevelNotifications(notificationsDispatcher,
|
|
// This should only be set true when called from the SSM process, to
|
|
// ensure that the change is only written to disk once
|
|
save = false) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
Log._jiboLog.info('Registering for log "LevelChanged" notifications');
|
|
notificationsDispatcher.on('LevelChanged', (changes) => {
|
|
Log._jiboLog.info('Got a log "LevelChanged" notification:', changes);
|
|
changes
|
|
.filter((change) => change.namespace.startsWith('T.'))
|
|
.forEach((change) => {
|
|
const namespace = change.namespace.slice(2);
|
|
const level = (['verbose', 'silly'].includes(change.level)
|
|
? 'debug'
|
|
: change.level);
|
|
Log._jiboLog.info(`Setting ${namespace} to ${level}`);
|
|
const log = new Log(namespace);
|
|
log.outputs.syslog = level;
|
|
});
|
|
if (save) {
|
|
Log._jiboLog.info('Saving config to disk');
|
|
Log.saveConfig();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
/**
|
|
* Flush all log lines that output channels may have cached in memory
|
|
* @static
|
|
* @method Log.flush
|
|
* @return {void}
|
|
*/
|
|
static flush() {
|
|
Object.keys(Log._outputHandlers)
|
|
.map((output) => Log._outputHandlers[output])
|
|
.forEach((handler) => handler && handler.flush());
|
|
}
|
|
static get _onRobot() {
|
|
// Check environment variables for run mode
|
|
let runMode = process.env.runMode || process.env.RUNMODE;
|
|
// Default to ON_ROBOT under arm/linux if not set
|
|
if (!runMode
|
|
&& process.platform === 'linux' && process.arch === 'arm') {
|
|
runMode = 'ON_ROBOT';
|
|
}
|
|
return runMode === 'ON_ROBOT';
|
|
}
|
|
static _loadConfig(loggingConfig) {
|
|
// Set this first, since it affects behavior later
|
|
if (loggingConfig.staticNamespaceLevels !== undefined) {
|
|
Log._staticNamespaceLevels = loggingConfig.staticNamespaceLevels;
|
|
}
|
|
if (loggingConfig.logUncaughtExceptions !== undefined) {
|
|
Log._globalErrorHandler.logUncaughtExceptions =
|
|
loggingConfig.logUncaughtExceptions;
|
|
}
|
|
if (loggingConfig.logUnhandledRejections !== undefined) {
|
|
Log._globalErrorHandler.logUnhandledRejections =
|
|
loggingConfig.logUnhandledRejections;
|
|
}
|
|
if (loggingConfig.namespaces) {
|
|
const outputPerNamespaceIn = loggingConfig.namespaces;
|
|
Object.keys(outputPerNamespaceIn).forEach((namespace) => {
|
|
const levelPerOutput = Log._outputPerNamespace[namespace] = {};
|
|
const levelPerOutputIn = outputPerNamespaceIn[namespace];
|
|
Object.keys(levelPerOutputIn).forEach((output) => {
|
|
const levelIn = levelPerOutputIn[output];
|
|
const level = levelIn;
|
|
levelPerOutput[output] = level;
|
|
});
|
|
});
|
|
// Fix the outputPerNamespace for the global logger
|
|
if (!Log._staticNamespaceLevels) {
|
|
Log.global.outputPerNamespace = Log._outputPerNamespace;
|
|
}
|
|
}
|
|
if (loggingConfig.outputs) {
|
|
const outputsIn = loggingConfig.outputs;
|
|
Object.keys(outputsIn).forEach((output) => {
|
|
if (!this._outputHandlers[output]) {
|
|
console.error(`Missing output ${output}`);
|
|
}
|
|
else {
|
|
this._outputHandlers[output].config = outputsIn[output];
|
|
}
|
|
});
|
|
}
|
|
if (loggingConfig.skipLocalConfig !== undefined) {
|
|
Log._skipLocalConfig = loggingConfig.skipLocalConfig;
|
|
}
|
|
if (loggingConfig.stackTraceLimit > -1) {
|
|
Error.stackTraceLimit = loggingConfig.stackTraceLimit;
|
|
}
|
|
}
|
|
static _loadLocalConfig() {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
// If we've already loaded up a local config file, just load it again
|
|
if (Log._localConfig) {
|
|
return Log._loadConfig(Log._localConfig);
|
|
}
|
|
// Otherwise, only try looking for a new file if we're not initialized
|
|
// This way, if there's no file, we don't do these checks when a
|
|
// process loads its own configuration
|
|
if (Log._initialized) {
|
|
return;
|
|
}
|
|
if (Log._onRobot) {
|
|
yield Log._loadLocalConfigOnRobot();
|
|
}
|
|
else {
|
|
yield Log._loadLocalConfigOffRobot();
|
|
}
|
|
});
|
|
}
|
|
// Don't create a default config file; only load it if it was
|
|
// manually placed there by an internal robot developer
|
|
static _loadLocalConfigOnRobot() {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
if (yield prify((cb) => {
|
|
fs.exists(Log._localConfigPath, cb);
|
|
}, false)) {
|
|
try {
|
|
Log._localConfig = JSON.parse(yield prify((cb) => {
|
|
fs.readFile(Log._localConfigPath, 'utf-8', cb);
|
|
}));
|
|
Log._loadConfig(Log._localConfig);
|
|
Log._jiboLog.debug(`Loaded local config from ${Log._localConfigPath}`);
|
|
}
|
|
catch (err) {
|
|
Log._jiboLog.warn(`Could not load logging config file ${Log._localConfigPath}`, err);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
// If not on a robot, read a user config file from their home/.jibo
|
|
// directory; place one there if there isn't already one there, for
|
|
// convenience
|
|
static _loadLocalConfigOffRobot() {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
// If there's a config file, load it up
|
|
if (yield prify((cb) => {
|
|
fs.exists(Log._localConfigPath, cb);
|
|
}, false)) {
|
|
try {
|
|
Log._loadConfig(JSON.parse(yield prify((cb) => {
|
|
fs.readFile(Log._localConfigPath, 'utf-8', cb);
|
|
})));
|
|
Log._jiboLog.debug(`Loaded local config from ${Log._localConfigPath}`);
|
|
}
|
|
catch (err) {
|
|
Log._jiboLog.warn(`Could not load logging config file ${Log._localConfigPath}`, err);
|
|
}
|
|
}
|
|
else {
|
|
yield Log.saveConfig();
|
|
}
|
|
});
|
|
}
|
|
// Chop off the last part of the namespace, including its delimiter
|
|
static _parentNamespace(namespace) {
|
|
const lastSlash = namespace.lastIndexOf(NAMESPACE_DELIMITER);
|
|
return lastSlash > -1
|
|
? namespace.slice(0, lastSlash)
|
|
: '';
|
|
}
|
|
/**
|
|
* Whether or not to log globally uncaught exceptions
|
|
* @static
|
|
* @name Log.logUncaughtExceptions
|
|
* @type {boolean}
|
|
*/
|
|
static set logUncaughtExceptions(log) {
|
|
Log._globalErrorHandler.logUncaughtExceptions = log;
|
|
}
|
|
static get logUncaughtExceptions() {
|
|
return Log._globalErrorHandler.logUncaughtExceptions;
|
|
}
|
|
/**
|
|
* Whether or not to log globally unhandled promise rejections
|
|
* @static
|
|
* @name Log.logUnhandledRejections
|
|
* @type {boolean}
|
|
*/
|
|
static set logUnhandledRejections(log) {
|
|
Log._globalErrorHandler.logUnhandledRejections = log;
|
|
}
|
|
static get logUnhandledRejections() {
|
|
return Log._globalErrorHandler.logUnhandledRejections;
|
|
}
|
|
// Check to see if the first level is greater than or equal to the second.
|
|
static _levelGreaterOrEqual(levelOne, levelTwo) {
|
|
return Level_1.levelOrder.indexOf(levelOne) >= Level_1.levelOrder.indexOf(levelTwo);
|
|
}
|
|
/**
|
|
* A reference to the top level logger instance with namespace ''
|
|
* @name Log#global
|
|
* @type {Log}
|
|
*/
|
|
get global() { return Log.global; }
|
|
/**
|
|
* Configuration for the output of this logger
|
|
* @readonly
|
|
* @name Log#outputs
|
|
* @type {LogOutputs}
|
|
*/
|
|
get outputs() {
|
|
return new LogOutputs_1.default(this);
|
|
}
|
|
/**
|
|
* Creates a new Log instance with namespace `this.namespace + '/' +
|
|
* subNamespace`
|
|
* @method Log#createChild
|
|
* @param {string} subNamespace New namespace which will be appended to
|
|
* the parent namespace
|
|
* @return {Log}
|
|
*/
|
|
createChild(subNamespace) {
|
|
const log = new Log(subNamespace, this);
|
|
log.robotID = this.robotID;
|
|
log.transID = this.transID;
|
|
return log;
|
|
}
|
|
set outputPerNamespace(outputPerNamespaceIn) {
|
|
if (outputPerNamespaceIn) {
|
|
Object.keys(outputPerNamespaceIn).forEach((namespace) => {
|
|
const outputPerNamespace = Log._staticNamespaceLevels
|
|
? Log._outputPerNamespace
|
|
: this._outputPerNamespace;
|
|
const levelPerOutput = outputPerNamespace[namespace] = {};
|
|
const levelPerOutputIn = outputPerNamespaceIn[namespace];
|
|
Object.keys(levelPerOutputIn).forEach((output) => {
|
|
levelPerOutput[output] = levelPerOutputIn[output];
|
|
});
|
|
});
|
|
}
|
|
}
|
|
/**
|
|
* Set the minimum logging level for a given output for this namespace
|
|
* This is generally not invoked directly, but by LogOutputs by setting
|
|
* one of the properties of the outputs property of a log instance
|
|
* e.g. `log.outputs.console = 'debug';`
|
|
* @method Log#setLevelForOutput
|
|
* @param {Output} output The output for which to set the level
|
|
* @param {Level} level The level to which to set the output
|
|
* @return {void}
|
|
*/
|
|
setLevelForOutput(output, level) {
|
|
const outputPerNamespace = Log._staticNamespaceLevels
|
|
? Log._outputPerNamespace
|
|
: this._outputPerNamespace;
|
|
if (!outputPerNamespace[this.namespace]) {
|
|
outputPerNamespace[this.namespace] = {};
|
|
}
|
|
outputPerNamespace[this.namespace][output.toString()] = level;
|
|
}
|
|
/**
|
|
* Check minimum logging level for each output channel for this log's
|
|
* namespace, and log the message if this level is debug or lower
|
|
* @method Log#debug
|
|
* @param {any[]} ...args The arguments to log
|
|
* @return {Log} Instance of log for chaining
|
|
*/
|
|
debug(...args) {
|
|
return this._log(types_1.Level.debug, ...args);
|
|
}
|
|
/**
|
|
* Check minimum logging level for each output channel for this log's
|
|
* namespace, and log the message if this level is info or lower
|
|
* @method Log#info
|
|
* @param {any[]} ...args The arguments to log
|
|
* @return {Log} Instance of log for chaining
|
|
*/
|
|
info(...args) {
|
|
return this._log(types_1.Level.info, ...args);
|
|
}
|
|
/**
|
|
* Check minimum logging level for each output channel for this log's
|
|
* namespace, and log the message if this level is warn or lower
|
|
* @method Log#warn
|
|
* @param {any[]} ...args The arguments to log
|
|
* @return {Log} Instance of log for chaining
|
|
*/
|
|
warn(...args) {
|
|
return this._log(types_1.Level.warn, ...args);
|
|
}
|
|
/**
|
|
* Check minimum logging level for each output channel for this log's
|
|
* namespace, and log the message if this level isn't none
|
|
* @method Log#error
|
|
* @param {any[]} ...args The arguments to log
|
|
* @return {Log} Instance of log for chaining
|
|
*/
|
|
error(...args) {
|
|
return this._log(types_1.Level.error, ...args);
|
|
}
|
|
/**
|
|
* A synonym for Log#debug
|
|
* @method Log#log
|
|
* @param {any[]} ...args The arguments to log
|
|
* @return {Log} Instance of log for chaining
|
|
*/
|
|
log(...args) {
|
|
this.debug(...args);
|
|
return this;
|
|
}
|
|
/**
|
|
* Log the error if it is set
|
|
* @method Log#iferr
|
|
* @param {Error|String} err The error which is checked and logged if
|
|
* truthy
|
|
* @param {any[]} [...args] Additional arguments to log along with err
|
|
* @return {Log} Instance of log for chaining
|
|
*/
|
|
iferr(err, ...args) {
|
|
if (err) {
|
|
args.push(err); // add the error to the end
|
|
this.error(...args);
|
|
}
|
|
return this;
|
|
}
|
|
/**
|
|
* Get the minimum logging level for the given output for this namespace.
|
|
* If a level isn't set for the namespace, it checks its parent namespace
|
|
* and so on until it finds one, or uses the global namespace.
|
|
* @method Log#getLevelForOutput
|
|
* @param {Output} output The output channel for which to get the level
|
|
*/
|
|
getLevelForOutput(output) {
|
|
let namespace = this.namespace;
|
|
const outputPerNamespace = Log._staticNamespaceLevels
|
|
? Log._outputPerNamespace
|
|
: this._outputPerNamespace;
|
|
let config = outputPerNamespace[namespace];
|
|
while (!(config && config[output.toString()])) {
|
|
if (!namespace || namespace.length < 1) {
|
|
break;
|
|
}
|
|
namespace = Log._parentNamespace(namespace);
|
|
config = outputPerNamespace[namespace];
|
|
}
|
|
return config && config[output.toString()]
|
|
? config[output.toString()]
|
|
: types_1.Level.none;
|
|
}
|
|
// Check minimum logging level for each output channel for this log's
|
|
// namespace, and log the message if the passed-in level is greater than or
|
|
// equal to the minimum logging level for the output
|
|
_log(level, ...args) {
|
|
Object.keys(Log._outputHandlers).forEach((output) => {
|
|
if (Log._levelGreaterOrEqual(level, this.getLevelForOutput(types_1.Output[output]))) {
|
|
Log._outputHandlers[output].write(new Date(), this.robotID, this.transID, Log.processName, Log.release, this.namespace ? `${Log.topLevelNamespace}.${this.namespace}` : Log.topLevelNamespace, level, ...args);
|
|
}
|
|
});
|
|
return this;
|
|
}
|
|
}
|
|
/**
|
|
* Current version of the library.
|
|
* @static
|
|
* @readonly
|
|
* @name Log.version
|
|
* @type {string}
|
|
*/
|
|
Log.version = '5.0.6';
|
|
/**
|
|
* The global logger, with empty namespace
|
|
* @static
|
|
* @readonly
|
|
* @name Log.global
|
|
* @type {string}
|
|
*/
|
|
Log.global = new Log();
|
|
/**
|
|
* Current version of the Jibo platform release.
|
|
* Can be overridden, for instance to be the version of a cloud skill
|
|
* instead of a robot
|
|
* @static
|
|
* @name Log.release
|
|
* @type {string}
|
|
*/
|
|
Log.release = getPlatformVersion_1.default().version;
|
|
/**
|
|
* Name of the currently running process, sent to syslog in the ProcessName
|
|
* header; should be set by each process during its initialization
|
|
* @static
|
|
* @name Log.processName
|
|
* @type {string}
|
|
*/
|
|
Log.processName = process.argv0;
|
|
/**
|
|
* The top-level namespace, added to the front of the namespace in
|
|
* syslog and file output; should be set by each process during its
|
|
* initialization
|
|
* @static
|
|
* @name Log.topLevelNamespace
|
|
* @type {string}
|
|
*/
|
|
Log.topLevelNamespace = 'T';
|
|
// Local logger for use only from this class
|
|
Log._jiboLog = new Log('Jibo.Log');
|
|
// Whether or not the default logging config has been loaded
|
|
Log._initialized = false;
|
|
// Whether or not to skip loading local logging configuration (for tests)
|
|
Log._skipLocalConfig = false;
|
|
// Whether to keep output levels per namespace statically or per instance
|
|
Log._staticNamespaceLevels = true;
|
|
// Global logging configuration, usually loaded from JSON
|
|
// Holds the minimum logging levels per output, per namespace
|
|
Log._outputPerNamespace = {};
|
|
// A special logger just for unhandled exceptions
|
|
Log._unhandledExceptionLogger = new Log('Unhandled');
|
|
Log._uncaughtMap = {};
|
|
// Global error handler, for globally uncaught exceptions and globally
|
|
// unhandled rejections
|
|
Log._globalErrorHandler = new utils_1.GlobalErrorHandler((...args) => {
|
|
const message = args[0] instanceof Error ? args[0].message : args[0];
|
|
let firstLog = false;
|
|
if (Log._uncaughtMap[message] === undefined) {
|
|
firstLog = true;
|
|
Log._uncaughtMap[message] = Date.now();
|
|
}
|
|
// //only log every 5 minutes if happening at 30fps
|
|
if (Date.now() - Log._uncaughtMap[message] > 60000 || firstLog) {
|
|
Log._unhandledExceptionLogger.error(...args);
|
|
Log._uncaughtMap[message] = Date.now();
|
|
}
|
|
});
|
|
Log.formatItem = utils_1.formatItem;
|
|
// These are here for testing purposes only
|
|
Log.ConsoleHandler = output_handlers_1.ConsoleHandler;
|
|
//static FileHandler = FileHandler;
|
|
Log.SyslogHandler = output_handlers_1.SyslogHandler;
|
|
exports.default = Log;
|
|
|
|
},{"./LogOutputs":2,"./defaultConfig":4,"./output-handlers":9,"./types":12,"./types/Level":10,"./utils":18,"./utils/PromiseUtils":14,"./utils/getPlatformVersion":16,"fs":undefined,"fs-extra":undefined,"os":undefined,"os-homedir":undefined,"path":undefined}],2:[function(require,module,exports){
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const types_1 = require("./types");
|
|
/**
|
|
* LogOutputs class - logging level for each output channel
|
|
* @class LogOutputs
|
|
* @param {Log} [_log] The log on which this is the outputs property
|
|
* @param {string} [_namespace?] Defaults to the log's namespace, but overridable
|
|
*/
|
|
class LogOutputs {
|
|
constructor(_log) {
|
|
this._log = _log;
|
|
if (!this._log) {
|
|
throw new Error('log is a required parameter');
|
|
}
|
|
}
|
|
/**
|
|
* Set the logging level for all output channels at once
|
|
* @name LogOutputs#all
|
|
* @type {Level}
|
|
*/
|
|
set all(level) {
|
|
this.console = level;
|
|
this.file = level;
|
|
this.pegasus = level;
|
|
this.syslog = level;
|
|
}
|
|
/**
|
|
* The logging level for the console output channel
|
|
* @name LogOutputs#console
|
|
* @type {Level}
|
|
*/
|
|
set console(level) {
|
|
this._log.setLevelForOutput(types_1.Output.console, level);
|
|
}
|
|
get console() {
|
|
return this._log.getLevelForOutput(types_1.Output.console);
|
|
}
|
|
/**
|
|
* The logging level for the file output channel
|
|
* @name LogOutputs#file
|
|
* @type {Level}
|
|
*/
|
|
set file(level) {
|
|
this._log.setLevelForOutput(types_1.Output.file, level);
|
|
}
|
|
get file() {
|
|
return this._log.getLevelForOutput(types_1.Output.file);
|
|
}
|
|
/**
|
|
* The logging level for the Pegasus output channel
|
|
* @name LogOutputs#pegasus
|
|
* @type {Level}
|
|
*/
|
|
set pegasus(level) {
|
|
this._log.setLevelForOutput(types_1.Output.pegasus, level);
|
|
}
|
|
get pegasus() {
|
|
return this._log.getLevelForOutput(types_1.Output.pegasus);
|
|
}
|
|
/**
|
|
* The logging level for the syslog output channel
|
|
* @name LogOutputs#syslog
|
|
* @type {Level}
|
|
*/
|
|
set syslog(level) {
|
|
this._log.setLevelForOutput(types_1.Output.syslog, level);
|
|
}
|
|
get syslog() {
|
|
return this._log.getLevelForOutput(types_1.Output.syslog);
|
|
}
|
|
}
|
|
exports.default = LogOutputs;
|
|
|
|
},{"./types":12}],3:[function(require,module,exports){
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
global.Singletons = global.Singletons || {};
|
|
class Singletons {
|
|
static enforce(candidate) {
|
|
let singleton = candidate;
|
|
let singletonName = candidate.name;
|
|
if (!global.Singletons[singletonName]) {
|
|
global.Singletons[singletonName] = singleton;
|
|
}
|
|
else {
|
|
singleton = global.Singletons[singletonName];
|
|
// let's only warn if the versions don't match
|
|
// console.warn(
|
|
// 'Singletons: using existing singleton',
|
|
// singletonName
|
|
// );
|
|
// optionally check if versions match (and warn if not)
|
|
if (candidate.version) {
|
|
let candidateVersion = candidate.version;
|
|
let singletonVersion = singleton.version;
|
|
if (typeof candidate.version === 'function') {
|
|
candidateVersion = candidate.version();
|
|
}
|
|
if (typeof singleton.version === 'function') {
|
|
singletonVersion = singleton.version();
|
|
}
|
|
if (candidateVersion !== singletonVersion) {
|
|
console.log(singletonName, 'singleton: existing version', singletonVersion, 'does not equal candidate version', candidateVersion);
|
|
}
|
|
}
|
|
}
|
|
return singleton;
|
|
}
|
|
}
|
|
exports.default = Singletons;
|
|
|
|
},{}],4:[function(require,module,exports){
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const types_1 = require("./types");
|
|
exports.default = {
|
|
staticNamespaceLevels: true,
|
|
logUncaughtExceptions: true,
|
|
logUnhandledRejections: true,
|
|
stackTraceLimit: 30,
|
|
skipLocalConfig: false,
|
|
outputs: {
|
|
console: {
|
|
outputFileAndLine: false,
|
|
outputLevel: false,
|
|
},
|
|
syslog: {
|
|
port: 514,
|
|
target: "127.0.0.1",
|
|
outputFileAndLine: false,
|
|
}
|
|
},
|
|
namespaces: {
|
|
'': {
|
|
console: types_1.Level.info,
|
|
file: types_1.Level.none,
|
|
syslog: types_1.Level.info,
|
|
},
|
|
},
|
|
};
|
|
|
|
},{"./types":12}],5:[function(require,module,exports){
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const types_1 = require("../types");
|
|
const OutputHandler_1 = require("./OutputHandler");
|
|
/**
|
|
* Output channel that logs to global.console or equivalent interface
|
|
* @class ConsoleHandler
|
|
* @extends OutputHandler
|
|
* @param {Console} [console = global.console] You may pass a alternative console
|
|
*/
|
|
class ConsoleHandler extends OutputHandler_1.default {
|
|
constructor(_console = global.console) {
|
|
super();
|
|
this._console = _console;
|
|
}
|
|
write(timestamp, robotID, transID, processName, release, namespace, level, ...args) {
|
|
const stringArgs = [];
|
|
// Place the log-level in front of everything, if required
|
|
if (this._config && this._config.outputLevel) {
|
|
stringArgs.push(`[${level}]`);
|
|
}
|
|
if (this._config && this._config.outputRobotAndTransIDs) {
|
|
stringArgs.push(robotID || '-');
|
|
stringArgs.push(transID || '-');
|
|
}
|
|
stringArgs.push(namespace);
|
|
// If the first argument passed by the code author is a string,
|
|
// include it in the paramenters to splice together into a single arg
|
|
const firstArgString = args.length && typeof args[0] === 'string';
|
|
if (firstArgString) {
|
|
stringArgs.push(args[0]);
|
|
}
|
|
const logArgs = [
|
|
// Splice the string arguments in front into a single item, to
|
|
// allow for the Console to honor string substitutions
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/console#Outputting_text_to_the_console
|
|
stringArgs.join(' '),
|
|
// If the first argument is a string, it's already been included
|
|
...(firstArgString ? args.slice(1) : args),
|
|
// Add the output filename and line to the end, if configured
|
|
...(this._config && this._config.outputFileAndLine
|
|
// The first four items on the stack are from jibo-log:
|
|
// 1. Log#debug/info/warn/error
|
|
// 2. Log#_log
|
|
// 3. forEach(output: OutputHandler)
|
|
// 4. OutputHandler#write
|
|
? [new Error().stack.split('\n')[4]]
|
|
: []),
|
|
];
|
|
switch (level) {
|
|
case types_1.Level.debug:
|
|
this._console.log(...logArgs);
|
|
break;
|
|
case types_1.Level.info:
|
|
this._console.info(...logArgs);
|
|
break;
|
|
case types_1.Level.warn:
|
|
this._console.warn(...logArgs);
|
|
break;
|
|
case types_1.Level.error:
|
|
this._console.error(...logArgs);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
exports.default = ConsoleHandler;
|
|
|
|
},{"../types":12,"./OutputHandler":7}],6:[function(require,module,exports){
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const utils_1 = require("../utils");
|
|
const osHomedir = require("os-homedir");
|
|
const OutputHandler_1 = require("./OutputHandler");
|
|
const path = require("path");
|
|
const RFS = require("rotating-file-stream");
|
|
const DEFAULT_CONFIG = Object.freeze({
|
|
filename: null,
|
|
size: '10M',
|
|
compress: true,
|
|
outputFileAndLine: false,
|
|
});
|
|
/**
|
|
* Output channel that logs to the filesystem
|
|
* @class FileHandler
|
|
*/
|
|
class FileHandler extends OutputHandler_1.default {
|
|
constructor() {
|
|
super();
|
|
// If FileConfig ever goes below depth one, this will need to be
|
|
// changed to a deep copy (lodash.assign)
|
|
this._config = Object.freeze(Object.assign({}, DEFAULT_CONFIG));
|
|
}
|
|
write(time, robotID, transID, processName, release, namespace, level, ...args) {
|
|
// only write to file if the writable stream is initialized
|
|
if (this._stream) {
|
|
const timestamp = time.toISOString();
|
|
const items = [
|
|
...args.map(item => utils_1.formatItem(item)),
|
|
...(this._config.outputFileAndLine
|
|
? [new Error().stack.split('\n')[4]]
|
|
: []),
|
|
];
|
|
const message = `${namespace}: ${items.join(' ')}`;
|
|
const versions = `[versions@1 release="${release}"]`;
|
|
const transaction = transID ? `[messageContext@1 transID="${transID}"]` : '';
|
|
const structuredData = `${versions}${transaction}`;
|
|
const fullText = `${timestamp} ${robotID || '-'} ${processName}[${process.pid},${level}]: ${structuredData || '-'} ${message}\n`;
|
|
this._stream._write(fullText, 'utf-8', console.error);
|
|
}
|
|
}
|
|
/**
|
|
* The filesystem output configuration for this handler
|
|
* @name FileHandler#config
|
|
* @type {FileConfig}
|
|
*/
|
|
set config(config) {
|
|
const oldConfig = this._config;
|
|
this._config = Object.freeze(Object.assign({}, this._config, config));
|
|
if (this._stream) {
|
|
this._stream.end();
|
|
}
|
|
if (config.filename && oldConfig.filename !== config.filename) {
|
|
if (config.filename.length > 0) {
|
|
try {
|
|
this._createStream();
|
|
}
|
|
catch (err) {
|
|
console.warn('Error opening log file for output,', err);
|
|
}
|
|
}
|
|
else {
|
|
// rotating-file-stream doesn't provide a way to close the file
|
|
// lame.
|
|
this._stream = null;
|
|
}
|
|
}
|
|
}
|
|
get config() {
|
|
return this._config;
|
|
}
|
|
_createStream() {
|
|
const filePath = path.resolve(this._config.filename.startsWith('~/')
|
|
? path.join(osHomedir(), this._config.filename.slice(2))
|
|
: this._config.filename);
|
|
const options = {};
|
|
if (this._config.size) {
|
|
options.size = this._config.size;
|
|
}
|
|
if (this._config.interval) {
|
|
options.interval = this._config.interval;
|
|
}
|
|
if (this._config.compress) {
|
|
options.compress = 'gzip';
|
|
}
|
|
this._stream = new RFS(filePath, options);
|
|
}
|
|
}
|
|
exports.default = FileHandler;
|
|
|
|
},{"../utils":18,"./OutputHandler":7,"os-homedir":undefined,"path":undefined,"rotating-file-stream":undefined}],7:[function(require,module,exports){
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
/**
|
|
* OutputHandler class - logging to global.console
|
|
* @abstract
|
|
* @class ConsoleHandler
|
|
* @extends OutputHandler
|
|
*/
|
|
class OutputHandler {
|
|
/**
|
|
* The output configuration for this handler
|
|
* @name OutputHandler#config
|
|
* @type {Config}
|
|
*/
|
|
set config(config) {
|
|
this._config = config;
|
|
}
|
|
get config() {
|
|
return this._config;
|
|
}
|
|
/**
|
|
* Flush any log lines this handler caches; default to no behavior
|
|
* @return {Promise<void>} Resolves when the flush is complete
|
|
*/
|
|
flush() {
|
|
return Promise.resolve();
|
|
}
|
|
}
|
|
exports.default = OutputHandler;
|
|
|
|
},{}],8:[function(require,module,exports){
|
|
"use strict";
|
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
});
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const utils_1 = require("../utils");
|
|
const types_1 = require("../types");
|
|
const OutputHandler_1 = require("./OutputHandler");
|
|
const Syslog = require("syslog2-pure-js");
|
|
// Default configuration
|
|
const DEFAULT_CONFIG = Object.freeze({
|
|
port: 514,
|
|
target: '127.0.0.1',
|
|
outputFileAndLine: false,
|
|
});
|
|
const FACILITY = 'local0';
|
|
/**
|
|
* Output channel that logs to syslog (/var/log/messages)
|
|
* Only enabled on linux/arm (e.g. Jibo robot)
|
|
* @class SyslogHandler
|
|
*/
|
|
class SyslogHandler extends OutputHandler_1.default {
|
|
static _toStructuredData(err) {
|
|
return Object.getOwnPropertyNames(err).reduce((obj, key) => Object.assign({}, obj, {
|
|
[key === 'stack' ? 'frames' : key]: (key === 'stack'
|
|
? JSON.stringify(SyslogHandler._getStackFrames(err))
|
|
: err[key])
|
|
}), {});
|
|
}
|
|
static _getStackFrames(err) {
|
|
return err.stack
|
|
.split('\n').slice(1)
|
|
.map(str => str
|
|
.replace(/^ at /, '')
|
|
.replace(/\)$/, '')
|
|
.split(' ('))
|
|
.map(frame => frame.length > 1 ? frame : ['', ...frame])
|
|
.map(frame => [frame[0], ...frame[1].split(':')])
|
|
.map(frame => {
|
|
return {
|
|
method: frame[0],
|
|
filename: frame[1],
|
|
line: parseInt(frame[2]),
|
|
column: parseInt(frame[3]),
|
|
};
|
|
});
|
|
}
|
|
constructor() {
|
|
super();
|
|
// don't bother on anything other than our linux/arm environment
|
|
this._enabled = process.platform === 'linux' && process.arch === 'arm';
|
|
// If SyslogConfig ever goes below depth one, this will need to be
|
|
// changed to a deep copy (lodash.assign)
|
|
this._config = Object.freeze(Object.assign({}, DEFAULT_CONFIG));
|
|
}
|
|
write(date, robotID, transID, processName, release, namespace, level, ...args) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
// only write to syslog if it's enabled
|
|
if (this._enabled) {
|
|
// Create a client if there isn't one already
|
|
if (!this._client) {
|
|
try {
|
|
yield this._createClient();
|
|
}
|
|
catch (err) {
|
|
return console.warn('Error connecting to syslog', err);
|
|
}
|
|
}
|
|
const appName = processName;
|
|
const errors = {};
|
|
// Pull errors out of message and into structured data with
|
|
// structured stack traces
|
|
const unformattedItems = args.reduce((items, item, index) => {
|
|
if (item instanceof Error) {
|
|
errors[index] =
|
|
SyslogHandler._toStructuredData(item);
|
|
// Add the error message to the log-message body
|
|
return [...items, item.message];
|
|
}
|
|
else {
|
|
// Add the entire non-Error item to the log-message body
|
|
return [...items, item];
|
|
}
|
|
}, []);
|
|
// Format items and add file and line, if required
|
|
const logArgs = unformattedItems.map(item => utils_1.formatItem(item));
|
|
if (this._config && this._config.outputFileAndLine) {
|
|
// The first four items on the stack are from jibo-log:
|
|
// 1. Log#debug/info/warn/error
|
|
// 2. Log#_log
|
|
// 3. forEach(output: OutputHandler)
|
|
// 4. OutputHandler#write
|
|
logArgs.push(new Error().stack.split('\n')[4]);
|
|
}
|
|
const message = `${namespace}: ${logArgs.join(' ')}`;
|
|
const severity = level === types_1.Level.error
|
|
? 'ERR'
|
|
: level.toString().toUpperCase();
|
|
// Build up the structured data object
|
|
const structuredData = Object.assign({}, (Object.keys(errors).length ? errors : {}), { versions: { release } }, (transID ? { messageContext: { transID } } : {}));
|
|
// Create a Glossy record for output
|
|
const record = { appName, date, message, severity, structuredData };
|
|
// Write it out to the syslog daemon
|
|
this._client.write(record);
|
|
}
|
|
});
|
|
}
|
|
/**
|
|
* The syslog output configuration for this handler
|
|
* @name SyslogHandler#config
|
|
* @type {SyslogConfig}
|
|
*/
|
|
set config(config) {
|
|
this._config = Object.freeze(Object.assign({}, this._config, config));
|
|
}
|
|
get config() {
|
|
return this._config;
|
|
}
|
|
// Create a syslog client on the configured port and IP/hostname
|
|
_createClient() {
|
|
return new Promise((resolve, reject) => {
|
|
this._client = Syslog.create({
|
|
connection: {
|
|
host: this._config.target,
|
|
port: this._config.port,
|
|
},
|
|
facility: FACILITY,
|
|
PEN: 1,
|
|
useStructuredData: true,
|
|
}, err => {
|
|
if (err) {
|
|
this._client = undefined;
|
|
reject(err);
|
|
}
|
|
else {
|
|
resolve();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
exports.default = SyslogHandler;
|
|
|
|
},{"../types":12,"../utils":18,"./OutputHandler":7,"syslog2-pure-js":undefined}],9:[function(require,module,exports){
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const ConsoleHandler_1 = require("./ConsoleHandler");
|
|
exports.ConsoleHandler = ConsoleHandler_1.default;
|
|
const FileHandler_1 = require("./FileHandler");
|
|
exports.FileHandler = FileHandler_1.default;
|
|
const OutputHandler_1 = require("./OutputHandler");
|
|
exports.OutputHandler = OutputHandler_1.default;
|
|
const SyslogHandler_1 = require("./SyslogHandler");
|
|
exports.SyslogHandler = SyslogHandler_1.default;
|
|
const types_1 = require("../types");
|
|
const consoleHandler = new ConsoleHandler_1.default();
|
|
const fileHandler = new FileHandler_1.default();
|
|
const syslogHandler = new SyslogHandler_1.default();
|
|
exports.outputHandlers = {
|
|
[types_1.Output.console]: consoleHandler,
|
|
[types_1.Output.file]: fileHandler,
|
|
[types_1.Output.syslog]: syslogHandler,
|
|
};
|
|
|
|
},{"../types":12,"./ConsoleHandler":5,"./FileHandler":6,"./OutputHandler":7,"./SyslogHandler":8}],10:[function(require,module,exports){
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
/**
|
|
* A level of logging output, debug/info/warn/error, or none
|
|
* @typedef Level
|
|
*/
|
|
var Level;
|
|
(function (Level) {
|
|
Level["none"] = "none";
|
|
Level["debug"] = "debug";
|
|
Level["info"] = "info";
|
|
Level["warn"] = "warn";
|
|
Level["error"] = "error";
|
|
})(Level || (Level = {}));
|
|
exports.default = Level;
|
|
exports.levelOrder = [
|
|
Level.debug,
|
|
Level.info,
|
|
Level.warn,
|
|
Level.error,
|
|
Level.none,
|
|
];
|
|
|
|
},{}],11:[function(require,module,exports){
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
/**
|
|
* A logging output channel, console/syslog/file
|
|
* @name Output
|
|
* @type enum
|
|
* @prop console 'console'
|
|
* @prop syslog 'syslog'
|
|
* @prop file 'file'
|
|
*/
|
|
var Output;
|
|
(function (Output) {
|
|
Output["console"] = "console";
|
|
Output["file"] = "file";
|
|
Output["pegasus"] = "pegasus";
|
|
Output["syslog"] = "syslog";
|
|
})(Output || (Output = {}));
|
|
exports.default = Output;
|
|
|
|
},{}],12:[function(require,module,exports){
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const Level_1 = require("./Level");
|
|
exports.Level = Level_1.default;
|
|
const Output_1 = require("./Output");
|
|
exports.Output = Output_1.default;
|
|
|
|
},{"./Level":10,"./Output":11}],13:[function(require,module,exports){
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const stream = require("stream");
|
|
class NullStream extends stream.Writable {
|
|
constructor(opts = {}) {
|
|
opts.objectMode = true;
|
|
super(opts);
|
|
}
|
|
_write(chunk, encoding, cb) {
|
|
cb();
|
|
return true;
|
|
}
|
|
}
|
|
exports.default = NullStream;
|
|
|
|
},{"stream":undefined}],14:[function(require,module,exports){
|
|
"use strict";
|
|
/**
|
|
* @fileOverview
|
|
*
|
|
* Created on 5/12/16.
|
|
* @author Siggi Orn <siggi@jibo.com>
|
|
*/
|
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
});
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
class PromiseUtils {
|
|
/**
|
|
* Returns promise that succeeds when the first input promise succeeds
|
|
* If all input promises fail, then the returned promise fails.
|
|
* @param {Promise<T>[]} promises
|
|
* @returns {Promise<T>}
|
|
*/
|
|
static firstToSucceed(promises) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
return new Promise((res, rej) => {
|
|
let errors = [];
|
|
let errorCount = 0;
|
|
for (let i = 0; i < promises.length; i++) {
|
|
promises[i].then(res).catch(e => {
|
|
errors[i] = e;
|
|
errorCount++;
|
|
if (errorCount === promises.length) {
|
|
rej(errors);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
}
|
|
static promisify(func, firstParamError = true) {
|
|
return new Promise((resolve, reject) => {
|
|
func((error, result) => {
|
|
if (firstParamError) {
|
|
if (error) {
|
|
reject(error);
|
|
}
|
|
else {
|
|
resolve(result);
|
|
}
|
|
}
|
|
else {
|
|
resolve(error);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
exports.PromiseUtils = PromiseUtils;
|
|
|
|
},{}],15:[function(require,module,exports){
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const util = require("util");
|
|
const format_error_1 = require("format-error");
|
|
// Format the passed object for string output
|
|
const FORMAT_ERROR_OPTIONS = {
|
|
noColor: true
|
|
};
|
|
const INSPECT_OPTIONS = {
|
|
depth: 3,
|
|
maxArrayLength: 10,
|
|
};
|
|
function _formatError(error) {
|
|
return _formatObject(format_error_1.format(error, FORMAT_ERROR_OPTIONS));
|
|
}
|
|
function _formatObject(obj) {
|
|
return util.inspect(obj, INSPECT_OPTIONS);
|
|
}
|
|
/**
|
|
* Format the passed item as a single-line string for logging (i.e. syslog)
|
|
* @function formatItem
|
|
* @param args {any[]} Item to format
|
|
* @return {string} Formatted line, ready for logging
|
|
*/
|
|
function formatItem(item) {
|
|
// If the object has a method specifically for logging usage, then use that
|
|
// instead of the original
|
|
const preformatted = item && typeof item.toLog === 'function' ? item.toLog() : item;
|
|
const message = typeof preformatted === 'string' ? preformatted.trim() :
|
|
preformatted instanceof Error ? _formatError(preformatted) :
|
|
_formatObject(preformatted);
|
|
return message
|
|
.replace(/\\n/g, '\\\\n')
|
|
.replace(/\r?\n/g, '\\n');
|
|
}
|
|
exports.formatItem = formatItem;
|
|
|
|
},{"format-error":undefined,"util":undefined}],16:[function(require,module,exports){
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
function getPlatformVersion() {
|
|
// Get the platform build version
|
|
let tbd;
|
|
try {
|
|
tbd = require('/opt/jibo/Jibo/Skills/jibo-tbd/package.json');
|
|
}
|
|
catch (err) {
|
|
tbd = { version: '8.67.5309' };
|
|
}
|
|
return tbd;
|
|
}
|
|
exports.default = getPlatformVersion;
|
|
|
|
},{"/opt/jibo/Jibo/Skills/jibo-tbd/package.json":undefined}],17:[function(require,module,exports){
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
/**
|
|
* Utility class to handle globally-uncaught exceptions and globally-unhandled
|
|
* promise rejections
|
|
* @class GlobalErrorHandler
|
|
* @param {string|Error} handleError Callback where errors are sent
|
|
*/
|
|
class GlobalErrorHandler {
|
|
constructor(handleError) {
|
|
this._handleError = handleError;
|
|
}
|
|
// Log uncaught exceptions caught by process
|
|
_uncaughtExceptionProcessLogger(error) {
|
|
this._handleError(error);
|
|
}
|
|
// Log uncaught exceptions caught by window
|
|
_uncaughtExceptionWindowLogger(message, filename, lineno, colno, error) {
|
|
this._handleError(`${message}, source: ${filename}, line: ${lineno}, column: ${colno}`, error);
|
|
}
|
|
/**
|
|
* Whether or not to log globally uncaught exceptions
|
|
* @name GlobalErrorHandler.logUncaughtExceptions
|
|
* @type {boolean}
|
|
*/
|
|
set logUncaughtExceptions(log) {
|
|
if (log && !this._loggingUncaughtExceptions) {
|
|
if (typeof window !== 'undefined') {
|
|
window.onerror = this._uncaughtExceptionWindowLogger.bind(this);
|
|
}
|
|
else {
|
|
process.on('uncaughtException', this._uncaughtExceptionProcessLogger.bind(this));
|
|
}
|
|
}
|
|
else if (!log && this._loggingUncaughtExceptions) {
|
|
if (typeof window !== 'undefined') {
|
|
window.onerror = null;
|
|
}
|
|
else {
|
|
process.removeListener('uncaughtException', this._uncaughtExceptionProcessLogger);
|
|
}
|
|
}
|
|
this._loggingUncaughtExceptions = log;
|
|
}
|
|
get logUncaughtExceptions() {
|
|
return this._loggingUncaughtExceptions;
|
|
}
|
|
// Log unhandled promise rejections caught by process
|
|
_unhandledRejectionProcessLogger(error) {
|
|
this._handleError(error);
|
|
}
|
|
// In electron, unhandledrejection event is on window, not process, and
|
|
// the callback signature is different
|
|
_unhandledRejectionWindowLogger(event) {
|
|
this._handleError(event.reason);
|
|
}
|
|
/**
|
|
* Whether or not to log globally unhandled promise rejections
|
|
* @name GlobalErrorHandler.logUnhandledRejections
|
|
* @type {boolean}
|
|
*/
|
|
set logUnhandledRejections(log) {
|
|
if (log && !this._loggingUnhandledRejections) {
|
|
if (typeof window !== 'undefined') {
|
|
window.onunhandledrejection =
|
|
this._unhandledRejectionWindowLogger.bind(this);
|
|
}
|
|
else {
|
|
process.on('unhandledRejection', this._unhandledRejectionProcessLogger.bind(this));
|
|
}
|
|
}
|
|
else if (!log && this._loggingUnhandledRejections) {
|
|
if (typeof window !== 'undefined') {
|
|
window.onunhandledrejection = null;
|
|
}
|
|
else {
|
|
process.removeListener('unhandledRejection', this._unhandledRejectionProcessLogger);
|
|
}
|
|
}
|
|
this._loggingUnhandledRejections = log;
|
|
}
|
|
get logUnhandledRejections() {
|
|
return this._loggingUnhandledRejections;
|
|
}
|
|
}
|
|
exports.GlobalErrorHandler = GlobalErrorHandler;
|
|
|
|
},{}],18:[function(require,module,exports){
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const formatting_1 = require("./formatting");
|
|
exports.formatItem = formatting_1.formatItem;
|
|
const global_errors_1 = require("./global-errors");
|
|
exports.GlobalErrorHandler = global_errors_1.GlobalErrorHandler;
|
|
const NullStream_1 = require("./NullStream");
|
|
exports.NullStream = NullStream_1.default;
|
|
const PromiseUtils_1 = require("./PromiseUtils");
|
|
exports.PromiseUtils = PromiseUtils_1.PromiseUtils;
|
|
|
|
},{"./NullStream":13,"./PromiseUtils":14,"./formatting":15,"./global-errors":17}],19:[function(require,module,exports){
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const output_handlers_1 = require("./output-handlers");
|
|
exports.OutputHandler = output_handlers_1.OutputHandler;
|
|
const types_1 = require("./types");
|
|
exports.Level = types_1.Level;
|
|
exports.Output = types_1.Output;
|
|
const Log_1 = require("./Log");
|
|
const LogOutputs_1 = require("./LogOutputs");
|
|
exports.LogOutputs = LogOutputs_1.default;
|
|
const Singletons_1 = require("./Singletons");
|
|
const Log = Singletons_1.default.enforce(Log_1.default);
|
|
exports.Log = Log;
|
|
Log.initialize();
|
|
|
|
},{"./Log":1,"./LogOutputs":2,"./Singletons":3,"./output-handlers":9,"./types":12}]},{},[19])(19)
|
|
});
|
|
|
|
//# sourceMappingURL=jibo-log.js.map
|