#pragma once #include #include #include #include #include #include #include #include #include #include #ifdef __ANDROID__ #include #endif #include #include #include namespace Looper::Log { struct LogStream { std::set outputs; static std::set global_outputs; int my_log_level; std::set streams; bool nested; bool need_prefix; std::vector names; std::set get_used_outputs(); #ifdef __ANDROID__ std::set android_outputs; #endif std::string line; LogStream(std::initializer_list names, int log_level, bool nested, void* discriminator); std::map substreams; public: virtual void _writec(const char chr); typedef std::lock_guard log_mutex_guard; static int log_level; virtual void writeprefix(); void write_level_prefix(size_t level); void write_level(size_t level, const char *msg); void write_level(size_t level, std::string msg); void writef_level(size_t level, const char *msg, ...); void vwritef_level(size_t level, const char *msg, va_list args); void writeln(const char *msg); void writeln_n(const char *msg, size_t n); void writeln(std::string msg); void writes(const char *msg); void writesn(const char *msg, size_t n); void writes(std::string msg); virtual void writec(const char chr); inline virtual ~LogStream() { } void vwritef(const char *fmt, va_list args); void writef(const char *fmt, ...); void vwritefln(const char *fmt, va_list args); void writefln(const char *fmt, ...); static const std::locale c_locale; inline void vwritef2(fmt::string_view fmt, fmt::format_args args) { return writes(fmt::vformat(c_locale, fmt, args)); } template inline void writef2(fmt::format_string fmt, T&&... args) { return vwritef2(fmt::string_view(fmt), fmt::make_format_args(args...)); } inline void vwritefln2(fmt::string_view fmt, fmt::format_args args) { return writeln(fmt::vformat(c_locale, fmt, args)); } template inline void writefln2(fmt::format_string fmt, T&&... args) { return vwritefln2(fmt::string_view(fmt), fmt::make_format_args(args...)); } LogStream &substream(std::string name); LogStream(std::initializer_list names, std::initializer_list streams, int log_level = 0); #ifdef __ANDROID__ LogStream(std::initializer_list names, std::initializer_list> outputs, int log_level = 0); #else LogStream(std::initializer_list names, std::initializer_list outputs, int log_level = 0); #endif protected: }; std::string get_log_name_by_idx(int idx); void init_logging(); void init_logging_subprocess(); typedef std::function log_stream_creation_function_t; void init_logging_custom(log_stream_creation_function_t fn); LogStream &get_log_stream_by_level(int level); #define LOG(level) (Looper::Log::get_log_stream_by_level(level)) #define TRACE LOG(-2) #define DEBUG LOG(-1) #define INFO LOG(0) #define WARNING LOG(1) #define ERROR LOG(2) void pop_log_streams(); class Context { std::function end; public: inline Context(std::function start, std::function end) { start(); this->end = end; } inline ~Context() { end(); } }; class LogContext : public Context { public: inline LogContext(std::function push_log_stream_fn) : Context(push_log_stream_fn, pop_log_streams) { } }; typedef std::map> LogStreamMap; } extern "C" { void write_log(int level, const char *log); void write_logln(int level, const char *log); }