Skip to content

Implement app.installation.id resource attribute #922

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
bencehornak opened this issue Apr 3, 2025 · 6 comments
Open

Implement app.installation.id resource attribute #922

bencehornak opened this issue Apr 3, 2025 · 6 comments

Comments

@bencehornak
Copy link
Contributor

bencehornak commented Apr 3, 2025

The experimental semconv app.installation.id got accepted recently (open-telemetry/semantic-conventions#1897), I think it would be a useful addition to the existing attributes provided by the SDK.

What makes its implementation a bit tricky, is that there are multiple ways you can implement this resource attribute on Android. In the specs we have listed these four options:

As @bidetofevil pointed out the most practical choice for this SDK is probably number two (UUID), however, I could imaging exposing a setter for each of the options, as they all have pros and cons.

OpenTelemetryRum.builder(this, config)
  .appInstallationIdProvider(UuidAppInstallationIdProvider()) // default behavior, if nothing is specified
  // or
  .appInstallationIdProvider(FirebaseAppInstallationIdProvider())
  // or
  .appInstallationIdProvider(AppSetIdAppInstallationIdProvider())
  // or
  .appInstallationIdProvider(AndroidIdAppInstallationIdProvider())
  // or
  .appInstallationIdProvider(object : AppInstallationIdProvider() { ... })
  // ...
@bidetofevil
Copy link
Contributor

For now, I think generating one and using it will be sufficient. If there's a need to override, we can take that in a separate PR?

@bencehornak
Copy link
Contributor Author

Sure, sounds good to me.

@breedx-splk
Copy link
Contributor

I started looking into implementing these and I think it's considerably trickier than we think, primarily due to the fact that this is a resource attribute, and resources are immutable and created in the hot path at app start.

  • uuid persistence -- does IO and would block the main thread, violating strict mode.
  • firebase installation id - retrieving this uses an async api, which would have to be made synchronous and would block the main thread, violating strict mode.
  • app set id - appears to use the AppSetManager.getAppSetId which is also async and has the same problems as the above
  • Settings.Secure.getString(app.contentResolver, ANDROID_ID) - appears to be synchronous, and it does generate a warning in IntelliJ but is probably fine.

The docs around Settings.getString(ANDROID_ID) (here) seem to suggest decent support below api 26 too, so this is what I'm leaning toward right now. Other ideas?

@bencehornak
Copy link
Contributor Author

@breedx-splk that's a really tricky one. The approach, which I'd consider the most optimal from the SDK user's point of view is to defer the creation of the Resource object until the async part, as it is only needed when the BufferDelegatingXXXExporters receive their actual exporters. So essentially the same trick would be needed as #709, but this time for the Resource object instead of the exporters.

That said, I don't see any straight-forward way to achieve this, as the Resource object is passed when creating the SdkLoggerProvider & co, which takes place in the synchronous block when constructing the OpenTelemetry object, and it is registered to a bunch of immutable objects (e.g. to LoggerSharedState, which is shared across all SdkLoggers created by the SdkLoggerProvider). I tried a hacky way to change this field with reflection, but it doesn't work unfortunately due to the JDK being strict when it comes to changing final fields on 'hidden' classes.

All the alternatives I can think of for delaying the registration of the Resource object are more intrusive or require huge refactors to the Java SDK.

So going forward I see these possible approaches:

  1. Look for other hacky ways to change the immutably registered Resource object
  2. Do not create the OpenTelemetry object asynchronously -> might actually speed up the app startup as the complex synchronous initialization code would take place on a background thread, however, using the OpenTelemetry object would become significantly trickier for the SDK users, as they cannot create traces, counters, etc., until the async code completes.
  3. Use the Settings.getString(ANDROID_ID) field, as it is synchronous
  4. Do IO in the main thread -> probably not acceptable, as fast app startup times are non-negotiable for mobile apps

At work I've implemented the 2nd alternative built on top of the Java SDK. It was easy for us, because we are only using logging, and our Logback OpenTelemetryAppender buffers log records in memory until the OpenTelemetry object is install()ed. Users of the Android SDK want to start traces, counters and the like early on, so it isn't that easy in this case.

This is where I currently am in this thought process, and I still haven't made up my mind, which of these alternatives to recommend. I was optimistic for the first one, but my simplest approach didn't work sadly.

Which of these alternatives do you find the most optimal? Can you think of other alternative solutions?

@bidetofevil
Copy link
Contributor

For app.installation.id, the disk IO is unavoidable IMO, but it could be minimized.

For anything that is tied to the built APK, we can generate a file at build time and load that in via the classloader. That has worked really well for us

@bidetofevil
Copy link
Contributor

Per our discussion at the SIG today, I think we should just store it in shared preferences and read it, and make a note in the docs saying that while this can cause a strict mode violation, it's the lesser of all evils and the practice impact of the implementation should be minimal (and lets make sure it is :-))

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

No branches or pull requests

3 participants