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.
Using native platform options? See Using Native Platform Options below.
SentrySetup.ktimport 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.
| Level | When to Use |
|---|---|
trace | Fine-grained debugging |
debug | Development diagnostics |
info | Normal operations, milestones |
warn | Potential issues, degraded state |
error | Failures that need attention |
fatal | Critical failures, system down |
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.
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.ktimport 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.
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.
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:
| Attribute | Description | Context |
|---|---|---|
sentry.environment | Environment from SDK config | Always |
sentry.release | Release version from SDK config | Always |
sentry.sdk.name | SDK name | Always |
sentry.sdk.version | SDK version | Always |
sentry.message.template | The original parameterized template string | If parameterized |
sentry.message.parameter.X | The parameters used to fill the template, where X is the positional index (0, 1, etc.) | If parameterized |
sentry.origin | Origin of the log | If from an integration |
sentry.replay_id | Session replay ID | If available |
os.name | Operating system name | If available |
os.version | Operating system version | If available |
device.brand | Device manufacturer | If available |
device.model | Device model name | If available |
device.family | Device family | If available |
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.ktimport 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.
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").