Jibo Log - Centralized logging facility ======================================= A module to centralize and control (and log to syslog or files) all logging messages. Use this everywhere instead of `console.log` and friends. To use: ```js const {Log} = require('jibo-log'); const log = new Log('my-namespace'); log.debug('this is a debug'); log.info('this is an info'); log.warn('this is a warning'); log.error('this is an error'); ``` Use `log.debug`, `log.info`, `log.warn`, `log.error`, instead of `console.log` and friends. `log.log` is also available, but it's just an alias for log.debug and is there mainly for compatibility with the console object. You specify a string to act as the name space of your log messages in the `new Log()` constructor call. The name space will appear in front of all your log messages. Each name space can be configured to show or discard messages above/below a certain level, and separately for each output channel (i.e. console, syslog, or file). `jibo-log` creates a hierarchy of namespaces, separated by slashes, and a lower-level namespace inherits the configuration of its closest ancestor, and may override that configuration. The level order is `debug` < `info` < `warn` < `error`. By default `debug` messages are not printed to the syslog or console, but `info` and above are. Syslog messages --------------- By default, syslog messages are enabled at the `info` level. However, note that they will only truly be turned on if and only if the current process's platform is `linux` and architecture is `arm`. Error logging helper -------------------- `log.iferr(err, [message])` A common JavaScript (and especially Node.js) convention is to indicate an error condition as the first argument in a callback (usually named `err` by convention). Frequently you want to log that such errors happened, but many times it doesn't affect your program flow because you still need to call some callback that you were given and are just going to pass the error upward. `log.iferr()` prints your message (at the `error` level) only if `err` is truthy. Your message is *followed* by `err` stringified. Use this: ```js log.iferr(err, 'error happened'); ``` Instead of this: ```js if (err) { log.error('error happened', err); } ``` Your code will be more readable (and you can save a bunch of typing). Logging uncaught exceptions --------------------------- `jibo-log` registers a listener for `uncaughtExceptions` so they can be logged. It will log the details of the exception and then re-throw the exception. It also registers a listener for unhandled promise errors. It seems that handling uncaughtExceptions can sometimes confuse the stack information about where the original exception happened. If you are debugging such an issue you can temporarily disable this functionality: ```js Log.logUncaughtExceptions = false; Log.logUnhandledRejections = false; ``` And the handlers will be uninstalled which may hopefully give you better information to help track down the problem. Please remove this call once you've resolved the issue or uncaught exceptions will not be logged and might be missed. File names and line numbers --------------------------- By default, logging to the console through `jibo-log` behaves the same way as logging directly to the global console. It will include a stack trace only if an Error object is called with `log.error`. If you are interested in seeing the filename and line number for every logging call (even `debug`, `info`, and `warn` calls), you can enable this feature by passing JSON configuration to `Log` (see the next section) with `outputs.console.outputFileAndLine` set to `true`. Logging configuration --------------------- Logging can be configured statically using a JSON file in the following format: ```json { "logUncaughtExceptions": true, "logUnhandledRejections": true, "outputs": { "console": { "outputFileAndLine": false }, "syslog": { "port": 514, "target": "127.0.0.1" }, "file": { "filename": "", "mode": "overwrite" } }, "namespaces": { "": { "console": "info", "syslog": "info" }, "Be.Radio.RadioPlayer": { "console": "debug" } } } ``` Once you've read the JSON file into an object of this format, or created one manually, you can pass it to the static `loadConfig` method on `Log` before performing any logging: ```js const fs = require('fs'); const {Log} = require('jibo-log'); Log.loadConfig(fs.readFileSync('/path/to/logging-config.json')); ``` In the `skills-service-manager`, the default configuration is specified separately for each robot mode, and can be modified per mode on a robot, in the four files found in `/usr/local/etc/jibo-ssm`. For `jibo-cli`, a default config file is created at `.jibo/t.logging.json` in your machine's home directory. If that file does not exist, run `jibo robot-list` once, and it will be created. When using Jibo's simulator, this file will be used. To use this configuration on robot, copy this file to the robot and adjust permissions with the following: ``` scp t.logging.json root@{robot-ip}:/var/jibo/ ssh root@{robot-ip} "chmod 755 /var/jibo/t.logging.json" ``` If the permissions are not set correctly, you can get this console warning: ```js Could not load logging config file /var/jibo/t.logging.json EACCES: permission denied, open '/var/jibo/t.logging.json' ```