2024-03-23 18:41:26 -07:00
|
|
|
#pragma once
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <streambuf>
|
|
|
|
#include <ostream>
|
|
|
|
#include <set>
|
2024-05-01 09:07:08 -07:00
|
|
|
#include <config.h>
|
2024-03-23 18:41:26 -07:00
|
|
|
#include <vector>
|
2024-04-28 12:31:40 -07:00
|
|
|
#include <variant>
|
2024-08-08 13:12:37 -07:00
|
|
|
#include <map>
|
|
|
|
#include <mutex>
|
|
|
|
#include <stack>
|
2024-04-28 12:31:40 -07:00
|
|
|
#ifdef __ANDROID__
|
|
|
|
#include <android/log.h>
|
|
|
|
#endif
|
2024-08-08 13:12:37 -07:00
|
|
|
#include <functional>
|
2024-10-14 21:27:16 -07:00
|
|
|
#include <fmt/core.h>
|
|
|
|
#include <fmt/format.h>
|
2024-03-23 18:41:26 -07:00
|
|
|
namespace Looper::Log {
|
|
|
|
struct LogStream {
|
|
|
|
std::set<FILE *> outputs;
|
|
|
|
static std::set<FILE *> global_outputs;
|
|
|
|
int my_log_level;
|
|
|
|
std::set<LogStream*> streams;
|
|
|
|
bool nested;
|
|
|
|
bool need_prefix;
|
|
|
|
std::vector<std::string> names;
|
|
|
|
std::set<FILE*> get_used_outputs();
|
2024-04-28 12:31:40 -07:00
|
|
|
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
std::set<android_LogPriority> android_outputs;
|
|
|
|
#endif
|
2024-08-08 13:12:37 -07:00
|
|
|
std::string line;
|
2024-04-28 12:31:40 -07:00
|
|
|
LogStream(std::initializer_list<std::string> names, int log_level, bool nested, void* discriminator);
|
2024-11-12 14:53:44 -08:00
|
|
|
std::map<std::string, LogStream*> substreams;
|
2024-03-23 18:41:26 -07:00
|
|
|
public:
|
2024-09-28 10:31:06 -07:00
|
|
|
virtual void _writec(const char chr);
|
2024-08-08 13:12:37 -07:00
|
|
|
typedef std::lock_guard<std::recursive_mutex> log_mutex_guard;
|
2024-03-23 18:41:26 -07:00
|
|
|
static int log_level;
|
2024-09-28 10:31:06 -07:00
|
|
|
virtual void writeprefix();
|
2024-08-08 13:12:37 -07:00
|
|
|
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);
|
2024-03-23 18:41:26 -07:00
|
|
|
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);
|
2024-08-08 13:12:37 -07:00
|
|
|
virtual void writec(const char chr);
|
2024-09-16 15:05:53 -07:00
|
|
|
inline virtual ~LogStream() { }
|
2024-03-23 18:41:26 -07:00
|
|
|
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, ...);
|
2024-10-14 21:27:16 -07:00
|
|
|
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 <typename... T>
|
|
|
|
inline void writef2(fmt::format_string<T...> 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 <typename... T>
|
|
|
|
inline void writefln2(fmt::format_string<T...> fmt, T&&... args) {
|
|
|
|
return vwritefln2(fmt::string_view(fmt), fmt::make_format_args(args...));
|
|
|
|
}
|
2024-11-12 14:53:44 -08:00
|
|
|
LogStream &substream(std::string name);
|
2024-03-23 18:41:26 -07:00
|
|
|
LogStream(std::initializer_list<std::string> names, std::initializer_list<LogStream*> streams, int log_level = 0);
|
2024-04-28 12:31:40 -07:00
|
|
|
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
LogStream(std::initializer_list<std::string> names, std::initializer_list<std::variant<FILE*, android_LogPriority>> outputs, int log_level = 0);
|
|
|
|
#else
|
2024-03-23 18:41:26 -07:00
|
|
|
LogStream(std::initializer_list<std::string> names, std::initializer_list<FILE*> outputs, int log_level = 0);
|
2024-04-28 12:31:40 -07:00
|
|
|
#endif
|
2024-08-08 13:12:37 -07:00
|
|
|
protected:
|
2024-03-23 18:41:26 -07:00
|
|
|
};
|
2024-09-28 10:31:06 -07:00
|
|
|
std::string get_log_name_by_idx(int idx);
|
2024-03-23 18:41:26 -07:00
|
|
|
void init_logging();
|
2024-08-08 13:12:37 -07:00
|
|
|
void init_logging_subprocess();
|
|
|
|
typedef std::function<LogStream*(int)> log_stream_creation_function_t;
|
|
|
|
void init_logging_custom(log_stream_creation_function_t fn);
|
2024-03-23 18:41:26 -07:00
|
|
|
LogStream &get_log_stream_by_level(int level);
|
2024-05-02 14:52:11 -07:00
|
|
|
#define LOG(level) (Looper::Log::get_log_stream_by_level(level))
|
2024-11-12 14:53:44 -08:00
|
|
|
#define TRACE LOG(-2)
|
2024-05-02 14:52:11 -07:00
|
|
|
#define DEBUG LOG(-1)
|
|
|
|
#define INFO LOG(0)
|
|
|
|
#define WARNING LOG(1)
|
|
|
|
#define ERROR LOG(2)
|
2024-08-08 13:12:37 -07:00
|
|
|
void pop_log_streams();
|
|
|
|
class Context {
|
|
|
|
std::function<void()> end;
|
|
|
|
public:
|
|
|
|
inline Context(std::function<void()> start, std::function<void()> end) {
|
|
|
|
start();
|
|
|
|
this->end = end;
|
|
|
|
}
|
|
|
|
inline ~Context() {
|
|
|
|
end();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
class LogContext : public Context {
|
|
|
|
public:
|
|
|
|
inline LogContext(std::function<void()> push_log_stream_fn) : Context(push_log_stream_fn, pop_log_streams) {
|
|
|
|
|
|
|
|
}
|
|
|
|
};
|
|
|
|
typedef std::map<int, std::stack<LogStream*>> LogStreamMap;
|
2024-05-02 14:52:11 -07:00
|
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
void write_log(int level, const char *log);
|
|
|
|
void write_logln(int level, const char *log);
|
2024-08-08 13:12:37 -07:00
|
|
|
}
|