chartjs-plugin-datasource-prometheus
chartjs-plugin-datasource-prometheus copied to clipboard
📊 Chart.js plugin for Prometheus
Welcome to chartjs-plugin-datasource-prometheus 👋
A Prometheus datasource for ChartJS.
Dependencies:
- requires chart.js 2.7 or later.
- requires moment.js 2.0 or later.
- requires prometheus-query 3.0 or later.
Demonstration:
https://samber.github.io/chartjs-plugin-datasource-prometheus/example/
I would be happy to add links to charts using this library. Feel free to reach me by creating an issue ;)
✨ Features
- Loads time-series from Prometheus into Chart.js.
- Similar to Grafana, but ported to Chart.js for public-facing web applications.
- UMD compatible, you can use it with any module loader
- Supports line chart only (for now!)
- Graph auto-refresh
- Date interval can be absolute or relative to
now
- Multiple Prometheus queries into the same chart
- Custom backend requests (useful for multitenant apps)
- Hooks available (styling, labeling, data presentation...)
- Custom chart messages for errors or empty Prometheus responses
- Break or continuous lines when gap in data
- Line styling
- Send queries with your own Prometheus driver
⚠️ This project is not intented to replace Grafana. For monitoring purpose or internal company graph showing, Grafana will definitely be better and more secure.
🚀 Installation
Via npm:
npm install momentjs chart.js --save
npm install chartjs-plugin-datasource-prometheus --save
Via CDN:
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/Chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datasource-prometheus/dist/chartjs-plugin-datasource-prometheus.umd.min.js"></script>
💡 Note that chartjs-plugin-datasource-prometheus must be loaded after Chart.js and Moment.js.
💡 Quick start
chartjs-plugin-datasource-prometheus can be used with ES6 modules, plain JavaScript and module loaders.
<canvas id="myChart"></canvas>
Then, you need to register the plugin to enable it for all charts in the page.
Chart.plugins.register(ChartDatasourcePrometheusPlugin);
Or, you can enable the plugin only for specific charts.
var chart = new Chart(ctx, {
plugins: [ChartDatasourcePrometheusPlugin],
options: {
// ...
}
});
In the example below, we display Go duration of garbage collection, for the last 12 hours:
var myChart = new Chart(ctx, {
type: 'line',
plugins: [ChartDatasourcePrometheusPlugin],
options: {
plugins: {
'datasource-prometheus': {
prometheus: {
endpoint: "https://prometheus.demo.do.prometheus.io",
baseURL: "/api/v1", // default value
},
query: 'sum by (job) (go_gc_duration_seconds)',
timeRange: {
type: 'relative',
// from 12 hours ago to now
start: -12 * 60 * 60 * 1000,
end: 0,
},
},
},
},
});
💬 Spec
Options
Property | Required | Description | Default |
---|---|---|---|
prometheus.endpoint | yes | Prometheus hostname | |
prometheus.baseURL | no | Prometheus metric path | "/api/v1" |
prometheus.headers | no | Headers to add to Prometheus request | |
prometheus.auth.username | no | Basic auth username | |
prometheus.auth.password | no | Basic auth password | |
prometheus.proxy.host | no | Proxy hostname | |
prometheus.proxy.port | no | Proxy port | |
prometheus.withCredentials | no | Send cookies in cross-site requests | false |
prometheus.timeout | no | Prometheus request timeout in milliseconds | 10000 |
query | yes | Prometheus query: string or function (see below). Supports multiple queries, using an array. | |
timeRange.type | no | Time range type: absolute or relative | "absolute" |
timeRange.start | yes | Time range start: Date object (absolute) or integer (relative) | |
timeRange.end | yes | Time range end: Date object (absolute) or integer (relative) | |
timeRange.step | no | Time between 2 data points | [computed] |
timeRange.minStep | no | Min time between 2 data points | null |
timeRange.msUpdateInterval | no | Update interval in millisecond | null |
fillGaps | no | Insert NaN values when values are missing in time range | false |
tension | no | Bezier curve tension of the line. Set to 0 to draw straightlines. This option is ignored if monotone cubic interpolation is used | 0.4 |
cubicInterpolationMode | no | "default" or "monotone" | "default" |
stepped | no | false, true, "before", "middle" or "after" | false |
fill | no | Fills the area under the line | false |
borderWidth | no | Should I explain this field? | 3 |
backgroundColor | no | Should I explain this field? | See library source code |
borderColor | no | Should I explain this field? | See library source code |
errorMsg.message | no | Overrides error messages | null |
errorMsg.font | no | Font of error messages | "16px normal 'Helvetica Nueue'" |
noDataMsg.message | no | Empty chart message | "No data to display" |
noDataMsg.font | no | Font of empty chart message | "16px normal 'Helvetica Nueue'" |
Hooks
Some hooks have been inserted into the library. It may help you to rewrite label names dynamically, set colors...
// 💡 For better serie labels, we are looking for a templating solution => please contribute ;)
Property | Required | Description | Prototype |
---|---|---|---|
findInLabelMap | no | Custom serie label | (serie: Metric) => string |
findInBorderColorMap | no | Custom serie line color | (serie: Metric) => string |
findInBackgroundColorMap | no | Custom serie background color | (serie: Metric) => string |
dataSetHook | no | Modify data on the fly, right before display | (datasets: ChartDataSet[]) => ChartDataSet[] |
Examples
Multiple queries in one chart
The query
field can be an array of queries. Returned series are aggregated in a single chart.
In case you want to show those queries on different axes, you can define a custom options.scales.yAxes
field.
var myChart = new Chart(ctx, {
type: 'line',
plugins: [ChartDatasourcePrometheusPlugin],
options: {
scales: {
yAxes: [
{position: 'left'},
{position: 'left'},
{position: 'right'},
]
},
plugins: {
'datasource-prometheus': {
prometheus: {
endpoint: "https://prometheus.demo.do.prometheus.io",
},
query: ['node_load1', 'node_load5', 'node_load15'],
timeRange: {
type: 'relative',
// from 12 hours ago to now
start: -12 * 60 * 60 * 1000,
end: 0,
},
},
},
},
});
Auto refresh
Animations should be disabled when chart refresh itself.
var myChart = new Chart(ctx, {
type: 'line',
plugins: [ChartDatasourcePrometheusPlugin],
options: {
animation: {
duration: 0,
},
plugins: {
'datasource-prometheus': {
prometheus: {
endpoint: "https://prometheus.demo.do.prometheus.io",
},
query: 'node_load1',
timeRange: {
type: 'relative',
// from 10 minutes ago to now
start: -1 * 10 * 60 * 1000,
end: 0,
msUpdateInterval: 5000,
},
},
},
},
});
Custom queries
In the context of a multitenant application, it is not a good idea to write a query on the browser side. In that scenario, you may need to send a custom request to your backend, which is responsible for doing the final Prometheus query.
In that case, the prometheus
field can be ommited. Just pass a function with the following prototype: (start: Date, end: Date, step: number) => Promise<any>
.
It can be combined with traditional string queries: query: ['node_load1', customReq]
.
// Here, we call a fictive API that gonna query Prometheus to get the list
// of comments, wrote by the current user during the past hour.
// This endpoint will return a Prometheus-like response.
function customReq(start, end, step) {
const startTimestamp = start.getTime() / 1000;
const endTimestamp = end.getTime() / 1000;
const url = `https://api.example.com/user/activity?event_type=comment.write&range_start=${startTimestamp}&end=${endTimestamp}&range_step=${step}`;
const headers = {'Authorization': 'Bearer Ainae1Ahchiew6UhseeCh7el'};
return fetch(url, { headers })
.then(response => response.json())
.then(response => response['data']);
}
const myChart = new Chart(ctx, {
type: 'line',
plugins: [ChartDatasourcePrometheusPlugin],
options: {
plugins: {
'datasource-prometheus': {
query: customReq,
timeRange: {
type: 'relative',
start: -1 * 60 * 60 * 1000, // 1h ago
end: 0, // now
},
},
},
},
});
🤯 Troubleshooting
CORS
Start your Prometheus instance with --web.cors.origin="www.example.com"
flag or even --web.cors.origin=".*"
if you like living dangerously. 😅
🔐 Security advisory
Please read the security advisory of prometheus-query library.
In the context of a multitenant application, it is not a good idea to write a query on the browser side. In that scenario, you may need to use the "custom request" feature.
🤝 Contributing
The Prometheus Datasource is open source and contributions from community (you!) are welcome.
There are many ways to contribute: writing code, documentation, reporting issues...
How-to
Author
👤 Samuel Berthe
- Twitter: @samuelberthe
- Github: @samber
👤 Frantisek Svoboda
💫 Show your support
Give a ⭐️ if this project helped you!
📝 License
Copyright © 2020 Samuel Berthe.
This project is MIT licensed.