336 lines
16 KiB
C++
336 lines
16 KiB
C++
// Copyright (c) 2023, AgiBot Inc.
|
|
// All rights reserved.
|
|
|
|
#pragma once
|
|
|
|
#include <functional>
|
|
#include <source_location>
|
|
#include <string>
|
|
#include <thread>
|
|
|
|
#include "util/block_queue.h"
|
|
#include "util/exception.h"
|
|
#include "util/format.h"
|
|
#include "util/time_util.h"
|
|
|
|
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 30
|
|
#include <sys/syscall.h>
|
|
#define gettid() syscall(SYS_gettid)
|
|
#endif
|
|
|
|
namespace aimrt::common::util {
|
|
|
|
constexpr uint32_t kLogLevelTrace = 0;
|
|
constexpr uint32_t kLogLevelDebug = 1;
|
|
constexpr uint32_t kLogLevelInfo = 2;
|
|
constexpr uint32_t kLogLevelWarn = 3;
|
|
constexpr uint32_t kLogLevelError = 4;
|
|
constexpr uint32_t kLogLevelFatal = 5;
|
|
|
|
class SimpleLogger {
|
|
public:
|
|
static uint32_t GetLogLevel() { return 0; }
|
|
|
|
static void Log(uint32_t lvl,
|
|
uint32_t line,
|
|
uint32_t column,
|
|
const char* file_name,
|
|
const char* function_name,
|
|
const char* log_data,
|
|
size_t log_data_size) {
|
|
static constexpr std::string_view kLvlNameArray[] = {
|
|
"Trace", "Debug", "Info", "Warn", "Error", "Fatal"};
|
|
|
|
static constexpr uint32_t kLvlNameArraySize =
|
|
sizeof(kLvlNameArray) / sizeof(kLvlNameArray[0]);
|
|
lvl = lvl >= kLvlNameArraySize ? (kLvlNameArraySize - 1) : lvl;
|
|
|
|
#if defined(_WIN32)
|
|
thread_local size_t tid(std::hash<std::thread::id>{}(std::this_thread::get_id()));
|
|
#else
|
|
thread_local size_t tid(gettid());
|
|
#endif
|
|
|
|
auto t = std::chrono::system_clock::now();
|
|
std::string log_str = ::aimrt_fmt::format(
|
|
"[{}.{:0>6}][{}][{}][{}:{}:{} @{}]{}",
|
|
GetTimeStr(std::chrono::system_clock::to_time_t(t)),
|
|
(GetTimestampUs(t) % 1000000),
|
|
kLvlNameArray[lvl],
|
|
tid,
|
|
file_name,
|
|
line,
|
|
column,
|
|
function_name,
|
|
std::string_view(log_data, log_data_size));
|
|
|
|
fprintf(stderr, "%s\n", log_str.c_str());
|
|
}
|
|
};
|
|
|
|
class SimpleAsyncLogger {
|
|
public:
|
|
SimpleAsyncLogger()
|
|
: log_thread_(std::bind(&SimpleAsyncLogger::LogThread, this)) {}
|
|
|
|
~SimpleAsyncLogger() {
|
|
queue_.Stop();
|
|
if (log_thread_.joinable()) log_thread_.join();
|
|
}
|
|
|
|
SimpleAsyncLogger(const SimpleAsyncLogger&) = delete;
|
|
SimpleAsyncLogger& operator=(const SimpleAsyncLogger&) = delete;
|
|
|
|
static uint32_t GetLogLevel() { return 0; }
|
|
|
|
void Log(uint32_t lvl,
|
|
uint32_t line,
|
|
uint32_t column,
|
|
const char* file_name,
|
|
const char* function_name,
|
|
const char* log_data,
|
|
size_t log_data_size) const {
|
|
static constexpr std::string_view kLvlNameArray[] = {
|
|
"Trace", "Debug", "Info", "Warn", "Error", "Fatal"};
|
|
|
|
static constexpr uint32_t kLvlNameArraySize =
|
|
sizeof(kLvlNameArray) / sizeof(kLvlNameArray[0]);
|
|
if (lvl >= kLvlNameArraySize) [[unlikely]]
|
|
lvl = kLvlNameArraySize;
|
|
|
|
#if defined(_WIN32)
|
|
thread_local size_t tid(std::hash<std::thread::id>{}(std::this_thread::get_id()));
|
|
#else
|
|
thread_local size_t tid(gettid());
|
|
#endif
|
|
|
|
auto t = std::chrono::system_clock::now();
|
|
std::string log_str = ::aimrt_fmt::format(
|
|
"[{}.{:0>6}][{}][{}][{}:{}:{} @{}]{}",
|
|
GetTimeStr(std::chrono::system_clock::to_time_t(t)),
|
|
(GetTimestampUs(t) % 1000000),
|
|
kLvlNameArray[lvl],
|
|
tid,
|
|
file_name,
|
|
line,
|
|
column,
|
|
function_name,
|
|
std::string_view(log_data, log_data_size));
|
|
try {
|
|
queue_.Enqueue(std::move(log_str));
|
|
} catch (...) {
|
|
}
|
|
}
|
|
|
|
private:
|
|
void LogThread() {
|
|
while (true) {
|
|
try {
|
|
auto log_str = queue_.Dequeue();
|
|
fprintf(stderr, "%s\n", log_str.c_str());
|
|
} catch (...) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
mutable BlockQueue<std::string> queue_;
|
|
std::thread log_thread_;
|
|
};
|
|
|
|
struct LoggerWrapper {
|
|
uint32_t GetLogLevel() const {
|
|
return get_log_level_func();
|
|
}
|
|
|
|
void Log(uint32_t lvl,
|
|
uint32_t line,
|
|
uint32_t column,
|
|
const char* file_name,
|
|
const char* function_name,
|
|
const char* log_data,
|
|
size_t log_data_size) const {
|
|
log_func(lvl, line, column, file_name, function_name, log_data, log_data_size);
|
|
}
|
|
|
|
using GetLogLevelFunc = std::function<uint32_t(void)>;
|
|
using LogFunc = std::function<void(uint32_t, uint32_t, uint32_t, const char*, const char*, const char*, size_t)>;
|
|
|
|
GetLogLevelFunc get_log_level_func = SimpleLogger::GetLogLevel;
|
|
LogFunc log_func = SimpleLogger::Log;
|
|
};
|
|
|
|
template <typename T>
|
|
concept LoggerType =
|
|
requires(T t) {
|
|
{ t.GetLogLevel() } -> std::same_as<uint32_t>;
|
|
{ t.Log(0, 0, 0, nullptr, nullptr, nullptr, 0) };
|
|
};
|
|
|
|
template <LoggerType Logger, typename... Args>
|
|
inline void LogImpl(const Logger& logger,
|
|
uint32_t lvl,
|
|
uint32_t line,
|
|
uint32_t column,
|
|
const char* file_name,
|
|
const char* function_name,
|
|
::aimrt_fmt::format_string<Args...> fmt,
|
|
Args&&... args) {
|
|
std::string log_str = ::aimrt_fmt::format(fmt, std::forward<Args>(args)...);
|
|
logger.Log(lvl, line, column, file_name, function_name, log_str.c_str(), log_str.size());
|
|
}
|
|
|
|
} // namespace aimrt::common::util
|
|
|
|
/// Log with the specified logger handle
|
|
#define AIMRT_HANDLE_LOG(__lgr__, __lvl__, __fmt__, ...) \
|
|
do { \
|
|
const auto& __cur_lgr__ = __lgr__; \
|
|
if (__lvl__ >= __cur_lgr__.GetLogLevel()) { \
|
|
std::string __log_str__ = ::aimrt_fmt::format(__fmt__, ##__VA_ARGS__); \
|
|
constexpr auto __location__ = std::source_location::current(); \
|
|
__cur_lgr__.Log( \
|
|
__lvl__, __location__.line(), __location__.column(), __location__.file_name(), \
|
|
__FUNCTION__, __log_str__.c_str(), __log_str__.size()); \
|
|
} \
|
|
} while (0)
|
|
|
|
/// Check and log with the specified logger handle
|
|
#define AIMRT_HANDLE_CHECK_LOG(__lgr__, __expr__, __lvl__, __fmt__, ...) \
|
|
do { \
|
|
if (!(__expr__)) [[unlikely]] { \
|
|
AIMRT_HANDLE_LOG(__lgr__, __lvl__, __fmt__, ##__VA_ARGS__); \
|
|
} \
|
|
} while (0)
|
|
|
|
/// Log and throw with the specified logger handle
|
|
#define AIMRT_HANDLE_LOG_THROW(__lgr__, __lvl__, __fmt__, ...) \
|
|
do { \
|
|
std::string __log_str__ = ::aimrt_fmt::format(__fmt__, ##__VA_ARGS__); \
|
|
const auto& __cur_lgr__ = __lgr__; \
|
|
if (__lvl__ >= __cur_lgr__.GetLogLevel()) { \
|
|
constexpr auto __location__ = std::source_location::current(); \
|
|
__cur_lgr__.Log( \
|
|
__lvl__, __location__.line(), __location__.column(), __location__.file_name(), \
|
|
__FUNCTION__, __log_str__.c_str(), __log_str__.size()); \
|
|
} \
|
|
throw aimrt::common::util::AimRTException(std::move(__log_str__)); \
|
|
} while (0)
|
|
|
|
/// Check and log and throw with the specified logger handle
|
|
#define AIMRT_HANDLE_CHECK_LOG_THROW(__lgr__, __expr__, __lvl__, __fmt__, ...) \
|
|
do { \
|
|
if (!(__expr__)) [[unlikely]] { \
|
|
AIMRT_HANDLE_LOG_THROW(__lgr__, __lvl__, __fmt__, ##__VA_ARGS__); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define AIMRT_HL_TRACE(__lgr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_LOG(__lgr__, aimrt::common::util::kLogLevelTrace, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_DEBUG(__lgr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_LOG(__lgr__, aimrt::common::util::kLogLevelDebug, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_INFO(__lgr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_LOG(__lgr__, aimrt::common::util::kLogLevelInfo, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_WARN(__lgr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_LOG(__lgr__, aimrt::common::util::kLogLevelWarn, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_ERROR(__lgr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_LOG(__lgr__, aimrt::common::util::kLogLevelError, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_FATAL(__lgr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_LOG(__lgr__, aimrt::common::util::kLogLevelFatal, __fmt__, ##__VA_ARGS__)
|
|
|
|
#define AIMRT_HL_CHECK_TRACE(__lgr__, __expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG(__lgr__, __expr__, aimrt::common::util::kLogLevelTrace, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_CHECK_DEBUG(__lgr__, __expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG(__lgr__, __expr__, aimrt::common::util::kLogLevelDebug, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_CHECK_INFO(__lgr__, __expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG(__lgr__, __expr__, aimrt::common::util::kLogLevelInfo, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_CHECK_WARN(__lgr__, __expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG(__lgr__, __expr__, aimrt::common::util::kLogLevelWarn, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_CHECK_ERROR(__lgr__, __expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG(__lgr__, __expr__, aimrt::common::util::kLogLevelError, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_CHECK_FATAL(__lgr__, __expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG(__lgr__, __expr__, aimrt::common::util::kLogLevelFatal, __fmt__, ##__VA_ARGS__)
|
|
|
|
#define AIMRT_HL_TRACE_THROW(__lgr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_LOG_THROW(__lgr__, aimrt::common::util::kLogLevelTrace, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_DEBUG_THROW(__lgr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_LOG_THROW(__lgr__, aimrt::common::util::kLogLevelDebug, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_INFO_THROW(__lgr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_LOG_THROW(__lgr__, aimrt::common::util::kLogLevelInfo, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_WARN_THROW(__lgr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_LOG_THROW(__lgr__, aimrt::common::util::kLogLevelWarn, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_ERROR_THROW(__lgr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_LOG_THROW(__lgr__, aimrt::common::util::kLogLevelError, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_FATAL_THROW(__lgr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_LOG_THROW(__lgr__, aimrt::common::util::kLogLevelFatal, __fmt__, ##__VA_ARGS__)
|
|
|
|
#define AIMRT_HL_CHECK_TRACE_THROW(__lgr__, __expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG_THROW(__lgr__, __expr__, aimrt::common::util::kLogLevelTrace, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_CHECK_DEBUG_THROW(__lgr__, __expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG_THROW(__lgr__, __expr__, aimrt::common::util::kLogLevelDebug, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_CHECK_INFO_THROW(__lgr__, __expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG_THROW(__lgr__, __expr__, aimrt::common::util::kLogLevelInfo, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_CHECK_WARN_THROW(__lgr__, __expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG_THROW(__lgr__, __expr__, aimrt::common::util::kLogLevelWarn, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_CHECK_ERROR_THROW(__lgr__, __expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG_THROW(__lgr__, __expr__, aimrt::common::util::kLogLevelError, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_HL_CHECK_FATAL_THROW(__lgr__, __expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG_THROW(__lgr__, __expr__, aimrt::common::util::kLogLevelFatal, __fmt__, ##__VA_ARGS__)
|
|
|
|
/// Log with the default logger handle in current scope
|
|
#ifndef AIMRT_DEFAULT_LOGGER_HANDLE
|
|
#define AIMRT_DEFAULT_LOGGER_HANDLE GetLogger()
|
|
#endif
|
|
|
|
#define AIMRT_TRACE(__fmt__, ...) \
|
|
AIMRT_HANDLE_LOG(AIMRT_DEFAULT_LOGGER_HANDLE, aimrt::common::util::kLogLevelTrace, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_DEBUG(__fmt__, ...) \
|
|
AIMRT_HANDLE_LOG(AIMRT_DEFAULT_LOGGER_HANDLE, aimrt::common::util::kLogLevelDebug, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_INFO(__fmt__, ...) \
|
|
AIMRT_HANDLE_LOG(AIMRT_DEFAULT_LOGGER_HANDLE, aimrt::common::util::kLogLevelInfo, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_WARN(__fmt__, ...) \
|
|
AIMRT_HANDLE_LOG(AIMRT_DEFAULT_LOGGER_HANDLE, aimrt::common::util::kLogLevelWarn, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_ERROR(__fmt__, ...) \
|
|
AIMRT_HANDLE_LOG(AIMRT_DEFAULT_LOGGER_HANDLE, aimrt::common::util::kLogLevelError, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_FATAL(__fmt__, ...) \
|
|
AIMRT_HANDLE_LOG(AIMRT_DEFAULT_LOGGER_HANDLE, aimrt::common::util::kLogLevelFatal, __fmt__, ##__VA_ARGS__)
|
|
|
|
#define AIMRT_CHECK_TRACE(__expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG(AIMRT_DEFAULT_LOGGER_HANDLE, __expr__, aimrt::common::util::kLogLevelTrace, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_CHECK_DEBUG(__expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG(AIMRT_DEFAULT_LOGGER_HANDLE, __expr__, aimrt::common::util::kLogLevelDebug, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_CHECK_INFO(__expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG(AIMRT_DEFAULT_LOGGER_HANDLE, __expr__, aimrt::common::util::kLogLevelInfo, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_CHECK_WARN(__expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG(AIMRT_DEFAULT_LOGGER_HANDLE, __expr__, aimrt::common::util::kLogLevelWarn, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_CHECK_ERROR(__expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG(AIMRT_DEFAULT_LOGGER_HANDLE, __expr__, aimrt::common::util::kLogLevelError, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_CHECK_FATAL(__expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG(AIMRT_DEFAULT_LOGGER_HANDLE, __expr__, aimrt::common::util::kLogLevelFatal, __fmt__, ##__VA_ARGS__)
|
|
|
|
#define AIMRT_TRACE_THROW(__fmt__, ...) \
|
|
AIMRT_HANDLE_LOG_THROW(AIMRT_DEFAULT_LOGGER_HANDLE, aimrt::common::util::kLogLevelTrace, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_DEBUG_THROW(__fmt__, ...) \
|
|
AIMRT_HANDLE_LOG_THROW(AIMRT_DEFAULT_LOGGER_HANDLE, aimrt::common::util::kLogLevelDebug, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_INFO_THROW(__fmt__, ...) \
|
|
AIMRT_HANDLE_LOG_THROW(AIMRT_DEFAULT_LOGGER_HANDLE, aimrt::common::util::kLogLevelInfo, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_WARN_THROW(__fmt__, ...) \
|
|
AIMRT_HANDLE_LOG_THROW(AIMRT_DEFAULT_LOGGER_HANDLE, aimrt::common::util::kLogLevelWarn, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_ERROR_THROW(__fmt__, ...) \
|
|
AIMRT_HANDLE_LOG_THROW(AIMRT_DEFAULT_LOGGER_HANDLE, aimrt::common::util::kLogLevelError, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_FATAL_THROW(__fmt__, ...) \
|
|
AIMRT_HANDLE_LOG_THROW(AIMRT_DEFAULT_LOGGER_HANDLE, aimrt::common::util::kLogLevelFatal, __fmt__, ##__VA_ARGS__)
|
|
|
|
#define AIMRT_CHECK_TRACE_THROW(__expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG_THROW(AIMRT_DEFAULT_LOGGER_HANDLE, __expr__, aimrt::common::util::kLogLevelTrace, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_CHECK_DEBUG_THROW(__expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG_THROW(AIMRT_DEFAULT_LOGGER_HANDLE, __expr__, aimrt::common::util::kLogLevelDebug, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_CHECK_INFO_THROW(__expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG_THROW(AIMRT_DEFAULT_LOGGER_HANDLE, __expr__, aimrt::common::util::kLogLevelInfo, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_CHECK_WARN_THROW(__expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG_THROW(AIMRT_DEFAULT_LOGGER_HANDLE, __expr__, aimrt::common::util::kLogLevelWarn, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_CHECK_ERROR_THROW(__expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG_THROW(AIMRT_DEFAULT_LOGGER_HANDLE, __expr__, aimrt::common::util::kLogLevelError, __fmt__, ##__VA_ARGS__)
|
|
#define AIMRT_CHECK_FATAL_THROW(__expr__, __fmt__, ...) \
|
|
AIMRT_HANDLE_CHECK_LOG_THROW(AIMRT_DEFAULT_LOGGER_HANDLE, __expr__, aimrt::common::util::kLogLevelFatal, __fmt__, ##__VA_ARGS__)
|