mirror of
https://github.com/zaphar/Heracles.git
synced 2025-07-23 12:39:50 -04:00
feat: allow you to set the axis type
This commit is contained in:
parent
a84326cb67
commit
ae669767c8
@ -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:
|
||||||
|
@ -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");
|
||||||
|
@ -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)]
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user