Loading

Configure the EDOT Android SDK

Stack Serverless Observability EDOT Android

This section contains a comprehensive list of all the configurable parameters available for the SDK, including those you can set during initialization and those you can adjust dynamically afterward.

Initialization configuration is available from the SDK builder shown in Agent setup. The following are its available parameters.

Provide your application name, version, and environment. For example:

class MyApp : android.app.Application {

    override fun onCreate() {
        super.onCreate()
        val agent = ElasticApmAgent.builder(this)
            .setServiceName("My app name")
            .setServiceVersion("1.0.0")
            .setDeploymentEnvironment("prod")
            // ...
            .build()
    }
}
  1. Name used by Kibana when listing your application on the Services page. Defaults to unknown. Refer to Why your app is referred to as a "service".
  2. Your app's version name. Defaults to the version provided in the PackageInfo.
  3. Your app's build type, flavor, backend environment, or a combination of these. Helpful to better analyze your app's data later in Kibana.

Configure where your app's telemetry is exported:

class MyApp : android.app.Application {

    override fun onCreate() {
        super.onCreate()
        val agent = ElasticApmAgent.builder(this)
            // ...
            .setExportUrl("https://my-elastic-apm-collector.endpoint")
            .setExportAuthentication(Authentication.ApiKey("my-api-key"))
            .setExportProtocol(ExportProtocol.HTTP)
            .build()
    }
}
  1. Your endpoint URL. If you don't have one yet, refer to Get the export endpoint.
  2. Your authentication method. You can use either an API key, a Secret token, or none. Defaults to None. API keys are the recommended method, if you don't have one yet, refer to Create an API key.
  3. The protocol used to communicate with your endpoint. It can be either HTTP or gRPC. Defaults to HTTP.
Tip

To provide these values from outside of your code, using an environment variable or a properties file for example, refer to Provide config values outside of your code.

You can provide an interceptor for the signals' export request headers, where you can read or modify them if needed.

class MyApp : android.app.Application {

    override fun onCreate() {
        super.onCreate()
        val agent = ElasticApmAgent.builder(this)
            // ...
            .setExportHeadersInterceptor(interceptor)
            .build()
    }
}

You can provide global interceptors for all spans and logs attributes. Interceptors are executed on every span or log creation, where you can read or modify them if needed.

This is useful for setting dynamic global attributes. If you'd like to set static global attributes, which are also applied to metrics, take a look at Intercept resources.

class MyApp : android.app.Application {

    override fun onCreate() {
        super.onCreate()
        val agent = ElasticApmAgent.builder(this)
            // ...
            .addSpanAttributesInterceptor(interceptor)
            .addLogRecordAttributesInterceptor(interceptor)
            .build()
    }
}

You can configure how sessions work. For example:

class MyApp : android.app.Application {

    override fun onCreate() {
        super.onCreate()
        val agent = ElasticApmAgent.builder(this)
            .setSessionSampleRate(1.0)
            // ...
            .build()
    }
}
  1. From version 1.1.0, you can provide your sample rate value. The value gets evaluated on every new session creation to determine whether the next session is sampled or not. When a session is not sampled, none of its signals are exported. Default value is 1.0.

You can configure how disk buffering works. For example:

class MyApp : android.app.Application {

    override fun onCreate() {
        super.onCreate()
        val agent = ElasticApmAgent.builder(this)
            .setDiskBufferingConfiguration(DiskBufferingConfiguration.enabled())
            // ...
            .build()
    }
}
  1. From version 1.1.0, you can configure whether the disk-buffering feature is turned on or off. It's turned on by default.

The agent creates a resource for your signals, which is a set of static global attributes. These attributes help Kibana properly display your application's data.

You can intercept these resources and read or modify them as shown in the following example.

class MyApp : android.app.Application {

    override fun onCreate() {
        super.onCreate()
        val agent = ElasticApmAgent.builder(this)
            // ...
            .setResourceInterceptor(interceptor)
            .build()
    }
}
Note

The resource interceptor is only applied during initialization, as this is the only time where resource attributes can be modified. If you'd like to set dynamic global attributes instead, take a look at Intercept attributes.

The SDK configures exporters for each signal (spans, logs, and metrics) to manage features like disk buffering and also to establish a connection with the Elastic export endpoint based on the provided export connectivity values.

You can intercept exporters to add your own logic, such as logging each signal that gets exported, or filtering some items that don't make sense for you to export. For example:

class MyApp : android.app.Application {

    override fun onCreate() {
        super.onCreate()
        val agent = ElasticApmAgent.builder(this)
            // ...
            .addSpanExporterInterceptor(interceptor)
            .addLogRecordExporterInterceptor(interceptor)
            .addMetricExporterInterceptor(interceptor)
            .build()
    }
}

This is a convenience tool to intercept HTTP-related spans. By default, the agent enhances HTTP span names to include domain:port when only an HTTP verb is set. This is often the case for HTTP client span names.

You can override this behavior by setting your own interceptor, or you can choose to set it to null to just turn it off. For example:

class MyApp : android.app.Application {

    override fun onCreate() {
        super.onCreate()
        val agent = ElasticApmAgent.builder(this)
            // ...
            .setHttpSpanInterceptor(interceptor)
            .build()
    }
}

Part of the work that the agent does when configuring the OpenTelemetry SDK on your behalf is to provide processors, which are needed to delegate data to the exporters. For spans, the agent provides a BatchSpanProcessor; for logs, a BatchLogRecordProcessor; whereas for metrics, it's a PeriodicMetricReader, which is analogous to a processor.

If you want to provide your own processors, you can do so by setting a custom ProcessorFactory, as shown in the example:

class MyApp : android.app.Application {

   override fun onCreate() {
      super.onCreate()
      val agent = ElasticApmAgent.builder(this)
         // ...
         .setProcessorFactory(factory)
         .build()
   }
}

The factory is called once during initialization and needs to provide a processor per signal. Each processor-provider method within the factory contains the configured exporter for that signal as an argument so that it's included into the processor as its delegate exporter.

Note

Not to be confused with OpenTelemetry's log signals. The internal logging policy is about the agent's internal logs that you should see in logcat only.

The agent creates logs using Android's Log type to notify about its internal events, so that you can check them out in logcat for debugging purposes. By default, all logs are printed for a debuggable app build. However, in the case of non-debuggable builds, only logs at the INFO level and higher are printed.

If you want to show specific logs from the agent, or even turn off logs altogether, you can do so by providing your own LoggingPolicy configuration. The following example shows how to allow all logs of level WARN and higher to be printed, whereas those lower than WARN are ignored.

class MyApp : android.app.Application {

    override fun onCreate() {
        super.onCreate()
        val agent = ElasticApmAgent.builder(this)
            // ...
            .setInternalLoggingPolicy(LoggingPolicy.enabled(LogLevel.WARN))
            .build()
    }
}

Dynamic configuration settings are available from an already built agent.

You can change any of the configuration values provided as part of the export connectivity setters, at any time by setting a new ExportEndpointConfiguration object, which overrides them all. For example:

class MyApp : android.app.Application {

    override fun onCreate() {
        super.onCreate()
        val agent = ElasticApmAgent.builder(this)
            // ...
            .build()
        agent.setExportEndpointConfiguration(configuration)
    }
}

You might need to get values such as an endpoint URL or API key or secret token from a local file in your project directory or an environment variable, or both. You can do this through the Android Gradle plugin and its build config fields, which provide a way to share Gradle info with your app's Kotlin/Java code.

The following example shows how to obtain configuration values from environment variables:

// Your app's build.gradle.kts file
plugins {
    // ...
}

val url = System.getenv("MY_ENV_WITH_MY_URL")
val apiKey = System.getenv("MY_ENV_WITH_MY_KEY")

android {
    // ...
    buildFeatures.buildConfig = true

    defaultConfig {
        // ...
        buildConfigField("String", "MY_EXPORT_URL", "\"$url\"")
        buildConfigField("String", "MY_EXPORT_API_KEY", "\"$apiKey\"")
    }
}
  1. Because build.gradle.kts files are written in Kotlin, you can get your environment variables the same way you would with regular Kotlin sources. The same applies to build.gradle files, which work with Groovy instead.
  2. Ensure Android's buildConfig feature is turned on.
  3. Adding build config fields to the android.defaultConfig block ensures they're available for all of your app's build variants. To provide different values per variant, you can create fields with the same name but different values for each of your build variants, as shown in Android's official docs.

You've properly created build config fields from environment variables. To use them in code, take a look at how to read build config fields in code.

Properties are a common way to provide values to JVM apps through files. Here's an example of how you could use them to provide config values to the agent.

Given the following example properties file:

my.url=http://localhost
my.api.key=somekey

This is what your build.gradle.kts configuration should look like:

// Your app's build.gradle.kts file
import java.util.Properties

plugins {
    // ...
}

val myPropertiesFile = project.file("myfile.properties")
val myProperties = Properties().apply {
    myPropertiesFile.inputStream().use { load(it) }
}

val url = myProperties["my.url"]
val apiKey = myProperties["my.api.key"]

android {
    // ...
    buildFeatures.buildConfig = true

    defaultConfig {
        // ...
        buildConfigField("String", "MY_EXPORT_URL", "\"$url\"")
        buildConfigField("String", "MY_EXPORT_API_KEY", "\"$apiKey\"")
    }
}
  1. Your file path is relative to your build.gradle.kts file. In this example, both files, build.gradle.kts and myfile.properties, are located in the same directory.
  2. Make sure Android's buildConfig feature is turned on.
  3. Adding your build config fields to the android.defaultConfig block ensures they're available for all of your app's build variants. To provide different values per variant, you can also create fields with the same name but different values for each of your build variants, as shown in Android's official docs.

You've properly created build config fields from a properties file. To use them in code, refer to read build config fields in code.

After adding build config fields in your build.gradle.kts file, you can now use them within your app's Kotlin or Java code by following these steps:

  1. Compile your project. The build config fields are generated during compilation, so this step is required so that you can find them in your code later.
  2. Find them within your app's BuildConfig generated type, as shown in the following example:
import my.app.namespace.BuildConfig
// ...

fun myMethod() {
    val agent = ElasticApmAgent.builder(application)
        // ...
        .setExportUrl(BuildConfig.MY_EXPORT_URL)
        .setExportAuthentication(Authentication.ApiKey(BuildConfig.MY_EXPORT_API_KEY))
        .build()
}
  1. There might be multiple BuildConfig types available to use in your code. The one that belongs to your app has a package name equal to your app's namespace value. So, for example, if your app's namespace is set to com.my.app, then the BuildConfig type you must use would be com.my.app.BuildType.
OSZAR »