Skip to content
This repository has been archived by the owner on Sep 4, 2024. It is now read-only.

Commit

Permalink
[feat] chart of query results
Browse files Browse the repository at this point in the history
  • Loading branch information
boristane committed Aug 23, 2023
1 parent 2774157 commit 8e4bc52
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added
- Added support for passing in the granularity when running queries
- Added fetching the datasets from the backend when prompting to select a dataset
- Added printing a chart of the query results

## [0.0.74] 2023-08-15
### Removed
Expand Down
28 changes: 26 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"release:patch": "npm version patch | xargs -i sh -c \"git push && git push && git push origin {}\""
},
"dependencies": {
"asciichart": "^1.5.25",
"aws-cron-parser": "^1.1.12",
"axios": "^0.26.1",
"chalk": "^4.1.2",
Expand All @@ -58,6 +59,7 @@
"yup": "^1.0.0-beta.8"
},
"devDependencies": {
"@types/asciichart": "^1.5.6",
"@types/express": "^4.17.15",
"@types/figlet": "^1.5.4",
"@types/flat": "^5.0.2",
Expand Down
4 changes: 2 additions & 2 deletions src/commands/query/handlers/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ async function createRun(data: {
granularity?: string;
config: UserConfig;
}) {
const { format, from, to, service, id, config, granularity, } = data;
const { format, from, to, service, id, config, granularity } = data;
const s = spinner.get();
const timeframe = getTimeframe(from, to);
s.start("Running the query ");
Expand Down Expand Up @@ -63,7 +63,7 @@ async function getApplicableDatasets(): Promise<Dataset[]> {
return datasets;
}

async function interactive(input: { queryId: string; service: string; format: OutputFormat; from: string; to: string; granularity: string, config: UserConfig }) {
async function interactive(input: { queryId: string; service: string; format: OutputFormat; from: string; to: string; granularity: string; config: UserConfig }) {
const s = spinner.get();
const { queryId, service, format, config } = input;
let { from, to, granularity } = input;
Expand Down
76 changes: 76 additions & 0 deletions src/commands/query/handlers/outputs.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import Table from "cli-table3";
import * as asciichart from "asciichart";

import { OutputFormat, tableChars } from "../../../shared";
import chalk from "chalk";
import { Aggregates, QueryRun, Series } from "../../../services/api/paths/query-runs";
import dayjs from "dayjs";
import outputs from "../../tail/outputs";
import { Event } from "../../../services/api/paths/events";
import { isObjectEqual } from "../../../utils";
import { writeFileSync } from "fs";

const { BASELIME_DOMAIN = "baselime.io" } = process.env;

Expand Down Expand Up @@ -64,12 +67,85 @@ function getQueryRun(data: { queryRun: QueryRun; aggregates?: Aggregates; series

console.log();
console.log(aggregatesTable.toString());

const config = {
offset: 3, // axis offset from the left (min 2)
padding: " ", // padding string for label formatting (can be overrided)
height: 15,
colors: [asciichart.green, asciichart.blue, asciichart.cyan, asciichart.magenta, asciichart.red],
};

const seriesData = getChartData({ aggregates, series });
if (seriesData.length) {
console.log();
const dataToPlot = seriesData[0].map((e: any) => e.data).slice(0, config.colors.length);
console.log(asciichart.plot(dataToPlot, config));
console.log();
const colorize = [chalk.green, chalk.blue, chalk.cyan, chalk.magenta, chalk.red];
seriesData[0].slice(0, config.colors.length).forEach((d, index) => {
const name = typeof d.name === "object" ? Object.values(d.name).join(" - ") : d.name;
console.log(` ${colorize[index](name)}`);
});
}
console.log();
console.log(
`Explore the query results: https://console.${BASELIME_DOMAIN}/${queryRun.workspaceId}/${queryRun.environmentId}/${queryRun.service}/queries/${queryRun.query.id}/${queryRun.id}`,
);
}

function getChartData(data: { aggregates?: Aggregates; series: Series[] }) {
const toHide = ["_count", "_firstSeen", "_lastSeen"];
const keys = data.aggregates ? Object.keys(data.aggregates[0]?.values || {}).filter((i) => !toHide.includes(i)) : [];

if (!(keys.length && data.aggregates)) {
return [];
}

const isGrouped = data.aggregates.some((c) => c.groups);
const groupBys = Object.keys(data.aggregates[0]?.groups || {});
const groups = groupBys.length
? data.aggregates.map((cal) => {
const a = Object.keys(cal.groups || {});
const res = {} as Record<string, any>;
a.forEach((key) => {
if (groupBys.some((g) => g === key)) res[key] = cal.groups?.[key];
});
return res;
})
: [];

const seriesArray = keys.map((key) => {
let series: { name: string | Record<string, any>; data: any[] }[];
if (isGrouped) {
series = groups.map((group) => {
return {
name: group,
data: data.series.map((s: any) => {
try {
const index = s.data.findIndex((d: any) => isObjectEqual(d.groups, group));
if (index > -1) {
return s.data[index].aggregates[key];
}
return 0;
} catch (e) {
return 0;
}
}),
};
});
} else {
series = [
{
name: key,
data: data.series.map((s: any) => (s.data.length ? s.data[0].aggregates[key] : 0)),
},
];
}
return series;
});
return seriesArray;
}

export default {
getQueryRun,
};
6 changes: 3 additions & 3 deletions src/commands/query/prompts/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export async function promptTo(): Promise<string> {
}

export async function promptGranularity(initial: number): Promise<string> {
const { granularity} = await prompt<{ granularity: string }>({
const { granularity } = await prompt<{ granularity: string }>({
type: "input",
name: "granularity",
initial: `${ms(initial)}`,
Expand All @@ -88,9 +88,9 @@ export async function promptGranularity(initial: number): Promise<string> {
export async function promptDatasets(applicableDatasets: Dataset[]): Promise<string[]> {
const choices: Record<string, string> = {};

applicableDatasets.forEach(dataset => {
applicableDatasets.forEach((dataset) => {
choices[dataset.id] = dataset.id;
})
});

let datasets: string[] = [];
while (!datasets.length) {
Expand Down
20 changes: 20 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,26 @@ class Logger {
}
}

export function isObjectEqual(obj1: any, obj2: any) {
var props1 = Object.getOwnPropertyNames(obj1);
var props2 = Object.getOwnPropertyNames(obj2);
if (props1.length !== props2.length) {
return false;
}
for (var i = 0; i < props1.length; i++) {
let val1 = obj1[props1[i]];
let val2 = obj2[props1[i]];
let isObjects = isObject(val1) && isObject(val2);
if ((isObjects && !isObjectEqual(val1, val2)) || (!isObjects && val1 !== val2)) {
return false;
}
}
return true;
}
function isObject(object: any) {
return object != null && typeof object === "object";
}

let logger: Logger;

export function getLogger() {
Expand Down

0 comments on commit 8e4bc52

Please sign in to comment.