How to add console log to allure report after each step (Java/Selenium/JUnit/Cucumber)?

The problem (Question) is that I need to add the console log after each test step to the allure report, well, or the entire output at the end of the test. Whatever tried … - in vain. Throw any ideas, thanks!

нормально с таким ником писать на русскоязычном форуме на английском

а вообще должна быть библиотечка доступа к аллюру в момент выполнения теста, и консольный лог можно добавлять в качестве параметра, или в описание, или еще куда

Спасибо, я учту, первый раз тут)
А не могли бы подсказать название библиотечки, не могу найти, либо если в качестве описания, то как это должно выглядеть?
Пробовал писать листенеры, ниче не работает что-то
Если есть под рукой пример записи лога и передачи параметром, буду очень благодарен, если поделитесь, спасибо.

Получить лог
LogEntries logEntries = driver.manage().logs().get(LogType.BROWSER);

Прикрепить что-либо к отчету:
https://docs.qameta.io/allure/#_attachments_3

Спасибо за совет, получаю следущее:
Allure.addAttachment("Console log: ", String.valueOf(webDriverActions.getDriver().manage().logs().get(LogType.BROWSER)));
После этой команды прикрепляет всего одну строку:
org.openqa.selenium.remote.RemoteLogs@160ad8eb
Команду записал в метод After, в чем может быть причина?

добавьте .getAll()

Теперь просто пустой массив [] возвращает(
Уверены, что лог браузера нужен? мне хотя бы весь вывод консоли прикрепить
Но в идеале нужно будет потом после каждого степа лог аттачить

Значит в консоли пусто.
Попробовал в FF проверить - получил ошибку в драйвере:
org.openqa.selenium.UnsupportedCommandException: POST /session/1113293e-105e-437b-935e-868656618cc3/log did not match a known command - создал тикет для geckodriver, т.к. для Хрома она работает, но не даёт тоже нужного результата - инфо-сообщения из консоли не попадают в лог. Даже если я ручками сеттю нужные уровни логов:

        LoggingPreferences logs = new LoggingPreferences(); 
        logs.enable(LogType.DRIVER, Level.ALL); 
        options.setCapability(CapabilityType.LOGGING_PREFS, logs);

Печаль какая-то. Необходимо чтобы кто-нить ещё проверил.
Сам использую свежие драйвера и браузеры. Селениум 3.141.59

На тикет для FF ответили - пока это не реализовано, т.к. в стандарте не описано что и как логгировать.
Да и для Хрома эта возможность тоже получается не очень задокументирована.

Понял, спасибо)
Буду искать библиотеки для связи с алюром или реализацию механизма логирования в AllureCucumber2Jvm и от этого пробовать.
Или искать как можно разрешить в Overview степов логи как на фото,

Ну, это легко, это можете добавить в конце теста, который завершился успешно:

Allure.getLifecycle().updateTestCase((t) -> { 
    t.setStatusDetails( t.getStatusDetails().setMessage("blablablabl"));
});

Всем привет, вот что использую я.

  1. Необходим листенер LogCatchListener extends TestListenerAdapter:
    где в beforeConfiguration( ITestResult tr)
    в котором вызывается класс MultithreadedConsoleOutputCatcher.startCatch();

  2. Сам класс: MultithreadedConsoleOutputCatcher

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.HashMap;

public class MultithreadedConsoleOutputCatcher {

    private static PrintStream originalStream;
    private static OutputStreamRouter router;

    public static synchronized void startCatch() {
        if (router == null) {
            originalStream = System.out;
            router = new OutputStreamRouter(originalStream);
            System.setOut(new PrintStream(router));
        }
        router.registryThread(Thread.currentThread());
    }

    public static String getContent() {
        return getContent(true);
    }

    public static synchronized String getContent(boolean clear) {
        if (router == null) {
            throw new RuntimeException();
        }
        return router.fetchThreadContent(Thread.currentThread(), clear);
    }

    public static synchronized void stopCatch() {
        if (router == null) {
            throw new RuntimeException();
        }
        router.unregistryThread(Thread.currentThread());
        if (router.getActiveRoutes() == 0) {
            System.setOut(originalStream);
            originalStream = null;
            router = null;
        }
    }

    static class OutputStreamRouter extends OutputStream {

        private HashMap<Thread, ByteArrayOutputStream> loggerStreams = new HashMap<>();
        private OutputStream original;

        public OutputStreamRouter(OutputStream original) {
            this.original = original;
        }

        public void registryThread(Thread thread) {
            if (loggerStreams.containsKey(thread)) throw new RuntimeException();
            loggerStreams.put(thread, new ByteArrayOutputStream(4096));
        }

        public void unregistryThread(Thread thread) {
            if (!loggerStreams.containsKey(thread)) throw new RuntimeException();
            loggerStreams.remove(thread);
        }

        public int getActiveRoutes() {
            return loggerStreams.size();
        }

        public String fetchThreadContent(Thread thread, boolean clear) {
            if (!loggerStreams.containsKey(thread)) throw new RuntimeException();
            String result = loggerStreams.get(thread).toString();
            if (clear) {
                loggerStreams.get(thread).reset();
            }
            return result;
        }

        @Override
        public synchronized void write(int b) throws IOException {
            original.write(b);
            if (loggerStreams.containsKey(Thread.currentThread())) {
                loggerStreams.get(Thread.currentThread()).write(b);
            }
        }

        @Override
        public synchronized void flush() throws IOException {
            original.flush();
        }

        @Override
        public synchronized void close() throws IOException {
            original.close();
        }
    }

}

  1. в том же листенере где вызывается start: создаем метод
@SuppressWarnings("UnusedReturnValue")
    @Attachment(value = "Test Log", type = "text/plain")
    public String stopCatch() {
        String result = MultithreadedConsoleOutputCatcher.getContent();
        MultithreadedConsoleOutputCatcher.stopCatch();
        return result;
    }

и вызываем stopCatch() в методах:

  • onConfigurationSkip
  • onConfigurationFailure
  • onTestFailure
  • onTestSuccess
  • onTestSkipped

В итоге в отчете это будет выглядеть вот так:

Неплохо. Но я думал, что идёт речь о консоли браузера.

Спасибо большое, но я вас наверное запутал, прошу прощения.
У меня кукумберовские тесты ранятся через junit же, а этот адаптер от testng, поэтому мне нужно написать листенер для junit(

1 пункт делается по аналогии с примером из JUnit 5 User Guide
И вы так и не уточнили какой именно лог нужен.

В идеальном варианте мне нужно, чтобы к каждому степу алюр репорта прикреплялся лог(все что попало в консоль (System.out)) от его начала (степа) до его конца. Или хотя бы приаттачить весь лог консоли в конец теста, надеюсь понятно объяснил :slight_smile:

То что я расписал, это для testng (забыл уточнить).
Он и перехватывает все что кладется в system.out, а точнее все что формирует log4j (я использую это).
В данном случае вы можете взять этот же класс, но использовать его в листенере junit

Что-то вы слишком заморачиваетсь

public class BrowserLogs {
    private static List logList;

    private static List getConsoleLog() {
        return Selenide.getWebDriverLogs(LogType.BROWSER);
    }

    public static void checkLogs() {
        logList = getConsoleLog();
        if (logList.size() > 0)
            addConsoleLogToReport();
    }

    @Attachment(value = "Browser console log", type = "text/plain")
    private static String addConsoleLogToReport() {
        StringBuilder sb = new StringBuilder();
        for (Object line : logList) {
            sb.append(line);
            sb.append("\t");
        }
        return sb.toString();
    }
}

Вызываем метод CheckLogs в конце теста или где там вам надо

Артём, а вы плохо читаете что именно хотят. Притом, такое решение .getWebDriverLogs(LogType.BROWSER) уже давалось.

1 лайк

не могли бы вы показать класс LogCatchListeners? и в аннотацию Listeners нужно ложить класс LogCatchListeners? В моем случае появился в allure report Test Log, но он пустой в чем может быть проблема? Спасибо за ответ