Skip to content

Commit d18f552

Browse files
First release
1 parent b95aa7b commit d18f552

File tree

9 files changed

+398
-0
lines changed

9 files changed

+398
-0
lines changed

.editorconfig

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# EditorConfig is awesome: https://EditorConfig.org
2+
3+
# top-most EditorConfig file
4+
root = true
5+
6+
[*]
7+
indent_style = space
8+
indent_size = 2
9+
end_of_line = lf
10+
charset = utf-8
11+
trim_trailing_whitespace = true
12+
insert_final_newline = true
13+
14+
[*.go]
15+
indent_style = tab
16+
indent_size = 4
17+
18+
[Makefile]
19+
indent_style = tab
20+
indent_size = 4

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
release/

Makefile

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
VERSION = "1.0.0"
2+
3+
dev:
4+
find -type f \( -name "*.go" \) | entr -r go run *.go
5+
6+
build: clean-build embed-assets amd64 arm
7+
@echo "Building amd64 and arm version"
8+
9+
embed-assets:
10+
go-bindata assets/...
11+
12+
clean-build:
13+
- rm release -Rf
14+
15+
amd64:
16+
mkdir -p release/linux-amd64
17+
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-X 'main.ldVersion=$(VERSION)'" -o release/linux-amd64/journalctl-proxy -v -a *.go
18+
19+
arm:
20+
mkdir -p release/linux-arm
21+
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -ldflags="-X 'main.ldVersion=$(VERSION)'" -o release/linux-arm/journalctl-proxy -v -a *.go

assets/index.html

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
8+
<title>journalctl</title>
9+
10+
<style>
11+
body {
12+
font-family: sans-serif;
13+
font-size: 13px;
14+
}
15+
16+
header {
17+
display: flex;
18+
align-items: center;
19+
}
20+
21+
header h1 {
22+
flex-grow: 1;
23+
}
24+
</style>
25+
26+
</head>
27+
28+
<body>
29+
30+
<header>
31+
<h1>journalctl proxy</h1>
32+
<div>
33+
<select onchange="startListeningToService()">
34+
<option>Select service</option>
35+
</select>
36+
</div>
37+
</header>
38+
39+
<table border="1" width="100%">
40+
<thead>
41+
<tr>
42+
<th>PID</th>
43+
<th>Unit</th>
44+
<th>Timestamp</th>
45+
<th>Message</th>
46+
</tr>
47+
</thead>
48+
<tbody></tbody>
49+
</table>
50+
51+
<script>
52+
53+
let socket = null;
54+
55+
const select = document.querySelector('select');
56+
const table = document.querySelector('table');
57+
58+
(async () => {
59+
const servicesRequest = await fetch('/list-services');
60+
const servicesList = await servicesRequest.text();
61+
62+
for (let line of servicesList.split('\n')) {
63+
line = line.trim();
64+
if (line === '') break;
65+
66+
if (!line.startsWith('UNIT')) {
67+
const serviceName = line.split(' ')[0];
68+
const option = document.createElement('option');
69+
option.value = serviceName.split('.')[0];
70+
option.innerText = serviceName;
71+
select.appendChild(option)
72+
}
73+
}
74+
})();
75+
76+
function startListeningToService() {
77+
if (socket) {
78+
socket.close(1000, 'Work complete');
79+
}
80+
81+
socket = new WebSocket(`ws://${window.location.host}/ws/${select.value}`);
82+
83+
socket.onopen = function (e) {
84+
console.log(`[open] Connection established with service: ${select.value}`);
85+
};
86+
87+
socket.onmessage = function (event) {
88+
const incomingMessage = JSON.parse(event.data);
89+
90+
const row = document.createElement('tr');
91+
const pid = document.createElement('td');
92+
const priority = document.createElement('td');
93+
const systemdUnit = document.createElement('td');
94+
const realtimeTimestamp = document.createElement('td');
95+
const message = document.createElement('td');
96+
97+
pid.innerText = incomingMessage._PID;
98+
systemdUnit.innerText = incomingMessage._SYSTEMD_UNIT;
99+
realtimeTimestamp.innerText = incomingMessage.__REALTIME_TIMESTAMP;
100+
message.innerText = incomingMessage.MESSAGE;
101+
102+
row.appendChild(pid);
103+
row.appendChild(systemdUnit);
104+
row.appendChild(realtimeTimestamp);
105+
row.appendChild(message);
106+
107+
table.appendChild(row);
108+
};
109+
}
110+
111+
</script>
112+
113+
</body>
114+
115+
</html>

bindata.go

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"compress/gzip"
6+
"fmt"
7+
"io"
8+
"strings"
9+
)
10+
11+
func bindata_read(data []byte, name string) ([]byte, error) {
12+
gz, err := gzip.NewReader(bytes.NewBuffer(data))
13+
if err != nil {
14+
return nil, fmt.Errorf("Read %q: %v", name, err)
15+
}
16+
17+
var buf bytes.Buffer
18+
_, err = io.Copy(&buf, gz)
19+
gz.Close()
20+
21+
if err != nil {
22+
return nil, fmt.Errorf("Read %q: %v", name, err)
23+
}
24+
25+
return buf.Bytes(), nil
26+
}
27+
28+
var _assets_index_html = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x56\xdd\x6e\xdb\x38\x13\xbd\xf7\x53\x4c\x85\x7e\xb0\x0c\xd4\x92\x8d\xef\x66\xe1\x48\x06\x82\xc4\xbb\xc8\xa2\x69\x83\xda\x41\xb7\xe8\x16\x29\x2d\x8d\x2d\x6e\x29\x52\x25\xc7\x51\xbc\x45\xde\x7d\x41\x51\xd6\x8f\xeb\x1a\x48\x2e\x62\x91\x33\x67\xe6\x9c\x99\x21\xa5\xe8\xd5\xf5\xfb\xab\xd5\xa7\xbb\x05\x64\x94\x8b\xf9\x20\xb2\x3f\x20\x98\xdc\xc6\x1e\x4a\x6f\x3e\x18\x00\x44\x19\xb2\x74\x3e\x00\x00\x88\x72\x24\x06\x49\xc6\xb4\x41\x8a\xbd\xfb\xd5\xef\xe3\xdf\xbc\xae\x29\x23\x2a\xc6\xf8\x7d\xc7\x1f\x63\xef\xaf\xf1\xfd\xe5\xf8\x4a\xe5\x05\x23\xbe\x16\xe8\x41\xa2\x24\xa1\xa4\xd8\xbb\x59\xc4\x98\x6e\xb1\x87\x94\x2c\xc7\xd8\x7b\xe4\x58\x16\x4a\x53\xc7\xb9\xe4\x29\x65\x71\x8a\x8f\x3c\xc1\x71\xb5\x78\x03\x5c\x72\xe2\x4c\x8c\x4d\xc2\x04\xc6\xd3\x60\x72\x08\x45\x9c\x04\xce\xff\x51\x3b\x2d\x99\x48\x48\x44\xa1\xdb\x19\x38\xb3\xa1\xbd\x5d\x40\xf5\xb7\x56\xe9\x1e\x7e\xd4\x0b\x80\x8d\x92\x34\xde\xb0\x9c\x8b\xfd\x0c\x0c\x93\x66\x6c\x50\xf3\xcd\x45\xdf\xc1\xf0\x7f\x71\x06\xd3\xff\x17\x4f\x07\xc3\xf3\xa0\x7e\xb0\x65\x42\xdd\x89\x98\x72\x53\x08\xb6\x9f\xc1\x46\xe0\x53\x1b\x87\x09\xbe\x95\x63\x4e\x98\x9b\x19\x24\x28\x09\xf5\xaf\x62\x65\xd3\x2e\x41\x81\x4f\xe3\xad\x56\xe5\x0c\xa6\x2d\xa0\xd2\x15\xd6\xc2\x6c\xb7\x42\xd7\x2e\xfb\x68\x15\x1e\xa4\xbb\x88\x07\xed\x51\x36\xed\x54\x09\x0a\xad\x9e\xf6\x51\x98\x4d\x1b\x7b\xca\x1f\xe7\x4d\xe6\xc8\xa0\xc0\x84\x40\xc9\x24\x63\x72\x8b\xb1\x67\x88\x69\x7a\xcb\x0d\xa1\xe4\x72\xbb\x52\x4b\xd4\xb6\x3f\xfe\xc8\x6b\x51\x00\x91\x2a\x88\x2b\x39\x5f\x3a\xb8\x71\x4e\x51\x58\x6f\xb7\xf1\x43\x97\xa0\xc9\x1e\x36\xe9\x9d\x1c\x4b\xbc\x6e\x30\x5b\x0b\x84\xb5\xd2\x29\xea\xd8\x9b\x7a\xe0\xc6\xc3\x9b\x4e\x26\xff\x6b\x72\x47\xd4\x8e\xac\x5b\xeb\x1e\x2d\xca\xe6\x77\x37\xd7\x51\x48\xd9\xf1\xf6\xbd\xe4\x74\x6a\x7f\xc5\x73\x34\xc4\xf2\xe2\x94\xf1\x16\x8d\x61\x5b\xec\x9b\xa2\xb0\x4d\x6a\x2d\x1d\x42\x11\x55\x8d\x89\x42\xf7\x5b\xeb\xac\x94\x35\x83\x9a\x68\x5e\xd0\xfc\x30\x0e\x02\x09\x8c\x4a\xbe\x21\x41\x0c\x72\x27\xc4\xc5\xc1\x92\x28\x69\x6c\x65\xab\x02\xc7\x90\xaa\x64\x97\xa3\xa4\xe0\xfb\x0e\xf5\xde\xd5\x5d\x69\x7f\xe8\x1c\x86\xa3\x8b\x1e\xcc\x15\xf3\xd7\xa8\xca\x6e\x41\x35\xca\x67\x66\x2f\x13\xf0\x47\x10\xcf\x3b\x83\x79\xe0\x50\x75\xd7\x7c\xc0\xef\x3b\x34\x96\x0c\x2b\x19\x27\xd8\x20\x25\x99\x3f\x0c\x05\x37\x34\x3e\x38\xb5\x4c\x8e\xe1\x76\xa8\x1a\xec\x51\xcc\x80\xf0\x89\xfc\x96\x8f\x3d\x93\x1a\x7c\x5b\x1d\xc1\x25\x82\xda\xf4\xc2\x04\xa6\x10\x9c\xfc\xe1\xdf\x72\x38\x1a\x75\xf8\x82\xf3\x8e\xab\x9f\x80\x34\xcf\xfd\x0e\x1d\x00\xbe\x01\xdf\x79\xc4\x31\x0c\x87\x23\x58\x6b\x64\xdf\x3a\x59\x9d\xcb\xab\x0a\x5e\x9d\x04\xf3\x91\x53\xe6\x0f\xef\xdf\xdd\xac\x8e\x53\x1d\xe9\x7b\xc7\xf2\x26\x73\x4d\x0f\x86\xa3\xcf\x93\x2f\x17\x27\x30\xee\x9c\x74\x1b\x94\x68\x64\x84\x0b\x81\x76\xe5\x0f\x9d\xc3\x70\xd4\x07\xbb\xdd\xe0\x91\x89\x9d\xcd\xd5\xc9\x7c\x48\x19\x9c\x48\x59\xa3\xb8\x94\xa8\x57\xf8\x44\x7d\x64\xdf\xd7\x8d\x53\xc0\x8a\x02\x65\x7a\x95\x71\x91\xfa\x0e\x3e\xea\xb8\x3d\x0f\x8e\x9f\x9e\x47\x9d\xe6\x6d\x76\x32\xa9\xe4\xfd\xf2\x2e\xe9\xd4\xd1\xd6\xdb\x1d\x80\x7e\x75\xdd\x5e\x90\x08\x65\xd0\x9f\x4e\x26\x93\x37\x30\xfc\xa8\xf4\x37\x48\x54\x5e\x08\x24\xec\xd6\xe6\xb9\xed\x60\x7b\x98\xb0\x84\x8f\xb8\x5e\x56\x6b\xff\x6b\x69\x66\x61\xf8\xfa\x47\xc9\x65\xaa\xca\x40\xa8\x84\x55\x45\xc9\x94\xa1\xe7\xb0\x34\xe1\xeb\x1f\xb5\xf4\xaa\xb8\xcf\x5f\xbb\xb3\x58\x73\x51\x52\x15\x68\x9b\xd6\x08\xf4\xb1\x4f\xda\x36\x57\x09\x0c\x84\xda\xfa\x5f\x3f\x5b\xef\x2f\x70\xa5\xa4\x44\xe7\x6e\x2f\x9a\xb5\xe0\x26\xc3\x14\x4a\x4e\xd9\xa1\x0d\x33\x38\x91\xbd\xd1\x76\x8a\x48\xee\x2e\xa6\x3e\x97\x47\x94\xf4\x33\x1f\x02\x2e\x13\x95\x73\xb9\xbd\x6d\x40\x7f\x2e\xdf\xbf\x0b\x0a\xfb\xae\x77\xa8\x20\x65\xc4\x46\xbd\x73\xe0\xa0\x5a\x95\x67\x86\x94\x74\x7f\x40\x1d\xa6\xe0\xe9\x39\x4c\x7a\x12\xa3\xb9\xd2\x9c\xf6\x2f\x06\x9a\xbd\x21\xcc\x53\x7b\xbb\xbf\x18\xab\x91\x09\xe2\x39\x36\xaf\x80\x17\x47\x68\xdb\x70\x1e\xd7\x01\x16\x3c\xed\x9d\xc4\xa3\xe6\x04\x0f\x77\x37\xd7\xdd\x44\x1d\x81\xe7\x71\xcb\x4f\xcb\xd5\xe2\xf6\xfa\xc1\x5e\x55\xdd\x00\x3f\xa9\x3c\x1f\xe6\xe1\xc3\xe2\xf2\xed\xea\xe6\x76\xf1\x60\xff\x2d\x57\x97\xb7\x77\xdd\x68\xb5\xe2\xb3\x31\x6e\x17\xcb\xe5\xe5\x1f\x8b\x9e\x6c\xad\xca\xde\xa5\x52\xf0\xb4\x57\xcf\x63\x7b\x47\xf6\x59\xbf\x9f\xd4\x9d\xf5\xae\xd9\xf7\x3b\x52\xbd\x0b\xfb\x41\x55\xd9\x3f\x80\xf5\xc3\xe0\xf0\x4d\xd6\xbe\xc3\xa3\xb0\xfe\x14\x8b\x42\xf7\x9d\xfd\x5f\x00\x00\x00\xff\xff\xfe\x7d\x8a\x21\x78\x0b\x00\x00")
29+
30+
func assets_index_html() ([]byte, error) {
31+
return bindata_read(
32+
_assets_index_html,
33+
"assets/index.html",
34+
)
35+
}
36+
37+
// Asset loads and returns the asset for the given name.
38+
// It returns an error if the asset could not be found or
39+
// could not be loaded.
40+
func Asset(name string) ([]byte, error) {
41+
cannonicalName := strings.Replace(name, "\\", "/", -1)
42+
if f, ok := _bindata[cannonicalName]; ok {
43+
return f()
44+
}
45+
return nil, fmt.Errorf("Asset %s not found", name)
46+
}
47+
48+
// AssetNames returns the names of the assets.
49+
func AssetNames() []string {
50+
names := make([]string, 0, len(_bindata))
51+
for name := range _bindata {
52+
names = append(names, name)
53+
}
54+
return names
55+
}
56+
57+
// _bindata is a table, holding each asset generator, mapped to its name.
58+
var _bindata = map[string]func() ([]byte, error){
59+
"assets/index.html": assets_index_html,
60+
}
61+
// AssetDir returns the file names below a certain
62+
// directory embedded in the file by go-bindata.
63+
// For example if you run go-bindata on data/... and data contains the
64+
// following hierarchy:
65+
// data/
66+
// foo.txt
67+
// img/
68+
// a.png
69+
// b.png
70+
// then AssetDir("data") would return []string{"foo.txt", "img"}
71+
// AssetDir("data/img") would return []string{"a.png", "b.png"}
72+
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
73+
// AssetDir("") will return []string{"data"}.
74+
func AssetDir(name string) ([]string, error) {
75+
node := _bintree
76+
if len(name) != 0 {
77+
cannonicalName := strings.Replace(name, "\\", "/", -1)
78+
pathList := strings.Split(cannonicalName, "/")
79+
for _, p := range pathList {
80+
node = node.Children[p]
81+
if node == nil {
82+
return nil, fmt.Errorf("Asset %s not found", name)
83+
}
84+
}
85+
}
86+
if node.Func != nil {
87+
return nil, fmt.Errorf("Asset %s not found", name)
88+
}
89+
rv := make([]string, 0, len(node.Children))
90+
for name := range node.Children {
91+
rv = append(rv, name)
92+
}
93+
return rv, nil
94+
}
95+
96+
type _bintree_t struct {
97+
Func func() ([]byte, error)
98+
Children map[string]*_bintree_t
99+
}
100+
var _bintree = &_bintree_t{nil, map[string]*_bintree_t{
101+
"assets": &_bintree_t{nil, map[string]*_bintree_t{
102+
"index.html": &_bintree_t{assets_index_html, map[string]*_bintree_t{
103+
}},
104+
}},
105+
}}

go.mod

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module github.com/mitjafelicijan/journalctl-proxy
2+
3+
go 1.16
4+
5+
require (
6+
github.com/gofiber/fiber/v2 v2.6.0
7+
github.com/gofiber/websocket/v2 v2.0.2
8+
)

go.sum

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4=
2+
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
3+
github.com/fasthttp/websocket v1.4.3 h1:qjhRJ/rTy4KB8oBxljEC00SDt6HUY9jLRfM601SUdS4=
4+
github.com/fasthttp/websocket v1.4.3/go.mod h1:5r4oKssgS7W6Zn6mPWap3NWzNPJNzUUh3baWTOhcYQk=
5+
github.com/gofiber/fiber/v2 v2.1.0/go.mod h1:aG+lMkwy3LyVit4CnmYUbUdgjpc3UYOltvlJZ78rgQ0=
6+
github.com/gofiber/fiber/v2 v2.6.0 h1:OywSUL6QPY/+/b89Ulnb8reovwm5QGjZQfk74v0R7Uc=
7+
github.com/gofiber/fiber/v2 v2.6.0/go.mod h1:f8BRRIMjMdRyt2qmJ/0Sea3j3rwwfufPrh9WNBRiVZ0=
8+
github.com/gofiber/websocket/v2 v2.0.2 h1:UA/6NpyG+vmPGlvJvW8MJPJpRFuS7abinZ5HbLuV8u0=
9+
github.com/gofiber/websocket/v2 v2.0.2/go.mod h1:7VBnzEVRK0K0eTIVc5GbXPF1JWUFnllY0X4cRtG2v78=
10+
github.com/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
11+
github.com/klauspost/compress v1.10.7 h1:7rix8v8GpI3ZBb0nSozFRgbtXKv+hOe+qfEpZqybrAg=
12+
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
13+
github.com/savsgio/gotils v0.0.0-20200608150037-a5f6f5aef16c h1:2nF5+FZ4/qp7pZVL7fR6DEaSTzuDmNaFTyqp92/hwF8=
14+
github.com/savsgio/gotils v0.0.0-20200608150037-a5f6f5aef16c/go.mod h1:TWNAOTaVzGOXq8RbEvHnhzA/A2sLZzgn0m6URjnukY8=
15+
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
16+
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
17+
github.com/valyala/fasthttp v1.14.0/go.mod h1:ol1PCaL0dX20wC0htZ7sYCsvCYmrouYra0zHzaclZhE=
18+
github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA=
19+
github.com/valyala/fasthttp v1.18.0 h1:IV0DdMlatq9QO1Cr6wGJPVW1sV1Q8HvZXAIcjorylyM=
20+
github.com/valyala/fasthttp v1.18.0/go.mod h1:jjraHZVbKOXftJfsOYoAjaeygpj5hr8ermTRJNroD7A=
21+
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a h1:0R4NLDRDZX6JcmhJgXi5E4b8Wg84ihbmUKp/GvSPEzc=
22+
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
23+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
24+
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
25+
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
26+
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
27+
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
28+
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
29+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
30+
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
31+
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
32+
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
33+
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
34+
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
35+
golang.org/x/sys v0.0.0-20201210223839-7e3030f88018 h1:XKi8B/gRBuTZN1vU9gFsLMm6zVz5FSCDzm8JYACnjy8=
36+
golang.org/x/sys v0.0.0-20201210223839-7e3030f88018/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
37+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
38+
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
39+
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

main.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"flag"
6+
"fmt"
7+
"log"
8+
"os/exec"
9+
10+
"github.com/gofiber/fiber/v2"
11+
"github.com/gofiber/fiber/v2/middleware/logger"
12+
"github.com/gofiber/fiber/v2/middleware/recover"
13+
"github.com/gofiber/websocket/v2"
14+
)
15+
16+
func main() {
17+
var port int
18+
19+
flag.IntVar(&port, "p", 8000, "Server port number")
20+
flag.Parse()
21+
22+
app := fiber.New(fiber.Config{
23+
Prefork: false,
24+
})
25+
26+
app.Use(recover.New())
27+
app.Use(logger.New())
28+
29+
app.Get("/", func(c *fiber.Ctx) error {
30+
data, err := Asset("assets/index.html")
31+
if err != nil {
32+
fmt.Println(err)
33+
}
34+
35+
c.Type("html", "utf-8")
36+
return c.SendString(string(data))
37+
})
38+
39+
app.Get("/list-services", func(c *fiber.Ctx) error {
40+
out, err := exec.Command("systemctl", "list-units", "--type=service", "--state=running", "--no-pager").Output()
41+
42+
if err != nil {
43+
fmt.Printf("%s", err)
44+
}
45+
46+
return c.SendString(string(out[:]))
47+
})
48+
49+
app.Use("/ws", func(c *fiber.Ctx) error {
50+
if websocket.IsWebSocketUpgrade(c) {
51+
c.Locals("allowed", true)
52+
return c.Next()
53+
}
54+
return fiber.ErrUpgradeRequired
55+
})
56+
57+
app.Get("/ws/:id", websocket.New(func(c *websocket.Conn) {
58+
var messageType int = 1
59+
var message []byte
60+
var err error
61+
62+
cmd := exec.Command("journalctl", "-b", "-u", fmt.Sprintf("%s.service", c.Params("id")), "-f", "-n", "5", "-o", "json")
63+
stdout, _ := cmd.StdoutPipe()
64+
cmd.Start()
65+
66+
scanner := bufio.NewScanner(stdout)
67+
for scanner.Scan() {
68+
message = []byte(scanner.Text())
69+
if err = c.WriteMessage(messageType, message); err != nil {
70+
log.Println(err)
71+
}
72+
}
73+
74+
cmd.Wait()
75+
}, websocket.Config{
76+
WriteBufferSize: 8192,
77+
}))
78+
79+
log.Fatal(app.Listen(fmt.Sprintf(":%d", port)))
80+
}

0 commit comments

Comments
 (0)