~aleteoryx/muditaos

0c3cc549b66d47a568f7c9c18a6665db46ae63bf — Mateusz Grzegorzek 5 years ago 6641592
[EGD-4706] Change log for RT1051 and Linux platform

Unify log for RT1051 and linux platform.
Add Logger class where common functions
for RT1051 and Linux are stored.
M module-utils/CMakeLists.txt => module-utils/CMakeLists.txt +2 -0
@@ 36,6 36,8 @@ set (SOURCES
        ${CMAKE_CURRENT_SOURCE_DIR}/ical/ParserICS.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/time/TimeRangeParser.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Utils.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/log/Logger.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/log/log.cpp
)

add_library(${PROJECT_NAME} STATIC ${SOURCES} ${BOARD_SOURCES})

D module-utils/board/cross/log.cpp => module-utils/board/cross/log.cpp +0 -351
@@ 1,351 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "../../log/log.hpp"
#include "../../segger/rtt/SEGGER_RTT.h"
#include <ticks.hpp>
extern "C"
{
#include "FreeRTOS.h"
}
#include "semphr.h"
#include <assert.h>
#include <board.h>
#include <critical.hpp>

/*
 * TODO: M.P
 * Redictering log output to serial console in this form need be considered as quick&dirty solution.
 * It should be refactored i.e serial terminal BSP created and used here instead of using RT1051's low-level routines
 * directly.
 */

#define LOGGER_BUFFER_SIZE 4096

#if LOG_USE_COLOR == 1
#define CONSOLE_ESCAPE_COLOR_BLACK              "\x1b[30m"
#define CONSOLE_ESCAPE_COLOR_RED                "\x1b[31m"
#define CONSOLE_ESCAPE_COLOR_GREEN              "\x1b[32m"
#define CONSOLE_ESCAPE_COLOR_YELLOW             "\x1b[33m"
#define CONSOLE_ESCAPE_COLOR_BLUE               "\x1b[34m"
#define CONSOLE_ESCAPE_COLOR_MAGENTA            "\x1b[35m"
#define CONSOLE_ESCAPE_COLOR_CYAN               "\x1b[36m"
#define CONSOLE_ESCAPE_COLOR_WHITE              "\x1b[37m"
#define CONSOLE_ESCAPE_COLOR_RESET              "\x1b[0m"
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_BLACK   "\x1b[40m"
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_RED     "\x1b[41m"
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_GREEN   "\x1b[42m"
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_YELLOW  "\x1b[43m"
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_BLUE    "\x1b[44m"
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_MAGENTA "\x1b[45m"
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_CYAN    "\x1b[46m"
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_WHITE   "\x1b[47m"
#else
#define CONSOLE_ESCAPE_COLOR_BLACK
#define CONSOLE_ESCAPE_COLOR_RED
#define CONSOLE_ESCAPE_COLOR_GREEN
#define CONSOLE_ESCAPE_COLOR_YELLOW
#define CONSOLE_ESCAPE_COLOR_BLUE
#define CONSOLE_ESCAPE_COLOR_MAGENTA
#define CONSOLE_ESCAPE_COLOR_CYAN
#define CONSOLE_ESCAPE_COLOR_WHITE
#define CONSOLE_ESCAPE_COLOR_RESET
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_BLACK
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_RED
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_GREEN
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_YELLOW
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_BLUE
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_MAGENTA
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_CYAN
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_WHITE
#endif

const char *level_names[] = {"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};

#if LOG_USE_COLOR == 1
static const char *level_colors[] = {"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"};
#else
static const char *level_colors[] = {"", "", "", "", "", ""};
#endif

#include <map>
#include <string>

namespace
{
    const char *critStr = "CRIT";
    const char *irqStr  = "IRQ";
} // namespace

struct Logger
{
    Logger(logger_level level = LOGTRACE) : level{level}
    {

        lock = xSemaphoreCreateMutex();

        assert(lock != NULL);

        /* Acquire lock */
        if (xSemaphoreTake(lock, 100) != pdPASS) {
            return;
        }

        level = level;

        /* Release lock */
        xSemaphoreGive(lock);
    }

    bool logLock()
    {
        // if called from the ISR use DI/EI. In all other cases use semaphore.
        if (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) {
            bt = cpp_freertos::CriticalSection::EnterFromISR();
        }
        else if (xSemaphoreTake(lock, 100) != pdPASS) {
            return false;
        }
        return true;
    }

    void logUnlock()
    {
        // if called from the ISR use DI/EI. In all other cases use semaphore.
        if (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) {
            cpp_freertos::CriticalSection::ExitFromISR(bt);
        }
        else {
            xSemaphoreGive(lock);
        }
    }

    std::map<std::string, logger_level> filtered = {
        // {"ServiceDB", logger_level::LOGFATAL},
        {"ApplicationManager", logger_level::LOGINFO},
        {"TS0710Worker", logger_level::LOGINFO},
        {"ServiceCellular", logger_level::LOGINFO},
        {"ServiceAntenna", logger_level::LOGINFO},
        {"ServiceFota", logger_level::LOGINFO},
        {"ServiceEink", logger_level::LOGINFO},
        {"ServiceDB", logger_level::LOGINFO},
        // make sure that we got defined map entries for at least crit and irq
        // make sure that we got defined map entries for at least crit and irq
        {critStr, logger_level::LOGTRACE},
        {irqStr, logger_level::LOGTRACE}};

    /// 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 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
    logger_level filterThreadName(const std::string &name)
    {
        return filtered[name];
    }

    xSemaphoreHandle lock;
    logger_level level;
    BaseType_t bt;
};

static Logger logger;
static char loggerBuffer[LOGGER_BUFFER_SIZE] = {0};

static inline size_t loggerBufferSizeLeft(char *ptr)
{
    assert(&loggerBuffer[LOGGER_BUFFER_SIZE] - ptr > 0);
    return &loggerBuffer[LOGGER_BUFFER_SIZE] - ptr;
}

void log_Printf(const char *fmt, ...)
{
    if (!logger.logLock()) {
        return;
    }

    char *ptr = loggerBuffer;
    va_list args;

    va_start(args, fmt);
    ptr += vsnprintf(ptr, loggerBufferSizeLeft(ptr), fmt, args);
    va_end(args);

    log_WriteToDevice((uint8_t *)loggerBuffer, ptr - loggerBuffer);

    logger.logUnlock();
}

/// get string description:
/// - in critical seciton - return CRIT
/// - in interrupt return - IRQ
/// - else return thread name
static inline const char *getTaskDesc()
{
    return xTaskGetCurrentTaskHandle() == NULL
               ? critStr
               : xPortIsInsideInterrupt() ? irqStr : pcTaskGetName(xTaskGetCurrentTaskHandle());
}

static void _log_Log(
    logger_level level, const char *file, int line, const char *function, const char *fmt, va_list args)
{
    if (!logger.logLock()) {
        return;
    }

    char *ptr = loggerBuffer;

    // filter out not interesing logs
    if (logger.filterThreadName(getTaskDesc()) >= level) {
        logger.logUnlock();
        return;
    }

    ptr += snprintf(
        ptr, loggerBufferSizeLeft(ptr), "%lu ms ", cpp_freertos::Ticks::TicksToMs(cpp_freertos::Ticks::GetTicks()));

#if LOG_USE_COLOR == 1

    ptr += snprintf(ptr,
                    loggerBufferSizeLeft(ptr),
                    "%s%-5s " CONSOLE_ESCAPE_COLOR_MAGENTA "[%-10s] \x1b[90m%s:%d:" CONSOLE_ESCAPE_COLOR_RESET,
                    level_colors[level],
                    level_names[level],
                    getTaskDesc(),
                    file,
                    line);
#else
    ptr += snprintf(ptr,
                    loggerBufferSizeLeft(ptr),
                    "%-5s [%s] %s:%s:%d: ",
                    level_names[level],
                    getTaskDesc(),
                    file,
                    function,
                    line);
#endif
    ptr += vsnprintf(ptr, loggerBufferSizeLeft(ptr), fmt, args);
    ptr += snprintf(ptr, loggerBufferSizeLeft(ptr), "\n");

    log_WriteToDevice((uint8_t *)loggerBuffer, ptr - loggerBuffer);

    /* Release lock */
    logger.logUnlock();
}

void log_Log(logger_level level, const char *file, int line, const char *function, const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    _log_Log(level, file, line, function, fmt, args);
    va_end(args);
}

/**
 * Update log level
 * @param level [in] - new log level
 */
void log_SetLevel(logger_level level)
{
    logger.level = level;
}

extern "C"
{

    void bt_log_custom(const char *file, int line, const char *foo, const char *fmt, ...)
    {
        va_list args;
        va_start(args, fmt);
        _log_Log(LOGTRACE, file, line, foo, fmt, args);
        va_end(args);
    }

    int printf(__const char *__restrict __format, ...)
    {
        /* Acquire lock */
        if (!logger.logLock()) {
            return -1;
        }

        char *ptr = loggerBuffer;
        va_list args;

        va_start(args, __format);
        ptr += vsnprintf(ptr, loggerBufferSizeLeft(ptr), __format, args);
        va_end(args);

        unsigned int numBytes = ptr - loggerBuffer;
        SEGGER_RTT_Write(0, (uint8_t *)loggerBuffer, numBytes);

        /* Release lock */
        logger.logUnlock();

        return numBytes;
    }

    int vprintf(const char *__restrict __format, va_list __arg)
    {
        /* Acquire lock */
        if (!logger.logLock()) {
            return -1;
        }
        char *ptr = loggerBuffer;
        ptr += vsnprintf(ptr, loggerBufferSizeLeft(ptr), __format, __arg);

        unsigned int numBytes = ptr - loggerBuffer;
        SEGGER_RTT_Write(0, (uint8_t *)loggerBuffer, numBytes);

        /* Release lock */
        logger.logUnlock();

        return numBytes;
    }

    int log_assert(__const char *__restrict __format, ...)
    {
        /* Acquire lock */
        if (!logger.logLock()) {
            return -1;
        }

        char *ptr = loggerBuffer;
        ptr += snprintf(
            ptr, loggerBufferSizeLeft(ptr), "%lu ms ", cpp_freertos::Ticks::TicksToMs(cpp_freertos::Ticks::GetTicks()));
        logger_level level = LOGFATAL;
        ptr += snprintf(ptr,
                        loggerBufferSizeLeft(ptr),
                        "%s%-5s " CONSOLE_ESCAPE_COLOR_MAGENTA "[%-10s] \x1b[31mASSERTION " CONSOLE_ESCAPE_COLOR_RESET,
                        level_colors[level],
                        level_names[level],
                        getTaskDesc());

        va_list args;
        va_start(args, __format);
        ptr += vsnprintf(ptr, loggerBufferSizeLeft(ptr), __format, args);
        va_end(args);

        unsigned int numBytes = ptr - loggerBuffer;

        log_WriteToDevice((uint8_t *)loggerBuffer, ptr - loggerBuffer);

        /* Release lock */
        logger.logUnlock();

        return numBytes;
    }

    void __assert_func(const char *file, int line, const char *func, const char *failedexpr)
    {
        log_assert("\"%s\" failed: file \"%s\", line %d%s%s\n",
                   failedexpr,
                   file,
                   line,
                   func ? ", function: " : "",
                   func ? func : "");

        abort();
        /* NOTREACHED */
    }
};

A module-utils/board/cross/log_rt1051.cpp => module-utils/board/cross/log_rt1051.cpp +120 -0
@@ 0,0 1,120 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <board.h>
#include <critical.hpp>
#include <gsl/gsl_util>
#include <macros.h>
#include "log/log.hpp"
#include "log/Logger.hpp"
#include "segger/rtt/SEGGER_RTT.h"
#include <ticks.hpp>

/// get string description:
/// - in critical seciton - return CRIT
/// - in interrupt return - IRQ
/// - else return thread name
static inline const char *getTaskDesc()
{
    return xTaskGetCurrentTaskHandle() == nullptr
               ? Log::Logger::CRIT_STR
               : xPortIsInsideInterrupt() ? Log::Logger::IRQ_STR : pcTaskGetName(xTaskGetCurrentTaskHandle());
}

namespace Log
{
    void Logger::addLogHeader(logger_level level, const char *file, int line, const char *function)
    {
        loggerBufferCurrentPos += snprintf(&loggerBuffer[loggerBufferCurrentPos],
                                           loggerBufferSizeLeft(),
                                           "%lu ms ",
                                           cpp_freertos::Ticks::TicksToMs(cpp_freertos::Ticks::GetTicks()));

        loggerBufferCurrentPos += snprintf(&loggerBuffer[loggerBufferCurrentPos],
                                           loggerBufferSizeLeft(),
                                           "%-5s [%s] %s:%s:%d: ",
                                           level_names[level],
                                           getTaskDesc(),
                                           file,
                                           function,
                                           line);
    }

    bool Logger::filterLogs(logger_level level)
    {
        return GetLogLevel(getTaskDesc()) < level;
    }

    void Logger::logToDevice(const char *fmt, va_list args)
    {
        loggerBufferCurrentPos = 0;
        loggerBufferCurrentPos += snprintf(&loggerBuffer[loggerBufferCurrentPos],
                                           loggerBufferSizeLeft(),
                                           "%lu ms ",
                                           cpp_freertos::Ticks::TicksToMs(cpp_freertos::Ticks::GetTicks()));

        loggerBufferCurrentPos += snprintf(&loggerBuffer[loggerBufferCurrentPos],
                                           loggerBufferSizeLeft(),
                                           "%-5s [%-10s] \x1b[31mASSERTION ",
                                           level_names[LOGFATAL],
                                           getTaskDesc());

        loggerBufferCurrentPos += vsnprintf(&loggerBuffer[loggerBufferCurrentPos], loggerBufferSizeLeft(), fmt, args);
        logToDevice(Device::DEFAULT, loggerBuffer, loggerBufferCurrentPos);
    }

    void Logger::logToDevice(Device device, std::string_view log, size_t length)
    {
        switch (device) {
        case Device::DEFAULT:
            log_WriteToDevice(reinterpret_cast<const uint8_t *>(log.data()), length);
            break;
        case Device::SEGGER_RTT:
            SEGGER_RTT_Write(0, reinterpret_cast<const void *>(log.data()), length);
            break;
        default:
            break;
        }
    }
} // namespace Log

using Log::Logger;

extern "C"
{
    int printf(__const char *__restrict __format, ...)
    {
        va_list args;
        va_start(args, __format);
        const auto result = Logger::get().log(Log::Device::SEGGER_RTT, __format, args);
        va_end(args);
        return result;
    }

    int vprintf(const char *__restrict __format, va_list __arg)
    {
        return Logger::get().log(Log::Device::SEGGER_RTT, __format, __arg);
    }

    int log_assert(__const char *__restrict __format, ...)
    {
        va_list args;
        va_start(args, __format);
        const auto result = Logger::get().logAssert(__format, args);
        va_end(args);
        return result;
    }

    void __assert_func(const char *file, int line, const char *func, const char *failedexpr)
    {
        log_assert("\"%s\" failed: file \"%s\", line %d%s%s\n",
                   failedexpr,
                   file,
                   line,
                   func ? ", function: " : "",
                   func ? func : "");

        abort();
        /* NOTREACHED */
    }
};

D module-utils/board/linux/log.cpp => module-utils/board/linux/log.cpp +0 -137
@@ 1,137 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "../../log/log.hpp"
#include <iostream>
#include <string>
#include <mutex>
#include <ticks.hpp>
#include <fstream>
#include <string_view>

#define LOGGER_BUFFER_SIZE 4096

#define CONSOLE_ESCAPE_COLOR_BLACK   "\x1b[30m"
#define CONSOLE_ESCAPE_COLOR_RED     "\x1b[31m"
#define CONSOLE_ESCAPE_COLOR_GREEN   "\x1b[32m"
#define CONSOLE_ESCAPE_COLOR_YELLOW  "\x1b[33m"
#define CONSOLE_ESCAPE_COLOR_BLUE    "\x1b[34m"
#define CONSOLE_ESCAPE_COLOR_MAGENTA "\x1b[35m"
#define CONSOLE_ESCAPE_COLOR_CYAN    "\x1b[36m"
#define CONSOLE_ESCAPE_COLOR_WHITE   "\x1b[37m"
#define CONSOLE_ESCAPE_COLOR_RESET   "\x1b[0m"

#define CONSOLE_ESCAPE_COLOR_BACKGROUND_BLACK   "\x1b[40m"
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_RED     "\x1b[41m"
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_GREEN   "\x1b[42m"
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_YELLOW  "\x1b[43m"
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_BLUE    "\x1b[44m"
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_MAGENTA "\x1b[45m"
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_CYAN    "\x1b[46m"
#define CONSOLE_ESCAPE_COLOR_BACKGROUND_WHITE   "\x1b[47m"

const char *level_names[] = {"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};

#if LOG_USE_COLOR == 1
static const char *level_colors[] = {"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"};
#endif

struct Logger
{
    Logger(logger_level level = LOGTRACE) : level{level}
    {}

    std::mutex lock;
    logger_level level;
};

static Logger logger;
static char loggerBuffer[LOGGER_BUFFER_SIZE] = {0};

void dumpToFile(std::string_view log, size_t length)
{
    static std::fstream logFile(logFileName, std::fstream::out);
    logFile.write(log.data(), length);
    logFile.flush();
}

void log_Printf(const char *fmt, ...)
{
    /* Acquire lock */
    std::lock_guard<std::mutex> guard(logger.lock);
    char *ptr = loggerBuffer;
    ptr[0]    = 0;
    va_list args;

    va_start(args, fmt);
    ptr += vsnprintf(ptr, LOGGER_BUFFER_SIZE - 1, fmt, args);
    va_end(args);

    std::cout << loggerBuffer;
    dumpToFile(loggerBuffer, ptr - loggerBuffer);
}

static void _log_Log(
    logger_level level, const char *file, int line, const char *function, const char *fmt, va_list args)
{
    if (level < logger.level) {
        return;
    }

    std::lock_guard<std::mutex> guard(logger.lock);

    char *ptr = loggerBuffer;

    ptr += snprintf(ptr,
                    &loggerBuffer[LOGGER_BUFFER_SIZE] - ptr,
                    "%d ms ",
                    cpp_freertos::Ticks::TicksToMs(cpp_freertos::Ticks::GetTicks()));

#if LOG_USE_COLOR == 1
    ptr += snprintf(ptr,
                    &loggerBuffer[LOGGER_BUFFER_SIZE] - ptr,
                    "%s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ",
                    level_colors[level],
                    level_names[level],
                    file,
                    line);
#else
    ptr += snprintf(
        ptr, &loggerBuffer[LOGGER_BUFFER_SIZE] - ptr, "%-5s %s:%s:%d: ", level_names[level], file, function, line);
#endif
    ptr += vsnprintf(ptr, &loggerBuffer[LOGGER_BUFFER_SIZE] - ptr, fmt, args);
    ptr += snprintf(ptr, &loggerBuffer[LOGGER_BUFFER_SIZE] - ptr, "\n");

    std::cout << loggerBuffer;
    dumpToFile(loggerBuffer, ptr - loggerBuffer);
}

__attribute__((weak)) void log_Log(
    logger_level level, const char *file, int line, const char *function, const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    _log_Log(level, file, line, function, fmt, args);
    va_end(args);
}

/**
 * Update log level
 * @param level [in] - new log level
 */
void log_SetLevel(logger_level level)
{
    logger.level = level;
}

extern "C"
{

    void bt_log_custom(const char *file, int line, const char *foo, const char *fmt, ...)
    {
        va_list args;
        va_start(args, fmt);
        _log_Log(LOGTRACE, file, line, foo, fmt, args);
        va_end(args);
    }
};

A module-utils/board/linux/log_linux.cpp => module-utils/board/linux/log_linux.cpp +55 -0
@@ 0,0 1,55 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "log/log.hpp"
#include "log/Logger.hpp"
#include <iostream>
#include <string_view>
#include <ticks.hpp>

#if LOG_USE_COLOR == 1
static const char *level_colors[] = {"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"};
#endif

namespace Log
{
    void Logger::addLogHeader(logger_level level, const char *file, int line, const char *function)
    {
        loggerBufferCurrentPos += snprintf(&loggerBuffer[loggerBufferCurrentPos],
                                           LOGGER_BUFFER_SIZE - loggerBufferCurrentPos,
                                           "%d ms ",
                                           cpp_freertos::Ticks::TicksToMs(cpp_freertos::Ticks::GetTicks()));
#if LOG_USE_COLOR == 1
        loggerBufferCurrentPos += snprintf(&loggerBuffer[loggerBufferCurrentPos],
                                           LOGGER_BUFFER_SIZE - loggerBufferCurrentPos,
                                           "%s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ",
                                           level_colors[level],
                                           level_names[level],
                                           file,
                                           line);
#else
        loggerBufferCurrentPos += snprintf(&loggerBuffer[loggerBufferCurrentPos],
                                           LOGGER_BUFFER_SIZE - loggerBufferCurrentPos,
                                           "%-5s %s:%s:%d: ",
                                           level_names[level],
                                           file,
                                           function,
                                           line);
#endif
    }

    bool Logger::filterLogs(logger_level _level)
    {
        return _level >= level;
    }

    void Logger::logToDevice(const char *, va_list)
    {
        assert(false && "Not implemented");
    }

    void Logger::logToDevice(Device, std::string_view log, size_t)
    {
        std::cout << log;
    }
} // namespace Log

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

#include "critical.hpp"
#include <fstream>
#include <gsl/gsl_util>
#include "Logger.hpp"
#include "macros.h"

namespace Log
{
    std::map<std::string, logger_level> Logger::filtered = {{"ApplicationManager", logger_level::LOGINFO},
                                                            {"TS0710Worker", logger_level::LOGINFO},
                                                            {"ServiceCellular", logger_level::LOGINFO},
                                                            {"ServiceAntenna", logger_level::LOGINFO},
                                                            {"ServiceFota", logger_level::LOGINFO},
                                                            {"ServiceEink", logger_level::LOGINFO},
                                                            {"ServiceDB", logger_level::LOGINFO},
                                                            {CRIT_STR, logger_level::LOGTRACE},
                                                            {IRQ_STR, logger_level::LOGTRACE}};
    const char *Logger::level_names[]                    = {"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};

    auto Logger::GetLogLevel(const std::string &name) -> logger_level
    {
        return filtered[name];
    }

    bool Logger::lock()
    {
        if (isIRQ()) {
            bt = cpp_freertos::CriticalSection::EnterFromISR();
        }
        else {
            return mutex.Lock();
        }
        return true;
    }

    auto Logger::log(Device device, const char *fmt, va_list args) -> int
    {
        if (!lock()) {
            return -1;
        }
        auto _ = gsl::finally([this] { unlock(); });

        loggerBufferCurrentPos = 0;
        loggerBufferCurrentPos += vsnprintf(&loggerBuffer[loggerBufferCurrentPos], loggerBufferSizeLeft(), fmt, args);
        logToDevice(device, loggerBuffer, loggerBufferCurrentPos);

        return loggerBufferCurrentPos;
    }

    void Logger::log(
        logger_level level, const char *file, int line, const char *function, const char *fmt, va_list args)
    {
        if (!filterLogs(level)) {
            return;
        }

        if (!lock()) {
            return;
        }
        auto _ = gsl::finally([this] { unlock(); });

        loggerBufferCurrentPos = 0;
        addLogHeader(level, file, line, function);

        loggerBufferCurrentPos += vsnprintf(&loggerBuffer[loggerBufferCurrentPos], loggerBufferSizeLeft(), fmt, args);
        loggerBufferCurrentPos += snprintf(&loggerBuffer[loggerBufferCurrentPos], loggerBufferSizeLeft(), "\n");

        logToDevice(Device::DEFAULT, loggerBuffer, loggerBufferCurrentPos);
    }

    auto Logger::logAssert(const char *fmt, va_list args) -> int
    {
        if (!lock()) {
            return -1;
        }
        auto _ = gsl::finally([this] { unlock(); });

        logToDevice(fmt, args);

        return loggerBufferCurrentPos;
    }

    void Logger::unlock()
    {
        if (isIRQ()) {
            cpp_freertos::CriticalSection::ExitFromISR(bt);
        }
        else {
            mutex.Unlock();
        }
    }
}; // namespace Log

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

#pragma once

#include <assert.h>
#include <board.h>
#include "log.hpp"
#include <map>
#include <mutex.hpp>

namespace Log
{
    enum class Device
    {
        DEFAULT,
        SEGGER_RTT
    };

    class Logger
    {
      public:
        [[nodiscard]] static Logger &get()
        {
            static Logger logger;
            return logger;
        }
        auto log(Device device, const char *fmt, va_list args) -> int;
        void log(logger_level level, const char *file, int line, const char *function, const char *fmt, va_list args);
        auto logAssert(const char *fmt, va_list args) -> int;

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

      private:
        Logger() = default;

        void addLogHeader(logger_level level,
                          const char *file     = nullptr,
                          int line             = -1,
                          const char *function = nullptr);
        [[nodiscard]] bool filterLogs(logger_level 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 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]] auto GetLogLevel(const std::string &name) -> logger_level;
        bool lock();
        void logToDevice(const char *fmt, va_list args);
        void logToDevice(Device device, std::string_view log, size_t length);
        [[nodiscard]] size_t loggerBufferSizeLeft() const noexcept
        {
            const auto sizeLeft = LOGGER_BUFFER_SIZE - loggerBufferCurrentPos;
            assert(sizeLeft > 0);
            return sizeLeft;
        }
        void unlock();

        BaseType_t bt;
        cpp_freertos::MutexStandard mutex;
        logger_level level{LOGTRACE};
        char loggerBuffer[LOGGER_BUFFER_SIZE] = {0};
        size_t loggerBufferCurrentPos         = 0;

        static const char *level_names[];
        static std::map<std::string, logger_level> filtered;
    };
} // namespace Log

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

#include "log.hpp"
#include "Logger.hpp"
#include <ticks.hpp>

using Log::Logger;

void log_Printf(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    Logger::get().log(Log::Device::DEFAULT, fmt, args);
    va_end(args);
}

void log_Log(logger_level level, const char *file, int line, const char *function, const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    Logger::get().log(level, file, line, function, fmt, args);
    va_end(args);
}

extern "C"
{
    void bt_log_custom(const char *file, int line, const char *foo, const char *fmt, ...)
    {
        va_list args;
        va_start(args, fmt);
        Logger::get().log(LOGTRACE, file, line, foo, fmt, args);
        va_end(args);
    }
}

M module-utils/log/log.hpp => module-utils/log/log.hpp +2 -2
@@ 62,7 62,6 @@ extern "C"
     */
    void log_Log(logger_level level, const char *file, int line, const char *function, const char *fmt, ...)
        __attribute__((format(printf, 5, 6)));
    void log_SetLevel(logger_level level);
    void log_Printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
    void log_WriteToDevice(const uint8_t *pBuffer, unsigned NumBytes);



@@ 84,7 83,8 @@ extern "C"

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
static const char *logFileName = "MuditaOS.log";
static const size_t LOGGER_BUFFER_SIZE  = 8192;
static const double MAX_BUFFER_UTIL_MEM = 0.8 * LOGGER_BUFFER_SIZE;
#pragma GCC diagnostic pop

#endif /* LOG_LOG_H_ */

M module-utils/targets/Target_Cross.cmake => module-utils/targets/Target_Cross.cmake +1 -1
@@ 1,6 1,6 @@
set(BOARD_SOURCES ${BOARD_SOURCES}

        ${CMAKE_CURRENT_SOURCE_DIR}/board/cross/log.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/board/cross/log_rt1051.cpp

        CACHE INTERNAL ""
        )

M module-utils/targets/Target_Linux.cmake => module-utils/targets/Target_Linux.cmake +1 -1
@@ 1,6 1,6 @@
set(BOARD_SOURCES

        ${CMAKE_CURRENT_SOURCE_DIR}/board/linux/log.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/board/linux/log_linux.cpp

        CACHE INTERNAL "")