visualise-elastic-profile
Version:
Visualise results from Profile API of ElasticSearch on the command line
89 lines • 4.25 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.stringifyProfile = void 0;
const chalk_1 = __importDefault(require("chalk"));
const utils_1 = require("./utils");
/**
* @param profileData JSON of the profilin data, checked against a runtype
* @param options configuring the resulting string
* @returns stringified represenentation of the profile
*/
const stringifyProfile = (profileData, options = { maxWidth: 80, color: true }) => {
const result = [];
let profile;
if (utils_1.NestedProfile.guard(profileData)) {
profile = utils_1.NestedProfile.check(profileData).profile;
}
else {
profile = utils_1.Profile.check(profileData);
}
const maxTimeInNanos = profile.shards
.flatMap((shard) => shard.searches)
.flatMap((search) => search.query)
.reduce((max, query) => Math.max(max, query.time_in_nanos), 0);
// Determine colors to use per query type
const queryTypes = (0, utils_1.getQueryTypesFromProfile)(profile);
const colorByQueryType = options.color
? new Map(Array.from(queryTypes.values()).map((type, idx) => [type, (0, utils_1.getColor)(type)]))
: undefined;
const gray = options.color ? chalk_1.default.gray : (value) => value;
const colorString = options.color ? (hex) => chalk_1.default.hex(hex) : (_) => (value) => value;
// Write out a legend if the output is colored
if (colorByQueryType !== undefined) {
result.push(gray('Legend:'));
for (const [type, color] of colorByQueryType) {
result.push(`${colorString(color)('███')} - ${type}`);
}
result.push('');
}
// Render each shard separately
for (const shard of profile.shards) {
result.push(`${gray('Shard:')} ${shard.id}`);
const queries = shard.searches.flatMap((query) => query.query);
for (const query of queries) {
const relativeMaxWidth = Math.floor((query.time_in_nanos / maxTimeInNanos) * options.maxWidth);
result.push((0, utils_1.queryToString)(query, { maxWidth: relativeMaxWidth, colorByQueryType }));
}
result.push('');
}
// Render stats of the leaf queries (the ones that actually take up the time in the end)
// Also render their breakdown aggregates over all shards
result.push(gray('Leaf queries (across all shards/queries):'));
const queries = (0, utils_1.getAllLeafQueriesFromProfile)(profile);
const queriesByTypeDescription = (0, utils_1.arrayToMultiMap)(queries, ({ type, description }) => `${type} ${description}`);
const durationsByDescription = Array.from(queriesByTypeDescription.values())
.map((queries) => {
const sumTimeInNanos = queries.reduce((sum, query) => sum + query.time_in_nanos, 0);
const breakdown = queries.reduce((memo, query) => {
var _a;
for (const [key, value] of Object.entries(query.breakdown)) {
memo[key] = ((_a = memo[key]) !== null && _a !== void 0 ? _a : 0) + value;
}
return memo;
}, {});
return {
type: queries[0].type,
description: queries[0].description,
breakdown,
color: colorByQueryType === null || colorByQueryType === void 0 ? void 0 : colorByQueryType.get(queries[0].type),
time_in_nanos: sumTimeInNanos,
};
})
.sort((a, b) => b.time_in_nanos - a.time_in_nanos);
for (const value of durationsByDescription) {
result.push(`${(0, utils_1.durationToString)(value.time_in_nanos)} - ${colorString(value.color)(`${value.type} ${value.description}`)}`);
const breakdown = Array.from(Object.entries(value.breakdown)).sort((a, b) => b[1] - a[1]);
for (const [key, aggregate] of breakdown) {
if (aggregate > 0) {
result.push(`\t${(0, utils_1.durationToString)(aggregate)} ${gray(key)}`);
}
}
result.push('');
}
return result.join('\n');
};
exports.stringifyProfile = stringifyProfile;
//# sourceMappingURL=index.js.map