Skip to content

Commit 424a121

Browse files
authored
Generate marshal JSON without gogo proto jsonpb (#13450)
This PR is part of an effort to remove usage of gogo proto in pdata and switch to a model where we enhance the pdatagen tool to generate compact (reflection free to avoid DCE disabling) and faster code. The list of the PRs will do: 1. Auto generate the JSON marshaling logic (this PR). 1. Auto generate the JSON unmarshaling logic and replace manually written code. 1. Auto generate the proto marshaling logic. 1. Auto generate the proto unmarshaling logic. 1. Remove the usage of auto-generate gogo proto code completely and generate field members in the pdata objects. 1. Add support for lazy unmarshaling. Performance improvements are more than 30x: **Before:** ``` BenchmarkLogsMarshalJSON BenchmarkLogsMarshalJSON-12 94 12541041 ns/op 8458944 B/op 196458 allocs/op BenchmarkMetricsMarshalJSON BenchmarkMetricsMarshalJSON-12 3 452309069 ns/op 350229024 B/op 8131400 allocs/op BenchmarkProfilesMarshalJSON BenchmarkProfilesMarshalJSON-12 30 36731071 ns/op 20317088 B/op 531652 allocs/op BenchmarkTracesMarshalJSON BenchmarkTracesMarshalJSON-12 8 132521260 ns/op 95920588 B/op 2208765 allocs/op ``` **After:** ``` BenchmarkLogsMarshalJSON BenchmarkLogsMarshalJSON-12 3000 403587 ns/op 282465 B/op 1487 allocs/op BenchmarkMetricsMarshalJSON BenchmarkMetricsMarshalJSON-12 72 16772373 ns/op 11856529 B/op 72833 allocs/op BenchmarkProfilesMarshalJSON BenchmarkProfilesMarshalJSON-12 1460 849419 ns/op 674545 B/op 1145 allocs/op BenchmarkTracesMarshalJSON BenchmarkTracesMarshalJSON-12 271 4344647 ns/op 3010259 B/op 16237 allocs/op ``` Signed-off-by: Bogdan Drutu <[email protected]>
1 parent 1b0fd82 commit 424a121

File tree

178 files changed

+3062
-348
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

178 files changed

+3062
-348
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver)
7+
component: pdata
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Use pdatagen to generate marshalJSON without using gogo proto jsonpb.
11+
12+
# One or more tracking issues or pull requests related to the change
13+
issues: [13450]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# Optional: The change log or logs in which this entry should be included.
21+
# e.g. '[user]' or '[user, api]'
22+
# Include 'user' if the change is relevant to end users.
23+
# Include 'api' if there is a change to a library API.
24+
# Default: '[user]'
25+
change_logs: [user]

internal/cmd/pdatagen/internal/message_field.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ const messageSetTestTemplate = `{{ if .isCommon -}}
3939
const messageCopyOrigTemplate = `{{ if .isCommon }}{{ if not .isBaseStructCommon }}internal.{{ end }}CopyOrig{{ else }}copyOrig{{ end }}
4040
{{- .returnType }}(&dest.{{ .originFieldName }}, &src.{{ .originFieldName }})`
4141

42+
const messageMarshalJSONTemplate = `{{- if eq .returnType "TraceState" }} if ms.orig.{{ .originFieldName }} != "" { {{ end -}}
43+
dest.WriteObjectField("{{ lowerFirst .originFieldName }}")
44+
{{- if .isCommon }}
45+
{{ if not .isBaseStructCommon }}internal.{{ end }}MarshalJSONStream{{ .returnType }}(
46+
{{- if not .isBaseStructCommon }}internal.{{ end }}New{{ .returnType }}(&ms.orig.{{ .originFieldName }}, ms.state), dest)
47+
{{- else }}
48+
ms.{{ .fieldName }}().marshalJSONStream(dest)
49+
{{- end }}{{ if eq .returnType "TraceState" -}} } {{- end }}`
50+
4251
type MessageField struct {
4352
fieldName string
4453
returnMessage *messageStruct
@@ -64,6 +73,11 @@ func (mf *MessageField) GenerateCopyOrig(ms *messageStruct) string {
6473
return executeTemplate(t, mf.templateFields(ms))
6574
}
6675

76+
func (mf *MessageField) GenerateMarshalJSON(ms *messageStruct) string {
77+
t := template.Must(templateNew("messageMarshalJSONTemplate").Parse(messageMarshalJSONTemplate))
78+
return executeTemplate(t, mf.templateFields(ms))
79+
}
80+
6781
func (mf *MessageField) templateFields(ms *messageStruct) map[string]any {
6882
return map[string]any{
6983
"isCommon": usedByOtherDataTypes(mf.returnMessage.packageName),

internal/cmd/pdatagen/internal/one_of_field.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ const oneOfCopyOrigTemplate = `switch t := src.{{ .originFieldName }}.(type) {
3939
{{- end }}
4040
}`
4141

42+
const oneOfMarshalJSONTemplate = `switch ov := ms.{{ .origAccessor }}.{{ .originFieldName }}.(type) {
43+
{{- range .values }}
44+
{{ .GenerateMarshalJSON $.baseStruct $.OneOfField }}
45+
{{- end }}
46+
}`
47+
4248
type OneOfField struct {
4349
originFieldName string
4450
typeName string
@@ -74,6 +80,11 @@ func (of *OneOfField) GenerateCopyOrig(ms *messageStruct) string {
7480
return executeTemplate(t, of.templateFields(ms))
7581
}
7682

83+
func (of *OneOfField) GenerateMarshalJSON(ms *messageStruct) string {
84+
t := template.Must(templateNew("oneOfMarshalJSONTemplate").Parse(oneOfMarshalJSONTemplate))
85+
return executeTemplate(t, of.templateFields(ms))
86+
}
87+
7788
func (of *OneOfField) templateFields(ms *messageStruct) map[string]any {
7889
return map[string]any{
7990
"baseStruct": ms,
@@ -99,4 +110,5 @@ type oneOfValue interface {
99110
GenerateSetWithTestValue(ms *messageStruct, of *OneOfField) string
100111
GenerateCopyOrig(ms *messageStruct, of *OneOfField) string
101112
GenerateType(ms *messageStruct, of *OneOfField) string
113+
GenerateMarshalJSON(ms *messageStruct, of *OneOfField) string
102114
}

internal/cmd/pdatagen/internal/one_of_message_value.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ const oneOfMessageCopyOrigTemplate = ` case *{{ .originStructType }}:
6868
const oneOfMessageTypeTemplate = `case *{{ .originStructName }}_{{ .originFieldName }}:
6969
return {{ .typeName }}`
7070

71+
const oneOfMessageMarshalJSONTemplate = `case *{{ .originStructName }}_{{ .originFieldName }}:
72+
dest.WriteObjectField("{{ lowerFirst .originFieldName }}")
73+
new{{ .returnType }}(ov.{{ .fieldName }}, ms.state).marshalJSONStream(dest)`
74+
7175
type OneOfMessageValue struct {
7276
fieldName string
7377
originFieldPackageName string
@@ -99,6 +103,11 @@ func (omv *OneOfMessageValue) GenerateType(ms *messageStruct, of *OneOfField) st
99103
return executeTemplate(t, omv.templateFields(ms, of))
100104
}
101105

106+
func (omv *OneOfMessageValue) GenerateMarshalJSON(ms *messageStruct, of *OneOfField) string {
107+
t := template.Must(templateNew("oneOfMessageMarshalJSONTemplate").Parse(oneOfMessageMarshalJSONTemplate))
108+
return executeTemplate(t, omv.templateFields(ms, of))
109+
}
110+
102111
func (omv *OneOfMessageValue) templateFields(ms *messageStruct, of *OneOfField) map[string]any {
103112
return map[string]any{
104113
"fieldName": omv.fieldName,

internal/cmd/pdatagen/internal/one_of_primitive_value.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ const oneOfPrimitiveCopyOrigTemplate = `case *{{ .originStructName }}_{{ .origin
5454
const oneOfPrimitiveTypeTemplate = `case *{{ .originStructName }}_{{ .originFieldName }}:
5555
return {{ .typeName }}`
5656

57+
const oneOfPrimitiveMarshalJSONTemplate = `case *{{ .originStructName }}_{{ .originFieldName }}:
58+
dest.WriteObjectField("{{ lowerFirst .originFieldName }}")
59+
dest.Write{{ upperFirst .returnType }}(ov.{{ .originFieldName }})`
60+
5761
type OneOfPrimitiveValue struct {
5862
fieldName string
5963
defaultVal string
@@ -87,6 +91,11 @@ func (opv *OneOfPrimitiveValue) GenerateType(ms *messageStruct, of *OneOfField)
8791
return executeTemplate(t, opv.templateFields(ms, of))
8892
}
8993

94+
func (opv *OneOfPrimitiveValue) GenerateMarshalJSON(ms *messageStruct, of *OneOfField) string {
95+
t := template.Must(templateNew("oneOfPrimitiveMarshalJSONTemplate").Parse(oneOfPrimitiveMarshalJSONTemplate))
96+
return executeTemplate(t, opv.templateFields(ms, of))
97+
}
98+
9099
func (opv *OneOfPrimitiveValue) templateFields(ms *messageStruct, of *OneOfField) map[string]any {
91100
return map[string]any{
92101
"structName": ms.getName(),

internal/cmd/pdatagen/internal/optional_primitive_field.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ const optionalPrimitiveCopyOrigTemplate = `if src{{ .fieldName }}, ok := src.{{
6767
dest.{{ .fieldName }}_ = nil
6868
}`
6969

70+
const optionalPrimitiveMarshalJSONTemplate = `if ms.Has{{ .fieldName }}() {
71+
dest.WriteObjectField("{{ lowerFirst .fieldName }}")
72+
dest.Write{{ upperFirst .returnType }}(ms.{{ .fieldName }}())
73+
}`
74+
7075
type OptionalPrimitiveField struct {
7176
fieldName string
7277
defaultVal string
@@ -94,6 +99,11 @@ func (opv *OptionalPrimitiveField) GenerateCopyOrig(ms *messageStruct) string {
9499
return executeTemplate(t, opv.templateFields(ms))
95100
}
96101

102+
func (opv *OptionalPrimitiveField) GenerateMarshalJSON(ms *messageStruct) string {
103+
t := template.Must(templateNew("optionalPrimitiveMarshalJSONTemplate").Parse(optionalPrimitiveMarshalJSONTemplate))
104+
return executeTemplate(t, opv.templateFields(ms))
105+
}
106+
97107
func (opv *OptionalPrimitiveField) templateFields(ms *messageStruct) map[string]any {
98108
return map[string]any{
99109
"structName": ms.getName(),

internal/cmd/pdatagen/internal/primitive_field.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ const primitiveSetTestTemplate = `tv.orig.{{ .originFieldName }} = {{ .testValue
4848

4949
const primitiveCopyOrigTemplate = `dest.{{ .originFieldName }} = src.{{ .originFieldName }}`
5050

51+
const primitiveMarshalJSONTemplate = `if ms.orig.{{ .originFieldName }} != {{ .defaultVal }} {
52+
dest.WriteObjectField("{{ lowerFirst .originFieldName }}")
53+
dest.Write{{ upperFirst .returnType }}(ms.orig.{{ .originFieldName }})
54+
}`
55+
5156
type PrimitiveField struct {
5257
fieldName string
5358
originFieldName string
@@ -76,6 +81,11 @@ func (pf *PrimitiveField) GenerateCopyOrig(ms *messageStruct) string {
7681
return executeTemplate(t, pf.templateFields(ms))
7782
}
7883

84+
func (pf *PrimitiveField) GenerateMarshalJSON(ms *messageStruct) string {
85+
t := template.Must(templateNew("primitiveMarshalJSONTemplate").Parse(primitiveMarshalJSONTemplate))
86+
return executeTemplate(t, pf.templateFields(ms))
87+
}
88+
7989
func (pf *PrimitiveField) templateFields(ms *messageStruct) map[string]any {
8090
return map[string]any{
8191
"structName": ms.getName(),

internal/cmd/pdatagen/internal/primitive_slice_field.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ const primitiveSliceCopyOrigTemplate = `dest.{{ .originFieldName }} =
2626
{{- if .isCommon }}{{ if not .isBaseStructCommon }}internal.{{ end }}CopyOrig{{ else }}copyOrig{{ end }}
2727
{{- .returnType }}(dest.{{ .originFieldName }}, src.{{ .originFieldName }})`
2828

29+
const primitiveSliceMarshalJSONTemplate = `dest.WriteObjectField("{{ lowerFirst .originFieldName }}")
30+
{{- if .isCommon }}
31+
{{ if not .isBaseStructCommon }}internal.{{ end }}MarshalJSONStream{{ .returnType }}(
32+
{{- if not .isBaseStructCommon }}internal.{{ end }}New{{ .returnType }}(&ms.orig.{{ .originFieldName }}, ms.state), dest)
33+
{{- else }}
34+
ms.{{ .fieldName }}().marshalJSONStream(dest)
35+
{{- end }}`
36+
2937
// PrimitiveSliceField is used to generate fields for slice of primitive types
3038
type PrimitiveSliceField struct {
3139
fieldName string
@@ -56,6 +64,11 @@ func (psf *PrimitiveSliceField) GenerateCopyOrig(ms *messageStruct) string {
5664
return executeTemplate(t, psf.templateFields(ms))
5765
}
5866

67+
func (psf *PrimitiveSliceField) GenerateMarshalJSON(ms *messageStruct) string {
68+
t := template.Must(templateNew("primitiveSliceMarshalJSONTemplate").Parse(primitiveSliceMarshalJSONTemplate))
69+
return executeTemplate(t, psf.templateFields(ms))
70+
}
71+
5972
func (psf *PrimitiveSliceField) templateFields(ms *messageStruct) map[string]any {
6073
return map[string]any{
6174
"structName": ms.getName(),

internal/cmd/pdatagen/internal/slice_field.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ const sliceCopyOrigTemplate = `dest.{{ .originFieldName }} =
4646
{{- if .isCommon }}{{ if not .isBaseStructCommon }}internal.{{ end }}CopyOrig{{ else }}copyOrig{{ end }}
4747
{{- .returnType }}(dest.{{ .originFieldName }}, src.{{ .originFieldName }})`
4848

49+
const sliceMarshalJSONTemplate = `if len(ms.orig.{{ .originFieldName }}) > 0 {
50+
dest.WriteObjectField("{{ lowerFirst .originFieldName }}")
51+
{{- if .isCommon }}
52+
{{ if not .isBaseStructCommon }}internal.{{ end }}MarshalJSONStream{{ .returnType }}(
53+
{{- if not .isBaseStructCommon }}internal.{{ end }}New{{ .returnType }}(&ms.orig.{{ .originFieldName }}, ms.state), dest)
54+
{{- else }}
55+
ms.{{ .fieldName }}().marshalJSONStream(dest)
56+
{{- end }}
57+
}`
58+
4959
type SliceField struct {
5060
fieldName string
5161
originFieldName string
@@ -79,6 +89,11 @@ func (sf *SliceField) GenerateCopyOrig(ms *messageStruct) string {
7989
return executeTemplate(t, sf.templateFields(ms))
8090
}
8191

92+
func (sf *SliceField) GenerateMarshalJSON(ms *messageStruct) string {
93+
t := template.Must(templateNew("sliceMarshalJSONTemplate").Parse(sliceMarshalJSONTemplate))
94+
return executeTemplate(t, sf.templateFields(ms))
95+
}
96+
8297
func (sf *SliceField) templateFields(ms *messageStruct) map[string]any {
8398
return map[string]any{
8499
"structName": ms.getName(),

internal/cmd/pdatagen/internal/templates/message.go.tmpl

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
package {{ .packageName }}
88

99
import (
10-
{{ range $index, $element := .imports -}}
11-
{{ $element }}
12-
{{ end }}
10+
{{ range $index, $element := .imports -}}
11+
{{ $element }}
12+
{{ end }}
1313
)
1414

1515
{{ .description }}
@@ -81,6 +81,15 @@ func (ms {{ .structName }}) getState() *internal.State {
8181
return internal.Get{{ .structName }}State(internal.{{ .structName }}(ms))
8282
}
8383
{{- else }}
84+
// marshalJSONStream marshals all properties from the current struct to the destination stream.
85+
func (ms {{ .structName }}) marshalJSONStream(dest *json.Stream) {
86+
dest.WriteObjectStart()
87+
{{ range .fields -}}
88+
{{ .GenerateMarshalJSON $.messageStruct }}
89+
{{ end -}}
90+
dest.WriteObjectEnd()
91+
}
92+
8493
func copyOrig{{ .structName }}(dest, src *{{ .originName }}) {
8594
{{- range .fields }}
8695
{{ .GenerateCopyOrig $.messageStruct }}

0 commit comments

Comments
 (0)