~aleteoryx/muditaos

4e685bb7ec84d6ed5f6e4eb64f8d71591a636fc7 — Lefucjusz 2 years ago 379df3e
[MOS-999] Provide additional info in log filename

Added info about product, OS version, commit hash
and serial number to log filename to simplify
triage and quick sanity check of the logs in
cases many log files have to be analyzed.
M harmony_changelog.md => harmony_changelog.md +1 -0
@@ 35,6 35,7 @@
* Added serial number to About section
* Added possibility to detect device's case colour
* Added extended information to crashdump filename
* Added extended information to log filename

### Changed / Improved


M module-services/service-desktop/endpoints/filesystem/FS_Helper.cpp => module-services/service-desktop/endpoints/filesystem/FS_Helper.cpp +3 -6
@@ 48,9 48,6 @@ namespace sdesktop::endpoints
        }
    } // namespace

    using sender::putToSendQueue;
    namespace fs = std::filesystem;

    auto FS_Helper::processGet(Context &context) -> ProcessResult
    {
        LOG_DEBUG("Handling GET");


@@ 68,7 65,7 @@ namespace sdesktop::endpoints
            response        = requestListDir(dir);
        }
        else {
            LOG_ERROR("unknown request");
            LOG_ERROR("Unknown request");
            response = {.status = http::Code::BadRequest};
        }



@@ 116,7 113,7 @@ namespace sdesktop::endpoints
                code = requestFileRemoval(fileName) ? http::Code::NoContent : http::Code::NotFound;
            }
            catch (const std::filesystem::filesystem_error &ex) {
                LOG_ERROR("Can't remove requested file, error: %d", ex.code().value());
                LOG_ERROR("Can't remove requested file %s, error: %d", fileName.c_str(), ex.code().value());
                code = http::Code::InternalServerError;
            }
        }


@@ 149,7 146,7 @@ namespace sdesktop::endpoints
        }

        if (!std::filesystem::exists(filePath)) {
            LOG_ERROR("file not found");
            LOG_ERROR("File %s not found", filePath.c_str());

            json11::Json::object response({{json::reason, json::fs::fileDoesNotExist}});
            return ResponseContext{.status = http::Code::NotFound, .body = response};

M module-utils/CrashdumpMetadataStore/CrashdumpMetadataStore.hpp => module-utils/CrashdumpMetadataStore/CrashdumpMetadataStore.hpp +6 -6
@@ 13,21 13,21 @@ namespace Store
        CrashdumpMetadata(const CrashdumpMetadata &) = delete;
        CrashdumpMetadata &operator=(const CrashdumpMetadata &) = delete;

        static CrashdumpMetadata &getInstance();
        [[nodiscard]] static CrashdumpMetadata &getInstance();

        void setSerialNumber(const std::string &serialNumber);
        const std::string &getSerialNumber();
        [[nodiscard]] const std::string &getSerialNumber();

        void setProductName(const std::string &product);
        const std::string &getProductName();
        [[nodiscard]] const std::string &getProductName();

        void setOsVersion(const std::string &osVersion);
        const std::string &getOsVersion();
        [[nodiscard]] const std::string &getOsVersion();

        void setCommitHash(const std::string &hash);
        const std::string &getCommitHash();
        [[nodiscard]] const std::string &getCommitHash();

        std::string getMetadataString();
        [[nodiscard]] std::string getMetadataString();

      private:
        CrashdumpMetadata();

M module-utils/log/CMakeLists.txt => module-utils/log/CMakeLists.txt +2 -1
@@ 19,10 19,11 @@ target_link_libraries(log
    PRIVATE
        utility
        purefs-paths
        crashdump-metadata-store
    PUBLIC
        module-os
        log-api
        utils-rotator    
        utils-rotator
        sys-service
)


M module-utils/log/Logger.cpp => module-utils/log/Logger.cpp +35 -14
@@ 5,8 5,17 @@
#include "LockGuard.hpp"
#include <ticks.hpp>
#include <purefs/filesystem_paths.hpp>

#include <fstream>
#include <CrashdumpMetadataStore.hpp>

namespace
{
    inline constexpr int statusSuccess         = 1;
    inline constexpr auto streamBufferSize     = 64 * 1024;
    inline constexpr auto logFileNamePrefix    = "MuditaOS";
    inline constexpr auto logFileNameExtension = ".log";
    inline constexpr auto logFileNameSeparator = "_";
} // namespace

namespace Log
{


@@ 23,7 32,7 @@ namespace Log
        return stream;
    }

    Logger::Logger() : rotator{".log"}, streamBuffer{std::make_unique<char[]>(streamBufferSize)}
    Logger::Logger() : streamBuffer{std::make_unique<char[]>(streamBufferSize)}, rotator{logFileNameExtension}
    {
        filtered = {
            {"ApplicationManager", LoggerLevel::LOGINFO},


@@ 137,12 146,12 @@ namespace Log

    [[nodiscard]] std::size_t Logger::lineBufferSizeLeft() const noexcept
    {
        const auto sizeLeft = LINE_BUFFER_SIZE - lineBufferCurrentPos;
        const auto sizeLeft = lineBufferSize - lineBufferCurrentPos;
        assert(sizeLeft > 0);
        return sizeLeft;
    }

    int Logger::writeLog(Device device, const char *fmt, va_list args)
    int Logger::writeLog([[maybe_unused]] Device device, const char *fmt, va_list args)
    {
        constexpr auto lineTerminationString = "\n";
        constexpr auto lineTerminationLength = 2; // '\n' + null-terminator


@@ 176,19 185,26 @@ namespace Log
    /// @return: < 0 - error occured during log flush
    /// @return:   0 - log flush did not happen
    /// @return:   1 - log flush successflul
    int Logger::dumpToFile(const std::filesystem::path &logPath, LoggerState loggerState)
    int Logger::dumpToFile(const std::filesystem::path &logDirectoryPath, LoggerState loggerState)
    {
        if (logFileName.empty()) {
            const auto &osMetadata = Store::CrashdumpMetadata::getInstance().getMetadataString();
            logFileName = std::string(logFileNamePrefix) + logFileNameSeparator + osMetadata + logFileNameExtension;
        }

        const auto logFilePath = logDirectoryPath / logFileName;

        std::error_code errorCode;
        auto firstDump = !std::filesystem::exists(logPath, errorCode);
        auto firstDump = !std::filesystem::exists(logFilePath, errorCode);

        if (errorCode) {
            if (loggerState == LoggerState::RUNNING) {
                LOG_ERROR("Failed to check if file '%s' exists, error: %d!", logPath.c_str(), errorCode.value());
                LOG_ERROR("Failed to check if file '%s' exists, error: %d!", logFilePath.c_str(), errorCode.value());
            }
            return -EIO;
        }

        if (const auto maxSizeExceeded = (!firstDump && (std::filesystem::file_size(logPath) > maxFileSize));
        if (const auto maxSizeExceeded = (!firstDump && (std::filesystem::file_size(logFilePath) > maxFileSize));
            maxSizeExceeded) {
            if (loggerState == LoggerState::RUNNING) {
                LOG_DEBUG("Max log file size exceeded. Rotating log files...");


@@ 196,7 212,7 @@ namespace Log

            {
                LockGuard lock(logFileMutex);
                rotator.rotateFile(logPath);
                rotator.rotateFile(logFilePath);
            }
            firstDump = true;
        }


@@ 210,10 226,10 @@ namespace Log
            /* In some implementations pubsetbuf has to be called before opening a stream to be effective */
            logFile.rdbuf()->pubsetbuf(streamBuffer.get(), streamBufferSize);

            logFile.open(logPath, std::fstream::out | std::fstream::app);
            logFile.open(logFilePath, std::fstream::out | std::fstream::app);
            if (!logFile.good()) {
                if (loggerState == LoggerState::RUNNING) {
                    LOG_ERROR("Failed to open log file '%s'!", logPath.c_str());
                    LOG_ERROR("Failed to open log file '%s'!", logFilePath.c_str());
                }
                return -EIO;
            }


@@ 224,14 240,14 @@ namespace Log
            logFile.write(logs.data(), logs.size());
            if (logFile.bad()) {
                if (loggerState == LoggerState::RUNNING) {
                    LOG_ERROR("Failed to flush logs to file '%s'!", logPath.c_str());
                    LOG_ERROR("Failed to flush logs to file '%s'!", logFilePath.c_str());
                }
                return -EIO;
            }
        }

        if (loggerState == LoggerState::RUNNING) {
            LOG_DEBUG("Flush to file '%s' ended successfully!", logPath.c_str());
            LOG_DEBUG("Flush to file '%s' ended successfully!", logFilePath.c_str());
        }

        return statusSuccess;


@@ 251,7 267,7 @@ namespace Log
        worker->close();
        writeLogsTimer.stop();
        buffer.nextBuffer();
        return dumpToFile(purefs::dir::getLogsPath() / LOG_FILE_NAME, LoggerState::STOPPED);
        return dumpToFile(purefs::dir::getLogsPath(), LoggerState::STOPPED);
    }

    void Logger::checkBufferState()


@@ 314,4 330,9 @@ namespace Log
            lineBufferCurrentPos += std::min(bufferSizeLeft, static_cast<std::size_t>(bytesParsed));
        }
    }

    std::size_t Logger::getMaxLineLength()
    {
        return lineBufferSize;
    }
} // namespace Log

M module-utils/log/Logger.hpp => module-utils/log/Logger.hpp +19 -16
@@ 46,14 46,15 @@ namespace Log
        void enableColors(bool enable);
        static void destroyInstance();
        std::string getLogs();
        void init(Application app, std::size_t fileSize = MAX_LOG_FILE_SIZE);
        void init(Application app, std::size_t fileSize = defaultMaxLogFileSize);
        void createTimer(sys::Service *parent);
        int log(Device device, const char *fmt, va_list args);
        int log(LoggerLevel level, const char *file, int line, const char *function, const char *fmt, va_list args);
        int logAssert(const char *fmt, va_list args);
        int dumpToFile(const std::filesystem::path &logPath, LoggerState loggerState = LoggerState::RUNNING);
        int dumpToFile(const std::filesystem::path &logDirectoryPath, LoggerState loggerState = LoggerState::RUNNING);
        int diagnosticDump();
        int flushLogs();
        [[nodiscard]] std::size_t getMaxLineLength();

        static constexpr auto CRIT_STR = "CRIT";
        static constexpr auto IRQ_STR  = "IRQ";


@@ 64,8 65,8 @@ namespace Log
        void addLogHeader(LoggerLevel level, const char *file = nullptr, int line = -1, const char *function = nullptr);
        [[nodiscard]] bool filterLogs(LoggerLevel level);
        /// Filter out not interesting logs via thread Name
        /// its' using fact that:
        /// - TRACE is level 0, for unedfined lookups it will be alvways trace
        /// it's using fact that:
        /// - TRACE is level 0, for undefined lookups it will be always trace
        /// - it will be one time init for apps which doesn't tell what level they should have
        /// - for others it will be o1 lookup so it's fine
        [[nodiscard]] LoggerLevel getLogLevel(const std::string &name);


@@ 77,31 78,33 @@ namespace Log
        void addFileHeader(std::ofstream &file) const;
        void checkBufferState();

        static constexpr std::size_t maxLogFilesCount      = 3;
        static constexpr std::size_t defaultMaxLogFileSize = 1024 * 1024 * 15; // 15 MB
        static constexpr std::size_t lineBufferSize        = 2048;

        cpp_freertos::MutexStandard mutex;
        cpp_freertos::MutexStandard logFileMutex;

        LoggerLevel loggerLevel{LOGTRACE};
        const LogColors *logColors            = &logColorsOff;
        char lineBuffer[LINE_BUFFER_SIZE]     = {0};
        std::size_t lineBufferCurrentPos      = 0;
        std::size_t maxFileSize               = MAX_LOG_FILE_SIZE;
        static const char *levelNames[];
        std::map<std::string, LoggerLevel> filtered;

        Application application;
        char lineBuffer[lineBufferSize]  = {0};
        std::size_t lineBufferCurrentPos = 0;
        std::size_t maxFileSize          = defaultMaxLogFileSize;
        std::string logFileName;

        LoggerBufferContainer buffer;
        std::unique_ptr<char[]> streamBuffer;

        utils::Rotator<MAX_LOG_FILES_COUNT> rotator;
        Application application;
        utils::Rotator<maxLogFilesCount> rotator;

        sys::TimerHandle writeLogsTimer;

        static const char *levelNames[];
        std::map<std::string, LoggerLevel> filtered;
        static Logger *_logger;
        std::unique_ptr<LoggerWorker> worker;

        static constexpr int statusSuccess = 1;

        static constexpr std::size_t streamBufferSize = 64 * 1024;
        std::unique_ptr<char[]> streamBuffer;
    };

    const char *getTaskDesc();

M module-utils/log/LoggerWorker.cpp => module-utils/log/LoggerWorker.cpp +1 -1
@@ 36,7 36,7 @@ namespace Log
        case Signal::DumpIntervalBuffer:
        case Signal::DumpDiagnostic:
            LOG_INFO("Received signal: %s", magic_enum::enum_name(command).data());
            Log::Logger::get().dumpToFile(purefs::dir::getLogsPath() / LOG_FILE_NAME);
            Log::Logger::get().dumpToFile(purefs::dir::getLogsPath());
            break;
        default:
            LOG_ERROR("Command not valid: %d", static_cast<int>(command));

M module-utils/log/api/log/log.hpp => module-utils/log/api/log/log.hpp +2 -39
@@ 1,35 1,7 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/*
 *  This module is wrapper over printf with additional thread safety provided and common logs levels.
 *
 *  USAGE:
 *
 *  Include this header in any file that wishes to write to logger(s).  In
 *  exactly one file (per executable), define LOG_MAIN first (e.g. in your
 *  main .c file).
 *
 *     #define LOG_MAIN
 *     #include "logs/log.h"
 *
 *  This will define the actual objects that all the other units will use.
 *  Then invoke log_Init(VFS_FILE* fp,logger_level level) function to initialize logger utility. If you want
 *additionally store logs into file pass valid file descriptor to init function. By default logger logs info into STDOUT
 *stream. After that logger is ready to use.
 *
 *  Examples:
 *  1)
 *   log_Init(NULL,LOGDEBUG);
 *   Send logs(level higher or equal to LOGDEBUG) to STDOUT stream.
 *
 *  2)
 *   log_Init('valid file pointer',LOGINFO);
 *   Send logs(level higher or equal to LOGINFO) to STDOUT stream and also to file specified by user.
 */

#ifndef LOG_LOG_H_
#define LOG_LOG_H_
#pragma once

#include "debug.hpp"
#include <stdint.h>


@@ 68,6 40,7 @@ extern "C"
#endif
    int log_Printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
    void log_WriteToDevice(const uint8_t *pBuffer, unsigned NumBytes);
    size_t log_getMaxLineLength();

/**
 * Log functions (one per level).


@@ 100,13 73,3 @@ extern "C"
#ifdef __cplusplus
}
#endif

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
static const size_t LINE_BUFFER_SIZE   = 2048;
static const char *LOG_FILE_NAME       = "MuditaOS.log";
static const int MAX_LOG_FILES_COUNT   = 3;
static const size_t MAX_LOG_FILE_SIZE  = 1024 * 1024 * 15; // 15 MB
#pragma GCC diagnostic pop

#endif /* LOG_LOG_H_ */

M module-utils/log/log.cpp => module-utils/log/log.cpp +5 -1
@@ 3,7 3,6 @@

#include <log/log.hpp>
#include <Logger.hpp>
#include <ticks.hpp>
#include <macros.h>

using Log::Logger;


@@ 46,6 45,11 @@ int log_Log(LoggerLevel level, const char *file, int line, const char *function,
    return result;
}

size_t log_getMaxLineLength()
{
    return Logger::get().getMaxLineLength();
}

extern "C"
{
    void bt_log_custom(const char *file, int line, const char *foo, const char *fmt, ...)

M module-utils/log/tests/CMakeLists.txt => module-utils/log/tests/CMakeLists.txt +10 -0
@@ 36,3 36,13 @@ add_catch2_executable(
        module-utils
        log
)

# Logger buffer container tests
add_catch2_executable(
    NAME
        utils-loggerbuffercontainer
    SRCS
        test_LoggerBufferContainer.cpp
    LIBS
        log
)

A module-utils/log/tests/test_LoggerBufferContainer.cpp => module-utils/log/tests/test_LoggerBufferContainer.cpp +25 -0
@@ 0,0 1,25 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <catch2/catch.hpp>
#include <LoggerBufferContainer.hpp>

TEST_CASE("Test if proper buffer is chosen")
{
    LoggerBufferContainer buffer;

    size_t bufferIndex = buffer.getCurrentIndex();
    REQUIRE(bufferIndex == 0);

    buffer.nextBuffer();
    bufferIndex = buffer.getCurrentIndex();
    REQUIRE(bufferIndex == 1);

    buffer.nextBuffer();
    bufferIndex = buffer.getCurrentIndex();
    REQUIRE(bufferIndex == 0);

    buffer.nextBuffer();
    bufferIndex = buffer.getCurrentIndex();
    REQUIRE(bufferIndex == 1);
}

M module-utils/log/tests/test_log.cpp => module-utils/log/tests/test_log.cpp +5 -5
@@ 6,20 6,20 @@
#include <log/log.hpp>
#include <string>

using namespace std;

TEST_CASE("Log tests")
{
    const auto lineBufferSize = log_getMaxLineLength();

    const int value                   = -423;
    const char *carray            = "carray";
    const string str                  = "string";
    const std::string str             = "string";
    const double double_value         = 6.5323;
    const unsigned int unsigned_value = 7821;
    char big_array[LINE_BUFFER_SIZE + 2];
    char big_array[lineBufferSize + 2];
    memset(big_array, 'X', sizeof(big_array));
    big_array[sizeof(big_array) - 1] = '\0';

    const auto loggerBufferSize = static_cast<int>(LINE_BUFFER_SIZE);
    const auto loggerBufferSize = static_cast<int>(lineBufferSize);
    int result           = LOG_TRACE("value: %d", value);
    REQUIRE(0 < result);
    REQUIRE(result <= loggerBufferSize);

M module-utils/log/tests/test_logDumps.cpp => module-utils/log/tests/test_logDumps.cpp +70 -64
@@ 1,15 1,23 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <catch2/catch.hpp>

#include <string>

#include <log/Logger.hpp>
#include <log/LoggerBufferContainer.hpp>
#include <CrashdumpMetadataStore/CrashdumpMetadataStore.hpp>

namespace
{
    inline constexpr auto productName       = "TestProduct";
    inline constexpr auto osVersion         = "6.6.6";
    inline constexpr auto commitHash        = "baadf00d";
    inline constexpr auto serialNumber      = "141120222134";
    inline constexpr auto filenamePrefix    = "MuditaOS";
    inline constexpr auto filenameExtension = ".log";
    inline constexpr auto filenameSeparator = "_";

    const std::filesystem::path logsDir = "./ut_logs";

    int countFiles(const std::filesystem::path &dir)
    {
        int sum = 0;


@@ 32,106 40,104 @@ namespace
        }
        return true;
    }

    void prepareCrashdumpStore()
    {
        Store::CrashdumpMetadata::getInstance().setProductName(productName);
        Store::CrashdumpMetadata::getInstance().setOsVersion(osVersion);
        Store::CrashdumpMetadata::getInstance().setCommitHash(commitHash);
        Store::CrashdumpMetadata::getInstance().setSerialNumber(serialNumber);
    }

} // namespace

TEST_CASE("Test if logs are dumped to a file without rotation")
{
    auto app                            = Log::Application{"TestApp", "rev", "tag", "branch"};
    constexpr auto MaxFileSize          = 1024 * 1024; // 1 MB
    constexpr auto TestLog              = "12345678";
    const std::filesystem::path logsDir = "./ut_logs";
    const auto testLogFile              = logsDir / "TestApp.log";
    static constexpr auto maxFileSize   = 1024 * 1024; // 1 MB
    static constexpr auto testLogString = "12345678";

    auto app = Log::Application{"TestApp", "rev", "tag", "branch"};

    /* Prepare the environment */
    prepareCrashdumpStore();

    const auto &osMetadata = Store::CrashdumpMetadata::getInstance().getMetadataString();
    const auto logFilename = std::string(filenamePrefix) + filenameSeparator + osMetadata + filenameExtension;
    const auto logFilePath = logsDir / logFilename;

    // Prepare the environment.
    if (std::filesystem::exists(logsDir)) {
        std::filesystem::remove_all(logsDir);
    }
    std::filesystem::create_directory(logsDir);

    // Initialize the logger with test parameters.
    Log::Logger::get().init(std::move(app), MaxFileSize);
    /* Initialize the logger with test parameters */
    Log::Logger::get().init(std::move(app), maxFileSize);
    REQUIRE(countFiles(logsDir) == 0);

    // Dump logs.
    LOG_ERROR(TestLog);
    Log::Logger::get().dumpToFile(testLogFile);
    /* Dump logs */
    LOG_ERROR("%s", testLogString);
    Log::Logger::get().dumpToFile(logsDir);
    REQUIRE(countFiles(logsDir) == 1);
    REQUIRE(checkIfLogFilesExist(testLogFile, 1));
    REQUIRE(checkIfLogFilesExist(logFilePath, 1) == true);

    LOG_ERROR(TestLog);
    Log::Logger::get().dumpToFile(testLogFile);
    LOG_ERROR("%s", testLogString);
    Log::Logger::get().dumpToFile(logsDir);
    REQUIRE(countFiles(logsDir) == 1);
    REQUIRE(checkIfLogFilesExist(testLogFile, 1));
    REQUIRE(checkIfLogFilesExist(logFilePath, 1) == true);

    // Clean-up the environment
    /* Clean-up the environment */
    std::filesystem::remove_all(logsDir);
}

TEST_CASE("Test if log files rotate")
{
    auto app                            = Log::Application{"TestApp", "rev", "tag", "branch"};
    constexpr auto MaxFileSize          = 10; // 10 bytes
    constexpr auto TestLog              = "12345678";
    const std::filesystem::path logsDir = "./ut_logs";
    const auto testLogFile              = logsDir / "TestApp.log";
    static constexpr auto maxFileSize   = 10; // 10 bytes
    static constexpr auto testLogString = "12345678";

    auto app = Log::Application{"TestApp", "rev", "tag", "branch"};

    /* Prepare the environment */
    prepareCrashdumpStore();

    const auto &osMetadata = Store::CrashdumpMetadata::getInstance().getMetadataString();
    const auto logFilename = std::string(filenamePrefix) + filenameSeparator + osMetadata + filenameExtension;
    const auto logFilePath = logsDir / logFilename;

    // Prepare the environment.
    if (std::filesystem::exists(logsDir)) {
        std::filesystem::remove_all(logsDir);
    }
    std::filesystem::create_directory(logsDir);

    // Initialize the logger with test parameters.
    Log::Logger::get().init(std::move(app), MaxFileSize);
    Log::Logger::get().init(std::move(app), maxFileSize);
    REQUIRE(countFiles(logsDir) == 0);

    // Dump logs.
    // Dumping logs to a file causes a log rotation.
    LOG_ERROR(TestLog);
    Log::Logger::get().dumpToFile(testLogFile);
    /* Dump logs. Dumping logs to a file causes files rotation. */
    LOG_ERROR("%s", testLogString);
    Log::Logger::get().dumpToFile(logsDir);
    REQUIRE(countFiles(logsDir) == 1);
    REQUIRE(checkIfLogFilesExist(testLogFile, 1));
    REQUIRE(checkIfLogFilesExist(logFilePath, 1) == true);

    LOG_ERROR(TestLog);
    Log::Logger::get().dumpToFile(testLogFile);
    LOG_ERROR("%s", testLogString);
    Log::Logger::get().dumpToFile(logsDir);
    REQUIRE(countFiles(logsDir) == 2);
    REQUIRE(checkIfLogFilesExist(testLogFile, 2));
    REQUIRE(checkIfLogFilesExist(logFilePath, 2) == true);

    LOG_ERROR(TestLog);
    Log::Logger::get().dumpToFile(testLogFile);
    LOG_ERROR("%s", testLogString);
    Log::Logger::get().dumpToFile(logsDir);
    REQUIRE(countFiles(logsDir) == 3);
    REQUIRE(checkIfLogFilesExist(testLogFile, 3));
    REQUIRE(checkIfLogFilesExist(logFilePath, 3) == true);

    LOG_ERROR(TestLog);
    Log::Logger::get().dumpToFile(testLogFile);
    LOG_ERROR("%s", testLogString);
    Log::Logger::get().dumpToFile(logsDir);
    REQUIRE(countFiles(logsDir) == 3);
    REQUIRE(checkIfLogFilesExist(testLogFile, 3));
    REQUIRE(checkIfLogFilesExist(logFilePath, 3) == true);

    LOG_ERROR(TestLog);
    Log::Logger::get().dumpToFile(testLogFile);
    LOG_ERROR("%s", testLogString);
    Log::Logger::get().dumpToFile(logsDir);
    REQUIRE(countFiles(logsDir) == 3);
    REQUIRE(checkIfLogFilesExist(testLogFile, 3));
    REQUIRE(checkIfLogFilesExist(logFilePath, 3) == true);

    // Clean-up the environment
    std::filesystem::remove_all(logsDir);
}

TEST_CASE("Test if choose proper buffer")
{
    LoggerBufferContainer buffer;

    size_t bufferIndex = buffer.getCurrentIndex();
    REQUIRE(bufferIndex == 0);

    buffer.nextBuffer();
    bufferIndex = buffer.getCurrentIndex();
    REQUIRE(bufferIndex == 1);

    buffer.nextBuffer();
    bufferIndex = buffer.getCurrentIndex();
    REQUIRE(bufferIndex == 0);

    buffer.nextBuffer();
    bufferIndex = buffer.getCurrentIndex();
    REQUIRE(bufferIndex == 1);
}

M pure_changelog.md => pure_changelog.md +1 -0
@@ 9,6 9,7 @@
* Added translations for Bluetooth conenction status label
* Added WCDMA recognition as 3G in status bar
* Added extended information to crashdump filename
* Added extended information to log filename

### Changed / Improved