yalantinglibs/include/easylog/record.hpp

204 lines
5.4 KiB
C++

/*
* Copyright (c) 2023, Alibaba Group Holding Limited;
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <charconv>
#include <chrono>
#include <cstring>
#include <type_traits>
#ifdef __linux__
#include <sys/syscall.h>
#include <unistd.h>
#endif
#if __has_include(<memory_resource>)
#include <memory_resource>
#endif
#include <sstream>
#include <string>
#include <string_view>
#include <util/meta_string.hpp>
#include <utility>
#include "iguana/detail/dragonbox_to_chars.h"
#if defined(_WIN32)
#ifndef _WINDOWS_
#ifndef WIN32_LEAN_AND_MEAN // Sorry for the inconvenience. Please include any
// related headers you need manually.
// (https://stackoverflow.com/a/8294669)
#define WIN32_LEAN_AND_MEAN // Prevent inclusion of WinSock2.h
#endif
#include <Windows.h> // Force inclusion of WinGDI here to resolve name conflict
#endif
#ifdef ERROR // Should be true unless someone else undef'd it already
#undef ERROR // Windows GDI defines this macro; make it a global enum so it
// doesn't conflict with our code
enum { ERROR = 0 };
#endif
#endif
enum class Severity {
NONE = 0,
TRACE = 1,
DEBUG = 2,
INFO = 3,
WARN = 4,
ERROR = 5,
CRITICAL = 6,
};
namespace easylog {
inline std::string_view severity_str(Severity severity) {
switch (severity) {
case Severity::TRACE:
return "TRACE ";
case Severity::DEBUG:
return "DEBUG ";
case Severity::INFO:
return "INFO ";
case Severity::WARN:
return "WARNING ";
case Severity::ERROR:
return "ERROR ";
case Severity::CRITICAL:
return "CRITICAL";
default:
return "NONE";
}
}
class record_t {
public:
record_t(auto tm_point, Severity severity, auto str)
: tm_point_(tm_point), severity_(severity), tid_(get_tid_impl()) {
std::memcpy(buf_, str.data(), str.size());
buf_len_ = str.size();
}
Severity get_severity() const { return severity_; }
const char *get_message() const { return ss_.data(); }
std::string_view get_file_str() const { return {buf_, buf_len_}; }
unsigned int get_tid() const { return tid_; }
auto get_time_point() const { return tm_point_; }
record_t &ref() { return *this; }
template <typename T>
record_t &operator<<(const T &data) {
using U = std::remove_cvref_t<T>;
if constexpr (std::is_floating_point_v<U>) {
char temp[40];
const auto end = jkj::dragonbox::to_chars(data, temp);
ss_.append(temp, std::distance(temp, end));
}
else if constexpr (std::is_same_v<char, U>) {
ss_.push_back(data);
}
else if constexpr (std::is_enum_v<U>) {
int val = (int)data;
*this << val;
}
else if constexpr (std::is_integral_v<U>) {
char buf[32];
auto [ptr, ec] = std::to_chars(buf, buf + 32, data);
ss_.append(buf, std::distance(buf, ptr));
}
else {
ss_.append(data);
}
return *this;
}
template <typename... Args>
record_t &sprintf(const char *fmt, Args... args) {
printf_string_format(fmt, args...);
return *this;
}
private:
template <typename... Args>
void printf_string_format(const char *fmt, Args... args) {
size_t size = snprintf(nullptr, 0, fmt, args...);
#if __has_include(<memory_resource>)
char arr[1024];
std::pmr::monotonic_buffer_resource resource(arr, 1024);
std::pmr::string buf{&resource};
#else
std::string buf;
#endif
buf.reserve(size + 1);
buf.resize(size);
snprintf(&buf[0], size + 1, fmt, args...);
ss_.append(buf);
}
unsigned int get_tid_impl() {
#ifdef _WIN32
return std::hash<std::thread::id>{}(std::this_thread::get_id());
#elif defined(__linux__)
return static_cast<unsigned int>(::syscall(__NR_gettid));
#elif defined(__FreeBSD__)
long tid;
syscall(SYS_thr_self, &tid);
return static_cast<unsigned int>(tid);
#elif defined(__rtems__)
return rtems_task_self();
#elif defined(__APPLE__)
uint64_t tid64;
pthread_threadid_np(NULL, &tid64);
return static_cast<unsigned int>(tid64);
#else
return 0;
#endif
}
std::chrono::system_clock::time_point tm_point_;
Severity severity_;
unsigned int tid_;
char buf_[64] = {};
size_t buf_len_ = 0;
#if __has_include(<memory_resource>)
char arr_[1024];
std::pmr::monotonic_buffer_resource resource_;
std::pmr::string ss_{&resource_};
#else
std::string ss_;
#endif
};
#define TO_STR(s) #s
#define GET_STRING(filename, line) \
[] { \
constexpr auto path = refvalue::meta_string{filename}; \
constexpr size_t pos = \
path.rfind(std::filesystem::path::preferred_separator); \
constexpr auto name = path.substr<pos + 1>(); \
constexpr auto prefix = name + ":" + TO_STR(line); \
return "[" + prefix + "] "; \
}()
} // namespace easylog