Giter Club home page Giter Club logo

chartjs-plugin-datasource-prometheus's Introduction

Welcome to chartjs-plugin-datasource-prometheus ๐Ÿ‘‹

NPM version jsDelivr Downloads License: MIT

A Prometheus datasource for ChartJS.

screenshot

Dependencies:

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
  • Have been tested with line chart and (stacked) bar chart. The library should be compatible with more chart types.
  • Graph auto-refresh
  • Date interval can be absolute or relative to now
  • Multiple Prometheus queries into the same chart
  • Stacked series
  • 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:

Add inside of <head> the following:

<script src="https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@3/dist/chartjs-adapter-date-fns.bundle.min.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datasource-prometheus@2/dist/chartjs-plugin-datasource-prometheus.umd.min.js" crossorigin="anonymous"></script>

๐Ÿ’ก Note that chartjs-plugin-datasource-prometheus must be loaded after Chart.js and the date-fns adapter.

Here is used the jsDelivr CDN with specifying only a major version so any minor and patch updates will be applied automatically. If you need to use a specific version or ESM the copy link from https://www.jsdelivr.com/package/npm/chartjs-plugin-datasource-prometheus

๐Ÿ’ก 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.registry.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
stacked no Whether values are stacked or not 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,
                },
            },
        },
    },
});

screenshot

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,
                },
            },
        },
    },
});

Update

Query update:

chart.options.plugins['datasource-prometheus'].query = "new query";
chart.update({});

Start/end range update:

chart.options.plugins['datasource-prometheus'].timeRange.start = startTime;
chart.update({});

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

๐Ÿ‘ค Frantisek Svoboda

๐Ÿ’ซ Show your support

Give a โญ๏ธ if this project helped you!

support us

๐Ÿ“ License

Copyright ยฉ 2020 Samuel Berthe.

This project is MIT licensed.

chartjs-plugin-datasource-prometheus's People

Contributors

alexbakker avatar andrey-vorobiev avatar dependabot[bot] avatar jbarkovic avatar mnutt avatar samber avatar sfrenkie avatar stokito avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

chartjs-plugin-datasource-prometheus's Issues

Cannot read properties of null (reading 'addEventListener')

Hi, i have got the error in the console

import { useEffect, useRef } from "react";
import Chart from "chart.js/auto";
import "chartjs-adapter-date-fns";
import ChartDatasourcePrometheusPlugin from "chartjs-plugin-datasource-prometheus";
import "./styles.css";

export default function App() {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const chartRef = useRef<Chart | null>(null);

  useEffect(() => {
    if (canvasRef.current) {
      chartRef.current = new Chart(canvasRef.current, {
        type: "line",
        data: {
          datasets: [],
        },
        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 1 hours ago to now
                start: -1 * 60 * 60 * 1000,
                end: 0,
              },
            },
          },
        },
      });
    }

    return () => {
      chartRef.current?.destroy();
    };
  }, []);

  return <canvas ref={canvasRef}></canvas>;
}

Playground:
https://codesandbox.io/p/sandbox/chartjs-prometheus-bug-4jq97s

Declaration file not found

image

First of all, thanks for this package! I've been thoroughly using it as a guide while I try to figure my way out in publishing my own (I hope you don't mind ๐Ÿ˜…)

I noticed you have types exported from Rollup, but it is not exactly used when node installed since you haven't specified it in the package.json. The fix should be as simple as adding a "types": "dist/index.d.ts", assuming that's the entry point (I'd be glad to open up a PR for that!). More on that here.

As an aside, rollup-plugin-ts seems to do better than rollup-plugin-typescript2, at least for me since the former has a similar behavior to Parcel's declaration generation (e.g. it tree-shakes things so you end up declaring/emitting only the public API).

Multiple queries on a single chart

Hello,
Thank you for this helpful plugin!

I understand this is not to replace Grafana, but is there a way to feed more than one query to the chart ?

My use case is to draw two lines, one for a total sum of type1 entities over time, and one for a sum of type2 entities overtime.
These come from two different prometheus metrics.

I can't find a way to do it on the same chart.

Any idea or workaround ?

Thanks again!

baseURL as public parameter

Hello @samber ,

Thanks for this grat plugin.

Would it be possible to make the internal parameter baseURL public ?

...
baseURL: this.endpoint + "/api/v1/",
 ...

something like this could be done here:

...
this.endpoint = options.endpoint.replace(/\/$/, "");
this.baseURL = options.baseURL || this.endpoint + "/api/v1/",
...

then here

...
baseURL: this.baseURL,
...

instead of :

...
baseURL: this.endpoint + "/api/v1/",,
...

My use case is that I proxy the request via a custom application and the url in my case would need to look like this when reaching my app:

  • https://my_super_app.com/prometheus?something=abc?somethingElse=efg

Then I manage the construction of the URL in my backend to format the URL as necessary.

Thanks

Chart.js 3.0 support

Chart.js 3.0 is out now, so it might be nice for this plugin to upgrade to it

Updating chart queries

Hi I am using this plugin to display a website via cdn.
Trying to update the chart query with this code does not update the chart or send a request to the backend

chart.options.plugins['datasource-prometheus'].query = "new query"; chart.update({});

Can I use it with vue.js ?

Hi, I made my webpage with Vue.js (& not familiar in chart.js)
In this document, it give me just only plain javascript example.
I'm trying to npm install all package and import just like a

<script>
import {Chart} from 'chart.js';
import {ChartDatasourcePrometheusPlugin} from 'chartjs-plugin-datasource-prometheus';
... 

in vue.js file, And use document's example almost same in some function

createChart(charId, q) {
            const ctx = document.getElementById(charId)
            console.log(charId, q)
            this.myChart = new Chart(ctx, {
                type: 'line',
                plugins: [{ChartDatasourcePrometheusPlugin}],
                options: {
                    plugins: {
                        'datasource-prometheus': {
                            prometheus: {
                                endpoint: this.promEndpoint,
                                baseURL: "/api/v1",   // default value
                            },
                            query: q,
                            timeRange: {
                                type: 'relative',
                                // from 12 hours ago to now
                                start: -12 * 60 * 60 * 1000,
                                end: 0,
                            },
                        },
                    },
                },
            }); }

When this code applied, there is no error but just empty canvas exsisted.

How should I apply this package into vue.js properly?

dataSetHook has an error

Hello I tried to use the dataSetHook but I am getting an error about

index.umd.ts:50 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'forEach')
    at cn (index.umd.ts:50:18)
    at dn (index.umd.ts:50:18)
    at bn.update (index.umd.ts:50:18)
    at An.update (index.umd.ts:50:18)
    at Object.resumeRendering (prometheus-query.umd.js:7:71)
    at prometheus-query.umd.js:7:71
cn	@	index.umd.ts:50
dn	@	index.umd.ts:50
update	@	index.umd.ts:50
update	@	index.umd.ts:50
resumeRendering	@	prometheus-query.umd.js:7
(anonymous)	@	prometheus-query.umd.js:7
Promise.catch (async)		
beforeUpdate	@	prometheus-query.umd.js:7
d	@	color.esm.js:97
_notify	@	index.umd.ts:50
notify	@	index.umd.ts:50
notifyPlugins	@	index.umd.ts:50
update	@	index.umd.ts:50
An	@	index.umd.ts:50
(anonymous)	@	main.js:175

I believe that this is an error on the dataSetHook since when I remove it this error is not showing in the console.

My code for initializing the chart looks like this:

var jitterChart = new Chart(ctxjitter, {
    type: 'line',
    plugins: [ChartDatasourcePrometheusPlugin],
    options: {
      animation: {
        duration: 0,
      },
      plugins: {
        'datasource-prometheus': {
          query: [jitterQuery,maxLatencyQuery],
          timeRange: {
            type: 'absolute',
            start: startDate,
            end: endDate,
            msUpdateInterval: 5000,
          },
          dataSetHook:(datasets) => {
            console.log(datasets);
          },
        },
      },
    },
  });

NOTE: Please correct me if this is an error from my end. thank you.

Exclude empty label set from caption

Sometimes for some reasons I exclude any labels from resulting time series data.
In this case we have captions of resulting charts in the form like: node_load1{}, node_load5{}, etc.
Is it possible to switch off drawing of empty label sets?

image

[feature] Histogram chart

Is it possible to draw a Histogram metric like request latency?

Thank you for the library, it's saved me.

Update data in chart without complete redraw

Hello,
I've just discovered Chart.js and this plugin, so the answer to my question is probably obvious.
But I was wondering, is there a way to use the "auto refresh" functionality of this plugin, without having the whole chart be redrawn completely.
Which is not very nice visually โ€” and probably not very efficient as well.
That's what I am talking about, when the data gets refreshed:
ezgif-4-4f73504d1908
I would have expected the timespan to grow, and the existing data be shifted to the left.
Do you see what I mean?
Thanks.

Documentation / example of findInLabelMap

I can't find any examples of how to use findInLabelMap to change the series labels in the final chart - are there any examples of how to use this to customize labels?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.