GoPLS Viewer

Home|gopls/internal/bug/bug.go
1// Copyright 2022 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package bug provides utilities for reporting internal bugs, and being
6// notified when they occur.
7//
8// Philosophically, because gopls runs as a sidecar process that the user does
9// not directly control, sometimes it keeps going on broken invariants rather
10// than panicking. In those cases, bug reports provide a mechanism to alert
11// developers and capture relevant metadata.
12package bug
13
14import (
15    "fmt"
16    "runtime"
17    "runtime/debug"
18    "sort"
19    "sync"
20)
21
22// PanicOnBugs controls whether to panic when bugs are reported.
23//
24// It may be set to true during testing.
25var PanicOnBugs = false
26
27var (
28    mu        sync.Mutex
29    exemplars map[string]Bug
30    waiters   []chan<- Bug
31)
32
33// A Bug represents an unexpected event or broken invariant. They are used for
34// capturing metadata that helps us understand the event.
35type Bug struct {
36    File        string // file containing the call to bug.Report
37    Line        int    // line containing the call to bug.Report
38    Description string // description of the bug
39    Data        Data   // additional metadata
40    Key         string // key identifying the bug (file:line if available)
41    Stack       string // call stack
42}
43
44// Data is additional metadata to record for a bug.
45type Data map[string]interface{}
46
47// Reportf reports a formatted bug message.
48func Reportf(format stringargs ...interface{}) {
49    Report(fmt.Sprintf(formatargs...), nil)
50}
51
52// Errorf calls fmt.Errorf for the given arguments, and reports the resulting
53// error message as a bug.
54func Errorf(format stringargs ...interface{}) error {
55    err := fmt.Errorf(formatargs...)
56    Report(err.Error(), nil)
57    return err
58}
59
60// Report records a new bug encountered on the server.
61// It uses reflection to report the position of the immediate caller.
62func Report(description stringdata Data) {
63    _filelineok := runtime.Caller(1)
64
65    key := "<missing callsite>"
66    if ok {
67        key = fmt.Sprintf("%s:%d"fileline)
68    }
69
70    if PanicOnBugs {
71        panic(fmt.Sprintf("%s: %s"keydescription))
72    }
73
74    bug := Bug{
75        File:        file,
76        Line:        line,
77        Descriptiondescription,
78        Data:        data,
79        Key:         key,
80        Stack:       string(debug.Stack()),
81    }
82
83    mu.Lock()
84    defer mu.Unlock()
85
86    if exemplars == nil {
87        exemplars = make(map[string]Bug)
88    }
89
90    if _ok := exemplars[key]; !ok {
91        exemplars[key] = bug // capture one exemplar per key
92    }
93
94    for _waiter := range waiters {
95        waiter <- bug
96    }
97    waiters = nil
98}
99
100// Notify returns a channel that will be sent the next bug to occur on the
101// server. This channel only ever receives one bug.
102func Notify() <-chan Bug {
103    mu.Lock()
104    defer mu.Unlock()
105
106    ch := make(chan Bug1// 1-buffered so that bug reporting is non-blocking
107    waiters = append(waitersch)
108    return ch
109}
110
111// List returns a slice of bug exemplars -- the first bugs to occur at each
112// callsite.
113func List() []Bug {
114    mu.Lock()
115    defer mu.Unlock()
116
117    var bugs []Bug
118
119    for _bug := range exemplars {
120        bugs = append(bugsbug)
121    }
122
123    sort.Slice(bugs, func(ij intbool {
124        return bugs[i].Key < bugs[j].Key
125    })
126
127    return bugs
128}
129
MembersX
Bug.File
Bug.Data
Bug.Key
Data
Reportf
Bug.Stack
Report.key
Notify.ch
Errorf.format
Errorf.args
Report
Report.RangeStmt_2496.waiter
List
List.RangeStmt_3031.bug
Report.file
List.bugs
runtime
exemplars
Bug
Reportf.args
Errorf.err
Report.description
fmt
debug
sort
Notify
sync
PanicOnBugs
mu
Bug.Line
Report._
Report.bug
Bug.Description
Reportf.format
Errorf
Report.data
Report.line
Report.ok
Members
X