adapt-authoring-mongodblogger/lib/MongoDBLoggerModule.js

import { AbstractApiModule, AbstractApiUtils } from 'adapt-authoring-api'
/**
 * Module for logging message to the MongoDB
 * @memberof mongodblogger
 * @extends {AbstractApiModule}
 */
class MongoDBLoggerModule extends AbstractApiModule {
  /** @override */
  async setValues () {
    /** @ignore */ this.root = 'logs'
    /** @ignore */ this.schemaName = 'log'
    /** @ignore */ this.collectionName = 'logs'
    /** @ignore */ this.routes = [
      {
        route: '/',
        validate: false,
        handlers: { get: this.queryHandler() },
        permissions: { get: ['read:logs'] }
      },
      {
        route: '/:_id',
        handlers: { get: this.requestHandler() },
        permissions: { get: ['read:logs'] },
        meta: {
          get: {
            summary: 'Retrieve debug logs',
            responses: {
              200: {
                description: '',
                content: {
                  'application/json': {
                    schema: { $ref: '#components/schemas/log' }
                  }
                }
              }
            }
          }
        }
      },
      {
        route: '/query',
        validate: false,
        handlers: { post: this.queryHandler() },
        permissions: { post: ['read:logs'] }
      }
    ]
    AbstractApiUtils.generateApiMetadata(this)
  }

  /** @override */
  async init () {
    await super.init()
    /**
     * Whether internal errors should be logged
     * @type {Boolean}
     */
    this.logInternalErrors = this.getConfig('logInternalErrors')
    // try and create the capped collection
    const [db, logger] = await this.app.waitForModule('mongodb', 'logger')
    try {
      const max = this.getConfig('maxLogCount')
      if(max > 0) {
        await db.client.db().createCollection(this.collectionName, { capped: true, max, size: max * 1000 })
      }
    } catch (e) {
      if (e.code !== 48) {
        return this.log('error', e)
      }
      if (!await db.getCollection(this.collectionName).isCapped()) {
        return this.log('warn', `'${this.collectionName}' collection already exists and is not capped`)
      }
    }
    logger.logHook.tap(this.logToDb.bind(this))
  }

  /**
   * Logs a message to the database
   * @param {Date} date When the data was logged
   * @param {String} level Severity of the message
   * @param {String} module Name of the module logging the message
   * @param {...*} data Other arguments to be logged
   */
  async logToDb (date, level, module, ...data) {
    try {
      const timestamp = date.toISOString()
      await this.insert({ timestamp, level, module, data })
    } catch (e) { // oh the irony...
      if (this.logInternalErrors) this.log('error', `failed to add log message to database, ${e}`)
    }
  }
}

export default MongoDBLoggerModule