Programming

Jul 222023
 

Quarkus framework has its own logging system, based on JBoss logging. There is a more or less simple system with configuration via properties (or yaml). In simple cases, features from default Quarkus logging are enough, but for complex cases, like MDC, log separation, etc standard Quarkus logging capability is insufficient.

Another thing that brings some problems is tests, especially in gradle, because there is no way to specify the logging level by package name for tests (at least it doesn’t work for me up to Quarkus v. 3.2.0).

So at least one solution – use another logging framework you like. It can be Logback, Log4J or even JUL. By the way, there is already developed option for using logback.xml as a log configuration source, but only in a static way – transcode logback.xml into standard Quarkus logging settings at the build stage.

In this case for using another logging framework we need to replace the existing one.

  • Remove unnecessary packages from the build: build.gradle
configurations.all {
 exclude group: 'org.jboss.logging', module: 'jboss-logmanager-embedded'
 exclude group: 'org.jboss.logging', module: 'commons-logging-jboss-logging'
 exclude group: 'org.jboss.slf4j', module: 'slf4j-jboss-logmanager'
 exclude group: 'org.slf4j', module: 'slf4j-jdk14'
}
  • Add required dependencies: build.gradle
dependencies {
...
 implementation "org.slf4j:slf4j-api:${slf4jVersion}"
 implementation "ch.qos.logback:logback-core:${logbackVersion}"
 implementation "ch.qos.logback:logback-classic:${logbackVersion}"
...
}
  • Use the required logging provider on the application start command
java -Dorg.jboss.logging.provider=slf4j -jar quarkus-runner.jar

Also sometimes we need to tune logging in gradle test task: build.gradle

test {
  systemProperty "java.util.logging.manager", "org.jboss.logmanager.LogManager"
  systemProperty "org.jboss.logging.provider", "slf4j"
// one file for multimodule project
  systemProperty 'logback.configurationFile', "${rootDir}/src/test/resources/logback-test.xml"
}

Apr 182020
 

One time I needed to use a counter for some heavy loaded process in multithread environment. As usual, I use the class java.util.concurrent.atomic.AtomicInteger, the methods incrementAndGet and decrementAndGet. But when I put these methods in only two places, absolutely synchronized by calls (increment and decrement counter in short time gap), I got a strange behavior with the counter – it constantly goes down to negative values. When I tried to view source code (OpenJDK 8), I saw this:

/**
     * Atomically increments by one the current value.
     *
     * @return the updated value
     */
    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

So, instead of incrementing value concurrently and returning new value after this, we have a function call, which returns a current value and increments value by one in the same place. May be this function (getAndAddInt) really increments value of AtomicInteger… or may be not, in this place we don’t know, because we know nothing about new value – we simply return old value + 1.

I found the same behavior in OpenJDK11 source code:

public final int incrementAndGet() {
    return U.getAndAddInt(this, VALUE, 1) + 1;
}

And the same code up to OpenJDK14: https://github.com/openjdk/jdk14u/blob/master/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java

Moreover, I wrote simple code with a volatile field and two methods for increasing/decreasing this field with ReentrantLock. And using this methods in the same places, where I used AtomicInteger methods, I got a different result – my counter was increased and decreased and had more plausible value, than AtomicInteger.