1 #pragma once
2 
3 #ifndef LOG_H_SPSC31OG
4 #define LOG_H_SPSC31OG
5 
6 #ifdef RPCLIB_ENABLE_LOGGING
7 
8 #include "format.h"
9 #include <chrono>
10 #include <cstdlib>
11 #include <iomanip>
12 #include <mutex>
13 #include <sstream>
14 
15 #include <inttypes.h>
16 #include <math.h>
17 #include <stdio.h>
18 #include <time.h>
19 
20 #ifdef _MSC_VER
21 #include <Windows.h>
22 #endif
23 
24 namespace rpc {
25 namespace detail {
26 class logger {
27 public:
instance()28     static logger &instance() {
29         static logger inst;
30         return inst;
31     }
32 
33     template <typename... Args>
trace(const char * channel,const char * file,const char * func,std::size_t line,const char * msg,Args...args)34     void trace(const char *channel, const char *file, const char *func,
35                std::size_t line, const char *msg, Args... args) {
36         (void)func;
37         basic_log("TRACE", channel,
38                   RPCLIB_FMT::format("{} ({}:{})",
39                                      RPCLIB_FMT::format(msg, args...), file,
40                                      line));
41     }
42 
43     template <typename... Args>
debug(const char * channel,const char * file,const char * func,std::size_t line,const char * msg,Args...args)44     void debug(const char *channel, const char *file, const char *func,
45                std::size_t line, const char *msg, Args... args) {
46         (void)func;
47         basic_log("DEBUG", channel,
48                   RPCLIB_FMT::format("{} ({}:{})",
49                                      RPCLIB_FMT::format(msg, args...), file,
50                                      line));
51     }
52 
53     template <typename... Args>
warn(const char * channel,const char * msg,Args...args)54     void warn(const char *channel, const char *msg, Args... args) {
55         basic_log("WARN", channel, RPCLIB_FMT::format(msg, args...));
56     }
57 
58     template <typename... Args>
error(const char * channel,const char * msg,Args...args)59     void error(const char *channel, const char *msg, Args... args) {
60         basic_log("ERROR", channel, RPCLIB_FMT::format(msg, args...));
61     }
62 
63     template <typename... Args>
info(const char * channel,const char * msg,Args...args)64     void info(const char *channel, const char *msg, Args... args) {
65         basic_log("INFO", channel, RPCLIB_FMT::format(msg, args...));
66     }
67 
68 private:
logger()69     logger() {}
70 
71 #ifdef _MSC_VER
now()72     static std::string now() {
73         std::stringstream ss;
74         SYSTEMTIME t;
75         GetSystemTime(&t);
76         ss << RPCLIB_FMT::format("{}-{}-{} {}:{}:{}.{:03}", t.wYear, t.wMonth,
77                                  t.wDay, t.wHour, t.wMinute, t.wSecond,
78                                  t.wMilliseconds);
79         return ss.str();
80     }
81 #else
now()82     static std::string now() {
83         std::stringstream ss;
84         timespec now_t = {};
85         clock_gettime(CLOCK_REALTIME, &now_t);
86         ss << std::put_time(
87                   std::localtime(reinterpret_cast<time_t *>(&now_t.tv_sec)),
88                   "%F %T")
89            << RPCLIB_FMT::format(
90                   ".{:03}", round(static_cast<double>(now_t.tv_nsec) / 1.0e6));
91         return ss.str();
92     }
93 #endif
94 
basic_log(const char * severity,const char * channel,std::string const & msg)95     void basic_log(const char *severity, const char *channel,
96                    std::string const &msg) {
97         using RPCLIB_FMT::arg;
98         std::lock_guard<std::mutex> lock(mut_print_);
99         RPCLIB_FMT::print("{time:16}  {severity:6}  {channel:12}    {msg:40}\n",
100                           arg("severity", severity), arg("channel", channel),
101                           arg("time", now()), arg("msg", msg));
102     }
103 
104 private:
105     std::mutex mut_print_;
106 };
107 } /* detail */
108 } /* rpc */
109 
110 #ifdef _MSC_VER
111 #define RPCLIB_CREATE_LOG_CHANNEL(Name)                                        \
112     static constexpr const char *rpc_channel_name = #Name;
113 #elif defined(__GNUC__)
114 #define RPCLIB_CREATE_LOG_CHANNEL(Name)                                        \
115     _Pragma("GCC diagnostic push")                                            \
116     _Pragma("GCC diagnostic ignored \"-Wunused-variable\"")                       \
117     static constexpr const char *rpc_channel_name = #Name;                  \
118     _Pragma("GCC diagnostic pop")
119 #elif defined(__clang__)
120     _Pragma("clang diagnostic push")                                            \
121     _Pragma("clang diagnostic ignored \"-Wunused-variable\"")                       \
122     static constexpr const char *rpc_channel_name = #Name;                  \
123     _Pragma("clang diagnostic pop")
124 #endif
125 
126 RPCLIB_CREATE_LOG_CHANNEL(global)
127 
128 #define LOG_INFO(...)                                                          \
129     rpc::detail::logger::instance().info(rpc_channel_name, __VA_ARGS__)
130 
131 #define LOG_WARN(...)                                                          \
132     rpc::detail::logger::instance().warn(rpc_channel_name, __VA_ARGS__)
133 
134 #define LOG_ERROR(...)                                                         \
135     rpc::detail::logger::instance().error(rpc_channel_name, __VA_ARGS__)
136 
137 #define LOG_DEBUG(...)                                                         \
138     rpc::detail::logger::instance().debug(rpc_channel_name, __FILE__,    \
139                                              __func__, __LINE__, __VA_ARGS__)
140 
141 #define LOG_TRACE(...)                                                         \
142     rpc::detail::logger::instance().trace(rpc_channel_name, __FILE__,    \
143                                              __func__, __LINE__, __VA_ARGS__)
144 
145 #define LOG_EXPR(Level, Expr) LOG_##Level("`" #Expr "` = {}", Expr)
146 
147 #else
148 
149 #define LOG_INFO(...)
150 #define LOG_WARN(...)
151 #define LOG_ERROR(...)
152 #define LOG_DEBUG(...)
153 #define LOG_TRACE(...)
154 #define LOG_EXPR(...)
155 #define RPCLIB_CREATE_LOG_CHANNEL(...)
156 
157 #endif
158 
159 #endif /* end of include guard: LOG_H_SPSC31OG */
160