Logging in Kotlin Applications: Best Practices for Beginners
\n\nLogging is not just about writing messages to a file. It is a system that helps a developer understand what is happening in the application in real time, quickly find errors, and analyze user behavior. In this article, we will look at how to properly organize logging in Kotlin applications, which libraries to use, and what mistakes to avoid.
\n\nWhy is logging needed?
\nLogging solves several key tasks:
\n- \n
- Debugging: allows you to see the sequence of calls and variable values without using a debugger. \n
- Monitoring: helps track the application's state in a production environment. \n
- Auditing: records user actions and system events. \n
- Performance: logs can help identify bottlenecks and delays. \n
Popular libraries for logging in Kotlin
\nIn the Kotlin and JVM ecosystem, there are several proven solutions. Let's look at the main ones:
\n- \n
- SLF4J (Simple Logging Facade for Java) — a facade that does not implement logging itself but provides a unified API for various implementations (Logback, Log4j2, etc.). \n
- Logback — the most popular SLF4J implementation. Fast, flexible, with support for rolling files. \n
- Log4j 2 — a powerful library with support for asynchronous logging and filtering. \n
- Kotlin Logging — a convenient wrapper over SLF4J that uses inline functions to minimize overhead. \n
Configuring Logback in a Kotlin project
\nLet's look at a step-by-step configuration of Logback, the most popular solution for Kotlin/JVM applications.
\n\nStep 1. Adding dependencies
\nIn the build.gradle.kts file, add:
dependencies {\n implementation("ch.qos.logback:logback-classic:1.4.14")\n implementation("io.github.microutils:kotlin-logging-jvm:3.0.5")\n}\n\nStep 2. Creating a configuration file
\nCreate a file src/main/resources/logback.xml:
<configuration>\n <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">\n <encoder>\n <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>\n </encoder>\n </appender>\n\n <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">\n <file>logs/app.log</file>\n <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">\n <fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern>\n <maxHistory>30</maxHistory>\n </rollingPolicy>\n <encoder>\n <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>\n </encoder>\n </appender>\n\n <root level="INFO">\n <appender-ref ref="CONSOLE"/>\n <appender-ref ref="FILE"/>\n </root>\n</configuration>\nThis configuration outputs logs to the console and to a file with daily rotation (logs are stored for 30 days).
\n\nStep 3. Using in code
\nLet's use the kotlin-logging library:
\nimport mu.KotlinLogging\n\nprivate val logger = KotlinLogging.logger {}\n\nfun main() {\n logger.info("Application started")\n logger.debug { "Variable value x = $x" }\n try {\n // some code\n } catch (e: Exception) {\n logger.error(e) { "Error during operation execution" }\n }\n}\n\nLogging levels: when to use what
\nChoosing the right level is the foundation of readable logs. Logback has the following levels