-
Notifications
You must be signed in to change notification settings - Fork 273
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reporter: allow extending samples with extra attributes #237
base: main
Are you sure you want to change the base?
Conversation
expectedIndices [][]uint64 | ||
expectedAttributeTable []*common.KeyValue | ||
}{ | ||
"empty": { | ||
profile: &profiles.Profile{}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why this was in the struct: it seems that simply making this a local temporary variable in the loop below is easier. I reworked it accordingly, but perhaps I'm missing something on why this was done like this originally.
@@ -29,7 +27,6 @@ func TestGetSampleAttributes(t *testing.T) { | |||
pid: 0, | |||
}, | |||
}, | |||
attributeMap: make(map[string]uint64), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
Overall looks better than the generics approach 👍 |
reporter/attrmgr.go
Outdated
return m.addAnyAttr(key, compound, &val) | ||
} | ||
|
||
func (m *AttrTableManager) AddStringAttr(key, value string) AttrIndex { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would skipping empty strings work here (as suggested in #233)? We can not just return a 0 index.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was under the impression that the discussion in #233 was leaning towards not doing the filtering in the function/component responsible for managing the attribute table. In the interest of not spreading the discussion over two issues, I'll let this PR wait until #233 is merged. If we decide on letting the manager fn filter, I can simply rework this to:
AppendStringAttr(attrs []AttrIndex, key, value string) []AttrIndex
// - inspect each trace and its meta when it is enqueued in the reporter | ||
// - produce extra meta info | ||
// - attach extra attributes to the trace | ||
type SampleAttrProducer interface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be moved to iface.go
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered that originally, but iface.go
is currently dedicated to the public interface implemented by any reporter. If found config.go
to be a better fit. I didn't want readers to incorrectly conclude that they have to implement this for a reporter.
reporter/attrmgr.go
Outdated
profile *profiles.Profile | ||
} | ||
|
||
func NewAttrTableManager(profile *profiles.Profile) *AttrTableManager { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*profiles.Profile
is internal to the package reporter. How are users of the package supposed to create it?
How should the integration look like, for a different kind of reporter, like for the OTel collector? see #208
From the updated testcase (TestGetSampleAttributes
), where this API is used, it looks more like this API builds a parallel *profiles.Profile
on top of an existing one just with attributes but without traces.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this private? It's a public type from the OTEL proto lib?
From the updated testcase (TestGetSampleAttributes), where this API is used, it looks more like this API builds a parallel *profiles.Profile on top of an existing one just with attributes but without traces.
No, it's just populating the attribute table portion. I'll apply the change that Tim suggested here to make this clearer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I looked through #208 now, and I think what you are referring to is that it will be private in the future, replaced by the pdata type? I hadn't followed up with the collector reporter impl -- still catching up after ~1 month mostly away from this repo here -- apologies! Fortunately the changes that Tim suggested (and that I have applied now) should allow the type to generalize to allow using it in the new reporter implementation as well.
reporter/attrmgr.go
Outdated
return m.addAnyAttr(key, compound, &val) | ||
} | ||
|
||
func (m *AttrTableManager) AddStringAttr(key, value string) AttrIndex { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This opens the discussion again around sending empty values for attributes that are not required - see #233
Co-authored-by: Tim Rühsen <[email protected]>
Rresolved conflict with profiling vs htlhash key
attrTable *[]*common.KeyValue | ||
} | ||
|
||
func NewAttrTableManager(attrTable *[]*common.KeyValue) *AttrTableManager { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively we could not take that any argument, and rename the type to AttrTableBuilder
. In that case I'd then add a new method GetAttrTable()
that returns the final built table. That'd change the workflow for the caller to:
- Create empty instance
- Populate it with
AddXXX
calls - Take the final table with
GetAttrTable()
and manually assign it to the attribute table field
Perhaps more obvious than mutating the slice field in place through a pointer? No strong preference here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about this as well (named it Get()
to not repeat AttrTable), but it comes with the downside that you need to call this function when done. And this can be forgotten, while the solution in this PR is safer from accidental failure.
My not very strong preference would be to avoid an extra Get
function call.
{key: "process.executable.build_id.htlhash", | ||
value: traceInfo.files[i].StringNoQuotes()}, | ||
}, attributeMap) | ||
attrMgr.AddStringAttr("process.executable.build_id.gnu", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Rename AddStringAttr
to AddString
to avoid repetition of "Attr". Same for AddIntAttr
.
This PR does two things:
Replace
addProfileAttributes
andattrKeyValue[T]
withAttrTableManager
I found the previous design with the generic on
addProfileAttributes
rather inelegant. Firstly, there's no covariance on Go generics, so it would take twoaddProfileAttributes
calls and anappend
to add both string and int attributes:opentelemetry-ebpf-profiler/reporter/otlp_reporter.go
Lines 669 to 675 in 47e8410
It also required reflection in
addProfileAttributes
for no good reason. IMHO this isn't really a good use-case for generics. InAttrTableManager
this is replaced with two separate methods that each add just one attribute.Secondly, a proper type for this results in a much cleaner interface for the second change discussed below.
Introduce
SampleAttrProducer
interfaceThis allows agent implementations to add custom sample attributes without maintaining a fork of the reporter implementation. It can gather extra meta-data when the trace is initially added and then emit extra attributes when the sample is sent out.