#pragma once
#include "BuildSettings.h"
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
#include <atomic>
#endif
OPENMPT_NAMESPACE_BEGIN
enum LogLevel
{
LogDebug = 5,
LogInformation = 4,
LogNotification = 3,
LogWarning = 2,
LogError = 1
};
inline mpt::ustring LogLevelToString(LogLevel level)
{
switch(level)
{
case LogError: return U_("error"); break;
case LogWarning: return U_("warning"); break;
case LogNotification: return U_("notify"); break;
case LogInformation: return U_("info"); break;
case LogDebug: return U_("debug"); break;
}
return U_("unknown");
}
class ILog
{
protected:
virtual ~ILog() { }
public:
virtual void AddToLog(LogLevel level, const mpt::ustring &text) const = 0;
};
namespace mpt
{
namespace log
{
#ifndef NO_LOGGING
#if defined(MPT_LOG_GLOBAL_LEVEL_STATIC)
#if (MPT_LOG_GLOBAL_LEVEL <= 0)
#define MPT_LOG_IS_DISABLED
#endif
static const int GlobalLogLevel = MPT_LOG_GLOBAL_LEVEL ;
#else
extern int GlobalLogLevel;
#endif
#if defined(MODPLUG_TRACKER) && !defined(MPT_LOG_IS_DISABLED)
extern bool FileEnabled;
extern bool DebuggerEnabled;
extern bool ConsoleEnabled;
void SetFacilities(const std::string &solo, const std::string &blocked);
bool IsFacilityActive(const char *facility);
#else
static MPT_FORCEINLINE bool IsFacilityActive(const char * ) { return true; }
#endif
#endif
#ifndef NO_LOGGING
class Logger
{
public:
void SendLogMessage(const mpt::source_location &loc, LogLevel level, const char *facility, const mpt::ustring &text);
};
#define MPT_LOG(level, facility, text) \
MPT_DO \
{ \
MPT_MAYBE_CONSTANT_IF(mpt::log::GlobalLogLevel >= ( level )) \
{ \
MPT_MAYBE_CONSTANT_IF(mpt::log::IsFacilityActive(( facility ))) \
{ \
mpt::log::Logger().SendLogMessage( MPT_SOURCE_LOCATION_CURRENT() , ( level ), ( facility ), ( text )); \
} \
} \
} MPT_WHILE_0 \
#else
#define MPT_LOG(level, facility, text) MPT_DO { } MPT_WHILE_0
#endif
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
namespace Trace {
extern std::atomic<bool> g_Enabled;
static inline bool IsEnabled() { return g_Enabled; }
enum class Direction : int8
{
Unknown = 0,
Enter = 1,
Leave = -1,
};
MPT_NOINLINE void Trace(const mpt::source_location & loc, Direction direction = Direction::Unknown) noexcept;
enum ThreadKind {
ThreadKindGUI,
ThreadKindAudio,
ThreadKindNotify,
ThreadKindWatchdir,
};
void Enable(std::size_t numEntries);
void Disable();
void SetThreadId(mpt::log::Trace::ThreadKind kind, uint32 id);
uint32 GetThreadId(mpt::log::Trace::ThreadKind kind);
void Seal();
bool Dump(const mpt::PathString &filename);
class Scope
{
private:
const mpt::source_location loc;
public:
MPT_FORCEINLINE Scope(mpt::source_location loc) noexcept
: loc(loc)
{
if(mpt::log::Trace::g_Enabled)
{
mpt::log::Trace::Trace(loc, mpt::log::Trace::Direction::Enter);
}
}
MPT_FORCEINLINE ~Scope() noexcept
{
if(mpt::log::Trace::g_Enabled)
{
mpt::log::Trace::Trace(loc, mpt::log::Trace::Direction::Leave);
}
}
};
#define MPT_TRACE_CONCAT_HELPER(x, y) x ## y
#define MPT_TRACE_CONCAT(x, y) MPT_TRACE_CONCAT_HELPER(x, y)
#define MPT_TRACE_SCOPE() mpt::log::Trace::Scope MPT_TRACE_CONCAT(MPT_TRACE_VAR, __LINE__)(MPT_SOURCE_LOCATION_CURRENT())
#define MPT_TRACE() MPT_DO { if(mpt::log::Trace::g_Enabled) { mpt::log::Trace::Trace(MPT_SOURCE_LOCATION_CURRENT()); } } MPT_WHILE_0
}
#else
#define MPT_TRACE_SCOPE() MPT_DO { } MPT_WHILE_0
#define MPT_TRACE() MPT_DO { } MPT_WHILE_0
#endif
} }
OPENMPT_NAMESPACE_END