Skip to content

Commit 358d3ed

Browse files
authored
Parca reporter and log uploader to support column fields. (#3162)
2 parents aa1c5ef + 84c165f commit 358d3ed

File tree

3 files changed

+111
-31
lines changed

3 files changed

+111
-31
lines changed

reporter/arrow.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ type LocationsWriter struct {
158158
Lines *array.ListBuilder
159159
Line *array.StructBuilder
160160
LineNumber *array.Int64Builder
161+
ColumnNumber *array.Uint64Builder
161162
FunctionName *array.BinaryDictionaryBuilder
162163
FunctionSystemName *array.BinaryDictionaryBuilder
163164
FunctionFilename *BinaryDictionaryRunEndBuilder
@@ -306,6 +307,9 @@ var (
306307
Type: arrow.ListOf(arrow.StructOf([]arrow.Field{{
307308
Name: "line",
308309
Type: arrow.PrimitiveTypes.Int64,
310+
}, {
311+
Name: "column",
312+
Type: arrow.PrimitiveTypes.Uint64,
309313
}, {
310314
Name: "function_name",
311315
Type: &arrow.DictionaryType{IndexType: arrow.PrimitiveTypes.Uint32, ValueType: arrow.BinaryTypes.Binary},
@@ -494,10 +498,11 @@ func NewLocationsWriter(mem memory.Allocator) *LocationsWriter {
494498
lines := locations.FieldBuilder(7).(*array.ListBuilder)
495499
line := lines.ValueBuilder().(*array.StructBuilder)
496500
lineNumber := line.FieldBuilder(0).(*array.Int64Builder)
497-
functionName := line.FieldBuilder(1).(*array.BinaryDictionaryBuilder)
498-
functionSystemName := line.FieldBuilder(2).(*array.BinaryDictionaryBuilder)
499-
functionFilename := binaryDictionaryRunEndBuilder(line.FieldBuilder(3))
500-
functionStartLine := line.FieldBuilder(4).(*array.Int64Builder)
501+
columnNumber := line.FieldBuilder(1).(*array.Uint64Builder)
502+
functionName := line.FieldBuilder(2).(*array.BinaryDictionaryBuilder)
503+
functionSystemName := line.FieldBuilder(3).(*array.BinaryDictionaryBuilder)
504+
functionFilename := binaryDictionaryRunEndBuilder(line.FieldBuilder(4))
505+
functionStartLine := line.FieldBuilder(5).(*array.Int64Builder)
501506

502507
return &LocationsWriter{
503508
IsComplete: isComplete,
@@ -513,6 +518,7 @@ func NewLocationsWriter(mem memory.Allocator) *LocationsWriter {
513518
Lines: lines,
514519
Line: line,
515520
LineNumber: lineNumber,
521+
ColumnNumber: columnNumber,
516522
FunctionName: functionName,
517523
FunctionSystemName: functionSystemName,
518524
FunctionFilename: functionFilename,

reporter/parca_reporter.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,6 +1293,7 @@ func (r *ParcaReporter) buildStacktraceRecord(ctx context.Context, stacktraceIDs
12931293
w.Lines.Append(true)
12941294
w.Line.Append(true)
12951295
w.LineNumber.Append(int64(0))
1296+
w.ColumnNumber.Append(uint64(0))
12961297
w.FunctionName.AppendString("missing stacktrace")
12971298
w.FunctionSystemName.AppendString("")
12981299
w.FunctionFilename.AppendNull()
@@ -1324,6 +1325,7 @@ func (r *ParcaReporter) buildStacktraceRecord(ctx context.Context, stacktraceIDs
13241325
w.Lines.Append(true)
13251326
w.Line.Append(true)
13261327
w.LineNumber.Append(int64(0))
1328+
w.ColumnNumber.Append(uint64(0))
13271329
w.FunctionName.AppendString("aborted")
13281330
w.FunctionSystemName.AppendString("")
13291331
w.FunctionFilename.AppendNull()
@@ -1405,6 +1407,7 @@ func (r *ParcaReporter) buildStacktraceRecord(ctx context.Context, stacktraceIDs
14051407
w.Lines.Append(true)
14061408
w.Line.Append(true)
14071409
w.LineNumber.Append(lineNumber)
1410+
w.ColumnNumber.Append(uint64(frame.SourceColumn))
14081411
w.FunctionName.AppendString(symbol)
14091412
w.FunctionSystemName.AppendString("")
14101413
w.MappingFile.AppendString("[kernel.kallsyms]")
@@ -1440,11 +1443,18 @@ func (r *ParcaReporter) buildStacktraceRecord(ctx context.Context, stacktraceIDs
14401443
if filePath == "" {
14411444
filePath = "UNKNOWN"
14421445
}
1443-
w.MappingFile.AppendString(frameKind.String())
1444-
w.MappingBuildID.AppendNull()
1446+
if frame.Mapping.Valid() && frame.Mapping.Value().File.Value().GnuBuildID != "" {
1447+
file := frame.Mapping.Value().File.Value()
1448+
w.MappingFile.AppendString(file.FileName.String())
1449+
w.MappingBuildID.AppendString(file.GnuBuildID)
1450+
} else {
1451+
w.MappingFile.AppendString(frameKind.String())
1452+
w.MappingBuildID.AppendNull()
1453+
}
14451454
w.Lines.Append(true)
14461455
w.Line.Append(true)
14471456
w.LineNumber.Append(lineNumber)
1457+
w.ColumnNumber.Append(uint64(frame.SourceColumn))
14481458
w.FunctionName.AppendString(functionName)
14491459
w.FunctionSystemName.AppendString("")
14501460
w.FunctionFilename.AppendString(filePath)

uploader/log_uploader.go

Lines changed: 89 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ type locationsReader struct {
5454
Lines *array.List
5555
Line *array.Struct
5656
LineNumber *array.Int64
57+
LineColumn *array.Uint64
5758
LineFunctionName *array.Dictionary
5859
LineFunctionNameDict *array.Binary
5960
LineFunctionSystemName *array.Dictionary
@@ -117,81 +118,138 @@ func getLocationsReader(locations *array.List) (*locationsReader, error) {
117118
return nil, fmt.Errorf("expected column %q to be of type Struct, got %T", "locations", locations.ListValues())
118119
}
119120

120-
const expectedLocationFields = 8
121-
if location.NumField() != expectedLocationFields {
122-
return nil, fmt.Errorf("expected location struct column to have %d fields, got %d", expectedLocationFields, location.NumField())
123-
}
121+
locationType := location.DataType().(*arrow.StructType)
124122

125-
address, ok := location.Field(0).(*array.Uint64)
123+
fieldIdx, ok := locationType.FieldIdx("address")
124+
if !ok {
125+
return nil, fmt.Errorf("missing required field %q in location struct", "address")
126+
}
127+
address, ok := location.Field(fieldIdx).(*array.Uint64)
126128
if !ok {
127-
return nil, fmt.Errorf("expected column address to be of type Uint64, got %T", location.Field(0))
129+
return nil, fmt.Errorf("expected column address to be of type Uint64, got %T", location.Field(fieldIdx))
128130
}
129131

130-
frameType, frameTypeDict, frameTypeDictValues, err := getREEBinaryDict(location.Field(1), "frame_type")
132+
fieldIdx, ok = locationType.FieldIdx("frame_type")
133+
if !ok {
134+
return nil, fmt.Errorf("missing required field %q in location struct", "frame_type")
135+
}
136+
frameType, frameTypeDict, frameTypeDictValues, err := getREEBinaryDict(location.Field(fieldIdx), "frame_type")
137+
if err != nil {
138+
return nil, err
139+
}
131140

132-
mappingStart, mappingStartValues, err := getREEUint64(location.Field(2), "mapping_start")
141+
fieldIdx, ok = locationType.FieldIdx("mapping_start")
142+
if !ok {
143+
return nil, fmt.Errorf("missing required field %q in location struct", "mapping_start")
144+
}
145+
mappingStart, mappingStartValues, err := getREEUint64(location.Field(fieldIdx), "mapping_start")
133146
if err != nil {
134147
return nil, err
135148
}
136149

137-
mappingLimit, mappingLimitValues, err := getREEUint64(location.Field(3), "mapping_limit")
150+
fieldIdx, ok = locationType.FieldIdx("mapping_limit")
151+
if !ok {
152+
return nil, fmt.Errorf("missing required field %q in location struct", "mapping_limit")
153+
}
154+
mappingLimit, mappingLimitValues, err := getREEUint64(location.Field(fieldIdx), "mapping_limit")
138155
if err != nil {
139156
return nil, err
140157
}
141158

142-
mappingOffset, mappingOffsetValues, err := getREEUint64(location.Field(4), "mapping_offset")
159+
fieldIdx, ok = locationType.FieldIdx("mapping_offset")
160+
if !ok {
161+
return nil, fmt.Errorf("missing required field %q in location struct", "mapping_offset")
162+
}
163+
mappingOffset, mappingOffsetValues, err := getREEUint64(location.Field(fieldIdx), "mapping_offset")
143164
if err != nil {
144165
return nil, err
145166
}
146167

147-
mappingFile, mappingFileDict, mappingFileDictValues, err := getREEBinaryDict(location.Field(5), "mapping_file")
168+
fieldIdx, ok = locationType.FieldIdx("mapping_file")
169+
if !ok {
170+
return nil, fmt.Errorf("missing required field %q in location struct", "mapping_file")
171+
}
172+
mappingFile, mappingFileDict, mappingFileDictValues, err := getREEBinaryDict(location.Field(fieldIdx), "mapping_file")
148173
if err != nil {
149174
return nil, err
150175
}
151176

152-
mappingBuildID, mappingBuildIDDict, mappingBuildIDValues, err := getREEBinaryDict(location.Field(6), "mapping_build_id")
177+
fieldIdx, ok = locationType.FieldIdx("mapping_build_id")
178+
if !ok {
179+
return nil, fmt.Errorf("missing required field %q in location struct", "mapping_build_id")
180+
}
181+
mappingBuildID, mappingBuildIDDict, mappingBuildIDValues, err := getREEBinaryDict(location.Field(fieldIdx), "mapping_build_id")
153182
if err != nil {
154183
return nil, err
155184
}
156185

157-
lines, ok := location.Field(7).(*array.List)
186+
fieldIdx, ok = locationType.FieldIdx("lines")
158187
if !ok {
159-
return nil, fmt.Errorf("expected column lines to be of type List, got %T", location.Field(7))
188+
return nil, fmt.Errorf("missing required field %q in location struct", "lines")
189+
}
190+
lines, ok := location.Field(fieldIdx).(*array.List)
191+
if !ok {
192+
return nil, fmt.Errorf("expected column lines to be of type List, got %T", location.Field(fieldIdx))
160193
}
161194

162195
line, ok := lines.ListValues().(*array.Struct)
163196
if !ok {
164197
return nil, fmt.Errorf("expected column line to be of type Struct, got %T", lines.ListValues())
165198
}
166199

167-
const expectedLineFields = 5
168-
if line.NumField() != expectedLineFields {
169-
return nil, fmt.Errorf("expected line struct column to have %d fields, got %d", expectedLineFields, line.NumField())
170-
}
200+
lineType := line.DataType().(*arrow.StructType)
171201

172-
lineNumber, ok := line.Field(0).(*array.Int64)
202+
fieldIdx, ok = lineType.FieldIdx("line")
203+
if !ok {
204+
return nil, fmt.Errorf("missing required field %q in line struct", "line")
205+
}
206+
lineNumber, ok := line.Field(fieldIdx).(*array.Int64)
173207
if !ok {
174-
return nil, fmt.Errorf("expected column line_number to be of type Int64, got %T", line.Field(0))
208+
return nil, fmt.Errorf("expected column line to be of type Int64, got %T", line.Field(fieldIdx))
209+
}
210+
211+
var lineColumn *array.Uint64
212+
if fieldIdx, ok = lineType.FieldIdx("column"); ok {
213+
lineColumn, ok = line.Field(fieldIdx).(*array.Uint64)
214+
if !ok {
215+
return nil, fmt.Errorf("expected column column to be of type Uint64, got %T", line.Field(fieldIdx))
216+
}
175217
}
176218

177-
lineFunctionName, lineFunctionNameDict, err := getBinaryDict(line.Field(1), "line_function_name")
219+
fieldIdx, ok = lineType.FieldIdx("function_name")
220+
if !ok {
221+
return nil, fmt.Errorf("missing required field %q in line struct", "function_name")
222+
}
223+
lineFunctionName, lineFunctionNameDict, err := getBinaryDict(line.Field(fieldIdx), "function_name")
178224
if err != nil {
179225
return nil, err
180226
}
181227

182-
lineFunctionSystemName, lineFunctionSystemNameDict, err := getBinaryDict(line.Field(2), "line_function_system_name")
228+
fieldIdx, ok = lineType.FieldIdx("function_system_name")
229+
if !ok {
230+
return nil, fmt.Errorf("missing required field %q in line struct", "function_system_name")
231+
}
232+
lineFunctionSystemName, lineFunctionSystemNameDict, err := getBinaryDict(line.Field(fieldIdx), "function_system_name")
183233
if err != nil {
184234
return nil, err
185235
}
186236

187-
lineFunctionFilename, lineFunctionFilenameDict, lineFunctionFilenameDictValues, err := getREEBinaryDict(line.Field(3), "line_function_filename")
237+
fieldIdx, ok = lineType.FieldIdx("function_filename")
238+
if !ok {
239+
return nil, fmt.Errorf("missing required field %q in line struct", "function_filename")
240+
}
241+
lineFunctionFilename, lineFunctionFilenameDict, lineFunctionFilenameDictValues, err := getREEBinaryDict(line.Field(fieldIdx), "function_filename")
188242
if err != nil {
189243
return nil, err
190244
}
191245

192-
lineFunctionStartLine, ok := line.Field(4).(*array.Int64)
246+
fieldIdx, ok = lineType.FieldIdx("function_start_line")
247+
if !ok {
248+
return nil, fmt.Errorf("missing required field %q in line struct", "function_start_line")
249+
}
250+
lineFunctionStartLine, ok := line.Field(fieldIdx).(*array.Int64)
193251
if !ok {
194-
return nil, fmt.Errorf("expected column line_function_start_line to be of type Int64, got %T", line.Field(4))
252+
return nil, fmt.Errorf("expected column function_start_line to be of type Int64, got %T", line.Field(fieldIdx))
195253
}
196254

197255
return &locationsReader{
@@ -216,6 +274,7 @@ func getLocationsReader(locations *array.List) (*locationsReader, error) {
216274
Lines: lines,
217275
Line: line,
218276
LineNumber: lineNumber,
277+
LineColumn: lineColumn,
219278
LineFunctionName: lineFunctionName,
220279
LineFunctionNameDict: lineFunctionNameDict,
221280
LineFunctionSystemName: lineFunctionSystemName,
@@ -369,6 +428,11 @@ func filterTraces(stacktraceIds *array.Binary, stacktraceReaders []stacktraceRea
369428

370429
w.FunctionFilename.AppendString(rdr.locations.functionFilenameString(int(lineStart)))
371430
w.LineNumber.Append(rdr.locations.LineNumber.Value(int(lineStart)))
431+
if rdr.locations.LineColumn != nil {
432+
w.ColumnNumber.Append(rdr.locations.LineColumn.Value(int(lineStart)))
433+
} else {
434+
w.ColumnNumber.Append(0)
435+
}
372436
w.FunctionName.AppendString(rdr.locations.functionNameString(int(lineStart)))
373437
w.FunctionSystemName.AppendString(rdr.locations.functionSystemNameString(int(lineStart)))
374438
w.FunctionStartLine.Append(rdr.locations.LineFunctionStartLine.Value(int(lineStart)))

0 commit comments

Comments
 (0)