profiler charts

This commit is contained in:
Jan Prochazka 2022-12-18 13:48:24 +01:00
parent 9a2631dc09
commit 2e37788471
9 changed files with 110 additions and 45 deletions

View File

@ -193,46 +193,83 @@ module.exports = {
}, },
extractTimelineChart_meta: true, extractTimelineChart_meta: true,
async extractTimelineChart({ jslid, formatterFunction, measures }) { async extractTimelineChart({ jslid, timestampFunction, aggregateFunction, measures }) {
const formater = requirePluginFunction(formatterFunction); const timestamp = requirePluginFunction(timestampFunction);
const datastore = new JsonLinesDatastore(getJslFileName(jslid), formater); const aggregate = requirePluginFunction(aggregateFunction);
const datastore = new JsonLinesDatastore(getJslFileName(jslid));
let mints = null; let mints = null;
let maxts = null; let maxts = null;
// pass 1 - counts stats, time range // pass 1 - counts stats, time range
await datastore.enumRows(row => { await datastore.enumRows(row => {
if (!mints || row.ts < mints) mints = row.ts; const ts = timestamp(row);
if (!maxts || row.ts > maxts) maxts = row.ts; if (!mints || ts < mints) mints = ts;
if (!maxts || ts > maxts) maxts = ts;
return true; return true;
}); });
const minTime = new Date(mints).getTime(); const minTime = new Date(mints).getTime();
const maxTime = new Date(maxts).getTime(); const maxTime = new Date(maxts).getTime();
const duration = maxTime - minTime; const duration = maxTime - minTime;
const STEPS = 100; const STEPS = 100;
const step = duration / STEPS; let stepCount = duration > 100 * 1000 ? STEPS : Math.round((maxTime - minTime) / 1000);
const labels = _.range(STEPS).map(i => new Date(minTime + step / 2 + step * i)); if (stepCount < 2) {
stepCount = 2;
}
const stepDuration = duration / stepCount;
const labels = _.range(stepCount).map(i => new Date(minTime + stepDuration / 2 + stepDuration * i));
const datasets = measures.map(m => ({ // const datasets = measures.map(m => ({
label: m.label, // label: m.label,
data: Array(STEPS).fill(0), // data: Array(stepCount).fill(0),
// }));
const mproc = measures.map(m => ({
...m,
})); }));
const data = Array(stepCount)
.fill(0)
.map(() => ({}));
// pass 2 - count measures // pass 2 - count measures
await datastore.enumRows(row => { await datastore.enumRows(row => {
if (!mints || row.ts < mints) mints = row.ts; const ts = timestamp(row);
if (!maxts || row.ts > maxts) maxts = row.ts; let part = Math.round((new Date(ts).getTime() - minTime) / stepDuration);
if (part < 0) part = 0;
for (let i = 0; i < measures.length; i++) { if (part >= stepCount) part - stepCount - 1;
const part = Math.round((new Date(row.ts).getTime() - minTime) / step); if (data[part]) {
datasets[i].data[part] += row[measures[i].field]; data[part] = aggregate(data[part], row, stepDuration);
} }
return true; return true;
}); });
datastore._closeReader(); datastore._closeReader();
// const measureByField = _.fromPairs(measures.map((m, i) => [m.field, i]));
// for (let mindex = 0; mindex < measures.length; mindex++) {
// for (let stepIndex = 0; stepIndex < stepCount; stepIndex++) {
// const measure = measures[mindex];
// if (measure.perSecond) {
// datasets[mindex].data[stepIndex] /= stepDuration / 1000;
// }
// if (measure.perField) {
// datasets[mindex].data[stepIndex] /= datasets[measureByField[measure.perField]].data[stepIndex];
// }
// }
// }
// for (let i = 0; i < measures.length; i++) {
// if (measures[i].hidden) {
// datasets[i] = null;
// }
// }
return { return {
labels, labels,
datasets, datasets: mproc.map(m => ({
label: m.label,
data: data.map(d => d[m.field] || 0),
})),
}; };
}, },
}; };

View File

@ -79,7 +79,8 @@ export interface EngineDriver {
supportsServerSummary?: boolean; supportsServerSummary?: boolean;
supportsDatabaseProfiler?: boolean; supportsDatabaseProfiler?: boolean;
profilerFormatterFunction?: string; profilerFormatterFunction?: string;
profilerChartFormatterFunction?: string; profilerTimestampFunction?: string;
profilerChartAggregateFunction?: string;
profilerChartMeasures?: { label: string; field: string }[]; profilerChartMeasures?: { label: string; field: string }[];
isElectronOnly?: boolean; isElectronOnly?: boolean;
supportedCreateDatabase?: boolean; supportedCreateDatabase?: boolean;

View File

@ -215,7 +215,8 @@
props: { props: {
jslid: `archive://${data.folderName}/${data.fileName}`, jslid: `archive://${data.folderName}/${data.fileName}`,
profilerFormatterFunction: eng.profilerFormatterFunction, profilerFormatterFunction: eng.profilerFormatterFunction,
profilerChartFormatterFunction: eng.profilerChartFormatterFunction, profilerTimestampFunction: eng.profilerTimestampFunction,
profilerChartAggregateFunction: eng.profilerChartAggregateFunction,
profilerChartMeasures: eng.profilerChartMeasures, profilerChartMeasures: eng.profilerChartMeasures,
}, },
}); });

View File

@ -58,7 +58,8 @@
export let database; export let database;
export let jslid; export let jslid;
export let profilerFormatterFunction; export let profilerFormatterFunction;
export let profilerChartFormatterFunction; export let profilerTimestampFunction;
export let profilerChartAggregateFunction;
export let profilerChartMeasures; export let profilerChartMeasures;
let profiling = false; let profiling = false;
@ -128,7 +129,8 @@
const data = await apiCall('jsldata/extract-timeline-chart', { const data = await apiCall('jsldata/extract-timeline-chart', {
jslid, jslid,
formatterFunction: profilerChartFormatterFunction || engine.profilerChartFormatterFunction, timestampFunction: profilerTimestampFunction || engine.profilerTimestampFunction,
aggregateFunction: profilerChartAggregateFunction || engine.profilerChartAggregateFunction,
measures: profilerChartMeasures || engine.profilerChartMeasures, measures: profilerChartMeasures || engine.profilerChartMeasures,
}); });
chartData = { chartData = {

View File

@ -1,12 +1,16 @@
const driver = require('./driver'); const driver = require('./driver');
const formatProfilerEntry = require('../frontend/formatProfilerEntry'); const {
const formatProfilerChartEntry = require('../frontend/formatProfilerChartEntry'); formatProfilerEntry,
extractProfileTimestamp,
aggregateProfileChartEntry,
} = require('../frontend/profilerFunctions');
module.exports = { module.exports = {
packageName: 'dbgate-plugin-mongo', packageName: 'dbgate-plugin-mongo',
drivers: [driver], drivers: [driver],
functions: { functions: {
formatProfilerEntry, formatProfilerEntry,
formatProfilerChartEntry, extractProfileTimestamp,
aggregateProfileChartEntry,
}, },
}; };

View File

@ -35,10 +35,15 @@ const driver = {
supportsServerSummary: true, supportsServerSummary: true,
supportsDatabaseProfiler: true, supportsDatabaseProfiler: true,
profilerFormatterFunction: 'formatProfilerEntry@dbgate-plugin-mongo', profilerFormatterFunction: 'formatProfilerEntry@dbgate-plugin-mongo',
profilerChartFormatterFunction: 'formatProfilerChartEntry@dbgate-plugin-mongo', profilerTimestampFunction: 'extractProfileTimestamp@dbgate-plugin-mongo',
profilerChartAggregateFunction: 'aggregateProfileChartEntry@dbgate-plugin-mongo',
profilerChartMeasures: [ profilerChartMeasures: [
{ label: 'Req count', field: 'count' }, { label: 'Req count/s', field: 'countPerSec' },
{ label: 'Duration', field: 'millis' }, { label: 'Avg duration', field: 'avgDuration' },
// { label: 'Req count/s', field: 'countPerSec', perSecond: true },
// { field: 'countAll', hidden: true },
// { label: 'Avg duration', field: 'millis', perField: 'countAll' },
], ],
databaseUrlPlaceholder: 'e.g. mongodb://username:password@mongodb.mydomain.net/dbname', databaseUrlPlaceholder: 'e.g. mongodb://username:password@mongodb.mydomain.net/dbname',

View File

@ -1,14 +0,0 @@
const _ = require('lodash');
const formatProfilerEntry = require('./formatProfilerEntry');
function formatProfilerChartEntry(obj) {
const fmt = formatProfilerEntry(obj);
return {
ts: fmt.ts,
millis: fmt.stats.millis,
count: 1,
};
}
module.exports = formatProfilerChartEntry;

View File

@ -1,12 +1,12 @@
import driver from './driver'; import driver from './driver';
import formatProfilerEntry from './formatProfilerEntry'; import { formatProfilerEntry, extractProfileTimestamp, aggregateProfileChartEntry } from './profilerFunctions';
import formatProfilerChartEntry from './formatProfilerChartEntry';
export default { export default {
packageName: 'dbgate-plugin-mongo', packageName: 'dbgate-plugin-mongo',
drivers: [driver], drivers: [driver],
functions: { functions: {
formatProfilerEntry, formatProfilerEntry,
formatProfilerChartEntry, extractProfileTimestamp,
aggregateProfileChartEntry,
}, },
}; };

View File

@ -69,4 +69,33 @@ function formatProfilerEntry(obj) {
}; };
} }
module.exports = formatProfilerEntry; function extractProfileTimestamp(obj) {
return obj.ts;
}
function aggregateProfileChartEntry(aggr, obj, stepDuration) {
// const fmt = formatProfilerEntry(obj);
const countAll = (aggr.countAll || 0) + 1;
const sumMillis = (aggr.sumMillis || 0) + obj.millis;
return {
countAll,
sumMillis,
countPerSec: (countAll / stepDuration) * 1000,
avgDuration: sumMillis / countAll,
};
// return {
// ts: fmt.ts,
// millis: fmt.stats.millis,
// countAll: 1,
// countPerSec: 1,
// };
}
module.exports = {
formatProfilerEntry,
extractProfileTimestamp,
aggregateProfileChartEntry,
};