General:
- Grafana server with dashboards that are to be exported, and datasources in "Server" (proxy) mode.
- User account on Grafana server that has Viewer access to the required dashboards
- This has been tested on Ubuntu 16.04 and a Mac
Packages:
- NodeJS, and the
puppeteer
package (npm install puppeteer
), which is used to run headless Chrome - In Linux, Puppeteer has the following library/tool dependencies (primarily related to
libx11
- see this post). I found that I didn't need extra packages on a Mac.
sudo apt-get install gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget
Scripts:
- The grafana_pdf.js file attached here, which carries out the PDF conversion using Puppeteer
Environment: Set the Grafana server URL, username, and password, and the output filename as environment variables.
export GF_DASH_URL="http://localhost:3000/d/x3g4Wx5ik/new-dashboard?kiosk"
export GF_USER=pdf_export
export GF_PASSWORD=StrongPassword1
export OUTPUT_PDF=output.pdf
Now export to PDF by calling the NodeJS script with the corresponding arguments:
node grafana_pdf.js $GF_DASH_URL $GF_USER:$GF_PASSWORD $OUTPUT_PDF
- The focus here is on single-page output. Getting "tall" dashboards to paginate nicely is an altogether separate endeavor.
- In its present form, the script adjusts the PDF and aspect ratio to fit the dashboard, with no regard for fitting on an actual page. It's also possible to get the output to be Letter or A4 sized - see comments in the code on how to achieve that; if the intent is to print, you'll probably also want to add a margin (TODO: Add a switch in the code)
- When you have a single
pdf_export
user that is a member of multiple organizations, if you try to exporting dashboards belonging to different organizations one after the other, you will occasionally get a "login" screen instead of a dashboard during the org switch. When that happens, I found that simply retrying does the trick.
Attached below are two example output PDFs (bigdashboard_output.pdf and output_energy.pdf). The former is based on https://play.grafana.org/d/000000003/big-dashboard, and the latter is from our own energy monitoring project (www.ammp.io).
Hi @svet-b! thanks for the quick response.
About #1
I understand that I could use "All" to make the dashboard show them all in a single graph. The problem is that when using this option, some dashboard items get broken.
The loop has solved the problem for now. I had to statically pass the name of the kubernetes nodes in the loop, I will try to identify the nodes via API (if possible).
I'm using a docker-compose and creating an array of all grafana's dashboards via APIKey (adjusting the names and ID's with JQ) and after that, I pass this array to your application that generates a pdf for each dashboard.
About #2
As I can't save the Elastic dashboard with the lines (panels) expanded (because the dashboard is applied via kubernetes services), I did the following: I manually expanded all the lines (panels) that were collapsed and copied the json code from the dashboard in this format . I edited the grafana service in kubernetes referring to the Elastic dashboard and applied this json. I was able to generate the PDF with all dashboard expanded items (panels), but this generated a new problem (#3) [lol]:
Now Elastic's dashboard needs more than one page. Only the graphics that fit on the first page of the PDF are displayed, the others (next pages of the PDF) show only the name and not the graphic. Is there any way to solve this?
By the way, whoever wants to use the APIkey and not user:password, just adjust it in the grafana_pdf.js file:
// Generate authorization header for basic auth
--//const auth_header = 'Basic ' + new Buffer.from(auth_string).toString('base64');
++const token = 'Bearer ' + auth_string;
// Set basic auth headers
--//await page.setExtraHTTPHeaders({'Authorization': auth_header});
++await page.setExtraHTTPHeaders({'Authorization': token});
Create an APIKey at Grafana and use with this command:
node grafana_pdf.js "http//grafanaurl.com/d/728b76cc/k8s-net-workload?orgId=1?kiosk" TOKEN out_file.pdf
Using with root, need this:
(async() => {
--//const browser = await puppeteer.launch();
++const browser = await puppeteer.launch({args: ['--no-sandbox', '--disable-setuid-sandbox']});
const page = await browser.newPage();
Hope it helps someone!
And Thanks again!