Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions syz-cluster/dashboard/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ func (h *dashboardHandler) statsPage(w http.ResponseWriter, r *http.Request) err
type StatsPageData struct {
Processed []*db.CountPerWeek
Findings []*db.CountPerWeek
Reports []*db.CountPerWeek
Delay []*db.DelayPerWeek
Distribution []*db.StatusPerWeek
}
Expand All @@ -231,6 +232,10 @@ func (h *dashboardHandler) statsPage(w http.ResponseWriter, r *http.Request) err
if err != nil {
return fmt.Errorf("failed to query findings data: %w", err)
}
data.Reports, err = h.statsRepo.ReportsPerWeek(r.Context())
if err != nil {
return fmt.Errorf("failed to query reports data: %w", err)
}
data.Delay, err = h.statsRepo.DelayPerWeek(r.Context())
if err != nil {
return fmt.Errorf("failed to query delay data: %w", err)
Expand Down Expand Up @@ -388,6 +393,9 @@ func errToStatus(f func(http.ResponseWriter, *http.Request) error) http.HandlerF
} else if errors.Is(err, errBadRequest) {
http.Error(w, err.Error(), http.StatusBadRequest)
} else if err != nil {
// TODO: if the error happened in the template, likely we've already printed
// something to w. Unless we're in streamBlob(), it makes sense to first collect
// the output in some buffer and only dump it after the exit from the handler.
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
Expand Down
6 changes: 5 additions & 1 deletion syz-cluster/dashboard/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ func TestURLs(t *testing.T) {
handler, baseURL := testServer(t, env)
urlGen := api.NewURLGenerator(baseURL)

urls := []string{urlGen.Series(ids.SeriesID)}
urls := []string{
baseURL,
baseURL + "/stats",
urlGen.Series(ids.SeriesID),
}
for _, buildID := range []string{ids.BaseBuildID, ids.PatchedBuildID} {
urls = append(urls, urlGen.BuildConfig(buildID))
urls = append(urls, urlGen.BuildLog(buildID))
Expand Down
16 changes: 16 additions & 0 deletions syz-cluster/dashboard/templates/graphs.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ <h2 class="h4">Findings (weekly)</h2>

<hr class="my-4">

<div class="chart-wrapper mb-4">
<h2 class="h4">Reports (weekly)</h2>
<p class="text-muted small">How many reports with findings have been published.</p>
<div id="reports_chart_div" style="width: 100%; height: 400px;"></div>
<p class="text-muted small">Click and drag to zoom into a time range. Right-click to reset.</p>
</div>

<hr class="my-4">

<div class="chart-wrapper mb-4">
<h2 class="h4">Wait Time before Fuzzing (avg hours, weekly)</h2>
<p class="text-muted small">How many hours have passed since the moment the series was published and the moment we started fuzzing it.</p>
Expand Down Expand Up @@ -67,9 +76,16 @@ <h2 class="h4">Status Distribution (weekly)</h2>
{{end}}
];

const reportsData = [
{{range .Reports}}
[new Date({{.Date.Format "2006-01-02"}}), {{.Count}}],
{{end}}
];

function drawAllCharts() {
drawChart('processed_chart_div', processedData, '#007bff');
drawChart('findings_chart_div', findingsData, '#dc3545');
drawChart('reports_chart_div', reportsData, '#dc3545');
drawChart('avg_wait_chart_div', delayData, 'black');
drawDistributionChart();
}
Expand Down
14 changes: 14 additions & 0 deletions syz-cluster/pkg/db/stats_repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,20 @@ ORDER BY Date`,
})
}

func (repo *StatsRepository) ReportsPerWeek(ctx context.Context) (
[]*CountPerWeek, error) {
return readEntities[CountPerWeek](ctx, repo.client.Single(), spanner.Statement{
SQL: `SELECT
TIMESTAMP_TRUNC(SessionReports.ReportedAt, WEEK) as Date,
COUNT(*) as Count
FROM Findings
JOIN SessionReports ON SessionReports.SessionID = Findings.SessionID
WHERE SessionReports.Moderation = FALSE AND SessionReports.ReportedAt IS NOT NULL
GROUP BY Date
ORDER BY Date`,
})
}

func (repo *StatsRepository) FindingsPerWeek(ctx context.Context) (
[]*CountPerWeek, error) {
return readEntities[CountPerWeek](ctx, repo.client.Single(), spanner.Statement{
Expand Down
2 changes: 2 additions & 0 deletions syz-cluster/pkg/db/stats_repo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ func TestStatsSQLs(t *testing.T) {
assert.NoError(t, err)
_, err = statsRepo.DelayPerWeek(ctx)
assert.NoError(t, err)
_, err = statsRepo.ReportsPerWeek(ctx)
assert.NoError(t, err)
}

dtd := &dummyTestData{t, ctx, client}
Expand Down
Loading