mirror of
https://github.com/timberjoegithub/grafana-statusmap.git
synced 2026-07-22 15:53:09 +00:00
Merge pull request #5 from flant/fix_color_legend
Fix color and opacity legend clip
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
|
||||
## Installation
|
||||
|
||||
Plugin can be installed via Git:
|
||||
Plugin can be installed with GF_INSTALL_PLUGINS="flant-statusmap-panel" or you can use Git and clone this repo:
|
||||
|
||||
```
|
||||
git clone git@github.com:flant/grafana-statusmap.git /var/lib/grafana/plugins/flant-statusmap-panel
|
||||
@@ -26,6 +26,7 @@ git clone git@github.com:flant/grafana-statusmap.git /var/lib/grafana/plugins/fl
|
||||
Alternatively, you can download [ZIP archive](https://github.com/flant/grafana-statusmap/archive/master.zip)
|
||||
of this repo and unpack it into /var/lib/grafana/plugins directory.
|
||||
|
||||
|
||||
## Motivation
|
||||
|
||||
We had a desperate need to visualize a set of timeseries statuses over time period, so we can
|
||||
@@ -140,7 +141,13 @@ This plugin is based on "Heatmap" panel by Grafana and partly inspired by ideas
|
||||
|
||||
#### Changelog
|
||||
|
||||
##### v0.0.2
|
||||
|
||||
- Install with GF_INSTALL_PLUGINS
|
||||
- Fix legend overlap
|
||||
|
||||
##### v0.0.1
|
||||
|
||||
- First public release
|
||||
|
||||
|
||||
|
||||
Vendored
+77
-25
@@ -4,11 +4,11 @@
|
||||
|
||||
## Features
|
||||
|
||||
* Group values into rows and buckets by query's legend
|
||||
* Grouping values into rows and buckets using legend from query
|
||||
* User defined color mapping
|
||||
* Multiple values in bucket display in tooltip
|
||||
* Interval shaping to better visual representation
|
||||
* Represent null values as empty bucket or as zero value
|
||||
* Multiple values in bucket can be displayed via tooltip
|
||||
* Increasing rows/buckets' interval for better visual representation
|
||||
* Representing null values as empty bucket or zero value
|
||||
|
||||
### Supported environment
|
||||
|
||||
@@ -17,59 +17,104 @@
|
||||
|
||||
## Installation
|
||||
|
||||
Plugin can be installed with git:
|
||||
Plugin can be installed with GF_INSTALL_PLUGINS="flant-statusmap-panel" or you can use Git and clone this repo:
|
||||
|
||||
```
|
||||
git clone git@github.com:flant/grafana-statusmap.git /var/lib/grafana/plugins/flant-statusmap-panel
|
||||
```
|
||||
|
||||
Or you can download ZIP archive of this repo and unpack it into /var/lib/grafana/plugins directory.
|
||||
Alternatively, you can download [ZIP archive](https://github.com/flant/grafana-statusmap/archive/master.zip)
|
||||
of this repo and unpack it into /var/lib/grafana/plugins directory.
|
||||
|
||||
|
||||
## Motivation
|
||||
|
||||
This plugin emerges from our needs to visually represent history of changes for a set of objects
|
||||
with discrete statuses.
|
||||
_Objects_ can be hosts, Kubernetes pods or coffee makers and _discrete statuses_ are a set
|
||||
of predefined values: something like `ok` = 0, `off` = 1, `fail` = 2.
|
||||
We had a desperate need to show a set of timeseries statuses over time period, so we can see
|
||||
a history of changes for objects' statuses. Since we maintain a lot of Kubernetes clusters
|
||||
(and related infrastructure), our main cases for that are visualization of servers & Kubernetes
|
||||
pods health states as well as HTTP services health checks. We've tried a variety of Grafana
|
||||
plugins available (they are listed in *Acknowledgements* below) but none of them could provide
|
||||
the features and visualization really close to what we've been looking for.
|
||||
|
||||
_Objects_ being visualized with this plugin may be different: not only IT components (e.g. server
|
||||
hosts and Kubernetes pods) but just anything you can imagine like coffee makers on the picture
|
||||
above. These objects should have _discrete statuses_ which are sets of predefined values, e.g.
|
||||
`ok` = 0, `off` = 1, `fail` = 2, etc.
|
||||
|
||||
## Configuration
|
||||
|
||||
Recommended setup is to create query for each possible status value with similar legend:
|
||||
### Prometheus
|
||||
|
||||
To work with data from Prometheus you will need to setup discrete statuses of your objects.
|
||||
Requirements to store these statuses in metrics are as follows:
|
||||
* metrics should have two values: `0` and `1`;
|
||||
* there should be a label with status' value.
|
||||
|
||||
When it's done, you can collect all the data via query, e.g.:
|
||||
|
||||
```
|
||||
(max_over_time(coffee_maker_status{status="<STATUS_VALUE>"}[$__interval]) == 1) * <STATUS_VALUE>
|
||||
```
|
||||
|
||||
If there was no such status (`<STATUS_VALUE>`) during query's interval, Prometheus would
|
||||
return nothing. Otherwise, status' value will be returned.
|
||||
|
||||
For example, if you have 5 statuses and a metric (`coffee_maker_status`) with 5 allowed
|
||||
values (`0`, `1`, `2`, `3`, `4`), you should transform this metric using the following rule:
|
||||
|
||||
```
|
||||
- record: coffee_maker_status:discrete
|
||||
expr: |
|
||||
count_values("status", coffee_maker_status)
|
||||
```
|
||||
|
||||
That's how `coffee_maker_status` metric with value `3` will be transformed into new metric:
|
||||
|
||||
```
|
||||
coffee_maker_status:discrete{status="3"} 1
|
||||
```
|
||||
|
||||
Now, when Prometheus has `0` and `1` values for each status, all these metrics can be
|
||||
aggregated, so you will get all available statuses of your objects over time.
|
||||
|
||||
### Panel
|
||||
|
||||
First of all, an individual query for each possible status' value should be created.
|
||||
Each query should also have similar legend for grouping:
|
||||
|
||||

|
||||
|
||||
Next define color mapping for status values in __Discrete__ color mode.
|
||||
Then, color mapping for status' values should be defined in __Discrete__ color mode:
|
||||
|
||||

|
||||
|
||||
|
||||
__Spectrum__ and __Opacity__ color modes works as in a [Heatmap](https://grafana.com/plugins/heatmap) plugin.
|
||||
_Note: __Spectrum__ and __Opacity__ color modes function the same way they do in [Heatmap](https://grafana.com/plugins/heatmap) plugin._
|
||||
|
||||
|
||||
### More options
|
||||
|
||||

|
||||
|
||||
__Multiple values__ check determine multiple values display mode. If check is unset then multiple values
|
||||
for one bucket treated as error. If check is on then color for bucket determined
|
||||
by value with least index in color mapping.
|
||||
__Multiple values__ checkbox specifies how they should be displayed:
|
||||
* If it's off, multiple values for one bucket are treated as error;
|
||||
* If it's on, color for such bucket would be determined by the value having least index in color mapping.
|
||||
|
||||

|
||||
|
||||
__Null values__ can be treated as empty buckets or displayed as color of 0 value.
|
||||
__Null values__ can be treated as empty buckets or displayed with the color of `0` value.
|
||||
|
||||

|
||||
|
||||
__Min width__ and __spacing__ are determine minimal bucket width and spacing between buckets.
|
||||
__Rounding__ is for round edges.
|
||||
__Min width__ and __spacing__ are used to specify minimal bucket width and spacing between buckets.
|
||||
__Rounding__ may be used to round edges.
|
||||
|
||||

|
||||
|
||||
|
||||
## Development
|
||||
|
||||
The easy way to test and develop plugin is to run Grafana instance in docker with following command in the directory containing the plugin.
|
||||
This will expose the local plugin on your machine to the Grafana container.
|
||||
To test and improve the plugin you can run Grafana instance in Docker using following command (in
|
||||
the directory containing Statusmap plugin):
|
||||
|
||||
```
|
||||
docker run --rm -it -v $PWD:/var/lib/grafana/plugins/flant-statusmap-panel \
|
||||
@@ -78,7 +123,8 @@ docker run --rm -it -v $PWD:/var/lib/grafana/plugins/flant-statusmap-panel \
|
||||
grafana/grafana:5.1.3
|
||||
```
|
||||
|
||||
Now run `grunt` to compile dist directory and start changes watcher:
|
||||
This will expose local plugin from your machine to Grafana container. Now run `grunt` to compile
|
||||
dist directory and start changes watcher:
|
||||
|
||||
```
|
||||
grunt watch
|
||||
@@ -86,13 +132,19 @@ grunt watch
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
Idea of a plugin comes from Dmitry Stolyarov @distol, initial version written by Sergey Gnuskov @gsmetal and final changes made by Ivan Mikheykin @diafour.
|
||||
The first public release of this plugin has been fully made by [Flant](https://flant.com/) engineers. The whole idea has come from Dmitry Stolyarov ([@distol](https://github.com/distol)), initial version has been written by Sergey Gnuskov ([@gsmetal](https://github.com/gsmetal)) and final changes has been made by Ivan Mikheykin ([@diafour](https://github.com/diafour)).
|
||||
|
||||
This plugin is based on a "Heatmap" panel by Grafana and inspired by ideas from Carpet plot, Discrete panel, Status Panel, Status Dot, Status By Group.
|
||||
This plugin is based on "Heatmap" panel by Grafana and partly inspired by ideas from Carpet plot, Discrete panel, Status Panel, Status Dot, Status By Group.
|
||||
|
||||
#### Changelog
|
||||
|
||||
##### v0.0.2
|
||||
|
||||
- Install with GF_INSTALL_PLUGINS
|
||||
- Fix legend overlap
|
||||
|
||||
##### v0.0.1
|
||||
|
||||
- First public release
|
||||
|
||||
|
||||
|
||||
Vendored
+8
-6
@@ -10,7 +10,7 @@ System.register(['angular', 'lodash', 'jquery', 'd3', './libs/d3-scale-chromatic
|
||||
var legend = d3.select(legendElem.get(0));
|
||||
clearLegend(elem);
|
||||
|
||||
var legendWidth = Math.floor(legendElem.outerWidth()) - 30;
|
||||
var legendWidth = Math.floor(legendElem.outerWidth()) - 30; // narrow legendWidth by 30px to get space for first and last tick values
|
||||
var legendHeight = legendElem.attr("height");
|
||||
|
||||
var rangeStep = 1;
|
||||
@@ -27,8 +27,9 @@ System.register(['angular', 'lodash', 'jquery', 'd3', './libs/d3-scale-chromatic
|
||||
|
||||
var colorScale = getColorScale(colorScheme, maxValue, minValue);
|
||||
legend.selectAll(".status-heatmap-color-legend-rect").data(valuesRange).enter().append("rect").attr("x", function (d) {
|
||||
return d * widthFactor;
|
||||
}).attr("y", 0).attr("width", rangeStep * widthFactor + 1) // Overlap rectangles to prevent gaps
|
||||
return d * widthFactor + 10;
|
||||
}) // shift all color rectangles to the right
|
||||
.attr("y", 0).attr("width", rangeStep * widthFactor + 1) // Overlap rectangles to prevent gaps
|
||||
.attr("height", legendHeight).attr("stroke-width", 0).attr("fill", function (d) {
|
||||
return colorScale(d);
|
||||
});
|
||||
@@ -41,7 +42,7 @@ System.register(['angular', 'lodash', 'jquery', 'd3', './libs/d3-scale-chromatic
|
||||
var legend = d3.select(legendElem.get(0));
|
||||
clearLegend(elem);
|
||||
|
||||
var legendWidth = Math.floor(legendElem.outerWidth()) - 30;
|
||||
var legendWidth = Math.floor(legendElem.outerWidth()) - 30; // narrow legendWidth by 30px to get space for first and last tick values
|
||||
var legendHeight = legendElem.attr("height");
|
||||
|
||||
var rangeStep = 10;
|
||||
@@ -55,8 +56,9 @@ System.register(['angular', 'lodash', 'jquery', 'd3', './libs/d3-scale-chromatic
|
||||
|
||||
var opacityScale = getOpacityScale(options, maxValue, minValue);
|
||||
legend.selectAll(".status-heatmap-opacity-legend-rect").data(valuesRange).enter().append("rect").attr("x", function (d) {
|
||||
return d * widthFactor;
|
||||
}).attr("y", 0).attr("width", rangeStep * widthFactor).attr("height", legendHeight).attr("stroke-width", 0).attr("fill", options.cardColor).style("opacity", function (d) {
|
||||
return d * widthFactor + 10;
|
||||
}) // shift all opacity rectangles to the right
|
||||
.attr("y", 0).attr("width", rangeStep * widthFactor).attr("height", legendHeight).attr("stroke-width", 0).attr("fill", options.cardColor).style("opacity", function (d) {
|
||||
return opacityScale(d);
|
||||
});
|
||||
|
||||
|
||||
Vendored
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 64 KiB |
+4
-4
@@ -89,7 +89,7 @@ function drawColorLegend(elem, colorScheme, rangeFrom, rangeTo, maxValue, minVal
|
||||
let legend = d3.select(legendElem.get(0));
|
||||
clearLegend(elem);
|
||||
|
||||
let legendWidth = Math.floor(legendElem.outerWidth()) - 30;
|
||||
let legendWidth = Math.floor(legendElem.outerWidth()) - 30; // narrow legendWidth by 30px to get space for first and last tick values
|
||||
let legendHeight = legendElem.attr("height");
|
||||
|
||||
let rangeStep = 1;
|
||||
@@ -108,7 +108,7 @@ function drawColorLegend(elem, colorScheme, rangeFrom, rangeTo, maxValue, minVal
|
||||
legend.selectAll(".status-heatmap-color-legend-rect")
|
||||
.data(valuesRange)
|
||||
.enter().append("rect")
|
||||
.attr("x", d => d * widthFactor)
|
||||
.attr("x", d => d * widthFactor + 10) // shift all color rectangles to the right
|
||||
.attr("y", 0)
|
||||
.attr("width", rangeStep * widthFactor + 1) // Overlap rectangles to prevent gaps
|
||||
.attr("height", legendHeight)
|
||||
@@ -123,7 +123,7 @@ function drawOpacityLegend(elem, options, rangeFrom, rangeTo, maxValue, minValue
|
||||
let legend = d3.select(legendElem.get(0));
|
||||
clearLegend(elem);
|
||||
|
||||
let legendWidth = Math.floor(legendElem.outerWidth()) - 30;
|
||||
let legendWidth = Math.floor(legendElem.outerWidth()) - 30; // narrow legendWidth by 30px to get space for first and last tick values
|
||||
let legendHeight = legendElem.attr("height");
|
||||
|
||||
let rangeStep = 10;
|
||||
@@ -139,7 +139,7 @@ function drawOpacityLegend(elem, options, rangeFrom, rangeTo, maxValue, minValue
|
||||
legend.selectAll(".status-heatmap-opacity-legend-rect")
|
||||
.data(valuesRange)
|
||||
.enter().append("rect")
|
||||
.attr("x", d => d * widthFactor)
|
||||
.attr("x", d => d * widthFactor + 10) // shift all opacity rectangles to the right
|
||||
.attr("y", 0)
|
||||
.attr("width", rangeStep * widthFactor)
|
||||
.attr("height", legendHeight)
|
||||
|
||||
Reference in New Issue
Block a user