Program Listing for File Log.hpp

Return to documentation for file (/tmp/ws/src/fastrtps/include/fastdds/dds/log/Log.hpp)

// Copyright 2019 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef _FASTDDS_DDS_LOG_LOG_HPP_
#define _FASTDDS_DDS_LOG_LOG_HPP_

#include <fastrtps/fastrtps_dll.h>
#include <thread>
#include <sstream>
#include <atomic>
#include <regex>

// Logging API:

// EPROSIMA LOG MACROS
#define EPROSIMA_LOG_INFO(cat, msg) EPROSIMA_LOG_INFO_IMPL_(cat, msg)
#define EPROSIMA_LOG_WARNING(cat, msg) EPROSIMA_LOG_WARNING_IMPL_(cat, msg)
#define EPROSIMA_LOG_ERROR(cat, msg) EPROSIMA_LOG_ERROR_IMPL_(cat, msg)

#if ENABLE_OLD_LOG_MACROS_
// Compile old eProsima macros for compatibility shake.
// However, these macros will be deprecated in future releases, so please do not use them.

#define logInfo(cat, msg) logInfo_(cat, msg)
#define logWarning(cat, msg) logWarning_(cat, msg)
#define logError(cat, msg) logError_(cat, msg)

#define logInfo_(cat, msg) EPROSIMA_LOG_INFO_IMPL_(cat, msg);
#define logWarning_(cat, msg) EPROSIMA_LOG_WARNING_IMPL_(cat, msg);
#define logError_(cat, msg) EPROSIMA_LOG_ERROR_IMPL_(cat, msg);

#endif  // ENABLE_OLD_LOG_MACROS_

namespace eprosima {
namespace fastdds {
namespace dds {

class LogConsumer;

class Log
{
public:

    enum Kind
    {
        Error,
        Warning,
        Info,
    };

    RTPS_DllAPI static void RegisterConsumer(
            std::unique_ptr<LogConsumer>&& consumer);

    RTPS_DllAPI static void ClearConsumers();

    RTPS_DllAPI static void ReportFilenames(
            bool);

    RTPS_DllAPI static void ReportFunctions(
            bool);

    RTPS_DllAPI static void SetVerbosity(
            Log::Kind);

    RTPS_DllAPI static Log::Kind GetVerbosity();

    RTPS_DllAPI static void SetCategoryFilter(
            const std::regex&);

    RTPS_DllAPI static void SetFilenameFilter(
            const std::regex&);

    RTPS_DllAPI static void SetErrorStringFilter(
            const std::regex&);

    RTPS_DllAPI static void Reset();

    RTPS_DllAPI static void Flush();

    RTPS_DllAPI static void KillThread();

    // Note: In VS2013, if you're linking this class statically, you will have to call KillThread before leaving
    // main, due to an unsolved MSVC bug.

    struct Context
    {
        const char* filename;
        int line;
        const char* function;
        const char* category;
    };

    struct Entry
    {
        std::string message;
        Log::Context context;
        Log::Kind kind;
        std::string timestamp;
    };

    RTPS_DllAPI static void QueueLog(
            const std::string& message,
            const Log::Context&,
            Log::Kind);
};

class LogConsumer
{
public:

    virtual ~LogConsumer() = default;

    virtual void Consume(
            const Log::Entry&) = 0;

protected:

    RTPS_DllAPI void print_timestamp(
            std::ostream& stream,
            const Log::Entry&,
            bool color) const;

    RTPS_DllAPI void print_header(
            std::ostream& stream,
            const Log::Entry&,
            bool color) const;

    RTPS_DllAPI void print_context(
            std::ostream& stream,
            const Log::Entry&,
            bool color) const;

    RTPS_DllAPI void print_message(
            std::ostream& stream,
            const Log::Entry&,
            bool color) const;

    RTPS_DllAPI void print_new_line(
            std::ostream& stream,
            bool color) const;
};

#if defined(WIN32)
#define __func__ __FUNCTION__
#endif // if defined(WIN32)

/********************
* Implementation of the log macros depending on the defined macros:
* HAVE_LOG_NO_<level> disable completly a verbosity level
* _INTERNALDEBUG || __INTERNALDEBUG  force to compile the log macro call even when it would not be added to queue
* EPROSIMA_LOG_INFO_IMPL_ would only be compiled if HAVE_LOG_NO_INFO is OFF and
* - FASTDDS_ENFORCE_LOG_INFO or (DEBUG and INTERNALDEBUG) are defined
*
* There are 3 implementations for each level:
* 1. Compile and add log to queue
* 2. Compile but do not add it to queue (with INTERNALDEBUG)
* 3. Do not compile
*
* Every macro (with implementation) occurs inside a code block so after call every internal variable is destroyed.
* Every macro declared has a do while(0).
* This will not generate an assembler instruction and forces the user of the macro to use ";" after calling it.
* https://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html
* NOTE: some compilation cases do not use do while loop and so they do not force ";".
* It is a risk that a user takes in exchange of a perfect way of non generating code in such cases.
********************/

/*********
* ERROR *
*********/
// Name of variables inside macros must be unique, or it could produce an error with external variables
#if !HAVE_LOG_NO_ERROR

#define EPROSIMA_LOG_ERROR_IMPL_(cat, msg)                                                                                 \
    do {                                                                                                               \
        using namespace eprosima::fastdds::dds;                                                                        \
        std::stringstream fastdds_log_ss_tmp__;                                                                        \
        fastdds_log_ss_tmp__ << msg;                                                                                   \
        Log::QueueLog(fastdds_log_ss_tmp__.str(), Log::Context{__FILE__, __LINE__, __func__, #cat}, Log::Kind::Error); \
    } while (0)

#elif (__INTERNALDEBUG || _INTERNALDEBUG)

#define EPROSIMA_LOG_ERROR_IMPL_(cat, msg)                          \
    do {                                                        \
        auto fastdds_log_lambda_tmp__ = [&]()                   \
                {                                               \
                    std::stringstream fastdds_log_ss_tmp__;     \
                    fastdds_log_ss_tmp__ << msg;                \
                };                                              \
        (void)fastdds_log_lambda_tmp__;                         \
    } while (0)
#else

#define EPROSIMA_LOG_ERROR_IMPL_(cat, msg)

#endif // ifndef LOG_NO_ERROR

/***********
* WARNING *
***********/
#if !HAVE_LOG_NO_WARNING

#define EPROSIMA_LOG_WARNING_IMPL_(cat, msg)                                                                            \
    do {                                                                                                            \
        using namespace eprosima::fastdds::dds;                                                                     \
        if (Log::GetVerbosity() >= Log::Kind::Warning)                                                              \
        {                                                                                                           \
            std::stringstream fastdds_log_ss_tmp__;                                                                 \
            fastdds_log_ss_tmp__ << msg;                                                                            \
            Log::QueueLog(                                                                                          \
                fastdds_log_ss_tmp__.str(), Log::Context{__FILE__, __LINE__, __func__, #cat}, Log::Kind::Warning);  \
        }                                                                                                           \
    } while (0)

#elif (__INTERNALDEBUG || _INTERNALDEBUG)

#define EPROSIMA_LOG_WARNING_IMPL_(cat, msg)                        \
    do {                                                        \
        auto fastdds_log_lambda_tmp__ = [&]()                   \
                {                                               \
                    std::stringstream fastdds_log_ss_tmp__;     \
                    fastdds_log_ss_tmp__ << msg;                \
                };                                              \
        (void)fastdds_log_lambda_tmp__;                         \
    } while (0)

#else

#define EPROSIMA_LOG_WARNING_IMPL_(cat, msg)

#endif // ifndef LOG_NO_WARNING

/********
* INFO *
********/
// Allow multiconfig platforms like windows to disable info queueing on Release and other non-debug configs
#if !HAVE_LOG_NO_INFO &&  \
    (defined(FASTDDS_ENFORCE_LOG_INFO) || \
    ((defined(__INTERNALDEBUG) || defined(_INTERNALDEBUG)) && (defined(_DEBUG) || defined(__DEBUG) || \
    !defined(NDEBUG))))

#define EPROSIMA_LOG_INFO_IMPL_(cat, msg)                                                                   \
    do {                                                                                                \
        using namespace eprosima::fastdds::dds;                                                         \
        if (Log::GetVerbosity() >= Log::Kind::Info)                                                     \
        {                                                                                               \
            std::stringstream fastdds_log_ss_tmp__;                                                     \
            fastdds_log_ss_tmp__ << msg;                                                                \
            Log::QueueLog(fastdds_log_ss_tmp__.str(), Log::Context{__FILE__, __LINE__, __func__, #cat}, \
                    Log::Kind::Info);                                                                   \
        }                                                                                               \
    } while (0)

#elif (__INTERNALDEBUG || _INTERNALDEBUG)

#define EPROSIMA_LOG_INFO_IMPL_(cat, msg)                       \
    do {                                                    \
        auto fastdds_log_lambda_tmp__ = [&]()               \
                {                                           \
                    std::stringstream fastdds_log_ss_tmp__; \
                    fastdds_log_ss_tmp__ << msg;            \
                };                                          \
        (void)fastdds_log_lambda_tmp__;                     \
    } while (0)

#else

#define EPROSIMA_LOG_INFO_IMPL_(cat, msg)

#endif // ifndef LOG_NO_INFO


} // namespace dds
} // namespace fastdds
} // namespace eprosima

#endif // ifndef _FASTDDS_DDS_LOG_LOG_HPP_