feat: Add MongoDB client event logging via database option logClientEvents (#9914)

This commit is contained in:
Manuel
2025-11-08 15:48:29 +01:00
committed by GitHub
parent 2424054221
commit b760733b98
9 changed files with 501 additions and 25 deletions

View File

@@ -1,16 +1,16 @@
// @flow
import { format as formatUrl, parse as parseUrl } from '../../../vendor/mongodbUrl';
import type { QueryOptions, QueryType, SchemaType, StorageClass } from '../StorageAdapter';
import { StorageAdapter } from '../StorageAdapter';
import MongoCollection from './MongoCollection';
import MongoSchemaCollection from './MongoSchemaCollection';
import { StorageAdapter } from '../StorageAdapter';
import type { SchemaType, QueryType, StorageClass, QueryOptions } from '../StorageAdapter';
import { parse as parseUrl, format as formatUrl } from '../../../vendor/mongodbUrl';
import {
parseObjectToMongoObjectForCreate,
mongoObjectToParseObject,
parseObjectToMongoObjectForCreate,
transformKey,
transformWhere,
transformUpdate,
transformPointerString,
transformUpdate,
transformWhere,
} from './MongoTransform';
// @flow-disable-next
import Parse from 'parse/node';
@@ -18,6 +18,7 @@ import Parse from 'parse/node';
import _ from 'lodash';
import defaults from '../../../defaults';
import logger from '../../../logger';
import Utils from '../../../Utils';
// @flow-disable-next
const mongodb = require('mongodb');
@@ -132,6 +133,7 @@ export class MongoStorageAdapter implements StorageAdapter {
_mongoOptions: Object;
_onchange: any;
_stream: any;
_logClientEvents: ?Array<any>;
// Public
connectionPromise: ?Promise<any>;
database: any;
@@ -154,6 +156,7 @@ export class MongoStorageAdapter implements StorageAdapter {
this.enableSchemaHooks = !!mongoOptions.enableSchemaHooks;
this.schemaCacheTtl = mongoOptions.schemaCacheTtl;
this.disableIndexFieldValidation = !!mongoOptions.disableIndexFieldValidation;
this._logClientEvents = mongoOptions.logClientEvents;
// Remove Parse Server-specific options that should not be passed to MongoDB client
// Note: We only delete from this._mongoOptions, not from the original mongoOptions object,
// because other components (like DatabaseController) need access to these options
@@ -162,6 +165,7 @@ export class MongoStorageAdapter implements StorageAdapter {
'schemaCacheTtl',
'maxTimeMS',
'disableIndexFieldValidation',
'logClientEvents',
'createIndexUserUsername',
'createIndexUserUsernameCaseInsensitive',
'createIndexUserEmail',
@@ -203,6 +207,31 @@ export class MongoStorageAdapter implements StorageAdapter {
client.on('close', () => {
delete this.connectionPromise;
});
// Set up client event logging if configured
if (this._logClientEvents && Array.isArray(this._logClientEvents)) {
this._logClientEvents.forEach(eventConfig => {
client.on(eventConfig.name, event => {
let logData = {};
if (!eventConfig.keys || eventConfig.keys.length === 0) {
logData = event;
} else {
eventConfig.keys.forEach(keyPath => {
logData[keyPath] = _.get(event, keyPath);
});
}
// Validate log level exists, fallback to 'info'
const logLevel = typeof logger[eventConfig.logLevel] === 'function' ? eventConfig.logLevel : 'info';
// Safe JSON serialization with Map/Set and circular reference support
const logMessage = `MongoDB client event ${eventConfig.name}: ${JSON.stringify(logData, Utils.getCircularReplacer())}`;
logger[logLevel](logMessage);
});
});
}
this.client = client;
this.database = database;
})