omni/log/ILog.h
File members: omni/log/ILog.h
// Copyright (c) 2020-2023, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#pragma once
#include "../core/Api.h"
#include "../core/BuiltIn.h"
#include "../core/IObject.h"
#include "../str/IReadOnlyCString.h"
#include "../log/LogChannel.h"
#include "../extras/OutArrayUtils.h"
#include "../../carb/thread/Util.h"
#include <cstring>
#include <vector>
#define OMNI_LOG_VERBOSE(channelOrFormat_, ...) \
OMNI_LOG_WRITE(channelOrFormat_, omni::log::Level::eVerbose, ##__VA_ARGS__)
#define OMNI_LOG_INFO(channelOrFormat_, ...) OMNI_LOG_WRITE(channelOrFormat_, omni::log::Level::eInfo, ##__VA_ARGS__)
#define OMNI_LOG_WARN(channelOrFormat_, ...) OMNI_LOG_WRITE(channelOrFormat_, omni::log::Level::eWarn, ##__VA_ARGS__)
#define OMNI_LOG_ERROR(channelOrFormat_, ...) OMNI_LOG_WRITE(channelOrFormat_, omni::log::Level::eError, ##__VA_ARGS__)
#define OMNI_LOG_FATAL(channelOrFormat_, ...) OMNI_LOG_WRITE(channelOrFormat_, omni::log::Level::eFatal, ##__VA_ARGS__)
#define OMNI_LOG_WRITE(channelOrFormat_, level_, ...) \
do \
{ \
OMNI_LOG_VALIDATE_FORMAT(channelOrFormat_, ##__VA_ARGS__) \
if (omni::log::detail::isChannelEnabled(level_, OMNI_LOG_DEFAULT_CHANNEL, channelOrFormat_)) \
{ \
omni::log::ILog* log_ = omniGetLogWithoutAcquire(); \
if (log_) \
{ \
omni::log::detail::writeLog(OMNI_LOG_DEFAULT_CHANNEL, channelOrFormat_, log_, level_, __FILE__, \
__func__, __LINE__, ##__VA_ARGS__); \
} \
} \
} while (0)
namespace omni
{
namespace log
{
enum class OMNI_ATTR("prefix=e") SettingBehavior : uint32_t
{
eInherit,
eOverride
};
enum class OMNI_ATTR("prefix=e") ChannelUpdateReason : uint32_t
{
eChannelAdded,
eChannelRemoved,
eLevelUpdated,
eEnabledUpdated,
eDescriptionUpdated,
};
enum class OMNI_ATTR("prefix=e") Level : int32_t
{
eVerbose = -2,
eInfo = -1,
eWarn = 0,
eError = 1,
eFatal = 2,
eDisabled = 3,
};
class ILogMessageConsumer_abi;
class ILogMessageConsumer;
class ILogChannelUpdateConsumer_abi;
class ILogChannelUpdateConsumer;
class ILog_abi;
class ILog;
class ILogMessageConsumer_abi
: public omni::core::Inherits<omni::core::IObject, OMNI_TYPE_ID("omni.log.ILogMessageConsumer")>
{
protected:
virtual void onMessage_abi(OMNI_ATTR("c_str, not_null") const char* channel,
Level level,
OMNI_ATTR("c_str") const char* moduleName,
OMNI_ATTR("c_str") const char* fileName,
OMNI_ATTR("c_str") const char* functionName,
uint32_t lineNumber,
OMNI_ATTR("c_str, not_null") const char* msg,
carb::thread::ProcessId pid,
carb::thread::ThreadId tid,
uint64_t timestamp) noexcept = 0;
};
class ILogChannelUpdateConsumer_abi
: public omni::core::Inherits<omni::core::IObject, OMNI_TYPE_ID("omni.log.ILogChannelUpdateConsumer")>
{
protected:
virtual void onChannelUpdate_abi(OMNI_ATTR("not_null") ILog* log,
omni::str::IReadOnlyCString* name,
ChannelUpdateReason reason) noexcept = 0;
};
class ILog_abi : public omni::core::Inherits<omni::core::IObject, OMNI_TYPE_ID("omni.log.ILog")>
{
protected:
virtual OMNI_ATTR("no_py") void log_abi(OMNI_ATTR("c_str, not_null") const char* channel,
Level level,
OMNI_ATTR("c_str") const char* moduleName,
OMNI_ATTR("c_str") const char* fileName,
OMNI_ATTR("c_str") const char* functionName,
uint32_t lineNumber,
OMNI_ATTR("c_str, not_null") const char* str,
uint32_t strCharCount) noexcept = 0;
virtual OMNI_ATTR("no_py") void logf_abi(OMNI_ATTR("c_str, not_null") const char* channel,
Level level,
OMNI_ATTR("c_str") const char* moduleName,
OMNI_ATTR("c_str") const char* fileName,
OMNI_ATTR("c_str") const char* functionName,
uint32_t lineNumber,
OMNI_ATTR("c_str, not_null") const char* format,
va_list args) noexcept = 0;
virtual OMNI_ATTR("consumer=onMessage_abi") void addMessageConsumer_abi(OMNI_ATTR("not_null")
ILogMessageConsumer* consumer) noexcept = 0;
virtual void removeMessageConsumer_abi(ILogMessageConsumer* consumer) noexcept = 0;
virtual OMNI_ATTR("no_api, no_py") omni::core::Result getMessageConsumers_abi( // disable omni.bind until OM-21202
OMNI_ATTR("out, count=*consumersCount, *not_null") ILogMessageConsumer** consumers,
OMNI_ATTR("in, out, not_null") uint32_t* consumersCount) noexcept = 0;
virtual void setLevel_abi(Level level) noexcept = 0;
virtual Level getLevel_abi() noexcept = 0;
virtual void setEnabled_abi(bool isEnabled) noexcept = 0;
virtual bool isEnabled_abi() noexcept = 0;
virtual OMNI_ATTR("py_not_prop") bool setAsync_abi(bool logAsync) noexcept = 0;
virtual OMNI_ATTR("py_not_prop") bool isAsync_abi() noexcept = 0;
virtual OMNI_ATTR("no_py") void addChannel_abi(OMNI_ATTR("c_str, not_null") const char* name,
OMNI_ATTR("in, out, not_null") Level* level,
OMNI_ATTR("c_str") const char* description) noexcept = 0;
virtual OMNI_ATTR("no_py") void removeChannel_abi(OMNI_ATTR("c_str, not_null") const char* name,
OMNI_ATTR("in, out, not_null") Level* level) noexcept = 0;
virtual OMNI_ATTR("no_api, no_py") omni::core::Result getChannelNames_abi( // disable omni.bind until OM-21202
OMNI_ATTR("out, count=*namesCount, *not_null") omni::str::IReadOnlyCString** names,
OMNI_ATTR("in, out, not_null") uint32_t* namesCount) noexcept = 0;
virtual void setChannelLevel_abi(OMNI_ATTR("c_str, not_null") const char* name,
Level level,
SettingBehavior behavior) noexcept = 0;
virtual omni::core::Result getChannelLevel_abi(OMNI_ATTR("c_str, not_null") const char* name,
OMNI_ATTR("out, not_null") Level* outLevel,
OMNI_ATTR("out, not_null") SettingBehavior* outBehavior) noexcept = 0;
virtual void setChannelEnabled_abi(OMNI_ATTR("c_str, not_null") const char* name,
bool isEnabled,
SettingBehavior behavior) noexcept = 0;
virtual omni::core::Result getChannelEnabled_abi(OMNI_ATTR("c_str, not_null") const char* name,
OMNI_ATTR("out, not_null") bool* outIsEnabled,
OMNI_ATTR("out, not_null")
SettingBehavior* outBehavior) noexcept = 0;
virtual void setChannelDescription_abi(OMNI_ATTR("c_str, not_null") const char* name,
OMNI_ATTR("c_str, not_null") const char* description) noexcept = 0;
virtual OMNI_ATTR("no_py") omni::core::Result getChannelDescription_abi( // OM-21456: disable omni.bind py bindings
OMNI_ATTR("c_str, not_null") const char* name,
OMNI_ATTR("out, not_null") omni::str::IReadOnlyCString** outDescription) noexcept = 0;
virtual bool isLoggingAtLevel_abi(OMNI_ATTR("c_str, not_null") const char* name, Level level) noexcept = 0;
virtual void flush_abi() noexcept = 0;
virtual void OMNI_ATTR("consumer=onChannelUpdate_abi")
addChannelUpdateConsumer_abi(OMNI_ATTR("not_null") ILogChannelUpdateConsumer* consumer) noexcept = 0;
virtual void removeChannelUpdateConsumer_abi(ILogChannelUpdateConsumer* consumer) noexcept = 0;
virtual OMNI_ATTR("no_api, no_py") omni::core::Result getChannelUpdateConsumers_abi( // disable omni.bind until
// OM-21202
OMNI_ATTR("out, count=*consumersCount, *not_null") ILogChannelUpdateConsumer** consumers,
OMNI_ATTR("in, out, not_null") uint32_t* consumersCount) noexcept = 0;
};
} // namespace log
} // namespace omni
#define OMNI_BIND_INCLUDE_INTERFACE_DECL
#include "ILog.gen.h"
#ifdef OMNI_COMPILE_AS_DYNAMIC_LIBRARY
OMNI_API omni::log::ILog* omniGetLogWithoutAcquire();
#else
inline omni::log::ILog* omniGetLogWithoutAcquire()
{
return static_cast<omni::log::ILog*>(omniGetBuiltInWithoutAcquire(OmniBuiltIn::eILog));
}
#endif
OMNI_API omni::log::ILog* omniCreateLog();
// omniGetModuleFilename is also forward declared in omni/core/Omni.h. Exhale doesn't like that.
#ifndef DOXYGEN_SHOULD_SKIP_THIS
OMNI_API const char* omniGetModuleFilename();
#endif
class omni::log::ILogMessageConsumer : public omni::core::Generated<omni::log::ILogMessageConsumer_abi>
{
};
class omni::log::ILogChannelUpdateConsumer : public omni::core::Generated<omni::log::ILogChannelUpdateConsumer_abi>
{
};
class omni::log::ILog : public omni::core::Generated<omni::log::ILog_abi>
{
public:
std::vector<omni::core::ObjectPtr<omni::log::ILogMessageConsumer>> getMessageConsumers() noexcept;
std::vector<omni::core::ObjectPtr<omni::str::IReadOnlyCString>> getChannelNames() noexcept;
std::vector<omni::core::ObjectPtr<omni::log::ILogChannelUpdateConsumer>> getChannelUpdateConsumers() noexcept;
void setChannelEnabled(const omni::log::LogChannelData& channel,
bool isEnabled,
omni::log::SettingBehavior behavior) noexcept
{
setChannelEnabled(channel.name, isEnabled, behavior);
}
omni::core::Result getChannelEnabled(const omni::log::LogChannelData& channel,
bool* outEnabled,
omni::log::SettingBehavior* outBehavior) noexcept
{
return getChannelEnabled(channel.name, outEnabled, outBehavior);
}
// We must expose setChannelEnabled(const char*, ...) since setChannelEnabled(LogChannelData, ...) hides it.
using omni::core::Generated<omni::log::ILog_abi>::setChannelEnabled;
using omni::core::Generated<omni::log::ILog_abi>::getChannelEnabled;
void setChannelLevel(const omni::log::LogChannelData& channel,
omni::log::Level level,
omni::log::SettingBehavior behavior) noexcept
{
setChannelLevel(channel.name, level, behavior);
}
omni::core::Result getChannelLevel(const omni::log::LogChannelData& channel,
omni::log::Level* outLevel,
omni::log::SettingBehavior* outBehavior) noexcept
{
return getChannelLevel(channel.name, outLevel, outBehavior);
}
// We must expose setChannelLevel(const char*, ...) since setChannelEnabled(LogChannelData, ...) hides it.
using omni::core::Generated<omni::log::ILog_abi>::setChannelLevel;
using omni::core::Generated<omni::log::ILog_abi>::getChannelLevel;
bool isLoggingAtLevel(const omni::log::LogChannelData& channel, omni::log::Level level)
{
return isLoggingAtLevel(channel.name, level);
}
// We must expose isLoggingAtLevel(const char*, ...) since isLoggingAtLevel(LogChannelData, ...) hides it.
using omni::core::Generated<omni::log::ILog_abi>::isLoggingAtLevel;
};
#define OMNI_BIND_INCLUDE_INTERFACE_IMPL
#include "ILog.gen.h"
namespace omni
{
namespace log
{
#ifndef DOXYGEN_SHOULD_SKIP_THIS
namespace detail
{
# if CARB_COMPILER_GNUC || CARB_TOOLCHAIN_CLANG
// clang sees compileTimeValidateFormat<>() as an unimplemented function (which it intentionally
// is) on mac and generates a warning. We'll just silence that warning.
CARB_IGNOREWARNING_CLANG_WITH_PUSH("-Wundefined-internal")
// Utilizes an __attribute__ to validates the given fmt at compile time. Does not produce any code. Works for GCC but
// not MSVC.
void compileTimeValidateFormat(const LogChannelData& channel, const char* fmt, ...) CARB_PRINTF_FUNCTION(2, 3);
// Utilizes an __attribute__ to validates the given fmt at compile time. Does not produce any code. Works for GCC but
// not MSVC.
void compileTimeValidateFormat(const char* fmt, ...) CARB_PRINTF_FUNCTION(1, 2);
# define OMNI_LOG_VALIDATE_FORMAT(...) \
if (false) \
{ \
omni::log::detail::compileTimeValidateFormat(__VA_ARGS__); \
}
CARB_IGNOREWARNING_CLANG_POP
# else
# define OMNI_LOG_VALIDATE_FORMAT(...)
# endif
// Implementation detail. Checks the message's level against the channel's level and logs as appropriate.
template <class... ArgList>
void writeLog(const LogChannelData& /*ignore*/,
const LogChannelData& channel,
ILog* log,
Level level,
const char* filename,
const char* function,
int32_t line,
const char* fmt,
ArgList&&... args)
{
log->logf(
channel.name, level, omniGetModuleFilename(), filename, function, line, fmt, std::forward<ArgList>(args)...);
}
// Implementation detail. Initiates logging to the default channel.
template <class... ArgList>
void writeLog(const LogChannelData& channel,
const char* fmt,
ILog* log,
Level level,
const char* filename,
const char* function,
int32_t line,
ArgList&&... args)
{
log->logf(
channel.name, level, omniGetModuleFilename(), filename, function, line, fmt, std::forward<ArgList>(args)...);
}
// Implementation detail. Checks the message's level against the channel's level.
inline bool isChannelEnabled(Level level, const LogChannelData& /*ignore*/, const LogChannelData& channel)
{
return (static_cast<Level>(channel.level) <= level);
}
// Implementation detail. Checks the message's level against the default channel
inline bool isChannelEnabled(Level level, const LogChannelData& channel, const char* /*fmt*/)
{
return (static_cast<Level>(channel.level) <= level);
}
} // namespace detail
#endif
inline void addModulesChannels()
{
auto log = omniGetLogWithoutAcquire();
if (log)
{
for (auto channel = getModuleLogChannels(); channel; channel = channel->next)
{
log->addChannel(channel->name, reinterpret_cast<Level*>(&channel->level), channel->description);
}
}
}
inline void removeModulesChannels()
{
auto log = omniGetLogWithoutAcquire();
if (log)
{
for (auto channel = getModuleLogChannels(); channel; channel = channel->next)
{
log->removeChannel(channel->name, reinterpret_cast<Level*>(&channel->level));
}
}
}
} // namespace log
} // namespace omni
#ifndef DOXYGEN_SHOULD_SKIP_THIS
inline std::vector<omni::core::ObjectPtr<omni::log::ILogMessageConsumer>> omni::log::ILog::getMessageConsumers() noexcept
{
std::vector<omni::core::ObjectPtr<omni::log::ILogMessageConsumer>> out;
auto result = omni::extras::getOutArray<omni::log::ILogMessageConsumer*>(
[this](omni::log::ILogMessageConsumer** consumers, uint32_t* consumersCount) // get func
{
std::memset(consumers, 0, sizeof(omni::log::ILogMessageConsumer*) * *consumersCount); // incoming ptrs
// must be nullptr
return this->getMessageConsumers_abi(consumers, consumersCount);
},
[&out](omni::log::ILogMessageConsumer** names, uint32_t namesCount) // fill func
{
out.reserve(namesCount);
for (uint32_t i = 0; i < namesCount; ++i)
{
out.emplace_back(names[i], omni::core::kSteal);
}
});
if (OMNI_FAILED(result))
{
OMNI_LOG_ERROR("unable to retrieve log channel settings consumers: 0x%08X", result);
}
return out;
}
inline std::vector<omni::core::ObjectPtr<omni::str::IReadOnlyCString>> omni::log::ILog::getChannelNames() noexcept
{
std::vector<omni::core::ObjectPtr<omni::str::IReadOnlyCString>> out;
auto result = omni::extras::getOutArray<omni::str::IReadOnlyCString*>(
[this](omni::str::IReadOnlyCString** names, uint32_t* namesCount) // get func
{
std::memset(names, 0, sizeof(omni::str::IReadOnlyCString*) * *namesCount); // incoming ptrs must be nullptr
return this->getChannelNames_abi(names, namesCount);
},
[&out](omni::str::IReadOnlyCString** names, uint32_t namesCount) // fill func
{
out.reserve(namesCount);
for (uint32_t i = 0; i < namesCount; ++i)
{
out.emplace_back(names[i], omni::core::kSteal);
}
});
if (OMNI_FAILED(result))
{
OMNI_LOG_ERROR("unable to retrieve log channel names: 0x%08X", result);
}
return out;
}
inline std::vector<omni::core::ObjectPtr<omni::log::ILogChannelUpdateConsumer>> omni::log::ILog::getChannelUpdateConsumers() noexcept
{
std::vector<omni::core::ObjectPtr<omni::log::ILogChannelUpdateConsumer>> out;
auto result = omni::extras::getOutArray<omni::log::ILogChannelUpdateConsumer*>(
[this](omni::log::ILogChannelUpdateConsumer** consumers, uint32_t* consumersCount) // get func
{
std::memset(consumers, 0, sizeof(omni::log::ILogChannelUpdateConsumer*) * *consumersCount); // incoming
// ptrs must
// be nullptr
return this->getChannelUpdateConsumers_abi(consumers, consumersCount);
},
[&out](omni::log::ILogChannelUpdateConsumer** names, uint32_t namesCount) // fill func
{
out.reserve(namesCount);
for (uint32_t i = 0; i < namesCount; ++i)
{
out.emplace_back(names[i], omni::core::kSteal);
}
});
if (OMNI_FAILED(result))
{
OMNI_LOG_ERROR("unable to retrieve log channel updated consumers: 0x%08X", result);
}
return out;
}
#endif