Avatar ·

Ошибка SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder" в WebSphere

Всем привет! Я новичок в Java и разрабатываю приложение для WebSphere Application Server. Использую SLF4J для логирования, но при запуске получаю ошибку:

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

После этого логи просто не пишутся. Вот мой код, где я пытаюсь использовать логгер:

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

public class MyService {
    private static final Logger logger = LoggerFactory.getLogger(MyService.class);

    public void doSomething() {
        logger.info("Начинаем выполнение метода");
        try {
            // какой-то код
            logger.debug("Промежуточный шаг выполнен");
        } catch (Exception e) {
            logger.error("Ошибка при выполнении", e);
        }
    }
}

В pom.xml у меня прописана зависимость:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.36</version>
</dependency>

Других SLF4J зависимостей нет. Приложение разворачивается на WebSphere 9. Я пробовал добавлять logback-classic и log4j-slf4j-impl, но тогда возникают конфликты с уже имеющимися библиотеками на сервере. Как правильно настроить SLF4J в WebSphere, чтобы логи работали? Что я делаю не так?

<<>>

Причина ошибки и полное решение

Ошибка SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder" означает, что SLF4J API найдена, но отсутствует реализация (binding) — библиотека, которая связывает SLF4J с конкретным фреймворком логирования (Logback, Log4j, java.util.logging и т.д.).

SLF4J — это фасад, а не самостоятельная система логирования. Он требует наличия одной (и только одной) реализации на classpath. В вашем случае добавлен только slf4j-api, а биндинг отсутствует, поэтому SLF4J переходит в режим no-operation (NOP) — все логи молча игнорируются.

Проблема с WebSphere

WebSphere уже включает свои версии SLF4J и Log4j. Если вы просто добавите logback-classic или log4j-slf4j-impl в своё приложение, возникнет конфликт — на classpath окажется несколько реализаций SLF4J, и он выберет первую попавшуюся, что часто приводит к непредсказуемому поведению.

Правильное решение

Есть три основных подхода. Рекомендую первый как самый надёжный:

Вариант 1: Использовать встроенное логирование WebSphere (рекомендуется)

WebSphere уже содержит реализацию SLF4J через com.ibm.ws.logging. Нужно только настроить связку:

  1. Убедитесь, что в pom.xml есть только slf4j-api (без других биндингов)
  2. Добавьте зависимость для моста к WebSphere Logging:
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.36</version>
    <scope>provided</scope>  <!-- Важно! -->
</dependency>

<dependency>
    <groupId>com.ibm.ws.logging</groupId>
    <artifactId>com.ibm.ws.logging.slf4j</artifactId>
    <version>1.0.0</version>  <!-- Версия зависит от WebSphere -->
    <scope>provided</scope>
</dependency>

Установите scope=provided для обеих зависимостей — это означает, что библиотеки будут взяты из сервера, а не упакованы в ваше приложение. Так вы избежите дублирования.

Вариант 2: Использовать Logback с изоляцией classpath

Если вам нужен именно Logback (например, для гибкой настройки формата логов), настройте родительский classloader WebSphere так, чтобы ваше приложение загружало свои библиотеки первыми:

  • В файле WEB-INF/ibm-web-bnd.xml добавьте:
<web-bnd xmlns="http://websphere.ibm.com/xml/ns/javaee">
    <classloader mode="PARENT_LAST"/>
</web-bnd>

Затем добавьте в pom.xml:

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.11</version>
</dependency>

При PARENT_LAST ваше приложение будет использовать свой Logback, а не встроенный в сервер.

Вариант 3: Использовать Log4j 2 через SLF4J

Если в WebSphere уже настроен Log4j, добавьте только мост:

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.20.0</version>
    <scope>provided</scope>
</dependency>

И убедитесь, что slf4j-api тоже имеет scope=provided.

Проверка после настройки

Добавьте в код тестовый вывод:

logger.info("SLF4J успешно сконфигурирован с {}", 
    LoggerFactory.getILoggerFactory().getClass().getName());

Если в логах появится имя класса реализации (например, ch.qos.logback.classic.LoggerContext или com.ibm.ws.logging.internal.slf4j.WsLoggerFactory) — всё работает правильно.

Дополнительная проверка

Убедитесь, что в classpath нет нескольких jar-файлов с разными реализациями SLF4J. Используйте команду:

mvn dependency:tree | grep slf4j

Вы должны увидеть только slf4j-api и одну реализацию (binding). Если их больше — удалите лишние зависимости.

<<>>

Простой способ: используйте SystemOutBridge от IBM

Если вам не нужна сложная настройка, а просто хочется, чтобы SLF4J логи писались в стандартный вывод WebSphere (SystemOut.log), воспользуйтесь библиотекой com.ibm.ws.logging.slf4j — это официальный мост от IBM.

Добавьте в pom.xml:

<dependency>
    <groupId>com.ibm.ws.logging</groupId>
    <artifactId>com.ibm.ws.logging.slf4j</artifactId>
    <version>1.0.0</version>
    <scope>provided</scope>
</dependency>

Измените scope для slf4j-api на provided. После этого ваши logger.info() будут автоматически перенаправляться в SystemOut.log WebSphere без дополнительных настроек.

Важно: Убедитесь, что версия com.ibm.ws.logging.slf4j соответствует версии вашего WebSphere. Для WAS 9 используйте 1.0.0, для WAS 8.5 — 1.0.0 тоже подходит. Если сомневаетесь, проверьте в консоли сервера: ${WAS_INSTALL_ROOT}/plugins/com.ibm.ws.logging.slf4j.jar.

Этот метод самый быстрый и не требует изменения classloader политик. Недостаток — вы не сможете тонко настроить формат логов (уровни, аппендеры), всё будет работать так, как настроено на сервере.