Skip to content

Commit 1417042

Browse files
committed
Refactoring and packaging for Firefox add-ons website
1 parent 07d6c51 commit 1417042

File tree

10 files changed

+153
-121
lines changed

10 files changed

+153
-121
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
node_modules/**
22
chrome-webstore-release.zip
3+
firefox-webstore-release.zip

extension/html/popup.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
width: 350px;
1818
outline: none;
1919
font-size: 100%;
20-
margin-bottom: 1rem;
20+
padding: 0;
21+
margin: 0.5em 0.5em 1rem;
2122
}
2223

2324
h1 {
@@ -26,20 +27,19 @@
2627

2728
textarea {
2829
width: 100%;
29-
height: 100%;
30+
height: 70%;
3031
font-size: inherit;
3132
}
3233

33-
footer {
34+
p {
3435
font-size: 85%;
35-
margin: 0.5rem 0;
3636
}
3737
</style>
3838
</head>
3939
<body>
4040
<h1>Paths treated as Prometheus endpoints</h1>
4141
<textarea id="paths-to-handle"></textarea>
42-
<footer>Separate paths by new line. Regular Expressions are supported, e.g.: ^/prometheus</footer>
42+
<p>Separate paths by new line. Regular Expressions are supported, e.g.: ^/prometheus</p>
4343
<script src="../js/popup.js"></script>
4444
</body>
4545
</html>

extension/js/background.js

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,35 @@ const defaultPaths = [
88
'^/actuator/prometheus'
99
]
1010

11+
const formatPrometheusMetrics = (body) => body
12+
.split(/\r?\n/)
13+
.map(line => {
14+
// line is a comment
15+
if (/^#/.test(line)) {
16+
return `<span class="comment">${line}</span>`
17+
}
18+
19+
// line is a metric
20+
// Named RegExp groups not supported by Firefox:
21+
// https://bugzilla.mozilla.org/show_bug.cgi?id=1362154
22+
// const tmp = line.match(/^(?<metric>[\w_]+)(?:\{(?<tags>.*)\})?\x20(?<value>.+)/)
23+
const tmp = line.match(/^([\w_]+)(?:\{(.*)\})?\x20(.+)/)
24+
25+
if (tmp && tmp.length > 1) {
26+
let [ _, metric, tags, value ] = tmp
27+
if (tags) {
28+
tags = tags.replace(/([^,]+?)="(.*?)"/g, '<span class="label-key">$1</span>="<span class="label-value">$2</span>"')
29+
tags = `{${tags}}`
30+
}
31+
32+
return `<span class="metric">${metric}</span>${tags || ''} <span class="value">${value}</span>`
33+
}
34+
35+
// line is something else, do nothing
36+
return line
37+
})
38+
.join('<br>')
39+
1140
// Listen for requests from content pages wanting to set up a port
1241
chrome.runtime.onConnect.addListener(port => {
1342
if (port.name !== 'promformat') {
@@ -16,43 +45,14 @@ chrome.runtime.onConnect.addListener(port => {
1645
}
1746

1847
port.onMessage.addListener(msg => {
19-
if (msg.name !== 'SENDING TEXT') {
48+
if (msg.name !== 'PROMETHEUS_METRICS_RAW_BODY') {
2049
return
2150
}
2251

23-
const html = msg.payload
24-
.split(/\r?\n/)
25-
.map(line => {
26-
// line is a comment
27-
if (/^#/.test(line)) {
28-
return `<span class="comment">${line}</span>`
29-
}
30-
31-
// line is a metric
32-
// Named RegExp groups not supported by Firefox:
33-
// https://bugzilla.mozilla.org/show_bug.cgi?id=1362154
34-
// const tmp = line.match(/^(?<metric>[\w_]+)(?:\{(?<tags>.*)\})?\x20(?<value>.+)/)
35-
const tmp = line.match(/^([\w_]+)(?:\{(.*)\})?\x20(.+)/)
36-
37-
if (tmp && tmp.length > 1) {
38-
let [ _, metric, tags, value ] = tmp
39-
if (tags) {
40-
tags = tags.replace(/([^,]+?)="(.*?)"/g, '<span class="label-key">$1</span>="<span class="label-value">$2</span>"')
41-
tags = `{${tags}}`
42-
}
43-
44-
return `<span class="metric">${metric}</span>${tags || ''} <span class="value">${value}</span>`
45-
}
46-
47-
// line is something else, do nothing
48-
return line
49-
})
50-
.join('<br>')
51-
52-
// Post the HTML string to the content script
52+
// Post the HTML string back to the content script
5353
port.postMessage({
54-
name: 'FORMATTED',
55-
payload: html
54+
name: 'PROMETHEUS_METRICS_FORMATTED_BODY',
55+
payload: formatPrometheusMetrics(msg.payload)
5656
})
5757

5858
// Disconnect

extension/js/content.js

Lines changed: 64 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,91 @@
11
/* global chrome */
22

3-
const compress = (text) => text.replace(/\s+/g, '')
3+
// Don't process HTTP response bodies over 30MB
4+
const MAX_BODY_SIZE_BYTES = 30 * 1024 * 1024
45

5-
const maxBodyLength = 3000000 // 3MB
6-
7-
const style = compress(`
8-
pre {
9-
display:none
10-
}
11-
#promformat {
12-
font-family: monospace;
13-
word-wrap: break-word;
14-
white-space: pre-wrap;
15-
}
16-
.comment {
17-
color: #6a737d;
18-
display: inline-block;
19-
}
20-
br + .comment {
21-
padding-top: 1em;
22-
}
23-
.comment + br + .comment {
24-
padding-top: 0;
25-
}
26-
27-
.metric { color: #000 }
28-
.value { color: #ff20ed }
29-
.label-key { color: blue }
30-
.label-value { color: green }
31-
`)
32-
33-
const port = chrome.runtime.connect({ name: 'promformat' })
34-
35-
// Add listener to receive response from BG when ready
36-
port.onMessage.addListener(msg => {
37-
switch (msg.name) {
38-
case 'FORMATTED' :
39-
// Insert CSS
40-
const promformatStyle = document.createElement('style')
41-
document.head.appendChild(promformatStyle)
42-
promformatStyle.insertAdjacentHTML('beforeend', style)
43-
44-
// Insert HTML content
45-
const promformatContent = document.createElement('div')
46-
promformatContent.id = 'promformat'
47-
document.body.appendChild(promformatContent)
48-
49-
promformatContent.innerHTML = msg.payload
50-
break
51-
52-
default :
53-
throw new Error(`Message not understood: ${msg.name}`)
54-
}
55-
})
56-
57-
function ready (data) {
6+
const sendBodyToFormatter = (storedData) => {
587
// Check if it is a Prometheus plain text response
598
// This is quite a basic assumption, as the browser cannot access the
609
// 'version' part of the content type to verify.
61-
const paths = data.paths.length ? data.paths : []
62-
6310
if (document.contentType !== 'text/plain') {
11+
port.disconnect()
6412
return
6513
}
6614

67-
for (var i = 0; i < paths.length; ++i) {
68-
if (document.location.pathname.match(paths[i])) {
69-
format()
70-
break
71-
}
15+
// Check if the current page's paths matches one of our whitelist
16+
if (!storedData.paths.some(path => document.location.pathname.match(path))) {
17+
port.disconnect()
18+
return
7219
}
73-
}
7420

75-
function format () {
76-
// Check if plain text wrapped in <pre> element exists and doesn't exceed maxBodyLength
21+
// Check if plain text wrapped in <pre> element exists and doesn't exceed
22+
// MAX_BODY_SIZE_BYTES
7723
const pre = document.body.querySelector('pre')
7824
const rawBody = pre && pre.innerText
7925

80-
if (!rawBody || rawBody.length > maxBodyLength) {
26+
if (!rawBody || rawBody.length > MAX_BODY_SIZE_BYTES) {
8127
port.disconnect()
8228
return
8329
}
8430

8531
// Post the contents of the PRE
8632
port.postMessage({
87-
name: 'SENDING TEXT',
33+
name: 'PROMETHEUS_METRICS_RAW_BODY',
8834
payload: rawBody
8935
})
9036
}
9137

38+
const renderFormattedHTML = (html) => {
39+
const style = `
40+
pre {
41+
display:none
42+
}
43+
#promformat {
44+
font-family: monospace;
45+
word-wrap: break-word;
46+
white-space: pre-wrap;
47+
}
48+
.comment {
49+
color: #6a737d;
50+
display: inline-block;
51+
}
52+
br + .comment {
53+
padding-top: 1em;
54+
}
55+
.comment + br + .comment {
56+
padding-top: 0;
57+
}
58+
59+
.metric { color: #000 }
60+
.value { color: #ff20ed }
61+
.label-key { color: blue }
62+
.label-value { color: green }
63+
`
64+
65+
// Insert CSS
66+
const promformatStyle = document.createElement('style')
67+
document.head.appendChild(promformatStyle)
68+
promformatStyle.insertAdjacentHTML('beforeend', style)
69+
70+
// Insert HTML content
71+
const promformatContent = document.createElement('div')
72+
promformatContent.id = 'promformat'
73+
document.body.appendChild(promformatContent)
74+
75+
promformatContent.innerHTML = html
76+
}
77+
78+
const port = chrome.runtime.connect({ name: 'promformat' })
79+
80+
// Add listener to receive response from background when ready
81+
port.onMessage.addListener(msg => {
82+
if (msg.name !== 'PROMETHEUS_METRICS_FORMATTED_BODY') {
83+
return
84+
}
85+
86+
renderFormattedHTML(msg.payload)
87+
})
88+
9289
document.addEventListener('DOMContentLoaded', () => {
93-
chrome.storage.sync.get({ paths: [] }, ready)
90+
chrome.storage.sync.get({ paths: [] }, sendBodyToFormatter)
9491
})

extension/manifest.json

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "Prometheus Formatter",
3-
"version": "1.2.4",
3+
"version": "2.0.0",
44
"manifest_version": 2,
55
"description": "Makes plain Prometheus metrics easier to read.",
66
"homepage_url": "https://github.com/fhemberger/prometheus-formatter",
@@ -37,11 +37,5 @@
3737
"permissions": [
3838
"activeTab",
3939
"storage"
40-
],
41-
"browser_specific_settings": {
42-
"gecko": {
43-
"id": "prometheus-formatter@frederic-hemberger.de",
44-
"strict_min_version": "72.0"
45-
}
46-
}
47-
}
40+
]
41+
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"description": "Browser extension which makes plain Prometheus metrics easier to read.",
55
"scripts": {
66
"test": "standard js/*.js --fix",
7-
"release": "node update-manifest.js && cd extension && zip -r ../webstore-release.zip html icons js LICENSE.txt manifest.json -x icons/.DS_Store js/.DS_Store .DS_Store"
7+
"release": "./package/package.sh"
88
},
99
"author": "Frederic Hemberger",
1010
"license": "MIT",

package/package.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/usr/bin/env bash
2+
set -uo pipefail
3+
4+
readonly DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
5+
6+
function package_zip () {
7+
cd "$1" && zip -r "$2" html icons js LICENSE.txt manifest.json -x icons/.DS_Store js/.DS_Store .DS_Store
8+
}
9+
10+
# Update manifest version number from package.json
11+
"$DIR/update-manifest-version.js"
12+
13+
# Package Chrome webstore release
14+
package_zip "$DIR/../extension" "$DIR/../chrome-webstore-release.zip"
15+
16+
# Package Firefox webstore release
17+
cp -r "$DIR/../extension" "$DIR/../extension-firefox"
18+
"$DIR/update-manifest-firefox.js"
19+
package_zip "$DIR/../extension-firefox" "$DIR/../firefox-webstore-release.zip"
20+
rm -r "$DIR/../extension-firefox"

package/update-manifest-firefox.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env node
2+
3+
const fs = require('fs')
4+
const path = require('path')
5+
const manifestPath = path.join(__dirname, '..', 'extension-firefox', 'manifest.json')
6+
const manifest = require(manifestPath)
7+
8+
// Firefox needs additional keys in the manifest.json which are not allowed in Chrome
9+
manifest.browser_specific_settings = {
10+
gecko: {
11+
id: 'prometheus-formatter@frederic-hemberger.de',
12+
strict_min_version: '72.0'
13+
}
14+
}
15+
16+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf8')

package/update-manifest-version.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env node
2+
3+
const fs = require('fs')
4+
const path = require('path')
5+
const pkg = require(path.join(__dirname, '..', 'package.json'))
6+
const manifestPath = path.join(__dirname, '..', 'extension', 'manifest.json')
7+
const manifest = require(manifestPath)
8+
9+
manifest.version = pkg.version
10+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf8')

update-manifest.js

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)