The Atatus mobile SDK forwards application logs from native Android and Android TV builds to Atatus over HTTP. Entries are batched on the device, enriched with attributes and tags you define, and bound to the RUM context active when they were emitted, so a log line resolves to the session and view that produced it.

Prerequisites

  • The Atatus SDK initialized in your application. See Android Monitoring Setup.
  • A RUM application in Atatus, which provisions the license key the SDK authenticates with.
Warning:

Authenticate with the license key, never your account API key. Anything shipped inside an APK is recoverable through decompilation, and the license key is the only credential scoped for client-side distribution.

Setup

1. Add the logs dependency

Declare the logs library in your application module's build script. It depends on the core SDK, so no additional coordinate is required:

copy
icon/buttons/copy
dependencies {
    implementation("com.atatus:atatus-sdk-android-logs:1.0.1")
}

2. Initialize the SDK

Logs share the core SDK instance with RUM, so initialization is identical to Android Monitoring Setup. Skip this step if the SDK is already initialized in your Application class:

copy
icon/buttons/copy
import android.app.Application
import com.atatus.android.Atatus
import com.atatus.android.core.configuration.Configuration
import com.atatus.android.privacy.TrackingConsent

class SampleApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        val configuration = Configuration.Builder(
            licenseKey = "<LICENSE_KEY>",
            env = "<ENV_NAME>",
            variant = "<APP_VARIANT_NAME>"
        )
            .build()

        Atatus.initialize(this, configuration, TrackingConsent.GRANTED)
    }
}

Guard against emitting logs before initialization completes:

copy
icon/buttons/copy
if (Atatus.isInitialized()) {
    // Your code here
}

3. Enable the logs feature

Enabling the feature registers the logs intake pipeline and its batch storage:

copy
icon/buttons/copy
import com.atatus.android.log.Logs
import com.atatus.android.log.LogsConfiguration

val logsConfiguration = LogsConfiguration.Builder().build()
Logs.enable(logsConfiguration)

4. Create a logger

A Logger is the entry point for emitting entries, and its builder fixes the enrichment and sampling applied to everything it sends. Create one per subsystem you want to filter on independently:

copy
icon/buttons/copy
import com.atatus.android.log.Logger

val logger = Logger.Builder()
    .setNetworkInfoEnabled(true)
    .setLogcatLogsEnabled(true)
    .setBundleWithRumEnabled(true)
    .setRemoteSampleRate(100f)
    .setName("<LOGGER_NAME>")
    .build()

Logger.Builder options:

Option Description
setNetworkInfoEnabled(true) Adds network connectivity attributes (carrier, connection type) to each log.
setLogcatLogsEnabled(true) Also writes logs to Logcat, so they appear in your local console.
setBundleWithRumEnabled(true) Links logs to the current RUM context so you can pivot between logs and sessions.
setRemoteSampleRate(100f) Percentage of logs sent to Atatus, from 0f to 100f. Defaults to 100f.
setName("<LOGGER_NAME>") Sets the logger name attribute.
setService("<SERVICE_NAME>") Sets the service name attribute.

5. Send log messages

Each method maps to an Android log priority, which drives severity filtering and alerting in Atatus:

copy
icon/buttons/copy
logger.d("A debug message.")
logger.i("Some relevant information.")
logger.w("An important warning.")
logger.e("An error was met!")
logger.wtf("What a terrible failure!")

Pass a Throwable to record the exception and its stack trace alongside the message:

copy
icon/buttons/copy
try {
    doSomething()
} catch (e: IOException) {
    logger.e("Error while doing something", e)
}

Attach attributes scoped to a single entry:

copy
icon/buttons/copy
logger.i("onPageStarted", attributes = mapOf("http.url" to url))

6. Add global attributes and tags

Attributes are structured key-value pairs that remain queryable in Atatus, unlike values interpolated into a message string. Scope them to one logger, or to every logger through the Logs feature:

copy
icon/buttons/copy
// Added to every log sent by this logger
logger.addAttribute("version_name", BuildConfig.VERSION_NAME)

// Added to every log sent by all loggers
Logs.addAttribute("version_code", BuildConfig.VERSION_CODE)

Tags partition logs into facets for filtering and aggregation:

copy
icon/buttons/copy
logger.addTag("build_type", BuildConfig.BUILD_TYPE)
logger.addTag("device", "android")

Remove attributes and tags once they fall out of scope, so later entries are not enriched with stale state:

copy
icon/buttons/copy
logger.removeAttribute("version_name")
Logs.removeAttribute("version_code")
logger.removeTagsWithKey("build_type")

Send data when the device is offline

Entries are serialized to batch files on disk and uploaded when network availability and battery level permit, so a session recorded offline is retained until connectivity returns. Batches exceeding their retention window are evicted to bound disk usage. No configuration is required.

Next steps