Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/pkg/river/vm/error.go
4095 views
1
package vm
2
3
import (
4
"fmt"
5
"strings"
6
7
"github.com/grafana/agent/pkg/river/ast"
8
"github.com/grafana/agent/pkg/river/diag"
9
"github.com/grafana/agent/pkg/river/internal/value"
10
"github.com/grafana/agent/pkg/river/printer"
11
"github.com/grafana/agent/pkg/river/token/builder"
12
)
13
14
// makeDiagnostic tries to convert err into a diag.Diagnostic. err must be an
15
// error from the river/internal/value package, otherwise err will be returned
16
// unmodified.
17
func makeDiagnostic(err error, assoc map[value.Value]ast.Node) error {
18
var (
19
node ast.Node
20
expr strings.Builder
21
message string
22
cause value.Value
23
24
// Until we find a node, we're not a literal error.
25
literal = false
26
)
27
28
isValueError := value.WalkError(err, func(err error) {
29
var val value.Value
30
31
switch ne := err.(type) {
32
case value.Error:
33
message = ne.Error()
34
val = ne.Value
35
case value.TypeError:
36
message = fmt.Sprintf("should be %s, got %s", ne.Expected, ne.Value.Type())
37
val = ne.Value
38
case value.MissingKeyError:
39
message = fmt.Sprintf("does not have field named %q", ne.Missing)
40
val = ne.Value
41
case value.ElementError:
42
fmt.Fprintf(&expr, "[%d]", ne.Index)
43
val = ne.Value
44
case value.FieldError:
45
fmt.Fprintf(&expr, ".%s", ne.Field)
46
val = ne.Value
47
}
48
49
cause = val
50
51
if foundNode, ok := assoc[val]; ok {
52
// If we just found a direct node, we can reset the expression buffer so
53
// we don't unnecessarily print element and field accesses for we can see
54
// directly in the file.
55
if literal {
56
expr.Reset()
57
}
58
59
node = foundNode
60
literal = true
61
} else {
62
literal = false
63
}
64
})
65
if !isValueError {
66
return err
67
}
68
69
if node != nil {
70
var nodeText strings.Builder
71
if err := printer.Fprint(&nodeText, node); err != nil {
72
// This should never panic; printer.Fprint only fails when given an
73
// unexpected type, which we never do here.
74
panic(err)
75
}
76
77
// Merge the node text with the expression together (which will be relative
78
// accesses to the expression).
79
message = fmt.Sprintf("%s%s %s", nodeText.String(), expr.String(), message)
80
} else {
81
message = fmt.Sprintf("%s %s", expr.String(), message)
82
}
83
84
// Render the underlying problematic value as a string.
85
var valueText string
86
if cause != value.Null {
87
be := builder.NewExpr()
88
be.SetValue(cause.Interface())
89
valueText = string(be.Bytes())
90
}
91
if literal {
92
// Hide the value if the node itself has the error we were worried about.
93
valueText = ""
94
}
95
96
d := diag.Diagnostic{
97
Severity: diag.SeverityLevelError,
98
Message: message,
99
Value: valueText,
100
}
101
if node != nil {
102
d.StartPos = ast.StartPos(node).Position()
103
d.EndPos = ast.EndPos(node).Position()
104
}
105
return d
106
}
107
108