LogFormatter
2.0.1indexedEnhances logging capabilities by determining and shortening logger names, extracting, shortening, and formatting stack traces with customizable options for improved readability and compactness.
Enhances logging capabilities by determining and shortening logger names, extracting, shortening, and formatting stack traces with customizable options for improved readability and compactness.
Log Formatter brings the powerful Logback log formatting capabilities as a logging framework independent implementation to all Kotlin Multiplatform targets.
Use it anywhere Kotlin runs (JVM, JS, Native) to produce highly customizable, clean, consistent, and compact log output.
Class Name
KClass or fully qualified name stringsStack Trace
implementation("net.codinux.log:log-formatter:2.0.1")
<dependency>
<groupId>net.codinux.log</groupId>
<artifactId>log-formatter-jvm</artifactId>
<version>2.0.1</version>
</dependency>
Each service class has a matching <ServiceClassName>Options class (e.g. StackTraceFormatterOptions).
Each of these provides a .Default object whose values match Logback’s default behavior.
Each service class can be configured in two ways:
.Default)val throwable = Throwable("Something went wrong", Throwable("Root cause"))
.apply { addSuppressed(Throwable("Suppressed exception")) }
val shortener = StackTraceShortener()
// keeps at maximum 3 frames per Throwable making it a quite compact and good readable stack trace
val max3FramesPerThrowable = shortener.shorten(throwable, maxFramesPerThrowable = 3)
val throwable = Throwable("Something went wrong")
val formatter = StackTraceFormatter()
println(formatter.format(throwable))
// shows how much better readable stack trace then is
println(formatter.format(StackTraceShortener().shorten(throwable, maxFramesPerThrowable = 3)))
// a lot of config options to format stack trace
println(formatter.format(throwable, StackTraceFormatterOptions(
messageLineIndent = "",
stackFrameIndent = " ",
causedByIndent = "",
causedByMessagePrefix = ,
suppressedExceptionIndent = ,
suppressedExceptionMessagePrefix = ,
lineSeparator = LineSeparator.System
)))
We provide different implementations of the LogEventFormatter interface to format a LogEvent, e.g. to output it on the console.
The one to take if you don't know which one to take. Provides a sensible default log pattern (explanation see below):
"%-5level %logger [%thread] - %message%n%exception"
You can specify which fields to log directly in code. E.g. to get the same pattern as above:
val formatter = FieldsLogEventFormatter(listOf(
LogLevelFormatter(FieldFormat(minWidth = 5, pad = FieldFormat.Padding.End)),
LiteralFormatter.Whitespace,
LoggerNameFormatter(),
LiteralFormatter(" ["),
ThreadNameFormatter(),
LiteralFormatter("] "),
MessageFormatter(),
LineSeparatorFormatter(),
ThrowableFormatter()
))
Provides the ability to specify the log output as a string pattern like "%-5level [%logger] (%thread) %message%n%exception".
It follows the same pattern format of Logback and JBoss Logging except that we do not support all of their fields.
Each conversion specifier starts with a percent sign % and is followed by optional format modifiers, a conversion word and optional parameters between braces.
The conversion word controls the data field to convert, e.g. logger name, level, date or thread name.
The format modifiers control field width, padding, and left or right justification.
E.g. %-10.-20logger specifies:
10-, default is padding at start) if field value is shorter than 1020-, default is truncation at start) if field value is longer than 20For a detailed explanation see: https://logback.qos.ch/manual/layouts.html#formatModifiers
Implemented conversion words are:
As they follow Logback's and JBoss Logging's implementation, for more information see: https://logback.qos.ch/manual/layouts.html#conversionWord
KClassTo get the package name, name of the class, enclosing class (if any) and declaring class, call:
// get package name (not available on JavaScript and WASM), class name and enclosing class name
// (in case of a Companion class, inner class, local class, anonymous function, lambda, ...)
val classNameComponents = ClassNameResolver.getClassNameComponents(TestClasses.OuterClass.InnerClass::class)
Be aware:
native we can only extract the direct class name with certainty, but not the enclosing and declaring class name, as there we only have the full qualified name (that is a string containing both, the package name and the class name). So we can only make educated guesses which parts belong to the class and with to the package name.JS/Browser, JS/Node and WASM the package is not available / known and only the direct / last class name component is available. For Companion objects e.g. this is "Companion".Used e.g. by Kotlin logging facade and LokiLogAppender for determining and shortening logger name from KClass or shortening and formatting stack trace.
Copyright 2025 codinux GmbH & Co. KG
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance the License.
You may obtain a copy of the License at
https:
Unless applicable law agreed to writing, software
distributed under the License distributed an BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express implied.
See the License the specific language governing permissions
limitations under the License.
fun extractStackTrace() {
val throwable = Throwable("Something went wrong", Throwable("Root cause"))
.apply { addSuppressed(Throwable("Suppressed exception")) }
val stackTrace = StackTraceExtractor().extractStackTrace(throwable)
printStackTrace(stackTrace)
}
private fun printStackTrace(stackTrace: StackTrace) {
println("Message line: ${stackTrace.messageLine}")
println("Stack frames:")
stackTrace.stackTrace.forEach { println(it.line) }
println("Count skipped common frames: ${stackTrace.countSkippedCommonFrames}")
stackTrace.suppressed.forEach { suppressed ->
println("Suppressed:")
printStackTrace(suppressed)
}
if (stackTrace.causedBy != null) {
println("Caused by:")
printStackTrace(stackTrace.causedBy!!)
}
}
| Conversion word | Description |
|---|
%level, %le, %l | Log level (like Info, Error, ...). |
%logger, %lo, %c | Logger (category) name that issued this log event. |
%message, %msg, %m | The message of this log event. |
%exception, %throwable, %ex, %e | The exception message and stack trace, if any. First option is the number of stack trace lines per Throwable. Second option is max nested throwables (causes). |
%rootException, %rEx | The same as %exception, but the root cause first = inverts the order of the nested exceptions, as the root cause is in most cases the most meaningful one. Options are the same as for %exception, see above. |
%date, %d | The date time at which the log event occurred. First option is the format pattern. If not set defaults to "yyyy-MM-dd HH:mm:ss,SSS". Understands most of the ISO format patterns, only available localization is English (e.g. for day name), see KMP DateTime.Second option is the time zone. Only supported value for now is "UTC". |
%thread, %th, %t | Name of the thread that generated the event. May not available on all systems. |
$n | Platform dependent line separator, e.g. \r\n on Windows or \n on Unix systems. |
| Class type | Platform | Class name | Declaring class name | Companion owner class Name |
|---|
| Companion | JVM | TestClass.Companion | TestClass | TestClass |
| Companion | Native | TestClass.Companion | null | TestClass |
| Companion | JS | Companion | null | null |
| Inner class | JVM | TestClass.InnerClass | TestClass | null |
| Inner class | Native | InnerClass | null | null |
| Inner class | JS | InnerClass | null | null |
| Inner class Companion | JVM | TestClass.InnerClass.Companion | TestClass | null |
| Inner class Companion | Native | InnerClass.Companion | null | InnerClass |
| Inner class Companion | JS | Companion | null | null |
Surfaced from shared tags and platforms — no rankings paid for.