Kronos-logging

Configure Kronos SQL execution logs with the bundled logger or a kronos-logging adapter.

Use the bundled logger

Configure SQL execution logging through Kronos.logging. The bundled logger is available from kronos-core; its JVM implementation can print to the console, write to files, or do both.

console and file

import com.kotlinorm.Kronos
import com.kotlinorm.enums.KLoggerType

with(Kronos.logging) {
    type = KLoggerType.DEFAULT_LOGGER
    path = ["console", "logs/kronos"]
}

When an ORM task executes, the bundled logger prints the operation type, SQL, parameters, and result.

output

[yyyy-MM-dd HH:mm:ss.SSS] [info] [Kronos] Executing [SELECT] task:
SQL:    SELECT `id`, `name` FROM `user` WHERE `id` = :id
PARAMS: {id=1}
Found rows: 1
-----------------------

Write bundled logs to a directory

Add a directory path to Kronos.logging.path when the bundled logger should create a daily log file.

file only

with(Kronos.logging) {
    type = KLoggerType.DEFAULT_LOGGER
    path = ["logs/kronos"]
}

The file name follows the bundled logger rule.

file

logs/kronos/kronos-log-yyyy-MM-dd.log

Enable or disable logging

Kronos.logging.enabled is the global output switch. It applies to bundled, platform and custom loggers on JVM and Kotlin/Native. The default is true, with path = ["console"].

Kronos.logging.enabled = false

Enable output again without losing the selected adapter, paths or custom factory:

Kronos.logging.enabled = true

Disabled logging skips adapter creation and lazy message construction. To filter by level while retaining the adapter's own level settings:

import com.kotlinorm.enums.KLogLevel

Kronos.logging.minimumLevel = KLogLevel.WARN

path selects bundled output destinations; an empty array stops that output without changing a custom or framework adapter:

Kronos.logging.path = []

On Kotlin/Native, the bundled adapter uses the console destination and includes exception stack traces. Directory output uses the JVM bundled logger. Applications can supply their platform logging integration through a custom factory:

Kronos.logging.factory = { source -> applicationLogger(source) }
// Return to the installed platform adapter.
Kronos.logging.factory = null

applicationLogger is an application function returning KLogger. The global switch and minimum level apply to its logger as well. Assigning a factory preserves logging.type.

Android logging

Android/JVM logging guidance is kept with the 📚Android SQLite integration chapter.

Add kronos-logging

Use kronos-logging when the application wants Kronos logs to go through an adapter such as Android Log, JDK Logger, or Apache Commons Logging.

gradle(kts)

dependencies {
    implementation("com.kotlinorm:kronos-logging:0.4.0")
}

maven

<dependency>
    <groupId>com.kotlinorm</groupId>
    <artifactId>kronos-logging</artifactId>
    <version>0.4.0</version>
</dependency>

Use JDK Logger

Call KronosLoggerApp.detectLoggerImplementation() once during application startup, then select the JDK logger type.

kotlin

import com.kotlinorm.Kronos
import com.kotlinorm.KronosLoggerApp
import com.kotlinorm.enums.KLoggerType

KronosLoggerApp.detectLoggerImplementation()

Kronos.logging.type = KLoggerType.JDK_LOGGER

JDK Logger receives the same ORM execution message.

output

INFO: Executing [INSERT] task:
SQL:    INSERT INTO `user` (`name`) VALUES (:name)
PARAMS: {name=Kronos}
Affected rows: 1
-----------------------

Use Apache Commons Logging

Add the Commons Logging API used by your application, then select KLoggerType.COMMONS_LOGGER.

gradle(kts)

dependencies {
    implementation("com.kotlinorm:kronos-logging:0.4.0")
    implementation("commons-logging:commons-logging:<latest-stable>")
}

kotlin

import com.kotlinorm.Kronos
import com.kotlinorm.KronosLoggerApp
import com.kotlinorm.enums.KLoggerType

KronosLoggerApp.detectLoggerImplementation()

Kronos.logging.type = KLoggerType.COMMONS_LOGGER

The adapter creates the target logger from classes on the runtime classpath. Add the logging API and binding used by your application before selecting its KLoggerType.

Use SLF4J with Logback

kronos-logging sends messages to SLF4J. Add one SLF4J binding to the application; Logback is a common choice.

gradle(kts)

dependencies {
    implementation("com.kotlinorm:kronos-logging:0.4.0")
    implementation("ch.qos.logback:logback-classic:<version>")
}

maven

<dependency>
    <groupId>com.kotlinorm</groupId>
    <artifactId>kronos-logging</artifactId>
    <version>0.4.0</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>${logback.version}</version>
</dependency>

Create src/main/resources/logback.xml and choose the appenders and levels for the application:

logback.xml

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger - %msg%n</pattern>
        </encoder>
    </appender>
    <logger name="com.kotlinorm" level="INFO"/>
    <root level="WARN">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

Select the SLF4J adapter during application startup:

kotlin

import com.kotlinorm.Kronos
import com.kotlinorm.KronosLoggerApp
import com.kotlinorm.enums.KLoggerType

KronosLoggerApp.detectLoggerImplementation()
Kronos.logging.type = KLoggerType.SLF4J_LOGGER

Use SLF4J with Log4j2

Log4j2 connects through its SLF4J 2 binding. Keep the three Log4j2 modules on the same version.

gradle(kts)

dependencies {
    implementation("com.kotlinorm:kronos-logging:0.4.0")
    implementation("org.apache.logging.log4j:log4j-api:<version>")
    runtimeOnly("org.apache.logging.log4j:log4j-core:<version>")
    runtimeOnly("org.apache.logging.log4j:log4j-slf4j2-impl:<version>")
}

maven

<dependency>
    <groupId>com.kotlinorm</groupId>
    <artifactId>kronos-logging</artifactId>
    <version>0.4.0</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>${log4j2.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>${log4j2.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j2-impl</artifactId>
    <version>${log4j2.version}</version>
</dependency>

Create src/main/resources/log4j2.xml and configure the com.kotlinorm logger:

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Logger name="com.kotlinorm" level="info"/>
        <Root level="warn">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

Detect an available adapter

detectLoggerImplementation() checks the runtime classpath and installs the detected platform adapter. An explicitly assigned Kronos.logging.factory is preserved.

kotlin

import com.kotlinorm.Kronos
import com.kotlinorm.KronosLoggerApp

KronosLoggerApp.detectLoggerImplementation()

println(Kronos.logging.type)

On a standard JVM project that only has the JDK logger available, the detected type is:

output

JDK_LOGGER

For full database connection setup, see 📚Connect to DB and 📚Global Config.