-
Notifications
You must be signed in to change notification settings - Fork 6
/
grafana_pdf.js
164 lines (137 loc) · 5.38 KB
/
grafana_pdf.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
"use strict";
const puppeteer = require("puppeteer");
// URL to load should be passed as first parameter
const url = process.argv[2];
// Username and password (with colon separator) should be second parameter
const auth_string = process.argv[3];
// Output file name should be third parameter
const outFile = process.argv[4];
// TODO: Output an error message if number of arguments is not right or arguments are invalid
// Set the browser width in pixels. The paper size will be calculated on the basus of 96dpi,
// so 1200 corresponds to 12.5".
// variables for debugging start
const VIEWPORT_WIDTH_IN_PX = 1920;
const VIEWPORT_HEIGHT_IN_PX = 1080;
const HEADLESS = true;
// variables for debugging end
// Note that to get an actual paper size, e.g. Letter, you will want to *not* simply set the pixel
// size here, since that would lead to a "mobile-sized" screen (816px), and mess up the rendering.
// Instead, set e.g. double the size here (1632px), and call page.pdf() with format: 'Letter' and
// scale = 0.5.
// Generate authorization header for basic auth
const auth_header = "Basic " + new Buffer.from(auth_string).toString("base64");
(async () => {
try {
const browser = await puppeteer.launch({
headless: HEADLESS,
defaultViewport: null,
ignoreHTTPSErrors: true,
args: [
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-web-security",
"--disable-features=IsolateOrigins",
"--disable-site-isolation-trials",
"--disable-features=BlockInsecurePrivateNetworkRequests",
"--disable-dev-shm-usage",
`--window-size=${VIEWPORT_WIDTH_IN_PX},${VIEWPORT_HEIGHT_IN_PX}`,
],
});
const page = await browser.newPage();
// Set basic auth headers
await page.setExtraHTTPHeaders({ Authorization: auth_header });
// Increase timeout from the default of 30 seconds to 120 seconds, to allow for slow-loading panels
await page.setDefaultNavigationTimeout(120000);
// Increasing the deviceScaleFactor gets a higher-resolution image. The width should be set to
// the same value as in page.pdf() below. The height is not important
await page.setViewport({
width: VIEWPORT_WIDTH_IN_PX,
height: VIEWPORT_HEIGHT_IN_PX,
deviceScaleFactor: 2,
isMobile: false,
});
// Wait until all network connections are closed (and none are opened withing 0.5s).
// In some cases it may be appropriate to change this to {waitUntil: 'networkidle2'},
// which stops when there are only 2 or fewer connections remaining.
await page.goto(url, { waitUntil: "networkidle0" });
// Hide all panel description (top-left "i") pop-up handles and, all panel resize handles
// Annoyingly, it seems you can't concatenate the two object collections into one
// await page.evaluate(() => {
// let infoCorners = document.getElementsByClassName("panel-info-corner");
// for (el of infoCorners) {
// el.hidden = true;
// }
// let resizeHandles = document.getElementsByClassName(
// "react-resizable-handle"
// );
// for (el of resizeHandles) {
// el.hidden = true;
// }
// });
// Get the height of the main canvas, and add a margin
var height_px =
(await page.evaluate(() => {
return document
.querySelector(".react-grid-layout")
.getBoundingClientRect().bottom;
})) + 20;
console.log("height of layout", height_px);
// == auto scroll to the bottom to solve long grafana dashboard start
async function autoScroll(page) {
await page.evaluate(async () => {
await new Promise((resolve, reject) => {
const SCROLL_BY = 150;
const SCROLL_STOP_TIMER = 300;
var totalHeight = 0;
var height_px = document
.querySelector(".react-grid-layout")
.getBoundingClientRect().bottom;
console.log("height of layout 1", height_px);
var timer = setInterval(() => {
var scrollHeight = height_px;
// select the scrollable view
// in newer version of grafana the scrollable div is 'scrollbar-view'
var scrollableEl =
document.querySelector(".view") ||
document.querySelector(".main-view .scrollbar-view");
// element.scrollBy(0, distance);
scrollableEl.scrollBy({
top: SCROLL_BY,
left: 0,
behavior: "smooth",
});
totalHeight += SCROLL_BY;
console.log("totalHeight", totalHeight);
if (totalHeight >= scrollHeight) {
clearInterval(timer);
resolve();
}
}, SCROLL_STOP_TIMER);
});
});
}
await autoScroll(page);
// == auto scroll to the bottom to solve long grafana dashboard end
if (HEADLESS) {
await page.pdf({
path: outFile,
width: VIEWPORT_WIDTH_IN_PX + "px",
height: height_px + "px",
// format: 'Letter', <-- see note above for generating "paper-sized" outputs
scale: 1,
displayHeaderFooter: false,
printBackground: true,
margin: {
top: 0,
right: 0,
bottom: 0,
left: 0,
},
});
console.log("PDF Generated Successfully. file path : ", outFile);
await browser.close();
}
} catch (error) {
console.log(error);
}
})();