dashboard/app: make reporting filtering more flexible

Reporting statuses are not flexible as they can't encode
all possible conditions. ReportingPassThrough is a good example.
Replace Status with Filter which accepts bug and can contain
arbitrary logic.
This commit is contained in:
Dmitry Vyukov 2017-12-28 10:43:17 +01:00
parent f9e22d6230
commit 2675701746
2 changed files with 23 additions and 32 deletions

View File

@ -47,8 +47,8 @@ type Config struct {
type Reporting struct {
// A unique name (the app does not care about exact contents).
Name string
// See ReportingStatus below.
Status ReportingStatus
// Filter can be used to conditionally skip this reporting or hold off reporting.
Filter ReportingFilter
// How many new bugs report per day.
DailyLimit int
// Type of reporting and its configuration.
@ -71,20 +71,21 @@ var (
clientKeyRe = regexp.MustCompile("^[a-zA-Z0-9]{16,128}$")
)
type ReportingStatus int
type (
FilterResult int
ReportingFilter func(bug *Bug) FilterResult
)
const (
// Send reports to this reporting stage.
ReportingActive ReportingStatus = iota
// Don't send anything to this reporting, but don't skip it as well.
ReportingSuspended
// Skip this reporting entirely.
ReportingDisabled
// Skip this reporting except for special bugs
// (no report, corrupted report, build error, etc).
ReportingPassThrough
FilterReport FilterResult = iota // Report bug in this reporting (default).
FilterSkip // Skip this reporting and proceed to the next one.
FilterHold // Hold off with reporting this bug.
)
func reportAllFilter(bug *Bug) FilterResult { return FilterReport }
func reportSkipFilter(bug *Bug) FilterResult { return FilterSkip }
func reportHoldFilter(bug *Bug) FilterResult { return FilterHold }
func (cfg *Config) ReportingByName(name string) *Reporting {
for i := range cfg.Reporting {
reporting := &cfg.Reporting[i]
@ -119,13 +120,17 @@ func init() {
panic(fmt.Sprintf("no reporting in namespace %q", ns))
}
reportingNames := make(map[string]bool)
for _, reporting := range cfg.Reporting {
for ri := range cfg.Reporting {
reporting := &cfg.Reporting[ri]
if reporting.Name == "" {
panic(fmt.Sprintf("empty reporting name in namespace %q", ns))
}
if reportingNames[reporting.Name] {
panic(fmt.Sprintf("duplicate reporting name %q", reporting.Name))
}
if reporting.Filter == nil {
reporting.Filter = reportAllFilter
}
reportingNames[reporting.Name] = true
if reporting.Config.Type() == "" {
panic(fmt.Sprintf("empty reporting type for %q", reporting.Name))

View File

@ -152,32 +152,18 @@ func currentReporting(c context.Context, bug *Bug) (*Reporting, *BugReporting, i
if reporting == nil {
return nil, nil, 0, "", fmt.Errorf("%v: missing in config", bugReporting.Name)
}
switch reporting.Status {
case ReportingActive:
break
case ReportingSuspended:
switch reporting.Filter(bug) {
case FilterReport:
return reporting, bugReporting, i, "", nil
case FilterHold:
return nil, nil, 0, fmt.Sprintf("%v: reporting suspended", bugReporting.Name), nil
case ReportingDisabled:
case FilterSkip:
continue
case ReportingPassThrough:
if !isSpecialBug(bug) {
continue
}
}
return reporting, bugReporting, i, "", nil
}
return nil, nil, 0, "", fmt.Errorf("no reporting left")
}
func isSpecialBug(bug *Bug) bool {
// We may consider introducing a bug type, but for now we just look at some fields.
return !bug.HasReport ||
bug.Title == corruptedReportTitle ||
strings.Contains(bug.Title, "build error") ||
strings.Contains(bug.Title, "boot error:") ||
strings.Contains(bug.Title, "test error:")
}
func reproStr(level dashapi.ReproLevel) string {
switch level {
case ReproLevelSyz: