Set Up Logs

Structured logs allow you to send, view and query logs sent from your applications within Sentry.

Stack traces tell you what broke. Logs tell you why. When an error fires, you get a snapshot of the failure, but the context leading up to it is often missing. Logs capture the journey — what the data looked like, which code paths executed, and what state the system was in.

Sentry Logs are high-cardinality — you can pass any attributes you want and search or filter by them later. No need to decide upfront which fields are important. Just log what might be useful and query it when you need it.

Logs for Kotlin Multiplatform are supported in Sentry Kotlin Multiplatform SDK version 0.24.0 and above.

Logs are supported on all platforms listed in Supported Platforms.

Enable logging by adding logs.enabled = true to your Sentry configuration.

SentrySetup.kt
Copied
import io.sentry.kotlin.multiplatform.Sentry

fun initializeSentry() {
  Sentry.init {
    it.dsn = "___PUBLIC_DSN___"
    it.logs.enabled = true
  }
}

Use Sentry.logger to send logs at different levels. A log message is required for Sentry to send the log.

LevelWhen to Use
traceFine-grained debugging
debugDevelopment diagnostics
infoNormal operations, milestones
warnPotential issues, degraded state
errorFailures that need attention
fatalCritical failures, system down
Copied
import io.sentry.kotlin.multiplatform.Sentry

Sentry.logger.trace("Entering function") { this["fn"] = "processOrder" }
Sentry.logger.debug("Cache lookup") { this["key"] = "user:123" }
Sentry.logger.info("Order created") { this["orderId"] = "order_456" }
Sentry.logger.warn("Rate limit approaching") { this["current"] = 95; this["max"] = 100 }
Sentry.logger.error("Payment failed") { this["reason"] = "card_declined" }
Sentry.logger.fatal("Database unavailable") { this["host"] = "primary" }

Pass structured data as attributes — these become searchable columns in Sentry.

Use the trailing lambda to attach attributes, or the full DSL with message() and attributes {} blocks for more complex logs.

You can use %s placeholders to create parameterized log messages. These will be automatically extracted as attributes.

Copied
import io.sentry.kotlin.multiplatform.Sentry

// Trailing lambda
Sentry.logger.info("User purchased product %s", productName) {
    this["userId"] = user.id
    this["referrer"] = "google"
}

// Full DSL
Sentry.logger.info {
    message("User purchased product %s", productName)
    attributes {
        this["userId"] = user.id
        this["referrer"] = "google"
    }
}

Use logs.beforeSend to filter or modify logs before they're sent. Return null to drop a log.

SentrySetup.kt
Copied
import io.sentry.kotlin.multiplatform.Sentry
import io.sentry.kotlin.multiplatform.log.SentryLogLevel

fun initializeSentry() {
  Sentry.init {
    it.dsn = "___PUBLIC_DSN___"
    it.logs.enabled = true
    it.logs.beforeSend = { log ->
      if (log.level == SentryLogLevel.DEBUG) {
        null
      } else {
        if (log.attributes.contains("password")) {
          log.attributes.remove("password")
        }
        log
      }
    }
  }
}

The beforeSend function receives a log object, and should return the log object if you want it to be sent to Sentry, or null if you want to discard it.

Instead of many small logs that are hard to correlate, emit one comprehensive log per operation with all relevant context.

This makes debugging dramatically faster — one query returns everything about a specific order, user, or request.

Copied
import io.sentry.kotlin.multiplatform.Sentry

// ❌ Scattered thin logs
Sentry.logger.info("Starting checkout")
Sentry.logger.info("Validating cart")
Sentry.logger.info("Processing payment")
Sentry.logger.info("Checkout complete")

// ✅ One wide event with full context
Sentry.logger.info("Checkout completed") {
    this["orderId"] = order.id
    this["userId"] = user.id
    this["cartValue"] = cart.total
    this["itemCount"] = cart.items.size
    this["paymentMethod"] = "stripe"
    this["duration"] = System.currentTimeMillis() - startTime
}

Add attributes that help you prioritize and debug:

  • User context — tier, account age, lifetime value
  • Transaction data — order value, item count
  • Feature state — active feature flags
  • Request metadata — endpoint, method, duration

This lets you filter logs by high-value customers or specific features.

Copied
import io.sentry.kotlin.multiplatform.Sentry

Sentry.logger.info("API request completed") {
    // User context
    this["userId"] = user.id
    this["userTier"] = user.plan // "free" | "pro" | "enterprise"

    // Request data
    this["endpoint"] = "/api/orders"
    this["method"] = "POST"
    this["duration"] = 234

    // Business context
    this["orderValue"] = 149.99
}

Sentry automatically attaches these attributes to every log:

AttributeDescriptionContext
sentry.environmentEnvironment from SDK configAlways
sentry.releaseRelease version from SDK configAlways
sentry.sdk.nameSDK nameAlways
sentry.sdk.versionSDK versionAlways
sentry.message.templateThe original parameterized template stringIf parameterized
sentry.message.parameter.XThe parameters used to fill the template, where X is the positional index (0, 1, etc.)If parameterized
sentry.originOrigin of the logIf from an integration
sentry.replay_idSession replay IDIf available
os.nameOperating system nameIf available
os.versionOperating system versionIf available
device.brandDevice manufacturerIf available
device.modelDevice model nameIf available
device.familyDevice familyIf available

Copied
Sentry.logger.error("User %s failed to purchase %s", userId, productName)

This sets sentry.message.template to "User %s failed to purchase %s", sentry.message.parameter.0 to the value of userId, and sentry.message.parameter.1 to the value of productName.

If you initialize the SDK with Native Platform Options, enable logs through the native SDK's configuration:

SentrySetup.android.kt
Copied
import io.sentry.kotlin.multiplatform.PlatformOptionsConfiguration

actual fun platformOptionsConfiguration(): PlatformOptionsConfiguration = {
    it.dsn = "___PUBLIC_DSN___"
    // Enable logs to be sent to Sentry
    it.logs.isEnabled = true
}

After initializing the SDK with the native platform options, you can use the common Sentry.logger API to send logs to Sentry.

Logs can get lost in certain crash scenarios, if the SDK can not send the logs before the app terminates. We are currently working on improving (#1, #2) this to ensure that all logs are sent, at the latest on the next app restart.

Was this helpful?
Help improve this content
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").