Skip to main content
Version: 2.1.x

Activity Trails & Structured Logging in KMP

An Activity Trail is a chronological sequence of breadcrumb events captured in the application leading up to an issue, crash, or goal completion.

Appxiom automatically records screen lifecycle transitions and button taps (Modifier.axTrackClick). Custom activity trails allow developers to add domain breadcrumbs across shared repositories, background sync workers, state machines, and third-party SDK calls.


1. Custom Activity Markers (Ax.setActivityMarkerAt)​

Record a discrete, high-value domain event marker:

import tech.appxiom.kmp.Ax

// Syntax: Ax.setActivityMarkerAt(where: String, marker: String)
Ax.setActivityMarkerAt("AuthService", "User requested biometric authentication")
Ax.setActivityMarkerAt("CartRepository", "Applied promo code SUMMER2026")
  • where: Name of the class, ViewModel, or service emitting the marker.
  • marker: Descriptive representation of the action or state change.

2. Structured Logging Helpers​

Appxiom provides built-in logging helpers in common code:

import tech.appxiom.kmp.axLog
import tech.appxiom.kmp.axPrint

// Outputs to console and attaches as an activity trail breadcrumb
axLog(tag = "SyncWorker", message = "Database sync started for 48 records")
axPrint("User tapped refresh button")

3. Integrating with Third-Party KMP Logging Libraries​

Kermit Integration​

Create a custom Kermit LogWriter to forward log statements to Appxiom:

import co.touchlab.kermit.LogWriter
import co.touchlab.kermit.Severity
import tech.appxiom.kmp.Ax

class AppxiomKermitWriter : LogWriter() {
override fun log(severity: Severity, message: String, tag: String, throwable: Throwable?) {
if (severity >= Severity.Info) {
val fullMessage = if (throwable != null) {
"$message\n${throwable.stackTraceToString()}"
} else {
message
}
Ax.setActivityMarkerAt(tag, fullMessage)
}
}
}

Add the writer during logger initialization:

import co.touchlab.kermit.Logger
import co.touchlab.kermit.platformLogWriter

val logger = Logger.withTag("MyApp").apply {
setLogWriters(platformLogWriter(), AppxiomKermitWriter())
}

Napier Integration​

Create a custom Napier Antilog:

import io.github.aakira.napier.Antilog
import io.github.aakira.napier.LogLevel
import tech.appxiom.kmp.Ax

class AppxiomAntilog : Antilog() {
override fun performLog(
priority: LogLevel,
tag: String?,
throwable: Throwable?,
message: String?
) {
if (priority.ordinal >= LogLevel.INFO.ordinal) {
val where = tag ?: "App"
val text = message ?: ""
Ax.setActivityMarkerAt(where, text)
}
}
}

Next Steps​

Learn how to measure critical business funnels in Goal Tracking & GFI.