Abrova
☰ Docs menu · Android SDK logging

Android SDK Logging

Structured logging for Android apps with automatic batching, exponential backoff, and lifecycle awareness via the native Kotlin SDK.

Last updated: 27 Oct 2026

Structured logging for Android apps with automatic batching, exponential backoff, and lifecycle awareness. Logs are buffered and sent in batches to minimize network usage and battery drain.

Automatic Batching

Logs are buffered and sent in batches (default: 50)

Exponential Backoff

Failed batches are retried with increasing delays (2s, 4s, 8s... up to 60s)

Max Buffer Size

Drops oldest logs when buffer exceeds 1000 to prevent memory issues

Lazy Timer

Timer only runs when buffer has logs — no battery drain when idle

User Context

Automatically attaches user ID set via AbrovaTrace.setUserId()

Native Kotlin

Built with Kotlin, supports API 19+ (Android 4.4+)

Enable Logging#

After initializing AbrovaTrace in your Application class, enable the logging service:

kotlin
import android.app.Application
import ir.abrova.trace.sdk.AbrovaTrace
import ir.abrova.trace.sdk.AbrovaTraceConfig

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()

        // Initialize AbrovaTrace first
        val config = AbrovaTraceConfig.Builder("ab_live_YOUR_API_KEY")
            .environment("production")
            .release(BuildConfig.VERSION_NAME)
            .build()

        AbrovaTrace.init(this, config)

        // Enable logging with a source identifier
        AbrovaTrace.enableLogging(
            sourceId = "my-android-app",
            sourceName = "My Android App",
            batchSize = 50,
            flushIntervalMs = 5000L
        )
    }
}

Sending Logs#

Convenience Methods

kotlin
import ir.abrova.trace.sdk.AbrovaTrace

// Info log
AbrovaTrace.info("User login successful", mapOf(
    "user_id" to "user_123"
))

// Warning log
AbrovaTrace.warn("Slow API response", mapOf(
    "endpoint" to "/api/users",
    "duration_ms" to 2500
))

// Error log
AbrovaTrace.logError("Database query failed", mapOf(
    "query" to "SELECT * FROM users",
    "error" to "Connection timeout"
))

// Debug log
AbrovaTrace.logDebug("Cache hit for key: user_123")

// Trace log
AbrovaTrace.trace("Entering function processPayment()")

// Fatal log
AbrovaTrace.fatal("App crashed unexpectedly", mapOf(
    "last_screen" to "checkout"
))

Generic Log Method

kotlin
import ir.abrova.trace.sdk.models.LogLevel

// Generic log with explicit level
AbrovaTrace.log(
    "Custom event",
    LogLevel.INFO,
    mapOf("key" to "value")
)

Log Levels#

  • trace — AbrovaTrace.trace() — Very detailed trace-level debugging
  • debug — AbrovaTrace.logDebug() — Debug information during development
  • info — AbrovaTrace.info() — General application information
  • warn — AbrovaTrace.warn() — Warnings about potential issues
  • error — AbrovaTrace.logError() — Errors that need attention
  • fatal — AbrovaTrace.fatal() — Critical/unrecoverable errors

Usage with Activities#

kotlin
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        AbrovaTrace.info("MainActivity created", mapOf("screen" to "main"))
    }

    private fun handlePurchase() {
        AbrovaTrace.info("Purchase initiated", mapOf(
            "product_id" to "premium_pack",
            "amount" to 99.99
        ))

        try {
            processPurchase()
            AbrovaTrace.info("Purchase completed", mapOf("amount" to 99.99))
        } catch (e: Exception) {
            AbrovaTrace.logError("Purchase failed", mapOf(
                "error" to e.message,
                "product_id" to "premium_pack"
            ))
            AbrovaTrace.captureException(e)
        }
    }

    override fun onDestroy() {
        if (isFinishing) {
            AbrovaTrace.flushLogs()
            AbrovaTrace.close()
        }
        super.onDestroy()
    }
}

Manual Operations#

kotlin
// Force flush all buffered logs
AbrovaTrace.flushLogs { success ->
  if (success) {
      Log.d("AbrovaTrace", "Logs flushed successfully")
  }
}

// Check buffer status
val pendingCount = AbrovaTrace.getPendingLogCount()
Log.d("AbrovaTrace", "Pending logs: $pendingCount")

Configuration#

OptionTypeRequiredDescription
sourceIdString?NoIdentifier for batch sending (e.g., "my-android-app")
sourceNameString?NoHuman-readable name for this source
batchSizeIntNoFlush when buffer reaches this size (default: 50)
flushIntervalMsLongNoMax time before flush in ms (default: 5000)

If you call a log method before enableLogging(), logging is switched on automatically with the defaults above (no sourceId). Without a sourceId, each log is sent individually to /api/logs/ingest and a failed send is not retried; with one, buffered logs go in one request to /api/logs/ingest/batch and a failed batch is retried. Logs are also flushed when the app goes to the background. While the app is in the background the flush timer does not run: logs are sent when the batch size is reached or when the app returns to the foreground.

Best Practices#

Enable Early

Enable logging right after AbrovaTrace.init() to capture all events

Use Source IDs

Set a meaningful sourceId to identify logs from this app in the dashboard

Add Metadata

Include structured metadata (user ID, screen name, etc.) for easier debugging

Use Appropriate Levels

Use info for normal events, warn for potential issues, error for failures

Flush on Shutdown

Call AbrovaTrace.flushLogs() before app close to ensure all logs are sent

Don't Over-Log

Avoid logging in tight loops — the buffer has a max size and will drop oldest logs

Was this page helpful?
Report a problem