neuray API Programmer's Manual

ilogger.h File Reference

Description

Logger interface class that supports message logging. See Logging.

Code Example

ilogger.h

‎/***************************************************************************************************
 * Copyright 2023 NVIDIA Corporation. All rights reserved.
 **************************************************************************************************/

#ifndef MI_BASE_ILOGGER_H
#define MI_BASE_ILOGGER_H

#include <cstdarg>
#include <cstdio>
#include <ostream>
#include <sstream>
#include <string>

#include <mi/base/config.h>
#include <mi/base/enums.h>
#include <mi/base/handle.h>
#include <mi/base/iinterface.h>
#include <mi/base/interface_declare.h>

namespace mi {

namespace base {

namespace details {

// Tags may be combined.
enum Message_tag
{
    TAG_NONE                    = 0u,      
    TAG_COMPATIBILITY           = 1u << 0, 
    TAG_UNRECOVERABLE           = 1u << 1, 
    TAG_API_INPUT               = 1u << 2, 
    TAG_API_USAGE               = 1u << 3, 
    TAG_VERSIONING              = 1u << 4, 
    TAG_SYSTEM_RESOURCE         = 1u << 5, 
    TAG_MEMORY                  = 1u << 6, 
    TAG_FILE                    = 1u << 7, 
    TAG_STATS                   = 1u << 8, 
    TAG_UNAVAILABLE             = 1u << 9  
};

} // namespace details

using namespace details;

struct Message_details
{
    enum { HOST_ID_LOCAL = 0 };
    enum {
        DEVICE_ID_CPU = -1,
        DEVICE_ID_UNKNOWN_CUDA = -2,
        DEVICE_ID_ALL_CUDA = -3
    };

    Uint32              
               host_id;

    Sint32              
               device_id;

    Uint32              
               tags;

    Uint32              
               message_id;

    Message_details()
    : host_id(HOST_ID_LOCAL)
    , device_id(DEVICE_ID_CPU)
    , tags(TAG_NONE)
    , message_id(0u)
    {}

    Message_details(
            const Uint32 
               host,
            const Sint32 
               device,
            const Uint32 
               tag,
            const Uint32 id)
    : host_id(host)
    , device_id(device)
    , tags(tag)
    , message_id(id)
    {}

    bool is_device() const
    {
        return device_id != DEVICE_ID_CPU;
    }

    bool is_tagged(const Uint32 required_tags) const
    {
        return (this->tags & required_tags) == required_tags;
    }

    Message_details& host(const Uint32 id)
    {
        host_id = id;
        return *this;
    }

    Message_details& device(const Sint32 id)
    {
        device_id = id;
        return *this;
    }

    Message_details& tag(const Uint32 t)
    {
        tags = t;
        return *this;
    }

    Message_details& tag(const Uint32 t, const Uint32 
               code)
    {
        tags = t;
        message_id = code;
        return *this;
    }

    Message_details& code(const Uint32 c)
    {
        message_id = c;
        return *this;
    }
};


class ILogger : public
    Interface_declare<0x4afbf19a,0x5fb7,0x4422,0xae,0x4b,0x25,0x13,0x06,0x2c,0x30,0x5f>
{
public:
    virtual void message(
        Message_severity level, const char* module_category, const char* message)
#ifdef MI_NEURAYLIB_DEPRECATED_LOG
        = 0;
#else
    {
        this->message(level,module_category,Message_details(),message);
    }
#endif

    virtual void message(
            Message_severity level,
            const char* module_category,
            const Message_details&,
            const char* message)
#ifdef MI_NEURAYLIB_DEPRECATED_LOG
    {
        this->message(level,module_category,message);
    }
#else
        = 0;
#endif
    
    inline void printf(
        Message_severity level, const char* module_category, const char* message, ...)
#ifdef MI_COMPILER_GCC
        __attribute__((format(printf, 4, 5)))
#endif
    {
        va_list args;
        va_start( args, message);
        char buffer[1024];
#ifdef MI_COMPILER_MSC
        vsnprintf_s( &buffer[0], sizeof( buffer), sizeof( buffer)-1, message, args);
#else
        vsnprintf( buffer, sizeof( buffer), message, args);
#endif
        this->message( level, module_category, Message_details(), buffer);
        va_end( args);
    }

    inline void printf(
        Message_severity level,
        const char* module_category,
        const Message_details& details,
        const char* message,
        ...)
#ifdef MI_COMPILER_GCC
        __attribute__((format(printf, 5, 6)))
#endif
    {
        va_list args;
        va_start( args, message);
        char buffer[1024];
#ifdef MI_COMPILER_MSC
        vsnprintf_s( buffer, sizeof( buffer), sizeof( buffer)-1, message, args);
#else
        vsnprintf( buffer, sizeof( buffer), message, args);
#endif
        this->message( level, module_category, details, buffer);
        va_end( args);
    }
};


class Log_stream;


// A specialization of std::stringbuf to be used together with #mi::base::Log_stream.
//
// Its sync() method is overridden to send the contents of the string buffer to the logger, and an
// additional method #set_log_level() allows to specify the log level of the next message.
class Log_streambuf : public std::stringbuf
{
public:
    // Constructor.
    //
    // \param stream             The stream used with this string buffer. Used to flush the stream
    //                           if the log level is changed.
    // \param module_category    The module and the category which specify the origin and the
    //                           functional area of this message. See #mi::base::ILogger::message()
    //                           for details.
    // \param default_level      The default log level. Used if no other log level is selected by
    //                           one of the manipulators.
    // \param default_details    The default message details. Used if no other details are set.
    Log_streambuf(
        Log_stream& stream,
        const std::string& module_category,
        Message_severity default_level = MESSAGE_SEVERITY_INFO,
        const Message_details& default_details = Message_details())
      : std::stringbuf( std::ios::out),
        m_stream( stream),
        m_default_level( default_level),
        m_default_details( default_details),
        m_module_category( module_category),
        m_details( default_details)
    {
        set_log_level( m_default_level);
    }

    // Destructor.
    ~Log_streambuf() throw()
    {
    }
    
    // Flushes the string buffer if not empty, and sets the log level of the next message to the
    // given log level.
    void set_log_level( Message_severity level);

    // Flushes the string buffer if not empty, and sets the log level of the next message to the
    // given log level.
    void set_details( const Message_details& details);

protected:

    // Sends the contents of the string buffer to the logger, clears the string buffer, and resets
    // the log level and details to their defaults.
    int sync();

private:

    Log_stream& m_stream;
    Message_severity m_default_level;
    Message_details m_default_details;
    std::string m_module_category;
    Message_severity m_level;
    Message_details m_details;
};

class Log_stream : public std::ostream
{
public:
    Log_stream(
        ILogger* logger,
        const char* module_category,
        Message_severity default_level = MESSAGE_SEVERITY_INFO,
        const Message_details& default_details = Message_details())
      : std::ostream( 0),
        m_buffer( *this, module_category ? module_category : "APP:MAIN",
                default_level, default_details),
        m_logger( logger, DUP_INTERFACE)
    {
        rdbuf( &m_buffer);
#if (__cplusplus >= 201402L)
        this->pword( get_index()) = this;
#endif
    }

    Log_stream(
        ILogger* logger,
        const std::string& module_category,
        Message_severity default_level = MESSAGE_SEVERITY_INFO,
        const Message_details& default_details = Message_details())
      : std::ostream( 0),
        m_buffer( *this, module_category, default_level, default_details),
        m_logger( logger, DUP_INTERFACE)
    {
        rdbuf( &m_buffer);
#if (__cplusplus >= 201402L)
        this->pword( get_index()) = this;
#endif
    }

    ~Log_stream() throw()
    {
        flush();
    }

    void set_log_level( Message_severity level) { m_buffer.set_log_level( level); }
    
    void set_details( const Message_details& details) { m_buffer.set_details( details); }

#if (__cplusplus >= 201402L)
    //  Returns the unique index into the private storage of std::ios_base.
    static int get_index()
    {
        // Static initialization is guaranteed to be thread-safe with C++11 and later. The method
        // std::ios_base::xalloc() is guaranteed to be thread-safe with C++14 and later.
        static const int s_index = std::ios_base::xalloc();
        return s_index;
    }
#endif

private:
    friend class Log_streambuf;

    Log_streambuf m_buffer;
    mi::base::Handle< ILogger> m_logger;

    // Primary customization point.
    // Note that this function may be called from the destructor.
    virtual void message(
            Message_severity level,
            const char* module_category,
            const Message_details& details,
            const char* message) const
    {
        m_logger->message( level, module_category, details, message);
    }
};



inline void Log_streambuf::set_log_level( Message_severity level)
{
    m_stream.flush();
    m_level = level;
}

inline void Log_streambuf::set_details( const Message_details& details)
{
    m_stream.flush();
    m_details = details;
}

inline int Log_streambuf::sync()
{
    std::stringbuf::sync();
    const std::string& s = str();
    if( !s.empty()) {
        m_stream.message( m_level, m_module_category.c_str(), m_details, s.c_str());
        str( "");
        m_level = m_default_level;
        m_details = m_default_details;
    }
    return 0;
}


template <typename C, typename T>
std::basic_ostream<C, T>& fatal( std::basic_ostream<C, T>& ostream)
{
#if (__cplusplus >= 201402L)
    if( ostream.pword( Log_stream::get_index()) == &ostream)
#endif
        static_cast<Log_stream&>( ostream).set_log_level( base::MESSAGE_SEVERITY_FATAL);
    return ostream;
}

template <typename C, typename T>
std::basic_ostream<C, T>& error( std::basic_ostream<C, T>& ostream)
{
#if (__cplusplus >= 201402L)
    if( ostream.pword( Log_stream::get_index()) == &ostream)
#endif
        static_cast<Log_stream&>( ostream).set_log_level( base::MESSAGE_SEVERITY_ERROR);
    return ostream;
}

template <typename C, typename T>
std::basic_ostream<C, T>& warning( std::basic_ostream<C, T>& ostream)
{
#if (__cplusplus >= 201402L)
    if( ostream.pword( Log_stream::get_index()) == &ostream)
#endif
        static_cast<Log_stream&>( ostream).set_log_level( base::MESSAGE_SEVERITY_WARNING);
    return ostream;
}

template <typename C, typename T>
std::basic_ostream<C, T>& info( std::basic_ostream<C, T>& ostream)
{
#if (__cplusplus >= 201402L)
    if( ostream.pword( Log_stream::get_index()) == &ostream)
#endif
        static_cast<Log_stream&>( ostream).set_log_level( base::MESSAGE_SEVERITY_INFO);
    return ostream;
}

template <typename C, typename T>
std::basic_ostream<C, T>& verbose( std::basic_ostream<C, T>& ostream)
{
#if (__cplusplus >= 201402L)
    if( ostream.pword( Log_stream::get_index()) == &ostream)
#endif
        static_cast<Log_stream&>( ostream).set_log_level( base::MESSAGE_SEVERITY_VERBOSE);
    return ostream;
}

template <typename C, typename T>
std::basic_ostream<C, T>& debug( std::basic_ostream<C, T>& ostream)
{
#if (__cplusplus >= 201402L)
    if( ostream.pword( Log_stream::get_index()) == &ostream)
#endif
        static_cast<Log_stream&>( ostream).set_log_level( base::MESSAGE_SEVERITY_DEBUG);
    return ostream;
}

template <typename C, typename T>
std::basic_ostream<C, T>& operator<<( std::basic_ostream<C, T>& ostream, const Message_details& md)
{
#if (__cplusplus >= 201402L)
    if( ostream.pword( Log_stream::get_index()) == &ostream)
#endif
        static_cast<Log_stream&>( ostream).set_details( md);
    return ostream;
}


namespace msg {

using namespace details;
typedef Message_tag Tag;
typedef Message_details Details;

inline Details tag_details(const Uint32 tags)
{
    return Details().tag(tags);
}

inline Details device_details(
        const Sint32 device=Details::DEVICE_ID_UNKNOWN_CUDA,
        const Uint32 tags=TAG_NONE)
{
    return Details().tag(tags).device(device);
}

}
 // end group mi_base_ilogger

} // namespace base

} // namespace mi

#endif // MI_BASE_ILOGGER_H

Namespaces

namespace 
Common namespace for APIs of NVIDIA Advanced Rendering Center GmbH. More...
namespace 
Namespace for the Base API. More...
namespace 
Namespace for details of the Base API. More...
namespace mi::base::msg

Classes

class 
The ILogger interface class supports logging of messages. More...
class 
Adapts mi::base::ILogger to a standard streaming interface. More...
struct 
Structured details to log messages. More...

Enumerations

enum  {TAG_NONE = 0u, TAG_COMPATIBILITY = 1u<<0, TAG_UNRECOVERABLE = 1u<<1, TAG_API_INPUT = 1u<<2, TAG_API_USAGE = 1u<<3, TAG_VERSIONING = 1u<<4, TAG_SYSTEM_RESOURCE = 1u<<5, TAG_MEMORY = 1u<<6, TAG_FILE = 1u<<7, TAG_STATS = 1u<<8, TAG_UNAVAILABLE = 1u<<9 }
Tags which help categorize log messages. More...

Functions

template< typename C, typename T> std::​basic_ostream < C , T >&  ( std::​basic_ostream < C , T >& ostream)
Manipulator for mi::base::Log_stream. More...
template< typename C, typename T> std::​basic_ostream < C , T >&  ( std::​basic_ostream < C , T >& ostream)
Manipulator for mi::base::Log_stream. More...
template< typename C, typename T> std::​basic_ostream < C , T >&  ( std::​basic_ostream < C , T >& ostream)
Manipulator for mi::base::Log_stream. More...
template< typename C, typename T> std::​basic_ostream < C , T >&  ( std::​basic_ostream < C , T >& ostream)
Manipulator for mi::base::Log_stream. More...
template< typename C, typename T> std::​basic_ostream < C , T >&  ( std::​basic_ostream < C , T >& ostream, const Message_details& md)
Manipulator for mi::base::Log_stream. More...
template< typename C, typename T> std::​basic_ostream < C , T >&  ( std::​basic_ostream < C , T >& ostream)
Manipulator for mi::base::Log_stream. More...
template< typename C, typename T> std::​basic_ostream < C , T >&  ( std::​basic_ostream < C , T >& ostream)
Manipulator for mi::base::Log_stream. More...