osgilogbackslf4jproviderequinox

equinox with slf4j can't find logback provider


So I have this OSGi project built with equinox with this gradle structure:

> Task :projects

------------------------------------------------------------
Root project 'project'
------------------------------------------------------------

Root project 'project'
No sub-projects

Included builds
+--- Included build ':callable-processor'
+--- Included build ':osgi-sun-misc'
+--- Included build ':path-collector'
+--- Included build ':robot-api'
+--- Included build ':robot-equinox'
+--- Included build ':robot-signal'
+--- Included build ':robot-instance'
+--- Included build ':utils'
\--- Included build ':reactive'

Main bundle is robot-equinox.

On the root (project), I have the following build.gradle configuration:

// project

ext.baseVersion = '2.0.0'
ext.buildTag = "SNAPSHOT"

group 'project'
version "${baseVersion}-${buildTag}"

project {
    quality = ALFA
}

configurations {
    bundleInstall
    bundleStart
    misc
}

dependencies {
    bundleInstall 'ch.qos.logback:logback-classic:1.3.5'
    bundleInstall 'ch.qos.logback:logback-core:1.3.5'
    bundleInstall 'org.slf4j:slf4j-api:2.0.5'

    bundleInstall 'org.apache.aries.spifly:org.apache.aries.spifly.dynamic.bundle:1.3.5'

    bundleInstall 'prodist:callable-processor'
    bundleInstall 'prodist:osgi-sun-misc'
    bundleInstall 'prodist:path-collector'
    bundleInstall 'prodist:reactive'
    bundleInstall 'prodist:robot-api'

    bundleStart 'ch.qos.logback:logback-classic:1.3.5'
    bundleStart 'ch.qos.logback:logback-core:1.3.5'
    bundleStart 'org.slf4j:slf4j-api:2.0.5'
    bundleStart 'prodist:robot-equinox'
}

And under robot-equinox I have the following configuration:

dependencies {
    implementation group: 'prodist', name: 'callable-processor'
    implementation group: 'prodist', name: 'path-collector'
    implementation group: 'prodist', name: 'robot-api'
    implementation group: 'prodist', name: 'reactive'
    implementation group: 'prodist', name: 'robot-instance'
    implementation group: 'prodist', name: 'utils'

    compileOnly group: 'org.osgi', name: 'osgi.core', version: '6.0.0'

    testImplementation group: 'org.hamcrest', name: 'hamcrest', version: '2.2'
    testImplementation group: 'org.mockito', name: 'mockito-core', version: '3.2.4'
    testImplementation group: 'org.reactivestreams', name: 'reactive-streams-tck', version: '1.0.3'
    testImplementation group: 'org.testng', name: 'testng', version: '7.1.0'

    testCompileOnly group: 'org.osgi', name: 'osgi.core', version: '6.0.0'
}

I'll give a sample of my log implementation on the main class, which is present under 'project'.

Application.java

package project.robot.equinox;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.*;
import java.security.SecureRandom;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;

import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);
    
    public Application ()
    {
        MDC.put("product.name", ProductInfo.getName());
        MDC.put("product.version", ProductInfo.getVersion());
    }
    
    public void activate (BundleContext bundleContext)
    {
        logger.atTrace().log(_S("activate: enter"));
    }
    
    ...
}

But when I start the Application, I'm getting this message on the osgi console:

osgi> SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.

My expectation was that by installing both - slf4j and logback, slf4j would recognize logback implementation and would work. How can I solve this problem?


Solution

  • Ok, so I found a solution and I'm going to post it here so it help someone else facing this same issue.

    In order to help SLF4J find his provider, I create a new bundle osgi-log - a "log bundle" with this configuration:

    group 'project'
    version '2.0.0'
    
    dependencies {
        api group: 'org.slf4j', name: 'slf4j-api', version: '2.0.5'
    
        implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.3.5'
        implementation group: 'ch.qos.logback', name: 'logback-core', version: '1.3.5'
        implementation group: 'org.ow2.asm', name: 'asm', version: '5.2'
        implementation group: 'org.ow2.asm', name: 'asm-commons', version: '5.2'
        implementation group: 'org.ow2.asm', name: 'asm-util', version: '5.2'
        implementation group: 'org.apache.aries.spifly', name: 'org.apache.aries.spifly.dynamic.bundle', version: '1.3.5'
    }
    

    And then, in each bundle who uses log, I added the following dependency:

    dependencies {
        (...)
    
        implementation group: 'project', name: 'osgi-log'
    }
    

    And when I started my application, the message about provider was gone and log was being registered as expected.

    I came to conclusion that Apache Aries spifly offers a ServiceLoader to SLF4J and helps him find provider, which in my case is logback.