|
const mongoose = require('mongoose'); |
|
const util = require('util'); |
|
|
|
function mongooseConfiguration(logger = {}) { |
|
// Used to enrich Mongoose object with our stuff (eg. a profiler) |
|
mongoose._userProvidedOptions = {}; |
|
|
|
mongoose._userProvidedOptions.profiler = { |
|
'preHook': function(next) { // Will mark down the query start time |
|
|
|
if (!Object.prototype.hasOwnProperty.call(this, '_userOptions')) { |
|
this._userOptions = {}; |
|
} |
|
|
|
// The property (of the query) we'll use to store our profiling stuff |
|
const profilingParentObject = this._userOptions; |
|
|
|
if ( |
|
Object.prototype.hasOwnProperty.call(mongoose, '_userProvidedOptions') |
|
&& Object.prototype.hasOwnProperty.call(mongoose._userProvidedOptions, 'profiler') |
|
) { |
|
profilingParentObject.profiling = { |
|
'startTime': new Date(), |
|
}; |
|
console.log(`[${new Date().toISOString()}] DEBUG: pre-hook: query started at ${profilingParentObject.profiling.startTime.toISOString()}`); |
|
} |
|
|
|
next(); |
|
}, |
|
'postHook': function(result, next) { // Will mark down the query end time and compute execution time |
|
console.log(`[${new Date().toISOString()}] DEBUG: post-hook: result_or_doc: ${util.inspect(result)}`); |
|
|
|
if ( |
|
Object.prototype.hasOwnProperty.call(mongoose, '_userProvidedOptions') |
|
&& Object.prototype.hasOwnProperty.call(mongoose._userProvidedOptions, 'profiler') |
|
) { |
|
// The property (of the query) we'll use to store our profiling stuff |
|
let profilingParentObject; |
|
if (Object.prototype.hasOwnProperty.call(this, '_userOptions')) { |
|
profilingParentObject = this._userOptions; |
|
if (Object.prototype.hasOwnProperty.call(profilingParentObject, 'profiling')) { |
|
profilingParentObject.profiling.endTime = new Date(); |
|
console.log(`[${new Date().toISOString()}] DEBUG: post-hook: query ended at ${profilingParentObject.profiling.endTime.toISOString()}`); |
|
if (Object.prototype.hasOwnProperty.call(profilingParentObject.profiling, 'startTime')) { |
|
profilingParentObject.profiling.duration = // In milliseconds |
|
profilingParentObject.profiling.endTime.getTime() |
|
- profilingParentObject.profiling.startTime.getTime(); |
|
console.log(`[${new Date().toISOString()}] DEBUG: post-hook: Duration: ${profilingParentObject.profiling.duration}`); |
|
} |
|
} |
|
} |
|
|
|
/* |
|
Value of `util.inspect(this)`: |
|
* insertMany operation : Model { my_collection } |
|
* find operation : Query { ... } |
|
* aggregate operation : Aggregate { ... } |
|
*/ |
|
console.log(`[${new Date().toISOString()}] DEBUG: post-hook: this: ${util.inspect(this)}`); |
|
|
|
let collectionName; |
|
let methodName; |
|
if (this instanceof mongoose.Query || this instanceof mongoose.Aggregate) { |
|
({ collectionName } = this.model().collection); |
|
methodName = this instanceof mongoose.Query ? this.op : 'aggregate'; |
|
} else if (this instanceof mongoose.Model) { |
|
collectionName = 'ModelOperation-Collection'; |
|
methodName = 'ModelOperation-Method'; |
|
} else { |
|
collectionName = 'ElseOperation-Collection'; |
|
methodName = 'ElseOperation-Method'; |
|
} |
|
console.log(`[${new Date().toISOString()}] DEBUG: post-hook: collectionName: ${collectionName}`); |
|
console.log(`[${new Date().toISOString()}] DEBUG: post-hook: methodName: ${methodName}`); |
|
|
|
// Text version of query: |
|
const query = this instanceof mongoose.Query ? this._conditions : this._pipeline; |
|
const queryAsString = JSON.stringify(query); |
|
|
|
// The object to hold obtained profiling information: |
|
const profilingInfos = { |
|
'collection': collectionName, |
|
'method': methodName, |
|
'query': queryAsString, |
|
}; |
|
|
|
if ( // Append duration information if any |
|
Object.prototype.hasOwnProperty.call(profilingParentObject, 'profiling') |
|
&& Object.prototype.hasOwnProperty.call(profilingParentObject.profiling, 'duration') |
|
) { |
|
profilingInfos.duration = profilingParentObject.profiling.duration; |
|
} |
|
|
|
if (result) { // Append obtained document count |
|
profilingInfos.documentCount = result.length; |
|
} |
|
|
|
// Assemble log message |
|
const profilingInfosString = Object.getOwnPropertyNames(profilingInfos) |
|
.map(key => `${key}:${profilingInfos[key]}`) |
|
.join(', '); |
|
const logOutput = `[${new Date().toISOString()}] Mongoose: ${profilingInfosString}`; |
|
|
|
// Log message using defined logger (if any) |
|
if (Object.prototype.hasOwnProperty.call(mongoose._userProvidedOptions.profiler, 'logger')) { |
|
mongoose._userProvidedOptions.profiler.logger(logOutput); |
|
} |
|
} |
|
|
|
next(); |
|
}, |
|
}; |
|
|
|
if (logger) { // |
|
mongoose._userProvidedOptions.profiler.logger = logger; |
|
} |
|
} |
|
|
|
module.exports = mongooseConfiguration; |
|
|
|
|