Skip to content

Commit 40eb5f9

Browse files
committed
system-wide/web: Add basic web ui back
Signed-off-by: Francisco Javier Honduvilla Coto <[email protected]>
1 parent c7e2ba6 commit 40eb5f9

File tree

5 files changed

+20
-157
lines changed

5 files changed

+20
-157
lines changed

cmd/parca-agent/main.go

+13-118
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import (
4848
"github.com/parca-dev/parca-agent/pkg/logger"
4949
"github.com/parca-dev/parca-agent/pkg/objectfile"
5050
"github.com/parca-dev/parca-agent/pkg/profiler"
51+
"github.com/parca-dev/parca-agent/pkg/template"
5152
)
5253

5354
var (
@@ -134,7 +135,6 @@ func main() {
134135
level.Warn(logger).Log("msg", "--temp-dir is deprecated and will be removed in a future release.")
135136
}
136137

137-
mux := http.NewServeMux()
138138
reg := prometheus.NewRegistry()
139139
reg.MustRegister(
140140
collectors.NewBuildInfoCollector(),
@@ -192,76 +192,31 @@ func main() {
192192
flags.SamplingRatio,
193193
)
194194

195+
mux := http.NewServeMux()
195196
mux.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
196197
mux.HandleFunc("/debug/pprof/", pprof.Index)
197198
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
198199
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
199200
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
200201
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
201-
/* // Temporarily comment out the web interface
202-
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
202+
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
203203
if r.URL.Path == "/favicon.ico" {
204204
return
205205
}
206206
if r.URL.Path == "/" {
207207
w.Header().Set("Content-Type", "text/html; charset=utf-8")
208-
activeProfilers := tm.ActiveProfilers()
209-
208+
profilers := pp.Profilers()
210209
statusPage := template.StatusPage{}
211210

212-
for _, profilerSet := range activeProfilers {
213-
for _, profiler := range profilerSet {
214-
profileType := ""
215-
labelSet := labels.Labels{}
216-
217-
for name, value := range profiler.Labels() {
218-
if name == "__name__" {
219-
profileType = string(value)
220-
}
221-
if name != "__name__" {
222-
labelSet = append(labelSet,
223-
labels.Label{Name: string(name), Value: string(value)})
224-
}
225-
}
226-
227-
sort.Sort(labelSet)
228-
229-
q := url.Values{}
230-
q.Add("debug", "1")
231-
q.Add("query", labelSet.String())
232-
233-
statusPage.ActiveProfilers = append(statusPage.ActiveProfilers, template.ActiveProfiler{
234-
Type: profileType,
235-
Labels: labelSet,
236-
Interval: flags.ProfilingDuration,
237-
NextStartedAgo: time.Since(profiler.NextProfileStartedAt()),
238-
Error: profiler.LastError(),
239-
Link: fmt.Sprintf("/query?%s", q.Encode()),
240-
})
241-
}
242-
}
243-
244-
sort.Slice(statusPage.ActiveProfilers, func(j, k int) bool {
245-
a := statusPage.ActiveProfilers[j].Labels
246-
b := statusPage.ActiveProfilers[k].Labels
247-
248-
l := len(a)
249-
if len(b) < l {
250-
l = len(b)
251-
}
252-
253-
for i := 0; i < l; i++ {
254-
if a[i].Name != b[i].Name {
255-
return a[i].Name < b[i].Name
256-
}
257-
if a[i].Value != b[i].Value {
258-
return a[i].Value < b[i].Value
259-
}
260-
}
261-
// If all labels so far were in common, the set with fewer labels comes first.
262-
return len(a)-len(b) < 0
263-
})
211+
for name, profiler := range profilers {
212+
statusPage.ActiveProfilers = append(statusPage.ActiveProfilers, template.ActiveProfiler{
213+
Name: name,
214+
Interval: flags.ProfilingDuration,
215+
NextStartedAgo: time.Since(profiler.NextProfileStartedAt()),
216+
Error: profiler.LastError(),
217+
})
264218

219+
}
265220
err := template.StatusPageTemplate.Execute(w, statusPage)
266221
if err != nil {
267222
http.Error(w,
@@ -273,68 +228,8 @@ func main() {
273228
return
274229
}
275230

276-
if strings.HasPrefix(r.URL.Path, "/query") {
277-
ctx := r.Context()
278-
query := r.URL.Query().Get("query")
279-
matchers, err := parser.ParseMetricSelector(query)
280-
if err != nil {
281-
http.Error(w,
282-
`query incorrectly formatted, expecting selector in form of: {name1="value1",name2="value2"}`,
283-
http.StatusBadRequest,
284-
)
285-
return
286-
}
287-
288-
// We profile every ProfilingDuration so leaving 1s wiggle room. If after
289-
// ProfilingDuration+1s no profile has matched, then there is very likely no
290-
// profiler running that matches the label-set.
291-
timeout := flags.ProfilingDuration + time.Second
292-
ctx, cancel := context.WithTimeout(ctx, timeout)
293-
defer cancel()
294-
295-
profile, err := profileListener.NextMatchingProfile(ctx, matchers)
296-
if profile == nil || errors.Is(err, context.Canceled) {
297-
http.Error(w, fmt.Sprintf(
298-
"No profile taken in the last %s that matches the requested label-matchers query. "+
299-
"Profiles are taken every %s so either the profiler matching the label-set has stopped profiling, "+
300-
"or the label-set was incorrect.",
301-
timeout, flags.ProfilingDuration,
302-
), http.StatusNotFound)
303-
return
304-
}
305-
if err != nil {
306-
http.Error(w, "Unexpected error occurred: "+err.Error(), http.StatusInternalServerError)
307-
return
308-
}
309-
310-
v := r.URL.Query().Get("debug")
311-
if v == "1" {
312-
w.Header().Set("Content-Type", "text/html; charset=utf-8")
313-
q := url.Values{}
314-
q.Add("query", query)
315-
316-
fmt.Fprintf(
317-
w,
318-
"<p><a title='May take up %s to retrieve' href='/query?%s'>Download Next Pprof</a></p>\n",
319-
flags.ProfilingDuration,
320-
q.Encode(),
321-
)
322-
fmt.Fprint(w, "<code><pre>\n")
323-
fmt.Fprint(w, profile.String())
324-
fmt.Fprint(w, "\n</pre></code>")
325-
return
326-
}
327-
328-
w.Header().Set("Content-Type", "application/vnd.google.protobuf+gzip")
329-
w.Header().Set("Content-Disposition", "attachment;filename=profile.pb.gz")
330-
err = profile.Write(w)
331-
if err != nil {
332-
level.Error(logger).Log("msg", "failed to write profile", "err", err)
333-
}
334-
return
335-
}
336231
http.NotFound(w, r)
337-
}) */
232+
})
338233

339234
ctx := context.Background()
340235
var g run.Group

pkg/template/statuspage.html

+3-13
Original file line numberDiff line numberDiff line change
@@ -53,36 +53,26 @@
5353
<p><b>Active Profilers</b></p>
5454
<table style="width:100%">
5555
<tr>
56-
<th>Profile Type</th>
57-
<th>Labels</th>
56+
<th>Profiler Name</th>
5857
<th>Next Profile Started</th>
5958
<th>Error</th>
60-
<th>Show Next Profile</th>
6159
</tr>
6260
{{- range $profiler := .ActiveProfilers }}
6361
<tr>
6462
<td>
65-
{{ .Type }}
66-
</td>
67-
<td>
68-
{{- range $label := .Labels }}
69-
<span class='label'>{{.Name}}="{{.Value}}"</span>
70-
{{- end }}
63+
{{ .Name }}
7164
</td>
7265
<td>
7366
{{ .NextStartedAgo }} ago
7467
</td>
7568
<td>
7669
{{ .Error }}
7770
</td>
78-
<td>
79-
<a title='May take up to {{ .Interval }} to display' href='{{ .Link }}'>Show Next Profile</a>
80-
</td>
8171
</tr>
8272
{{- else }}
8373
<tr>
8474
<td>
85-
No active profilers
75+
No active profilers (this should never happen)
8676
</td>
8777
</tr>
8878
{{- end }}

pkg/template/template.go

+1-5
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ import (
1818
_ "embed"
1919
"html/template"
2020
"time"
21-
22-
"github.com/prometheus/prometheus/model/labels"
2321
)
2422

2523
//go:embed statuspage.html
@@ -28,12 +26,10 @@ var StatusPageTemplateBytes []byte
2826
var StatusPageTemplate = template.Must(template.New("statuspage").Parse(string(StatusPageTemplateBytes)))
2927

3028
type ActiveProfiler struct {
31-
Type string
32-
Labels labels.Labels
29+
Name string
3330
Interval time.Duration
3431
NextStartedAgo time.Duration
3532
Error error
36-
Link string
3733
}
3834

3935
type StatusPage struct {

pkg/template/template_test.go

+1-10
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"testing"
2121
"time"
2222

23-
"github.com/prometheus/prometheus/model/labels"
2423
"github.com/stretchr/testify/require"
2524
)
2625

@@ -31,18 +30,10 @@ func TestStatusPageTemplate(t *testing.T) {
3130
res := bytes.NewBuffer(nil)
3231
err = StatusPageTemplate.Execute(res, &StatusPage{
3332
ActiveProfilers: []ActiveProfiler{{
34-
Type: "test_profile_type",
35-
Labels: []labels.Label{{
36-
Name: "name1",
37-
Value: "value1",
38-
}, {
39-
Name: "name2",
40-
Value: "value2",
41-
}},
33+
Name: "fake_profiler",
4234
Interval: time.Second * 10,
4335
NextStartedAgo: time.Second * 3,
4436
Error: errors.New("test"),
45-
Link: "/test123",
4637
}},
4738
})
4839
require.NoError(t, err)

pkg/template/testdata/statuspage.html

+2-11
Original file line numberDiff line numberDiff line change
@@ -53,29 +53,20 @@
5353
<p><b>Active Profilers</b></p>
5454
<table style="width:100%">
5555
<tr>
56-
<th>Profile Type</th>
57-
<th>Labels</th>
56+
<th>Profiler Name</th>
5857
<th>Next Profile Started</th>
5958
<th>Error</th>
60-
<th>Show Next Profile</th>
6159
</tr>
6260
<tr>
6361
<td>
64-
test_profile_type
65-
</td>
66-
<td>
67-
<span class='label'>name1="value1"</span>
68-
<span class='label'>name2="value2"</span>
62+
fake_profiler
6963
</td>
7064
<td>
7165
3s ago
7266
</td>
7367
<td>
7468
test
7569
</td>
76-
<td>
77-
<a title='May take up to 10s to display' href='/test123'>Show Next Profile</a>
78-
</td>
7970
</tr>
8071
</table>
8172
</div>

0 commit comments

Comments
 (0)