Grafana dashboard export in PDF
Grafana dashboard export in PDF
Thanks to @dumy for it's guides you can find it here:
https://flows.nodered.org/flow/482d3b2c9736fc1544dd62b50778d8d9
I have made some changes to export the page in "Dark mode" and i have added some "tutorials" for Puppeteer
Requisites:
-node-red-contrib-string - https://flows.nodered.org/node/node-red-contrib-string
-Puppeteer
This can be installed with
npm i puppeteer
Than you have to go to your node-red installation folder and change settings.js and add this line
puppeteer:require('puppeteer')
under "functionGlobalContext"
Setup:
In setting dashboard go to the module link and set link from Node-Red ❤️ N.B. Remeber to flag "Include current time range"
http://localhost:1880/grafana/${__dashboard.uid}/${__dashboard.name}
Change "localhost:1880" with your ip/dns
Resulted:
When you click the button this flow will be executed:
In the node function there are 3 parameters that needs to be change:
// URL to load should be passed as first parameter const url = 'http://localhost:3000/d/' + msg.req.params.uid + '/' + msg.req.params.name +'?orgId=1&kiosk&from=' + msg.payload.from + '&to=' + msg.payload.to;
// Username and password (with colon separator) should be second parameter const auth_string = 'username:password!';
// Output file name should be third parameter const outfile = '';
After call the link resulted in pdf
it is a simple method to export grafana pages in pdf,
Thank you ✌️
[{"id":"39737d292e7049b0","type":"tab","label":"Flow 2","disabled":false,"info":"","env":[]},{"id":"1dd5c082c89e4ce8","type":"change","z":"39737d292e7049b0","name":"Set Headers","rules":[{"t":"set","p":"headers","pt":"msg","to":"{}","tot":"json"},{"t":"set","p":"headers.content-type","pt":"msg","to":"application/pdf","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1010,"y":220,"wires":[["c33065c85ad230e5"]]},{"id":"c33065c85ad230e5","type":"http response","z":"39737d292e7049b0","name":"","x":1190,"y":220,"wires":[]},{"id":"0450c51d52c34862","type":"debug","z":"39737d292e7049b0","name":"debug 34","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":420,"y":180,"wires":[]},{"id":"99e0ba3034fd43bc","type":"string","z":"39737d292e7049b0","name":"replace","methods":[{"name":"replaceAll","params":[{"type":"str","value":" "},{"type":"str","value":"-"}]},{"name":"toLowerCase","params":[]}],"prop":"req.params.name","propout":"req.params.name","object":"msg","objectout":"msg","x":420,"y":220,"wires":[["6941f6754120136f"]]},{"id":"6941f6754120136f","type":"switch","z":"39737d292e7049b0","name":"","property":"payload.Light","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":590,"y":220,"wires":[["cf908096a8907dda","02673b9ff34538fe"]]},{"id":"02673b9ff34538fe","type":"function","z":"39737d292e7049b0","name":"exportToPDFDark","func":"// @ts-nocheck\n\n// const puppeteer = require('puppeteer');\nconst puppeteer = global.get(\"puppeteer\");\n// const odbc = global.get(\"odbc\");\n\n// URL to load should be passed as first parameter\nconst url = 'http://localhost:3000/d/' + msg.req.params.uid + '/' + msg.req.params.name +'?orgId=1&kiosk&from=' + msg.payload.from + '&to=' + msg.payload.to;\n// Username and password (with colon separator) should be second parameter\n\nconst auth_string = 'username:password';\n// Output file name should be third parameter\nconst outfile = '' + msg.req.params.uid+'.pdf';\n\n\n// TODO: Output an error message if number of arguments is not right or arguments are invalid\n\n// Set the browser width in pixels. The paper size will be calculated on the basus of 96dpi,\n// so 1200 corresponds to 12.5\".\nconst width_px = 1920;\n// Note that to get an actual paper size, e.g. Letter, you will want to *not* simply set the pixel\n// size here, since that would lead to a \"mobile-sized\" screen (816px), and mess up the rendering.\n// Instead, set e.g. double the size here (1632px), and call page.pdf() with format: 'Letter' and\n// scale = 0.5.\n\n// Generate authorization header for basic auth\n// @ts-ignore\nconst auth_header = 'Basic ' + new Buffer.from(auth_string).toString('base64');\n\n\n const browser = await puppeteer.launch({headless:\"new\"});\n const page = await browser.newPage();\n\n // Set basic auth headers\n await page.setExtraHTTPHeaders({ 'Authorization': auth_header });\n\n // Increase timeout from the default of 30 seconds to 120 seconds, to allow for slow-loading panels\n await page.setDefaultNavigationTimeout(1200000);\n\n // Increasing the deviceScaleFactor gets a higher-resolution image. The width should be set to\n // the same value as in page.pdf() below. The height is not important\n await page.setViewport({\n width: width_px,\n height: 5000,\n deviceScaleFactor: 2,\n isMobile: false\n })\n\n // Wait until all network connections are closed (and none are opened withing 0.5s).\n // In some cases it may be appropriate to change this to {waitUntil: 'networkidle2'},\n // which stops when there are only 2 or fewer connections remaining.\n await page.goto(url, { waitUntil: 'networkidle0' });\n\n // Hide all panel description (top-left \"i\") pop-up handles and, all panel resize handles\n // Annoyingly, it seems you can't concatenate the two object collections into one\n await page.evaluate(() => {\n let infoCorners = document.getElementsByClassName('panel-info-corner');\n for (el of infoCorners) { el.hidden = true; };\n let resizeHandles = document.getElementsByClassName('react-resizable-handle');\n for (el of resizeHandles) { el.hidden = true; };\n });\n \n // Get the height of the main canvas, and add a margin\n var height_px = 1200;\n height_px = await page.evaluate(() => {\n return document.getElementsByClassName('react-grid-layout')[0].getBoundingClientRect().bottom;\n }) + 20;\n \n await page.addStyleTag({\n content: `\n html {\n -webkit-print-color-adjust: exact !important;\n -webkit-filter: opacity(1) !important;\n }\n `\n });\n \n const pdf = await page.pdf({\n // path: outfile,\n width: width_px + 'px',\n height: height_px + 'px',\n // format: 'A4',\n // landscape: true,\n // format: 'Letter', <-- see note above for generating \"paper-sized\" outputs\n scale: 1,\n displayHeaderFooter: false,\n margin: {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n },\n });\n \n await browser.close();\nmsg.topic = url;\nmsg.payload = pdf;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":790,"y":220,"wires":[["1dd5c082c89e4ce8"]]},{"id":"cf908096a8907dda","type":"debug","z":"39737d292e7049b0","name":"debug 36","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":760,"y":180,"wires":[]},{"id":"895671cc7f376f8c","type":"http in","z":"39737d292e7049b0","name":"","url":"/grafana/:uid/:name","method":"get","upload":false,"swaggerDoc":"","x":190,"y":220,"wires":[["99e0ba3034fd43bc","0450c51d52c34862"]]}]