1515package tfstep
1616
1717import (
18+ "bytes"
1819 "fmt"
1920 "strings"
2021
@@ -23,6 +24,7 @@ import (
2324 tfconfig "github.com/kubewharf/kelemetry/pkg/frontend/tf/config"
2425 tftree "github.com/kubewharf/kelemetry/pkg/frontend/tf/tree"
2526 "github.com/kubewharf/kelemetry/pkg/manager"
27+ utilmarshal "github.com/kubewharf/kelemetry/pkg/util/marshal"
2628 "github.com/kubewharf/kelemetry/pkg/util/zconstants"
2729)
2830
@@ -37,6 +39,11 @@ func init() {
3739 manager .Ptr (& tfconfig.VisitorStep [PruneTagsVisitor ]{}),
3840 & manager.List [tfconfig.RegisteredStep ]{},
3941 )
42+ manager .Global .ProvideListImpl (
43+ "tf-step/remove-inherited-tag-visitor" ,
44+ manager .Ptr (& tfconfig.VisitorStep [RemoveInheritedTagVisitor ]{}),
45+ & manager.List [tfconfig.RegisteredStep ]{},
46+ )
4047}
4148
4249type ReplaceNameVisitor struct {}
@@ -92,3 +99,74 @@ func removeZconstantKeys(tags model.KeyValues) model.KeyValues {
9299 }
93100 return newTags
94101}
102+
103+ // An inherited tag is a tag in a span/log that also appears in its parent/owning span with the same key and value.
104+ // These tags are often useless and may be removed for brevity.
105+ //
106+ // This visitor assumes that each tag only appears once.
107+ type RemoveInheritedTagVisitor struct {
108+ // Spans with a matching traceSource tag (empty string for extension spans) will have inherited tags removed.
109+ TraceSources utilmarshal.StringFilter `json:"traceSources"`
110+
111+ // Whether to remove inherited span tags for matched spans.
112+ Spans bool `json:"spans"`
113+ // Whether to remove inherited log tags for matched spans.
114+ Logs bool `json:"logs"`
115+
116+ parentTags map [string ]any
117+ }
118+
119+ func (visitor RemoveInheritedTagVisitor ) Kind () string { return "RemoveInheritedTagVisitor" }
120+
121+ func removeInherited (parentTags map [string ]any , tags []model.KeyValue ) []model.KeyValue {
122+ outTags := []model.KeyValue {}
123+
124+ for _ , tag := range tags {
125+ if parentValue , parentHasKey := parentTags [tag .Key ]; parentHasKey {
126+ var equal bool
127+ if binary , isBinary := parentValue .([]byte ); isBinary && tag .VType == model .BinaryType {
128+ equal = bytes .Equal (binary , tag .VBinary )
129+ } else {
130+ equal = parentValue == tag .Value ()
131+ }
132+
133+ if ! equal {
134+ outTags = append (outTags , tag )
135+ }
136+ }
137+ }
138+
139+ return outTags
140+ }
141+
142+ func (visitor RemoveInheritedTagVisitor ) Enter (tree * tftree.SpanTree , span * model.Span ) tftree.TreeVisitor {
143+ spanTags := make (map [string ]any , len (span .Tags ))
144+ var traceSource string
145+ for _ , tag := range span .Tags {
146+ spanTags [tag .Key ] = tag .Value ()
147+ if tag .Key == zconstants .TraceSource {
148+ traceSource = tag .VStr
149+ }
150+ }
151+
152+ if visitor .TraceSources .Matches (traceSource ) {
153+ if visitor .Spans {
154+ span .Tags = removeInherited (visitor .parentTags , span .Tags )
155+ }
156+
157+ if visitor .Logs {
158+ for i := range span .Logs {
159+ log := & span .Logs [i ]
160+ log .Fields = removeInherited (spanTags , log .Fields )
161+ }
162+ }
163+ }
164+
165+ return RemoveInheritedTagVisitor {
166+ TraceSources : visitor .TraceSources ,
167+ Logs : visitor .Logs ,
168+ parentTags : spanTags ,
169+ }
170+ }
171+
172+ func (visitor RemoveInheritedTagVisitor ) Exit (tree * tftree.SpanTree , span * model.Span ) {}
0 commit comments