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,
async extractTimelineChart({ jslid, formatterFunction, measures }) {
const formater = requirePluginFunction(formatterFunction);
const datastore = new JsonLinesDatastore(getJslFileName(jslid), formater);
async extractTimelineChart({ jslid, timestampFunction, aggregateFunction, measures }) {
const timestamp = requirePluginFunction(timestampFunction);
const aggregate = requirePluginFunction(aggregateFunction);
const datastore = new JsonLinesDatastore(getJslFileName(jslid));
let mints = null;
let maxts = null;
// pass 1 - counts stats, time range
await datastore.enumRows(row => {
if (!mints || row.ts < mints) mints = row.ts;
if (!maxts || row.ts > maxts) maxts = row.ts;
const ts = timestamp(row);
if (!mints || ts < mints) mints = ts;
if (!maxts || ts > maxts) maxts = ts;
return true;
});
const minTime = new Date(mints).getTime();
const maxTime = new Date(maxts).getTime();
const duration = maxTime - minTime;
const STEPS = 100;
const step = duration / STEPS;
const labels = _.range(STEPS).map(i => new Date(minTime + step / 2 + step * i));
let stepCount = duration > 100 * 1000 ? STEPS : Math.round((maxTime - minTime) / 1000);
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 => ({
label: m.label,
data: Array(STEPS).fill(0),
// const datasets = measures.map(m => ({
// label: m.label,
// data: Array(stepCount).fill(0),
// }));
const mproc = measures.map(m => ({
...m,
}));
const data = Array(stepCount)
.fill(0)
.map(() => ({}));
// pass 2 - count measures
await datastore.enumRows(row => {
if (!mints || row.ts < mints) mints = row.ts;
if (!maxts || row.ts > maxts) maxts = row.ts;
for (let i = 0; i < measures.length; i++) {
const part = Math.round((new Date(row.ts).getTime() - minTime) / step);
datasets[i].data[part] += row[measures[i].field];
const ts = timestamp(row);
let part = Math.round((new Date(ts).getTime() - minTime) / stepDuration);
if (part < 0) part = 0;
if (part >= stepCount) part - stepCount - 1;
if (data[part]) {
data[part] = aggregate(data[part], row, stepDuration);
}
return true;
});
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 {
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;
supportsDatabaseProfiler?: boolean;
profilerFormatterFunction?: string;
profilerChartFormatterFunction?: string;
profilerTimestampFunction?: string;
profilerChartAggregateFunction?: string;
profilerChartMeasures?: { label: string; field: string }[];
isElectronOnly?: boolean;
supportedCreateDatabase?: boolean;

View File

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

View File

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

View File

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

View File

@ -35,10 +35,15 @@ const driver = {
supportsServerSummary: true,
supportsDatabaseProfiler: true,
profilerFormatterFunction: 'formatProfilerEntry@dbgate-plugin-mongo',
profilerChartFormatterFunction: 'formatProfilerChartEntry@dbgate-plugin-mongo',
profilerTimestampFunction: 'extractProfileTimestamp@dbgate-plugin-mongo',
profilerChartAggregateFunction: 'aggregateProfileChartEntry@dbgate-plugin-mongo',
profilerChartMeasures: [
{ label: 'Req count', field: 'count' },
{ label: 'Duration', field: 'millis' },
{ label: 'Req count/s', field: 'countPerSec' },
{ 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',

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 formatProfilerEntry from './formatProfilerEntry';
import formatProfilerChartEntry from './formatProfilerChartEntry';
import { formatProfilerEntry, extractProfileTimestamp, aggregateProfileChartEntry } from './profilerFunctions';
export default {
packageName: 'dbgate-plugin-mongo',
drivers: [driver],
functions: {
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,
};