We have all had issues with Grafana generating static png charts for some time now. The root cause is PhantomJS. According to the docs on Grafana’s website:
PhantomJS is deprecated since Grafana v6.4 and will be removed in a future release. Please migrate to Grafana image renderer plugin or remote rendering service.
For at least a year now rendering the images on an RPi has been unavailable as PhantomJS would run amok and consume all the resources until openHAB itself was killed by the kernel. As of the past couple of weeks, it appears there has been an update made where rendering the pngs using PhantomJS even on more powerful machines no longer works (perhaps they finally removed the library).
Why not just use a webview? I’ve never had good luck with webviews. Either the Android app won’t show it, or it won’t work through a reverse proxy or through myopenhab.org. If I generate static images it works everywhere.
Thankfully, Grafana now provides a separate image renderer plugin for rendering charts to pngs.
Installation
You have a few options for installing this plugin.
-
If Grafana is installed on your machine, you can use grafana-cli.
grafana-cli plugins install grafana-image-renderer
-
Alternatively, you can download the zip file and unpack it into the plugins folder (see the link above for the latest links to the downloads).
-
Finally, you can run the renderer as a separate service using Docker. This approach is handy if you want to host the render on a host separate from your Grafana instance.
I run Grafana in Docker and I tried to install the plugin but it will not work. I get the following error:
Oct 9 15:05:49 argus 1f33221f8c3a[1686]: t=2019-10-09T15:05:49-0600 lvl=eror msg="Rendering failed." logger=context userId=0 orgId=1 uname= error="Rendering failed: Error: Failed to launch chrome!\n/var/lib/grafana/plugins/grafana-image-renderer/chrome-linux/chrome: error while loading shared libraries: libX11.so.6: cannot open shared object file: No such file or directory\n\n\nTROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md\n"
Oct 9 15:05:49 argus 1f33221f8c3a[1686]: t=2019-10-09T15:05:49-0600 lvl=eror msg="Request Completed" logger=context userId=0 orgId=1 uname= method=GET path=/render/d-solo/000000001/home-automation status=500 remote_addr=10.10.1.138 time_ms=16 size=1722 referer="http://argus:3000/d/000000001/home-automation?orgId=1"
So it looks like I have to host a separate container for the renderer. Instructions for doing so are located at https://github.com/grafana/grafana-image-renderer/blob/master/docs/remote_rendering_using_docker.md.
That provides a DockerCompose file. I use Ansible so I’ll show that below:
- name: Pull and run latest Grafana image
docker_container:
detach: True
exposed_ports:
- "3000"
hostname: grafana.koshak.net
image: grafana/grafana
log_driver: syslog
name: grafana
env:
GF_USERS_ALLOW_SIGN_UP: "false"
GF_AUTH_ANONYMOUS_ENABLED: "true"
GF_SECURITY_ALLOW_EMBEDDING: "true"
GF_SECURITY_COOKIE_SECURE: "true"
GF_SECURITY_COOKIE_SAMESITE: "none"
GF_RENDERING_SERVER_URL: "http://10.10.1.127:8081/render"
GF_RENDERING_CALLBACK_URL: "http://10.10.1.127:3000/"
GF_LOG_FILTERS: "rendering:debug"
published_ports:
- "3000:3000"
pull: True
restart: True
restart_policy: always
volumes:
- "{{ grafana_data }}:/var/lib/grafana"
- "/etc/localtime:/etc/localtime:ro"
- "/etc/passwd:/etc/passwd:ro"
- name: Pull and run the latest grafana image renderer
docker_container:
detach: True
exposed_ports:
- 8081
image: grafana/grafana-image-renderer:latest
log_driver: syslog
name: grafana-image-renderer
published_ports:
- "8081:8081"
pull: True
restart: True
restart_policy: always
NOTE: I need to change the IP address above to use the ansible variables to make it more generic. You should use the IP address of the machine these containers are deployed to.
Use
Just like with PhantomJS, click on the title of one of your panels in Grafana and choose “Share”
Then click on “Direct link rendered image”. See InfluxDB+Grafana persistence and graphing or the Grafana docs for details on how to fill in the URL parameters for the time periods you care about.
See Grafana Image Charts for a Rule that will call the URL to generate the chart images only as often as necessary based on the time period currently selected in the UI. Without something like this, Grafana will be generating the images for all the panels and all the views whether they are being used or not. Since this is an expensive operation, using this Rule will reduce the cost to the minimum.