SYNC: Merge pull request #7 from dbgate/feature/applog

This commit is contained in:
Jan Prochazka
2025-08-05 17:13:33 +02:00
committed by Diflow
parent ac0aebd751
commit a96f1d0b49
83 changed files with 1014 additions and 242 deletions

View File

@@ -102,7 +102,7 @@ module.exports = {
...fileType('.matview.sql', 'matview.sql'),
];
} catch (err) {
logger.error(extractErrorLogData(err), 'Error reading archive files');
logger.error(extractErrorLogData(err), 'DBGM-00001 Error reading archive files');
return [];
}
},

View File

@@ -99,7 +99,7 @@ function authMiddleware(req, res, next) {
return next();
}
logger.error(extractErrorLogData(err), 'Sending invalid token error');
logger.error(extractErrorLogData(err), 'DBGM-00098 Sending invalid token error');
return unauthorizedResponse(req, res, 'invalid token');
}

View File

@@ -45,7 +45,7 @@ module.exports = {
const resp = await callCloudApiGet('content-list');
return resp;
} catch (err) {
logger.error(extractErrorLogData(err), 'Error getting cloud content list');
logger.error(extractErrorLogData(err), 'DBGM-00099 Error getting cloud content list');
return [];
}

View File

@@ -116,12 +116,12 @@ function getPortalCollections() {
}
}
logger.info({ connections: connections.map(pickSafeConnectionInfo) }, 'Using connections from ENV variables');
logger.info({ connections: connections.map(pickSafeConnectionInfo) }, 'DBGM-00005 Using connections from ENV variables');
const noengine = connections.filter(x => !x.engine);
if (noengine.length > 0) {
logger.warn(
{ connections: noengine.map(x => x._id) },
'Invalid CONNECTIONS configuration, missing ENGINE for connection ID'
'DBGM-00006 Invalid CONNECTIONS configuration, missing ENGINE for connection ID'
);
}
return connections;
@@ -530,7 +530,7 @@ module.exports = {
socket.emit('got-volatile-token', { strmid, savedConId: conid, volatileConId: volatile._id });
return { success: true };
} catch (err) {
logger.error(extractErrorLogData(err), 'Error getting DB token');
logger.error(extractErrorLogData(err), 'DBGM-00100 Error getting DB token');
return { error: err.message };
}
},
@@ -546,7 +546,7 @@ module.exports = {
const resp = await authProvider.login(null, null, { conid: volatile._id }, req);
return resp;
} catch (err) {
logger.error(extractErrorLogData(err), 'Error getting DB token');
logger.error(extractErrorLogData(err), 'DBGM-00101 Error getting DB token');
return { error: err.message };
}
},

View File

@@ -76,7 +76,7 @@ module.exports = {
handle_error(conid, database, props) {
const { error } = props;
logger.error(`Error in database connection ${conid}, database ${database}: ${error}`);
logger.error(`DBGM-00102 Error in database connection ${conid}, database ${database}: ${error}`);
if (props?.msgid) {
const [resolve, reject] = this.requests[props?.msgid];
reject(error);
@@ -144,7 +144,7 @@ module.exports = {
handle_copyStreamError(conid, database, { copyStreamError }) {
const { progressName } = copyStreamError;
const { runid } = progressName;
logger.error(`Error in database connection ${conid}, database ${database}: ${copyStreamError}`);
logger.error(`DBGM-00103 Error in database connection ${conid}, database ${database}: ${copyStreamError}`);
socket.emit(`runner-done-${runid}`);
},
@@ -193,7 +193,7 @@ module.exports = {
if (newOpened.disconnected) return;
const funcName = `handle_${msgtype}`;
if (!this[funcName]) {
logger.error(`Unknown message type ${msgtype} from subprocess databaseConnectionProcess`);
logger.error(`DBGM-00104 Unknown message type ${msgtype} from subprocess databaseConnectionProcess`);
return;
}
@@ -204,7 +204,7 @@ module.exports = {
this.close(conid, database, false);
});
subprocess.on('error', err => {
logger.error(extractErrorLogData(err), 'Error in database connection subprocess');
logger.error(extractErrorLogData(err), 'DBGM-00114 Error in database connection subprocess');
if (newOpened.disconnected) return;
this.close(conid, database, false);
});
@@ -226,7 +226,7 @@ module.exports = {
try {
conn.subprocess.send({ msgid, ...message });
} catch (err) {
logger.error(extractErrorLogData(err), 'Error sending request do process');
logger.error(extractErrorLogData(err), 'DBGM-00115 Error sending request do process');
this.close(conn.conid, conn.database);
}
});
@@ -236,7 +236,7 @@ module.exports = {
queryData_meta: true,
async queryData({ conid, database, sql }, req) {
testConnectionPermission(conid, req);
logger.info({ conid, database, sql }, 'Processing query');
logger.info({ conid, database, sql }, 'DBGM-00007 Processing query');
const opened = await this.ensureOpened(conid, database);
// if (opened && opened.status && opened.status.name == 'error') {
// return opened.status;
@@ -283,7 +283,7 @@ module.exports = {
runScript_meta: true,
async runScript({ conid, database, sql, useTransaction, logMessage }, req) {
testConnectionPermission(conid, req);
logger.info({ conid, database, sql }, 'Processing script');
logger.info({ conid, database, sql }, 'DBGM-00008 Processing script');
const opened = await this.ensureOpened(conid, database);
sendToAuditLog(req, {
category: 'dbop',
@@ -304,7 +304,7 @@ module.exports = {
runOperation_meta: true,
async runOperation({ conid, database, operation, useTransaction }, req) {
testConnectionPermission(conid, req);
logger.info({ conid, database, operation }, 'Processing operation');
logger.info({ conid, database, operation }, 'DBGM-00009 Processing operation');
sendToAuditLog(req, {
category: 'dbop',
@@ -481,7 +481,7 @@ module.exports = {
try {
existing.subprocess.send({ msgtype: 'ping' });
} catch (err) {
logger.error(extractErrorLogData(err), 'Error pinging DB connection');
logger.error(extractErrorLogData(err), 'DBGM-00116 Error pinging DB connection');
this.close(conid, database);
return {
@@ -530,7 +530,7 @@ module.exports = {
try {
existing.subprocess.kill();
} catch (err) {
logger.error(extractErrorLogData(err), 'Error killing subprocess');
logger.error(extractErrorLogData(err), 'DBGM-00117 Error killing subprocess');
}
}
this.opened = this.opened.filter(x => x.conid != conid || x.database != database);
@@ -924,7 +924,7 @@ module.exports = {
executeSessionQuery_meta: true,
async executeSessionQuery({ sesid, conid, database, sql }, req) {
testConnectionPermission(conid, req);
logger.info({ sesid, sql }, 'Processing query');
logger.info({ sesid, sql }, 'DBGM-00010 Processing query');
sessions.dispatchMessage(sesid, 'Query execution started');
const opened = await this.ensureOpened(conid, database);

View File

@@ -13,6 +13,7 @@ const dbgateApi = require('../shell');
const { getLogger } = require('dbgate-tools');
const platformInfo = require('../utility/platformInfo');
const { checkSecureFilePathsWithoutDirectory, checkSecureDirectories } = require('../utility/security');
const { AppLogDatastore, getRecentAppLogRecords } = require('../utility/AppLogDatastore');
const logger = getLogger('files');
function serialize(format, data) {
@@ -28,6 +29,9 @@ function deserialize(format, text) {
}
module.exports = {
currentLogReader: null,
currentLogParamsKey: null,
list_meta: true,
async list({ folder }, req) {
if (!hasPermission(`files/${folder}/read`, req)) return [];
@@ -253,7 +257,7 @@ module.exports = {
createZipFromJsons_meta: true,
async createZipFromJsons({ db, filePath }) {
logger.info(`Creating zip file from JSONS ${filePath}`);
logger.info(`DBGM-00011 Creating zip file from JSONS ${filePath}`);
await dbgateApi.zipJsonLinesData(db, filePath);
return true;
},
@@ -279,7 +283,7 @@ module.exports = {
const FOLDERS = ['sql', 'sqlite'];
for (const folder of FOLDERS) {
if (fileName.toLowerCase().endsWith('.' + folder)) {
logger.info(`Saving ${folder} file ${fileName}`);
logger.info(`DBGM-00012 Saving ${folder} file ${fileName}`);
await fs.copyFile(filePath, path.join(filesdir(), folder, fileName));
socket.emitChanged(`files-changed`, { folder: folder });
@@ -291,7 +295,7 @@ module.exports = {
}
}
throw new Error(`${fileName} doesn't have one of supported extensions: ${FOLDERS.join(', ')}`);
throw new Error(`DBGM-00013 ${fileName} doesn't have one of supported extensions: ${FOLDERS.join(', ')}`);
},
exportFile_meta: true,
@@ -311,4 +315,28 @@ module.exports = {
await fs.copyFile(sourceFilePath, targetFilePath);
return true;
},
getAppLog_meta: true,
async getAppLog({ offset = 0, limit = 100, dateFrom = 0, dateTo = new Date().getTime(), filters = {} }) {
const paramsKey = `${dateFrom}-${dateTo}`;
if (paramsKey != this.currentLogParamsKey) {
if (this.currentLogReader) {
this.currentLogReader._closeReader();
this.currentLogReader = null;
}
this.currentLogReader = new AppLogDatastore({ timeFrom: dateFrom, timeTo: dateTo });
this.currentLogParamsKey = paramsKey;
}
return this.currentLogReader.getRows(offset, limit, filters);
},
getRecentAppLog_meta: true,
getRecentAppLog({ limit }) {
const res = getRecentAppLogRecords();
if (limit) {
return res.slice(-limit);
}
return res;
},
};

View File

@@ -48,7 +48,7 @@ require=null;
async function run() {
${script}
await dbgateApi.finalizer.run();
logger.info('Finished job script');
logger.info('DBGM-00014 Finished job script');
}
dbgateApi.runScript(run);
`;
@@ -132,7 +132,7 @@ module.exports = {
const pluginNames = extractPlugins(scriptText);
// console.log('********************** SCRIPT TEXT **********************');
// console.log(scriptText);
logger.info({ scriptFile }, 'Running script');
logger.info({ scriptFile }, 'DBGM-00015 Running script');
// const subprocess = fork(scriptFile, ['--checkParent', '--max-old-space-size=8192'], {
const subprocess = fork(
scriptFile,
@@ -171,7 +171,7 @@ module.exports = {
subprocess.on('exit', code => {
// console.log('... EXITED', code);
this.rejectRequest(runid, { message: 'No data returned, maybe input data source is too big' });
logger.info({ code, pid: subprocess.pid }, 'Exited process');
logger.info({ code, pid: subprocess.pid }, 'DBGM-00016 Exited process');
socket.emit(`runner-done-${runid}`, code);
this.opened = this.opened.filter(x => x.runid != runid);
});
@@ -222,7 +222,7 @@ module.exports = {
subprocess.on('exit', code => {
console.log('... EXITED', code);
logger.info({ code, pid: subprocess.pid }, 'Exited process');
logger.info({ code, pid: subprocess.pid }, 'DBGM-00017 Exited process');
this.dispatchMessage(runid, `Finished external process with code ${code}`);
socket.emit(`runner-done-${runid}`, code);
if (onFinished) {
@@ -258,7 +258,7 @@ module.exports = {
severity: 'error',
message: extractErrorMessage(err),
});
logger.error(extractErrorLogData(err), 'Caught error on stdin');
logger.error(extractErrorLogData(err), 'DBGM-00118 Caught error on stdin');
});
}

View File

@@ -24,7 +24,7 @@ module.exports = {
if (!match) return;
const pattern = match[1];
if (!cron.validate(pattern)) return;
logger.info(`Schedule script ${file} with pattern ${pattern}`);
logger.info(`DBGM-00018 Schedule script ${file} with pattern ${pattern}`);
const task = cron.schedule(pattern, () => runners.start({ script: text }));
this.tasks.push(task);
},

View File

@@ -103,7 +103,7 @@ module.exports = {
this.close(conid, false);
});
subprocess.on('error', err => {
logger.error(extractErrorLogData(err), 'Error in server connection subprocess');
logger.error(extractErrorLogData(err), 'DBGM-00119 Error in server connection subprocess');
if (newOpened.disconnected) return;
this.close(conid, false);
});
@@ -121,7 +121,7 @@ module.exports = {
try {
existing.subprocess.kill();
} catch (err) {
logger.error(extractErrorLogData(err), 'Error killing subprocess');
logger.error(extractErrorLogData(err), 'DBGM-00120 Error killing subprocess');
}
}
this.opened = this.opened.filter(x => x.conid != conid);
@@ -191,7 +191,7 @@ module.exports = {
try {
opened.subprocess.send({ msgtype: 'ping' });
} catch (err) {
logger.error(extractErrorLogData(err), 'Error pinging server connection');
logger.error(extractErrorLogData(err), 'DBGM-00121 Error pinging server connection');
this.close(conid);
}
})
@@ -244,7 +244,7 @@ module.exports = {
try {
conn.subprocess.send({ msgid, ...message });
} catch (err) {
logger.error(extractErrorLogData(err), 'Error sending request');
logger.error(extractErrorLogData(err), 'DBGM-00122 Error sending request');
this.close(conn.conid);
}
});

View File

@@ -165,7 +165,7 @@ module.exports = {
message: 'Executing query',
});
logger.info({ sesid, sql }, 'Processing query');
logger.info({ sesid, sql }, 'DBGM-00019 Processing query');
this.dispatchMessage(sesid, 'Query execution started');
session.subprocess.send({
msgtype: 'executeQuery',
@@ -186,7 +186,7 @@ module.exports = {
throw new Error('Invalid session');
}
logger.info({ sesid, command }, 'Processing control command');
logger.info({ sesid, command }, 'DBGM-00020 Processing control command');
this.dispatchMessage(sesid, `${_.startCase(command)} started`);
session.subprocess.send({ msgtype: 'executeControlCommand', command });
@@ -224,7 +224,7 @@ module.exports = {
throw new Error('Invalid session');
}
logger.info({ sesid }, 'Starting profiler');
logger.info({ sesid }, 'DBGM-00021 Starting profiler');
session.loadingReader_jslid = jslid;
session.subprocess.send({ msgtype: 'startProfiler', jslid });
@@ -271,7 +271,7 @@ module.exports = {
try {
session.subprocess.send({ msgtype: 'ping' });
} catch (err) {
logger.error(extractErrorLogData(err), 'Error pinging session');
logger.error(extractErrorLogData(err), 'DBGM-00145 Error pinging session');
return {
status: 'error',

View File

@@ -28,7 +28,7 @@ module.exports = {
}
const uploadName = crypto.randomUUID();
const filePath = path.join(uploadsdir(), uploadName);
logger.info(`Uploading file ${data.name}, size=${data.size}`);
logger.info(`DBGM-00025 Uploading file ${data.name}, size=${data.size}`);
data.mv(filePath, () => {
res.json({
@@ -115,7 +115,7 @@ module.exports = {
return response.data;
} catch (err) {
logger.error(extractErrorLogData(err), 'Error uploading gist');
logger.error(extractErrorLogData(err), 'DBGM-00148 Error uploading gist');
return {
apiErrorMessage: err.message,