Skip to content

Capture click events for compose#1002

Merged
breedx-splk merged 7 commits into
open-telemetry:mainfrom
cleverchuk:cc/compose
Jun 17, 2025
Merged

Capture click events for compose#1002
breedx-splk merged 7 commits into
open-telemetry:mainfrom
cleverchuk:cc/compose

Conversation

@cleverchuk
Copy link
Copy Markdown
Contributor

fixes #986

This PR takes inspiration from here and here to realize the feature.

@cleverchuk cleverchuk requested a review from a team as a code owner June 9, 2025 11:07
@breedx-splk
Copy link
Copy Markdown
Contributor

Thanks, looking forward to reviewing!

One initial thought -- the new module is instrumentation/compose and only contains the click instrumentation. Compose is asked about a lot...do you foresee adding more instrumentation to the same module, or do we think it might be better broken out, such as instrumentation/compose/click and instrumentation/compose/navigation etc.? This isn't a blocking question, just curious what people think.

@bidetofevil
Copy link
Copy Markdown
Contributor

I like @breedx-splk's suggestion. Compose is an entire framework, and there could be instrumentation for many aspects of it. Having them live in separate modules seem like the right thing to do, as you might not want all of them.

Comment thread gradle/libs.versions.toml Outdated
autoService = "1.1.1"
androidx-navigation = "2.7.7"
#noinspection GradleDependency
compose = "1.3.0"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What's the reason you chose 1.3.0? Is it that you can only support versions at runtime that is greater than or equal to this version?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

What's the reason you chose 1.3.0?

1.3.0 because that's when the layoutDelegate field was added to LayoutNode class.

Is it that you can only support versions at runtime that is greater than or equal to this version?

yes

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think there's no need to pin it to this version in the project, since we add it as compileOnly and the README explains that the minimum version required is 1.3.0. So I'd remove the #noinspection GradleDependency and set it to the latest version available.

ctx.openTelemetry
.logsBridge
.loggerBuilder("io.opentelemetry.android.instrumentation.compose")
.build() as ExtendedLogger,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Will this work with disk buffering, @LikeTheSalad ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is a good point. I'm not sure it would cause issues, but in general I don't think we should rely on extended types unless we have no choice. Can we change this to use plain Logger instead, @cleverchuk ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Unfortunately, the event name stuff is all incubating, which means that any time we want to create events we have to do the cast until it's done incubating. See the network change instrumentation for an existing precedent.

import android.view.Window.Callback
import androidx.annotation.RequiresApi

internal class WindowCallbackWrapper(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Will this work with versions less than M if two of these methods are not callable? If the behavior in L is unpredictable as a result, I would just make the whole class require M and simply not add the instrumentation if it's not at least M

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

this is similar to view-click one. IIRC animal-sniffer gave me a lot of grief when i made it class only and i think the tests didn't run correctly either with what you're suggesting.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Tests that use the AndroidX or Roboletric runner will by default use the minApiVersion. You can use the @Config annotation to specify a working Android version and then test that a non-working one wouldn't have this added. Have a look at AgentInitTest among others.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

what are you suggesting, change the min api to M?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm suggesting changing the tests to run as if it were M, and only including this instrumentation if it were M+.

No worries about this. I'll see if I can refactor and throw a test up quickly today since this was merged already

val yCoordinateAttr: AttributeKey<Long> = longKey("app.screen.coordinate.y")
val viewIdAttr: AttributeKey<Long> = longKey("app.widget.id")

class ComposeLayoutNodeUtil {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why not make the whole class internal so you don't have a public object with inaccessible methods outside the module?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

it'll cause a compile-time error when put on the class because it's being accessed here and here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Right. It's because ComposeClickEventGenerator is public and this is part of the interface. Can that be internal as well? What you have here is a concept that is partially leaking publicly, but not really accessible which isn't great.

I think you have a few options:

  • Make everything public
  • Make everything internal
  • Make the Util class completely private/internal and don't expose it in the interface of ComposeClickEventGenerator

Any of these would work

Copy link
Copy Markdown
Contributor

@breedx-splk breedx-splk left a comment

Choose a reason for hiding this comment

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

This is great @cleverchuk thanks for the addition! I left a few comments, but things are mostly looking good from my perspective. Cheers!

Copy link
Copy Markdown
Contributor

@breedx-splk breedx-splk left a comment

Choose a reason for hiding this comment

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

Thanks again! 🚀

Copy link
Copy Markdown
Contributor

@LikeTheSalad LikeTheSalad left a comment

Choose a reason for hiding this comment

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

Thank you 🙏

@cleverchuk
Copy link
Copy Markdown
Contributor Author

cleverchuk commented Jun 17, 2025

I'm gonna close the PR and reopen it later because it looks like the compiler suppression doesn't work from 1.6.0+.

@cleverchuk cleverchuk closed this Jun 17, 2025
@cleverchuk
Copy link
Copy Markdown
Contributor Author

cleverchuk commented Jun 17, 2025

okay, we can only claim to support 1.3.0 - 1.5.4. i'll work on figuring out how to support the rest. also moved to new package because it seemed like everyone liked the idea.

@cleverchuk cleverchuk reopened this Jun 17, 2025
@breedx-splk breedx-splk merged commit a4c401e into open-telemetry:main Jun 17, 2025
10 checks passed
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.

Capture click events for compose views

4 participants