File: httpstatus.go

package info (click to toggle)
mtail 3.2.24-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,384 kB
  • sloc: yacc: 647; makefile: 226; sh: 78; lisp: 77; awk: 17
file content (117 lines) | stat: -rw-r--r-- 3,022 bytes parent folder | download
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
// Copyright 2021 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package runtime

import (
	"fmt"
	"html/template"
	"io"
	"net/http"

	"github.com/jaqx0r/mtail/internal/runtime/vm"
)

const loaderTemplate = `
<h2 id="loader">Program Loader</h2>
<table border="1">
<tr>
<th>program name</th>
<th>errors</th>
<th>load errors</th>
<th>load successes</th>
<th>unloads</th>
<th>runtime errors</th>
<th>last runtime error</th>
</tr>
<tr>
{{range $name, $errors := $.Errors}}
<td>{{ if index $.ProgLoaded $name}}<a href="/progz?prog={{$name}}">{{$name}}</a>{{else}}{{$name}}{{end}}</td>
<td>
{{if $errors}}
{{$errors}}
{{else}}
No compile errors
{{end}}
</td>
<td>{{index $.Loaderrors $name}}</td>
<td>{{index $.Loadsuccess $name}}</td>
<td>{{index $.Unloads $name}}</td>
<td>{{index $.RuntimeErrors $name}}</td>
<td><pre>{{index $.RuntimeErrorString $name}}</pre></td>
</tr>
{{end}}
</table>
`

// WriteStatusHTML writes the current state of the loader as HTML to the given writer w.
func (r *Runtime) WriteStatusHTML(w io.Writer) error {
	t, err := template.New("loader").Parse(loaderTemplate)
	if err != nil {
		return err
	}
	r.programErrorMu.RLock()
	defer r.programErrorMu.RUnlock()
	data := struct {
		ProgLoaded         map[string]bool
		Errors             map[string]error
		Loaderrors         map[string]string
		Loadsuccess        map[string]string
		Unloads            map[string]string
		RuntimeErrors      map[string]string
		RuntimeErrorString map[string]string
	}{
		make(map[string]bool),
		r.programErrors,
		make(map[string]string),
		make(map[string]string),
		make(map[string]string),
		make(map[string]string),
		make(map[string]string),
	}
	for name := range r.programErrors {
		if ProgLoadErrors.Get(name) != nil {
			data.Loaderrors[name] = ProgLoadErrors.Get(name).String()
		}
		if ProgLoads.Get(name) != nil {
			data.Loadsuccess[name] = ProgLoads.Get(name).String()
		}
		if ProgUnloads.Get(name) != nil {
			data.Unloads[name] = ProgUnloads.Get(name).String()
		}
		if vm.ProgRuntimeErrors.Get(name) != nil {
			data.RuntimeErrors[name] = vm.ProgRuntimeErrors.Get(name).String()
		}
		r.handleMu.RLock()
		if h, ok := r.handles[name]; ok {
			data.ProgLoaded[name] = true
			data.RuntimeErrorString[name] = h.vm.RuntimeErrorString()
		}
		r.handleMu.RUnlock()
	}
	return t.Execute(w, data)
}

func (r *Runtime) ProgzHandler(w http.ResponseWriter, req *http.Request) {
	prog := req.URL.Query().Get("prog")
	if prog != "" {
		r.handleMu.RLock()
		handle, ok := r.handles[prog]
		r.handleMu.RUnlock()
		if !ok {
			http.Error(w, "No program found", http.StatusNotFound)
			return
		}
		fmt.Fprint(w, handle.vm.DumpByteCode())
		fmt.Fprintf(w, "\nLast runtime error:\n%s", handle.vm.RuntimeErrorString())
		return
	}
	r.handleMu.RLock()
	defer r.handleMu.RUnlock()
	w.Header().Add("Content-type", "text/html")
	fmt.Fprintf(w, "<ul>")
	for prog := range r.handles {
		fmt.Fprintf(w, "<li><a href=\"?prog=%s\">%s</a></li>", prog, prog)
	}
	fmt.Fprintf(w, "</ul>")
}