ostrio:loggermongo

v2.1.0Published 2 years ago

support support

Logging: To MongoDB

MongoDB adapter for logger driver. Store application's logs and messages in MongoDB.

Whenever you log message(s) on Client or Sever, it goes directly into MongoDB.

Features:

  • 👷‍♂️ 100% tests coverage;
  • 💪 Flexible log level filters;
  • 👨‍💻 userId is automatically passed and logged, data is associated with logged-in user;
  • 📟 Pass logs from Client to MongoDB on Server;
  • 🕷 Catch all browser's errors and exceptions.

Installation:

meteor add ostrio:logger # If not yet installed
meteor add ostrio:loggermongo

ES6 Import:

1import { Logger } from 'meteor/ostrio:logger';
2import { LoggerMongo } from 'meteor/ostrio:loggermongo';

Usage

Initialize Logger instance and pass it into LoggerMongo constructor to enable logging into the log file.

Initialization [Isomorphic]

new LoggerMongo(LoggerInstance, options)

  • LoggerInstance {Logger} - from new Logger()
  • options {Object}
  • options.collection {Mongo.Collection} - Use to pass your own MongoDB collection instance, {Mongo.Collection} returned from new Mongo.Collection()
  • options.collectionName {String} - MongoDB collection name, default: ostrioMongoLogger
  • options.format {Function} - Must return plain object, which will be used as log-record. Arguments:
    • opts {Object}
    • opts.userId {String}
    • opts.date {Date} - Report date
    • opts.timestamp {Number} - Report timestamp in milliseconds
    • opts.level {String} - Message level, one of: ERROR, FATAL, WARN, DEBUG, INFO, TRACE, *
    • opts.message {String} - Report message
    • opts.additional {Object} - Additional info passed as object

Note: You can't pass both collection and collectionName simultaneously. Set only one of those options. If both options is presented collection is more prioritized

Example:

1import { Logger } from 'meteor/ostrio:logger';
2import { LoggerMongo } from 'meteor/ostrio:loggermongo';
3
4// Initialize Logger:
5const log = new Logger();
6
7// Initialize and enable LoggerMongo with default settings:
8(new LoggerMongo(log)).enable();

Example 2:

1import { Logger } from 'meteor/ostrio:logger';
2import { LoggerMongo } from 'meteor/ostrio:loggermongo';
3
4// Initialize Logger:
5const log = new Logger();
6const appLogs = new Mongo.Collection('appLogs');
7
8// Initialize LoggerMongo with collection instance:
9const logMongo = new LoggerMongo(log, {
10  collection: appLogs
11});
12
13// Enable LoggerMongo with default settings:
14logMongo.enable();

Example 3:

1import { Logger } from 'meteor/ostrio:logger';
2import { LoggerMongo } from 'meteor/ostrio:loggermongo';
3
4// Initialize Logger:
5const log = new Logger();
6
7// Initialize LoggerMongo with custom collection name:
8const logMongo = new LoggerMongo(log, {
9  collectionName: 'appLogs'
10});
11
12// Enable LoggerMongo with default settings:
13logMongo.enable();

Initialize with custom adapter settings: [Isomorphic]

1import { Logger } from 'meteor/ostrio:logger';
2import { LoggerMongo } from 'meteor/ostrio:loggermongo';
3
4const log = new Logger();
5(new LoggerMongo(log)).enable({
6  enable: true,
7  filter: ['ERROR', 'FATAL', 'WARN'], // Filters: 'ERROR', 'FATAL', 'WARN', 'DEBUG', 'INFO', 'TRACE', '*'
8  client: true, // Set to `false` to avoid Client to Server logs transfer
9  server: true  // Allow logging on Server
10});

Logging Collection Schema:

1({
2  userId: {
3    type: String
4  },
5  date: {
6    type: Date
7  },
8  timestamp: {
9    type: Number
10  },
11  level: {
12    type: String
13  },
14  message: {
15    type: String
16  },
17  additional: {  // <- passed object into 'data' argument
18    type: Object // upon logging will be available for search
19  }
20});

Set custom indexes on collection: [Server]

Read more at: ensureIndex docs

1import { Logger } from 'meteor/ostrio:logger';
2import { LoggerMongo } from 'meteor/ostrio:loggermongo';
3
4const log = new Logger();
5const logMongo = new LoggerMongo(log, {
6  collectionName: 'appLogs' // Use custom collection name
7});
8
9if (Meteor.isServer) {
10  // PRECAUTION: make sure you understand what you're doing and why
11  // Do not ever blindly copy-paste, see: https://github.com/veliovgroup/Meteor-logger-mongo/issues/19
12  logMongo.collection._ensureIndex({level: 1}, {background: true});
13  logMongo.collection._ensureIndex({userId: 1}, {background: true});
14  logMongo.collection._ensureIndex({date: 1}, {background: true});
15  logMongo.collection._ensureIndex({timestamp: 1}, {background: true});
16}

Log message: [Isomorphic]

1import { Logger } from 'meteor/ostrio:logger';
2import { LoggerMongo } from 'meteor/ostrio:loggermongo';
3
4const log = new Logger();
5(new LoggerMongo(log)).enable();
6
7/*
8  message {String} - Any text message
9  data    {Object} - [optional] Any additional info as object
10  userId  {String} - [optional] Current user id
11 */
12log.info(message, data, userId);
13log.debug(message, data, userId);
14log.error(message, data, userId);
15log.fatal(message, data, userId);
16log.warn(message, data, userId);
17log.trace(message, data, userId);
18log._(message, data, userId); // Shortcut
19
20// Use with throw
21throw log.error(message, data, userId);

Catch-all Client's errors example: [Client]

1/* Store original window.onerror */
2const _GlobalErrorHandler = window.onerror;
3
4window.onerror = function (msg, url, line) {
5  log.error(msg, {file: url, onLine: line});
6  if (_GlobalErrorHandler) {
7    _GlobalErrorHandler.apply(this, arguments);
8  }
9};

Catch-all Server's errors example: [Server]

1const bound = Meteor.bindEnvironment((callback) => {callback();});
2process.on('uncaughtException', function (err) {
3  bound(() => {
4    log.error('Server Crashed!', err);
5    console.error(err.stack);
6    process.exit(7);
7  });
8});

Catch-all Meteor's errors example: [Server]

1// store original Meteor error
2const originalMeteorDebug = Meteor._debug;
3Meteor._debug = function (message, stack) {
4  const additional = { message };
5  additional.stack = util.inspect(stack, false, null).split('\n');
6  log.error('Meteor Error!', additional);
7  return originalMeteorDebug.apply(this, arguments);
8};

Use multiple logger(s) with different settings: [Isomorphic]

1import { Logger } from 'meteor/ostrio:logger';
2import { LoggerMongo } from 'meteor/ostrio:loggermongo';
3
4const log1 = new Logger();
5const log2 = new Logger();
6
7/*
8 * Separate settings and collection
9 * for info, debug and other messages
10 */
11(new LoggerMongo(log1, {
12  collectionName: 'appLogs'
13})).enable({
14  filter: ['DEBUG', 'INFO', 'LOG', 'TRACE'],
15  client: true,
16  server: true
17});
18
19/*
20 * Separate settings and collection
21 * for errors, exceptions, warnings and etc.
22 */
23(new LoggerMongo(log2, {
24  collectionName: 'AppErrors'
25})).enable({
26  filter: ['ERROR', 'FATAL', 'WARN'],
27  client: true,
28  server: true
29});

Running Tests

  1. Clone this package
  2. In Terminal (Console) go to directory where package is cloned
  3. Then run:

Meteor/Tinytest

meteor test-packages ./

Support this awesome package:

Support our open source contribution: