Skip to content

Published fat JAR bundles slf4j-nop, silently disables logging in consumers #13

Description

@Jintumoni

Summary

The published io.akeyless:cloudid artifact is built as a fat JAR with slf4j-nop module and META-INF/services/org.slf4j.spi.SLF4JServiceProvider service registration physically embedded into it.

Any consumer application that picks up the bundled org.slf4j.LoggerFactory has its SLF4J binding silently replaced with NOP. Every logger.info(...)/logger.error(...) call in consuming JVM is dropped; no warning and no exceptions are thrown.

Verification

Inspect the published JAR directly:

$ unzip -l cloudid-v0.2.4.jar | grep -E "slf4j|SLF4JServiceProvider"
        0  04-12-2024 14:20   org/slf4j/
        0  04-12-2024 14:20   org/slf4j/nop/
        0  04-12-2024 14:20   META-INF/maven/org.slf4j/
        0  04-12-2024 14:20   META-INF/maven/org.slf4j/slf4j-nop/
        0  04-12-2024 14:20   org/slf4j/event/
        0  04-12-2024 14:20   org/slf4j/helpers/
        0  04-12-2024 14:20   org/slf4j/spi/
        0  04-12-2024 14:20   META-INF/maven/org.slf4j/slf4j-api/
       32  04-12-2024 14:20   META-INF/services/org.slf4j.spi.SLF4JServiceProvider

A diagnostic snippet in the consumer confirms what the JVM ends up bound to:

import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
  
public class Main {  
	private final static Logger logger = LoggerFactory.getLogger(Main.class);  
	public static void main(String[] args) {  
		Class<?> c = org.slf4j.LoggerFactory.class;  
		System.out.println(c.getName() + " loaded from " + c.getProtectionDomain().getCodeSource().getLocation());  
		logger.info("hello from slf4j logger");  
	}  
}

// With cloud id:
// org.slf4j.LoggerFactory loaded from file:path/to/.gradle/cache/cloudid-v0.2.4.jar


// Without cloud id:
// org.slf4j.LoggerFactory loaded from file:path/to/.gradle/cache/slf4j-api-1.7.25.jar
// 2026-05-05 11:05:33 [main] INFO  org.example - hello from slf4j logger

Suggested fix

Don't bundle a binding at all. Library code should depend on slf4j-api only; the application chooses the binding. slf4j-nop should not be on the main classpath. This is the SLF4J author's explicit guidance for libraries

Why this is high severity for consumers

  • The failure mode is silent; no warning, no log line. Just empty log files.
  • It affects all SLF4J logging in the consuming application, not only code paths that touch akeyless.
  • The root cause is non obvious. Standard debugging steps (status logger, classpath inspection, version checks) all show a healthy logging stack; only direct inspection of the published JAR's contents reveals the problem.
  • Standard exclusion mechanisms (gradle exclude group) do not work, leading consumers to spend significant time before realising the JAR is the problem.

Environment

  • io.akeyless:cloudid:v0.2.4 and likely present in earlier versions as well
  • log4j-api:2.17.1 + log4j-core:2.17.1 + log4j-slf4j-impl:2.17.1

Sample Gradle file snippet

repositories {
    mavenCentral()
    maven { url 'https://akeyless.jfrog.io/artifactory/akeyless-java' }
}

dependencies {
    testImplementation platform('org.junit:junit-bom:5.9.1')
    testImplementation 'org.junit.jupiter:junit-jupiter'


    // Log4j2 core + API
    implementation 'org.apache.logging.log4j:log4j-api:2.17.1'
    implementation 'org.apache.logging.log4j:log4j-core:2.17.1'

    // Bridge: routes SLF4J → Log4j2
    implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.17.1'

    implementation('io.akeyless:cloudid:v0.2.4') {
        exclude group: 'org.slf4j'
        exclude group: 'log4j'
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions