
Logging to console, files, network, SigNoz and Firebase; global crash handling across coroutines, threads and native signals; install wrapper protects entry point and writes persistent, async-signal-safe crash reports.
A Kotlin Multiplatform logging library with support for terminal, file, network, SigNoz, and Firebase output - plus global crash handling across coroutines, threads, native signals, and browser exceptions.
| Platform | Console | File | Network | SigNoz | Firebase | Crash Handling |
|---|---|---|---|---|---|---|
| Android | + | + | + | + | + | + |
| iOS | + | + | + | + | + | + |
| Desktop JVM | + | + | + | + | + | + |
| Desktop Native (MinGW / Linux / POSIX) | + | + | + | + | + | + |
| Browser (JS) | + | + (IndexedDB) | + | + | + | + |
Add the dependency to your shared module:
// build.gradle.kts
dependencies {
implementation("io.github.cheerwizard:print:1.0.0")
}Call Print.install() once at the entry point of your app. All code inside the trailing lambda is guarded by Print's crash handlers — any uncaught exception will be caught and reported through your configured loggers.
Print.install(
logLevel = LogLevel.WARNING, // optional, default is VERBOSE
crashReportFilepath = "logs/crash-report-2026-01-10.log", // optional, default is logs/crash-report-{currentDate}.log
loggers = setOf(
ConsoleLogger(),
FileLogger(filepath),
SignozLogger(host),
FirebaseLogger(clientId, secret, measurementId),
CustomLogger() // implement Logger or NetworkLogger
)
) {
// your app entry point code here
// crashes in this block are caught and reported automatically
}The context parameter is required — it gives Print access to platform-specific functions such as file I/O paths, native signal registration, and platform metadata attached to log events.
enum class LogLevel {
NONE, // disables all logging
VERBOSE, // everything (default)
INFO,
DEBUG,
WARNING,
ERROR,
FATAL
}The logLevel set at install time acts as a global minimum — loggers will not receive events below it.
Print.v("MyTag", "Verbose message")
Print.i("MyTag", "Info message")
Print.d("MyTag", "Debug message")
Print.w("MyTag", "Warning message")
Print.e("MyTag", "Error message")
Print.e("MyTag", Throwable())
Print.f("MyTag", "Fatal message")
Print.f("MyTag", Throwable())Logs to the platform's standard output with log level labels.
ConsoleLogger()Persists logs to a local file in append mode. Survives app restarts and is the target for crash reports.
On the browser platform, logs are stored in window.indexedDB when available.
FileLogger(filepath = "/data/logs/app.log")Sends structured logs to a SigNoz endpoint. Events are forwarded as structured JSON with level, tag, timestamp, and platform metadata.
SignozLogger(host = "https://ingest.signoz.io")Sends logs and events to Firebase Analytics / Crashlytics.
FirebaseLogger(
clientId = "your-client-id",
secret = "your-secret",
measurementId = "G-XXXXXXXXXX"
)Implement the Logger interface for simple loggers, or NetworkLogger for loggers that send data over the network:
class MyLogger : Logger {
override fun log(level: LogLevel, tag: String, message: String) {
// your implementation
}
}
class MyNetworkLogger : NetworkLogger {
override suspend fun send(level: LogLevel, tag: String, message: String) {
// your implementation
}
}
Print.install(
// ...
loggers = setOf(MyLogger(), MyNetworkLogger())
)Crash handling is enabled automatically for all code inside the Print.install {} lambda. No separate setup is needed.
| Crash Type | Platforms |
|---|---|
Coroutine exceptions (CoroutineExceptionHandler) |
All |
Thread uncaught exceptions (Thread.setDefaultUncaughtExceptionHandler) |
JVM, Android |
Native signal crashes (SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS) |
Android, Desktop JVM, Desktop Native |
Browser uncaught exceptions (window.onerror, unhandledrejection) |
Browser |
iOS uncaught exceptions (NSException) |
iOS |
Native crash reports are written synchronously using async-signal-safe I/O, so the report is preserved even when the process is about to terminate.
A Kotlin Multiplatform logging library with support for terminal, file, network, SigNoz, and Firebase output - plus global crash handling across coroutines, threads, native signals, and browser exceptions.
| Platform | Console | File | Network | SigNoz | Firebase | Crash Handling |
|---|---|---|---|---|---|---|
| Android | + | + | + | + | + | + |
| iOS | + | + | + | + | + | + |
| Desktop JVM | + | + | + | + | + | + |
| Desktop Native (MinGW / Linux / POSIX) | + | + | + | + | + | + |
| Browser (JS) | + | + (IndexedDB) | + | + | + | + |
Add the dependency to your shared module:
// build.gradle.kts
dependencies {
implementation("io.github.cheerwizard:print:1.0.0")
}Call Print.install() once at the entry point of your app. All code inside the trailing lambda is guarded by Print's crash handlers — any uncaught exception will be caught and reported through your configured loggers.
Print.install(
logLevel = LogLevel.WARNING, // optional, default is VERBOSE
crashReportFilepath = "logs/crash-report-2026-01-10.log", // optional, default is logs/crash-report-{currentDate}.log
loggers = setOf(
ConsoleLogger(),
FileLogger(filepath),
SignozLogger(host),
FirebaseLogger(clientId, secret, measurementId),
CustomLogger() // implement Logger or NetworkLogger
)
) {
// your app entry point code here
// crashes in this block are caught and reported automatically
}The context parameter is required — it gives Print access to platform-specific functions such as file I/O paths, native signal registration, and platform metadata attached to log events.
enum class LogLevel {
NONE, // disables all logging
VERBOSE, // everything (default)
INFO,
DEBUG,
WARNING,
ERROR,
FATAL
}The logLevel set at install time acts as a global minimum — loggers will not receive events below it.
Print.v("MyTag", "Verbose message")
Print.i("MyTag", "Info message")
Print.d("MyTag", "Debug message")
Print.w("MyTag", "Warning message")
Print.e("MyTag", "Error message")
Print.e("MyTag", Throwable())
Print.f("MyTag", "Fatal message")
Print.f("MyTag", Throwable())Logs to the platform's standard output with log level labels.
ConsoleLogger()Persists logs to a local file in append mode. Survives app restarts and is the target for crash reports.
On the browser platform, logs are stored in window.indexedDB when available.
FileLogger(filepath = "/data/logs/app.log")Sends structured logs to a SigNoz endpoint. Events are forwarded as structured JSON with level, tag, timestamp, and platform metadata.
SignozLogger(host = "https://ingest.signoz.io")Sends logs and events to Firebase Analytics / Crashlytics.
FirebaseLogger(
clientId = "your-client-id",
secret = "your-secret",
measurementId = "G-XXXXXXXXXX"
)Implement the Logger interface for simple loggers, or NetworkLogger for loggers that send data over the network:
class MyLogger : Logger {
override fun log(level: LogLevel, tag: String, message: String) {
// your implementation
}
}
class MyNetworkLogger : NetworkLogger {
override suspend fun send(level: LogLevel, tag: String, message: String) {
// your implementation
}
}
Print.install(
// ...
loggers = setOf(MyLogger(), MyNetworkLogger())
)Crash handling is enabled automatically for all code inside the Print.install {} lambda. No separate setup is needed.
| Crash Type | Platforms |
|---|---|
Coroutine exceptions (CoroutineExceptionHandler) |
All |
Thread uncaught exceptions (Thread.setDefaultUncaughtExceptionHandler) |
JVM, Android |
Native signal crashes (SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS) |
Android, Desktop JVM, Desktop Native |
Browser uncaught exceptions (window.onerror, unhandledrejection) |
Browser |
iOS uncaught exceptions (NSException) |
iOS |
Native crash reports are written synchronously using async-signal-safe I/O, so the report is preserved even when the process is about to terminate.