31#include <condition_variable>
48#include <netinet/ip.h>
52#include <sys/socket.h>
60#define OAK_DEBUG(...) oak::log(oak::level::debug, __VA_ARGS__)
61#define OAK_INFO(...) oak::log(oak::level::info, __VA_ARGS__)
62#define OAK_WARN(...) oak::log(oak::level::warn, __VA_ARGS__)
63#define OAK_ERROR(...) oak::log(oak::level::error, __VA_ARGS__)
64#define OAK_OUTPUT(...) oak::log(oak::level::output, __VA_ARGS__)
126#ifdef OAK_USE_SOCKETS
127 static int log_socket;
159#ifdef OAK_USE_SOCKETS
171 if (
sizeof...(args) > 0)
200 const std::string &
file);
202template <
typename... Args>
210 std::string prefix =
"";
223 std::vformat(
"\"level\": \"{}\"", std::make_format_args(lvl));
225 prefix += std::vformat(
"level={} ", std::make_format_args(lvl));
229 auto now = std::chrono::system_clock::now();
230 auto now_time_t = std::chrono::system_clock::to_time_t(now);
231 std::tm now_tm = *std::localtime(&now_time_t);
232 std::ostringstream oss;
234 oss <<
", \"date\": \"" << std::put_time(&now_tm,
"%Y-%m-%d")
237 oss <<
"date=" << std::put_time(&now_tm,
"%Y-%m-%d") <<
" ";
242 auto now = std::chrono::system_clock::now();
243 auto now_time_t = std::chrono::system_clock::to_time_t(now);
244 std::tm now_tm = *std::localtime(&now_time_t);
245 std::ostringstream oss;
247 oss <<
", \"time\": \"" << std::put_time(&now_tm,
"%H:%M:%S")
250 oss <<
"time=" << std::put_time(&now_tm,
"%H:%M:%S") <<
" ";
255 std::string
pid = std::to_string(getpid());
257 prefix +=
", \"pid\": " +
pid;
259 prefix += std::vformat(
"pid={} ", std::make_format_args(
pid));
263 std::ostringstream oss;
264 oss << std::this_thread::get_id();
265 std::string
tid = oss.str();
267 prefix +=
", \"tid\": " +
tid;
269 prefix += std::vformat(
"tid={} ", std::make_format_args(
tid));
277 std::string formatted_string =
278 std::vformat(fmt, std::make_format_args(std::forward<Args>(args)...));
280 return std::vformat(
"{}\"message\": \"{}\" }}\n",
281 std::make_format_args(prefix, formatted_string));
282 return std::vformat(
"{}{}\n",
283 std::make_format_args(prefix, formatted_string));
284 }
catch (
const std::exception &e) {
289template <
typename... Args>
303template <
typename... Args>
314#ifdef OAK_USE_SOCKETS
315template <
typename... Args>
316void log_to_socket(
const level &lvl,
const std::string &fmt, Args &&...args)
318 if (
get_level() > lvl || logger::log_socket < 0)
320 std::string formatted_string =
log_to_string(lvl, fmt, args...);
324void log_to_socket(
const std::string &str);
327template <
typename... Args>
328void log(
const level &lvl,
const std::string &fmt, Args &&...args)
332 std::string formatted_string =
log_to_string(lvl, fmt, args...);
336#ifdef OAK_USE_SOCKETS
337 if (logger::log_socket > 0)
338 log_to_socket(formatted_string);
342#ifdef OAK_USE_SOCKETS
344[[nodiscard]] std::expected<int, std::string>
345set_socket(
const std::string &sock_addr);
347[[nodiscard]] std::expected<int, std::string>
348set_socket(
const std::string &addr,
short unsigned int port,
353template <
typename... Args>
354inline void out(
const std::string &fmt, Args &&...args)
359template <
typename... Args>
360inline void debug(
const std::string &fmt, Args &&...args)
365template <
typename... Args>
366inline void info(
const std::string &fmt, Args &&...args)
371template <
typename... Args>
372inline void warn(
const std::string &fmt, Args &&...args)
377template <
typename... Args>
378inline void error(
const std::string &fmt, Args &&...args)
383template <
typename... Args>
384inline void output(
const std::string &fmt, Args &&...args)
389template <
typename... Args>
390inline void async(
const level &lvl,
const std::string &fmt, Args &&...args)
392 (void) std::async([lvl, fmt, args...]() {
log(lvl, fmt, args...); });
399template <>
struct std::formatter<
oak::level>
401 constexpr auto parse(format_parse_context &ctx)
406 template <
typename FormatContext>
412 return format_to(ctx.out(),
"error");
414 return format_to(ctx.out(),
"warn");
416 return format_to(ctx.out(),
"info");
418 return format_to(ctx.out(),
"debug");
420 return format_to(ctx.out(),
"output");
422 return format_to(ctx.out(),
"unknown");
427template <>
struct std::formatter<
oak::flags>
429 constexpr auto parse(format_parse_context &ctx)
434 template <
typename FormatContext>
440 return format_to(ctx.out(),
"none");
442 return format_to(ctx.out(),
"level");
444 return format_to(ctx.out(),
"date");
446 return format_to(ctx.out(),
"time");
448 return format_to(ctx.out(),
"pid");
450 return format_to(ctx.out(),
"tid");
452 return format_to(ctx.out(),
"unknown");
void add_to_queue(const std::string &str, const destination &d)
void out(const std::string &fmt, Args &&...args)
void log_to_stdout(const level &lvl, const std::string &fmt, Args &&...args)
void log_to_file(const level &lvl, const std::string &fmt, Args &&...args)
std::expected< int, std::string > set_file(const std::string &file)
std::expected< int, std::string > settings_file(const std::string &file)
void add_flags(flags flg, Args &&...args)
void set_flags(flags flg, Args &&...args)
void set_level(const oak::level &lvl)
std::string constexpr log_to_string(const level &lvl, const std::string &fmt, Args &&...args)
void async(const level &lvl, const std::string &fmt, Args &&...args)
void log(const level &lvl, const std::string &fmt, Args &&...args)
long unsigned int get_flags()
static std::ofstream log_file
static std::condition_variable log_cv
static std::deque< queue_element > log_queue
static std::optional< std::jthread > writer_thread
static long unsigned int flag_bits
static std::mutex log_mutex
static std::atomic< bool > close_writer
queue_element(const std::string &msg, const oak::destination &d)