rpcsx/rpcs3/util/logs.hpp

169 lines
3.7 KiB
C++
Raw Normal View History

#pragma once // No BOM and only basic ASCII in this header, or a neko will die
2020-03-07 10:29:23 +01:00
#include <cstdint>
2020-03-28 15:28:23 +01:00
#include <map>
2020-03-06 20:29:16 +01:00
#include <memory>
2020-03-07 10:29:23 +01:00
#include <string>
#include <vector>
#include <initializer_list>
#include "util/atomic.hpp"
2020-03-07 10:29:23 +01:00
#include "Utilities/StrFmt.h"
2016-05-13 16:01:48 +02:00
namespace logs
{
2020-03-07 10:29:23 +01:00
enum class level : unsigned
{
always, // Highest log severity (cannot be disabled)
fatal,
error,
todo,
success,
warning,
notice,
2017-05-13 20:30:37 +02:00
trace, // Lowest severity (usually disabled)
};
struct channel;
// Message information
struct message
{
2017-05-13 20:30:37 +02:00
channel* ch;
level sev;
private:
2016-08-05 18:49:45 +02:00
// Send log message to global logger instance
void broadcast(const char*, const fmt_type_info*, ...) const;
friend struct channel;
};
2020-03-06 20:29:16 +01:00
struct stored_message
{
message m;
u64 stamp;
std::string prefix;
std::string text;
};
class listener
{
// Next listener (linked list)
atomic_t<listener*> m_next{};
2016-08-05 18:49:45 +02:00
friend struct message;
public:
constexpr listener() = default;
2017-01-25 00:22:19 +01:00
virtual ~listener();
// Process log message
2017-02-22 10:52:03 +01:00
virtual void log(u64 stamp, const message& msg, const std::string& prefix, const std::string& text) = 0;
// Add new listener
static void add(listener*);
2020-03-06 20:29:16 +01:00
// Special purpose
void broadcast(const stored_message&) const;
};
struct channel
{
2016-02-01 22:55:43 +01:00
// Channel prefix (added to every log message)
const char* const name;
// The lowest logging level enabled for this channel (used for early filtering)
atomic_t<level> enabled;
// Initialize channel
constexpr channel(const char* name) noexcept
: name(name)
, enabled(level::notice)
{
}
#define GEN_LOG_METHOD(_sev)\
const message msg_##_sev{this, level::_sev};\
2020-12-18 08:39:54 +01:00
template <typename CharT, usz N, typename... Args>\
void _sev(const CharT(&fmt)[N], const Args&... args)\
2020-02-04 19:37:00 +01:00
{\
if (level::_sev <= enabled.observe()) [[unlikely]]\
2020-02-04 19:37:00 +01:00
{\
if constexpr (sizeof...(Args) > 0)\
{\
static constexpr fmt_type_info type_list[sizeof...(Args) + 1]{fmt_type_info::make<fmt_unveil_t<Args>>()...};\
msg_##_sev.broadcast(reinterpret_cast<const char*>(fmt), type_list, u64{fmt_unveil<Args>::get(args)}...);\
}\
else\
{\
msg_##_sev.broadcast(reinterpret_cast<const char*>(fmt), nullptr);\
}\
2020-02-04 19:37:00 +01:00
}\
}\
GEN_LOG_METHOD(always)
GEN_LOG_METHOD(fatal)
GEN_LOG_METHOD(error)
GEN_LOG_METHOD(todo)
GEN_LOG_METHOD(success)
GEN_LOG_METHOD(warning)
GEN_LOG_METHOD(notice)
GEN_LOG_METHOD(trace)
#undef GEN_LOG_METHOD
};
struct registerer
{
registerer(channel& _ch);
};
2017-05-13 20:30:37 +02:00
// Log level control: set all channels to level::notice
void reset();
// Log level control: set all channels to level::always
void silence();
2017-05-13 20:30:37 +02:00
// Log level control: register channel if necessary, set channel level
void set_level(const std::string&, level);
2020-01-31 10:09:34 +01:00
// Log level control: get channel level
level get_level(const std::string&);
2020-01-31 13:04:40 +01:00
2020-03-28 15:28:23 +01:00
// Log level control: set specific channels to level::fatal
void set_channel_levels(const std::map<std::string, logs::level>& map);
2020-01-31 13:04:40 +01:00
// Get all registered log channels
std::vector<std::string> get_channels();
// Helper: no additional name specified
constexpr const char* make_channel_name(const char* name)
{
return name;
}
// Helper: special channel name specified
constexpr const char* make_channel_name(const char*, const char* name, ...)
{
return name;
}
2020-03-06 20:29:16 +01:00
// Called in main()
std::unique_ptr<logs::listener> make_file_listener(const std::string& path, u64 max_size);
// Called in main()
void set_init(std::initializer_list<stored_message>);
}
#if __cpp_constinit >= 201907
#define LOG_CONSTINIT constinit
#else
#define LOG_CONSTINIT
#endif
#define LOG_CHANNEL(ch, ...) LOG_CONSTINIT inline ::logs::channel ch(::logs::make_channel_name(#ch, ##__VA_ARGS__)); \
namespace logs { inline ::logs::registerer reg_##ch{ch}; }
LOG_CHANNEL(rsx_log, "RSX");