feat: allow you to set the axis type

This commit is contained in:
Jeremy Wall 2024-05-22 13:01:35 -04:00
parent a84326cb67
commit ae669767c8
6 changed files with 50 additions and 31 deletions

View File

@ -10,10 +10,11 @@
# overlaying: "y" # overlaying: "y"
side: left side: left
tickformat: "~%" tickformat: "~%"
# type: "log" # The type of axis.
plots: # List of pluts to show on the graph plots: # List of pluts to show on the graph
- source: http://heimdall:9001 # Prometheus source uri for this plot - source: http://heimdall:9001 # Prometheus source uri for this plot
query: 'sum by (instance)(irate(node_cpu_seconds_total{FILTERS, job="nodestats"}[5m]))' # The PromQL query for this plot query: 'sum by (instance)(irate(node_cpu_seconds_total{FILTERS, job="nodestats"}[5m]))' # The PromQL query for this plot
meta: # metadata for this plot config: # configuration for this plot
name_format: "`${labels.instance}`" # javascript template literal to format the trace name name_format: "`${labels.instance}`" # javascript template literal to format the trace name
fill: tozeroy fill: tozeroy
span: # The span for this range query span: # The span for this range query
@ -40,13 +41,13 @@
# You can use the FILTERS placeholder to indicate where user selected filters should be placed. # You can use the FILTERS placeholder to indicate where user selected filters should be placed.
query: | query: |
sum by (instance)(irate(node_cpu_seconds_total{FILTERS mode="system",job="nodestats"}[5m])) / sum by (instance)(irate(node_cpu_seconds_total{FILTERS, job="nodestats"}[5m])) sum by (instance)(irate(node_cpu_seconds_total{FILTERS mode="system",job="nodestats"}[5m])) / sum by (instance)(irate(node_cpu_seconds_total{FILTERS, job="nodestats"}[5m]))
meta: config:
name_format: "`${labels.instance} system`" name_format: "`${labels.instance} system`"
yaxis: "y" yaxis: "y"
- source: http://heimdall:9001 - source: http://heimdall:9001
query: | query: |
sum by (instance)(irate(node_cpu_seconds_total{mode="user",job="nodestats"}[5m])) / sum by (instance)(irate(node_cpu_seconds_total{job="nodestats"}[5m])) sum by (instance)(irate(node_cpu_seconds_total{mode="user",job="nodestats"}[5m])) / sum by (instance)(irate(node_cpu_seconds_total{job="nodestats"}[5m]))
meta: config:
name_format: "`${labels.instance} user`" name_format: "`${labels.instance} user`"
yaxis: "y2" yaxis: "y2"
- title: Node memory - title: Node memory
@ -57,7 +58,7 @@
plots: plots:
- source: http://heimdall:9001 - source: http://heimdall:9001
query: 'node_memory_MemFree_bytes{job="nodestats"}' query: 'node_memory_MemFree_bytes{job="nodestats"}'
meta: config:
name_format: "`${labels.instance}`" name_format: "`${labels.instance}`"
- title: Log Test Dashboard 1 - title: Log Test Dashboard 1
span: span:

View File

@ -27,7 +27,7 @@ use crate::query::{
}; };
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PlotMeta { pub struct PlotConfig {
name_format: Option<String>, name_format: Option<String>,
fill: Option<FillTypes>, fill: Option<FillTypes>,
yaxis: Option<String>, yaxis: Option<String>,
@ -57,6 +57,22 @@ pub enum AxisSide {
Left, Left,
} }
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum AxisType {
#[serde(rename = "-")]
Default,
#[serde(rename = "linear")]
Linear,
#[serde(rename = "log")]
Log,
#[serde(rename = "date")]
Date,
#[serde(rename = "category")]
Category,
#[serde(rename = "multicategory")]
MultiCategory,
}
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AxisDefinition { pub struct AxisDefinition {
anchor: Option<String>, anchor: Option<String>,
@ -64,6 +80,8 @@ pub struct AxisDefinition {
side: Option<AxisSide>, side: Option<AxisSide>,
#[serde(rename = "tickformat")] #[serde(rename = "tickformat")]
tick_format: Option<String>, tick_format: Option<String>,
#[serde(rename = "type")]
plot_type: Option<AxisType>,
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
@ -86,7 +104,7 @@ pub struct Dashboard {
pub struct SubPlot { pub struct SubPlot {
pub source: String, pub source: String,
pub query: String, pub query: String,
pub meta: PlotMeta, pub config: PlotConfig,
} }
#[derive(Deserialize, Serialize, Clone)] #[derive(Deserialize, Serialize, Clone)]
@ -222,7 +240,7 @@ impl Graph {
&plot.source, &plot.source,
&plot.query, &plot.query,
self.query_type.clone(), self.query_type.clone(),
plot.meta.clone(), plot.config.clone(),
); );
if let Some(filters) = filters { if let Some(filters) = filters {
debug!(?filters, "query connection with filters"); debug!(?filters, "query connection with filters");

View File

@ -16,7 +16,7 @@ use std::collections::HashMap;
use chrono::prelude::*; use chrono::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::dashboard::PlotMeta; use crate::dashboard::PlotConfig;
mod loki; mod loki;
mod prom; mod prom;
@ -48,8 +48,8 @@ pub struct LogLine {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub enum MetricsQueryResult { pub enum MetricsQueryResult {
Series(Vec<(HashMap<String, String>, PlotMeta, Vec<DataPoint>)>), Series(Vec<(HashMap<String, String>, PlotConfig, Vec<DataPoint>)>),
Scalar(Vec<(HashMap<String, String>, PlotMeta, DataPoint)>), Scalar(Vec<(HashMap<String, String>, PlotConfig, DataPoint)>),
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]

View File

@ -20,7 +20,7 @@ use prometheus_http_query::{
}; };
use tracing::debug; use tracing::debug;
use crate::dashboard::PlotMeta; use crate::dashboard::PlotConfig;
use super::{DataPoint, MetricsQueryResult, QueryType, TimeSpan}; use super::{DataPoint, MetricsQueryResult, QueryType, TimeSpan};
@ -35,7 +35,7 @@ pub struct PromQueryConn<'conn> {
span: Option<TimeSpan>, span: Option<TimeSpan>,
query_type: QueryType, query_type: QueryType,
filters: Option<&'conn HashMap<&'conn str, &'conn str>>, filters: Option<&'conn HashMap<&'conn str, &'conn str>>,
pub meta: PlotMeta, pub meta: PlotConfig,
} }
impl<'conn> PromQueryConn<'conn> { impl<'conn> PromQueryConn<'conn> {
@ -43,7 +43,7 @@ impl<'conn> PromQueryConn<'conn> {
source: &'a str, source: &'a str,
query: &'a str, query: &'a str,
query_type: QueryType, query_type: QueryType,
meta: PlotMeta, meta: PlotConfig,
) -> Self { ) -> Self {
Self { Self {
source, source,
@ -159,7 +159,7 @@ impl<'conn> PromQueryConn<'conn> {
} }
} }
pub fn prom_to_samples(data: Data, meta: PlotMeta) -> MetricsQueryResult { pub fn prom_to_samples(data: Data, meta: PlotConfig) -> MetricsQueryResult {
match data { match data {
Data::Matrix(mut range) => MetricsQueryResult::Series( Data::Matrix(mut range) => MetricsQueryResult::Series(
range range

View File

@ -83,7 +83,7 @@
*/ */
/** /**
* @typedef PlotMeta * @typedef PlotConfig
* @type {object} * @type {object}
* @property {string=} name_format * @property {string=} name_format
* @property {string=} yaxis * @property {string=} yaxis

View File

@ -252,13 +252,13 @@ export class GraphPlot extends HTMLElement {
/** /**
* Formats the name for the plot trace. * Formats the name for the plot trace.
* @param {PlotMeta} meta * @param {PlotConfig} config
* @param {Map<string, string>} labels * @param {Map<string, string>} labels
* @return string * @return string
*/ */
formatName(meta, labels) { formatName(config, labels) {
var name = ""; var name = "";
const formatter = meta.name_format const formatter = config.name_format
if (formatter) { if (formatter) {
name = eval(formatter); name = eval(formatter);
} else { } else {
@ -435,8 +435,8 @@ export class GraphPlot extends HTMLElement {
return null; return null;
} }
} }
const meta = /** @type {PlotMeta} */(triple[1]); const config = /** @type {PlotConfig} */(triple[1]);
var yaxis = meta.yaxis || "y"; var yaxis = config.yaxis || "y";
// https://plotly.com/javascript/reference/layout/yaxis/ // https://plotly.com/javascript/reference/layout/yaxis/
const series = triple[2]; const series = triple[2];
const trace = /** @type GraphTrace */({ const trace = /** @type GraphTrace */({
@ -449,10 +449,10 @@ export class GraphPlot extends HTMLElement {
yaxis: yaxis, yaxis: yaxis,
//yhoverformat: yaxis.tickformat, //yhoverformat: yaxis.tickformat,
}); });
if (meta.fill) { if (config.fill) {
trace.fill = meta.fill; trace.fill = config.fill;
} }
var name = this.formatName(meta, labels); var name = this.formatName(config, labels);
if (name) { trace.name = name; } if (name) { trace.name = name; }
for (const point of series) { for (const point of series) {
trace.x.push(new Date(point.timestamp * 1000)); trace.x.push(new Date(point.timestamp * 1000));
@ -472,15 +472,15 @@ export class GraphPlot extends HTMLElement {
return null; return null;
} }
} }
const meta = /** @type {PlotMeta} */(triple[1]); const config = /** @type {PlotConfig} */(triple[1]);
const series = triple[2]; const series = triple[2];
const trace = /** @type GraphTrace */({ const trace = /** @type GraphTrace */({
type: "bar", type: "bar",
x: [], x: [],
y: [], y: [],
yhoverformat: meta["d3_tick_format"], yhoverformat: config["d3_tick_format"],
}); });
var name = this.formatName(meta, labels); var name = this.formatName(config, labels);
if (name) { trace.name = name; } if (name) { trace.name = name; }
trace.y.push(series.value); trace.y.push(series.value);
trace.x.push(trace.name); trace.x.push(trace.name);
@ -490,11 +490,11 @@ export class GraphPlot extends HTMLElement {
/** /**
* @param {Array} stream * @param {Array} stream
* *
* @returns {{dates: Array<string>, meta: Array<string>, lines: Array<string>}} * @returns {{dates: Array<string>, config: Array<string>, lines: Array<string>}}
*/ */
buildStreamPlot(stream) { buildStreamPlot(stream) {
const dateColumn = []; const dateColumn = [];
const metaColumn = []; const configColumn = [];
const logColumn = []; const logColumn = [];
loopStream: for (const pair of stream) { loopStream: for (const pair of stream) {
@ -513,11 +513,11 @@ export class GraphPlot extends HTMLElement {
// For streams the timestamps are in nanoseconds // For streams the timestamps are in nanoseconds
let timestamp = new Date(line.timestamp / 1000000); let timestamp = new Date(line.timestamp / 1000000);
dateColumn.push(timestamp.toISOString()); dateColumn.push(timestamp.toISOString());
metaColumn.push(labelsName); configColumn.push(labelsName);
logColumn.push(ansiToHtml(line.line)); logColumn.push(ansiToHtml(line.line));
} }
} }
return { dates: dateColumn, meta: metaColumn, lines: logColumn }; return { dates: dateColumn, config: configColumn, lines: logColumn };
} }
/** /**
@ -580,7 +580,7 @@ export class GraphPlot extends HTMLElement {
}); });
const columns = this.buildStreamPlot(logLineList.Stream); const columns = this.buildStreamPlot(logLineList.Stream);
trace.cells.values.push(columns.dates); trace.cells.values.push(columns.dates);
trace.cells.values.push(columns.meta); trace.cells.values.push(columns.config);
trace.cells.values.push(columns.lines); trace.cells.values.push(columns.lines);
traces.push(trace); traces.push(trace);
} else if (logLineList.StreamInstant) { } else if (logLineList.StreamInstant) {