Skip to content

shift process management from Probe to Manager #2029

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

damemi
Copy link
Contributor

@damemi damemi commented Mar 20, 2025

Part of setting up for exposing the Probe API -- the main goal of this PR is to shift usage of the internal process package from the base Probe implementation to the Manager.

#1943 moved process analysis to the manager, so this follows a similar pattern of consolidating process handling into the manager.

Functionally, that means moving a lot of the Probe initialization to the manager. So now, instead of thinking "the Probe sets itself up" the flow is more "the Manager sets up the Probe"

This is a WIP right now showing the basic idea, the tougher part will be decoupling Process info from Consts

@damemi damemi force-pushed the decouple-process-from-probe branch 2 times, most recently from 8d8aa32 to 6b65138 Compare March 20, 2025 18:48
Copy link
Contributor

@MrAlias MrAlias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of decoupling the probe from process management, but it seems like this is just shuffling existing patterns out of a probe without refactoring the details deep in the functionality. I think we need to drill deeper into what the process interactions are for a probe and likely redesign around that.

Comment on lines 57 to 55
// GetUprobes returns a list of *Uprobes for the Probe.
GetUprobes() []*Uprobe

// GetConsts returns a list of Consts for the Probe.
GetConsts() []Const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are duplicates of the Manifest method which contains these values.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, and it wasn't clear to me because we change the name of them in the Manifest: Uprobes->FunctionSymbol and Consts->StructFieldIDs

The latter I think is because the Manifest doesn't actually store all the Consts in the Probe, just the consts for fields. If we're loading the uprobes in the manager now and injecting the consts there, we'll need all of the consts.

Do you think we should refactor the Manifest struct a bit to align better with the Probe definition?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should definitely unify these types respectively.

Given they are static to a probe, keeping their definitions in the Manifest seems appropriate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MrAlias looking more at the Manifest, I think this change in particular makes it redundant and everything it provides can be in the Probe itself. Given that we are defining the Probe as a more static representation now, I pushed an update to remove the Manifest type entirely and just use the references from it directly in the Probe.

Let me know if there's some other reason for Manifest I'm missing

@damemi damemi force-pushed the decouple-process-from-probe branch from 4cd3c36 to 39d7f0b Compare April 3, 2025 18:44
@damemi
Copy link
Contributor Author

damemi commented Apr 3, 2025

@MrAlias I did some more refactoring based on the last sig call. Basically, the Manager will now track a reference to the "initialized" probe, ie the probe+its collection+its closers. Then all collection/closer interaction can be done in the manager.

It's just a step, but let me know what you think

@damemi
Copy link
Contributor Author

damemi commented Apr 3, 2025

@MrAlias and now that I think about it, the collection/closer stuff could be set in the Manifest, but is the manifest intended to be mutable like that (ie, updated once the Probe is initialized) or just a static representation of the Probe's defintion?

@MrAlias
Copy link
Contributor

MrAlias commented Apr 8, 2025

just a static representation of the Probe's defintion?

My intent was for it to be static.

@damemi damemi changed the title (wip) shift process management from Probe to Manager shift process management from Probe to Manager Apr 8, 2025
@damemi damemi marked this pull request as ready for review April 8, 2025 19:51
@damemi damemi requested a review from a team as a code owner April 8, 2025 19:51
@damemi damemi force-pushed the decouple-process-from-probe branch 6 times, most recently from e0d26fa to 71a7496 Compare April 10, 2025 20:56
Copy link
Contributor

@MrAlias MrAlias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't looks to be a working example. I'm not sure how far I can review because of this.

Comment on lines 57 to 55
// GetUprobes returns a list of *Uprobes for the Probe.
GetUprobes() []*Uprobe

// GetConsts returns a list of Consts for the Probe.
GetConsts() []Const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should definitely unify these types respectively.

Given they are static to a probe, keeping their definitions in the Manifest seems appropriate.

Comment on lines 64 to 65
// ProbeReference is used by the Manager to track an initialized reference
// to a Probe and its related resources such as its ebpf.Collection and io.Closers.
type ProbeReference struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be unexported. It is only used internal to this package.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also not clear why this is needed. The collection field is never used (it is ineffectively set, but never read), and the closers field could just be captured in a thin wrapper around a Probe implementation (given it is already an interface).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replied above that this should have been set on a pointer, sorry about that confusion. But I'm curious what you mean by the closers field being a wrapper around a Probe. If I understand you correctly, that sounds like what I'm basically trying to do here, but could you explain what you have in mind? If it simplifies this then awesome

if err != nil {
return errors.Join(err, m.cleanup())
}
i.collection = c
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an unused write to i.collection

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we are using it in the Close function,
the collection allows us to maybe make the closing mechanism simpler?
see
https://github.com/cilium/ebpf/blob/49a06b1fe26190a4c2a702932f611c6eff908d3a/collection.go#L904

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I gotcha, just this is writing to a value, not a reference. When this function returns the passed argument remains unchanged. This assignment is to a copied value that is not used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was a mistake on my part, it should be a pointer reference so we can access it when closing as Ron pointed out

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid programming side effects. Instead, we should use standard Go programming practices and have any values we want to use from a function be returned.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please elaborate what you mean?

@damemi damemi force-pushed the decouple-process-from-probe branch 5 times, most recently from 3b5bcce to 2c0dcaa Compare May 2, 2025 19:30
@damemi damemi force-pushed the decouple-process-from-probe branch from 2c0dcaa to d1d8c62 Compare May 2, 2025 19:43
@damemi
Copy link
Contributor Author

damemi commented May 2, 2025

Hi all, thanks for the feedback so far and for your patience on my end getting back to you.

I pushed some more updates, notably:

  • Unexported locally used types and methods in the manager
  • Made sure probeReference fields are set by reference (the new Go testing framework actually helped catch this, thanks @MrAlias for that work)
  • Collapsed the Manifest field into Probe. It seems like Manifest is mostly redundant at this point when we can get what that provided from the Probe itself (ID, uprobes, and struct fields). Downside is this adds methods to the Probe type, but I think they make sense (GetUprobes, GetConsts, GetID).

For the consts, I made a type that has a method to just get the StructField consts to preserve the current behavior of Manifest. This looks like it's only used in a test though, so if we don't need it then I'm find dropping it.

This now passes the tests, but I'm sure there's more we can do so please take another look. I squashed the commits down to give us a clean slate at this point. Thanks!

@@ -47,3 +47,5 @@ examples/kafka-go/producer/producer
examples/kafka-go/consumer/consumer

go.work*

opentelemetry-helm-charts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed.

Suggested change
opentelemetry-helm-charts

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This folder got created somehow, I think while I was running one of the generators. It shouldn't be committed, and it should be in our gitignore. I can open a separate PR for this change if you'd prefer

// Probe is the instrument used by instrumentation for a Go package to measure
// and report on the state of that packages operation.
type Probe interface {
// Manifest returns the Probe's instrumentation Manifest. This includes all
// the information about the package the Probe instruments.
Manifest() Manifest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replacing this with individual mentions does not seem advantageous.

Methods cannot be added to an interface in a backwards compatible manner. Fields and methods can be added to a strict in a backwards compatible manner.

There is also no way for default behavior for an interface other than compile time failures. A struct can be designed to apply sane defaults are expressive errors.

I feel we should continue to hold static definitions about the probe in a manifest type of some sort instead of this flattening. Methods for the probe should be added for actions the probe makes and other components will can to initiate those actions.

@damemi
Copy link
Contributor Author

damemi commented May 3, 2025 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants