mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
profiler charts
This commit is contained in:
parent
9a2631dc09
commit
2e37788471
@ -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),
|
||||
})),
|
||||
};
|
||||
},
|
||||
};
|
||||
|
3
packages/types/engines.d.ts
vendored
3
packages/types/engines.d.ts
vendored
@ -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;
|
||||
|
@ -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,
|
||||
},
|
||||
});
|
||||
|
@ -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 = {
|
||||
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
@ -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',
|
||||
|
||||
|
@ -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;
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
@ -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,
|
||||
};
|
Loading…
Reference in New Issue
Block a user