mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Phlare: Fix panic on empty pprof profile (#64888)
This commit is contained in:
@@ -374,16 +374,19 @@ func treeToNestedSetDataFrame(tree *ProfileTree, profileTypeID string) *data.Fra
|
||||
labelField := NewEnumField("label", nil)
|
||||
fileNameField := NewEnumField("fileName", nil)
|
||||
|
||||
walkTree(tree, func(tree *ProfileTree) {
|
||||
levelField.Append(int64(tree.Level))
|
||||
valueField.Append(tree.Value)
|
||||
selfField.Append(tree.Self)
|
||||
// todo: inline functions
|
||||
// tree.Inlined
|
||||
lineNumberField.Append(tree.Function.Line)
|
||||
labelField.Append(tree.Function.FunctionName)
|
||||
fileNameField.Append(tree.Function.FileName)
|
||||
})
|
||||
// Tree can be nil if profile was empty, we can still send empty frame in that case
|
||||
if tree != nil {
|
||||
walkTree(tree, func(tree *ProfileTree) {
|
||||
levelField.Append(int64(tree.Level))
|
||||
valueField.Append(tree.Value)
|
||||
selfField.Append(tree.Self)
|
||||
// todo: inline functions
|
||||
// tree.Inlined
|
||||
lineNumberField.Append(tree.Function.Line)
|
||||
labelField.Append(tree.Function.FunctionName)
|
||||
fileNameField.Append(tree.Function.FileName)
|
||||
})
|
||||
}
|
||||
|
||||
frame.Fields = append(frame.Fields, labelField.GetField(), fileNameField.GetField())
|
||||
return frame
|
||||
|
||||
@@ -109,42 +109,50 @@ func makeDataQuery() *backend.DataQuery {
|
||||
}
|
||||
|
||||
func Test_treeToNestedDataFrame(t *testing.T) {
|
||||
tree := &ProfileTree{
|
||||
Value: 100, Level: 0, Self: 1, Function: &Function{FunctionName: "root"}, Nodes: []*ProfileTree{
|
||||
{
|
||||
Value: 40, Level: 1, Self: 2, Function: &Function{FunctionName: "func1", FileName: "1", Line: 1},
|
||||
t.Run("sample profile tree", func(t *testing.T) {
|
||||
tree := &ProfileTree{
|
||||
Value: 100, Level: 0, Self: 1, Function: &Function{FunctionName: "root"}, Nodes: []*ProfileTree{
|
||||
{
|
||||
Value: 40, Level: 1, Self: 2, Function: &Function{FunctionName: "func1", FileName: "1", Line: 1},
|
||||
},
|
||||
{Value: 30, Level: 1, Self: 3, Function: &Function{FunctionName: "func2", FileName: "2", Line: 2}, Nodes: []*ProfileTree{
|
||||
{Value: 15, Level: 2, Self: 4, Function: &Function{FunctionName: "func1:func3", FileName: "3", Line: 3}},
|
||||
}},
|
||||
},
|
||||
{Value: 30, Level: 1, Self: 3, Function: &Function{FunctionName: "func2", FileName: "2", Line: 2}, Nodes: []*ProfileTree{
|
||||
{Value: 15, Level: 2, Self: 4, Function: &Function{FunctionName: "func1:func3", FileName: "3", Line: 3}},
|
||||
}},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
frame := treeToNestedSetDataFrame(tree, "memory:alloc_objects:count:space:bytes")
|
||||
frame := treeToNestedSetDataFrame(tree, "memory:alloc_objects:count:space:bytes")
|
||||
|
||||
labelConfig := &data.FieldConfig{
|
||||
TypeConfig: &data.FieldTypeConfig{
|
||||
Enum: &data.EnumFieldConfig{
|
||||
Text: []string{"root", "func1", "func2", "func1:func3"},
|
||||
labelConfig := &data.FieldConfig{
|
||||
TypeConfig: &data.FieldTypeConfig{
|
||||
Enum: &data.EnumFieldConfig{
|
||||
Text: []string{"root", "func1", "func2", "func1:func3"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
filenameConfig := &data.FieldConfig{
|
||||
TypeConfig: &data.FieldTypeConfig{
|
||||
Enum: &data.EnumFieldConfig{
|
||||
Text: []string{"", "1", "2", "3"},
|
||||
}
|
||||
filenameConfig := &data.FieldConfig{
|
||||
TypeConfig: &data.FieldTypeConfig{
|
||||
Enum: &data.EnumFieldConfig{
|
||||
Text: []string{"", "1", "2", "3"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
require.Equal(t,
|
||||
[]*data.Field{
|
||||
data.NewField("level", nil, []int64{0, 1, 1, 2}),
|
||||
data.NewField("value", nil, []int64{100, 40, 30, 15}).SetConfig(&data.FieldConfig{Unit: "short"}),
|
||||
data.NewField("self", nil, []int64{1, 2, 3, 4}).SetConfig(&data.FieldConfig{Unit: "short"}),
|
||||
data.NewField("line", nil, []int64{0, 1, 2, 3}),
|
||||
data.NewField("label", nil, []int64{0, 1, 2, 3}).SetConfig(labelConfig),
|
||||
data.NewField("fileName", nil, []int64{0, 1, 2, 3}).SetConfig(filenameConfig),
|
||||
}, frame.Fields)
|
||||
}
|
||||
require.Equal(t,
|
||||
[]*data.Field{
|
||||
data.NewField("level", nil, []int64{0, 1, 1, 2}),
|
||||
data.NewField("value", nil, []int64{100, 40, 30, 15}).SetConfig(&data.FieldConfig{Unit: "short"}),
|
||||
data.NewField("self", nil, []int64{1, 2, 3, 4}).SetConfig(&data.FieldConfig{Unit: "short"}),
|
||||
data.NewField("line", nil, []int64{0, 1, 2, 3}),
|
||||
data.NewField("label", nil, []int64{0, 1, 2, 3}).SetConfig(labelConfig),
|
||||
data.NewField("fileName", nil, []int64{0, 1, 2, 3}).SetConfig(filenameConfig),
|
||||
}, frame.Fields)
|
||||
})
|
||||
|
||||
t.Run("nil profile tree", func(t *testing.T) {
|
||||
frame := treeToNestedSetDataFrame(nil, "memory:alloc_objects:count:space:bytes")
|
||||
require.Equal(t, 6, len(frame.Fields))
|
||||
require.Equal(t, 0, frame.Fields[0].Len())
|
||||
})
|
||||
}
|
||||
|
||||
var fooProfile = &googlev1.Profile{
|
||||
|
||||
Reference in New Issue
Block a user