1 #pragma once
2 
3 #include <cstdio>
4 #include <map>
5 #include <string>
6 #include <thread>
7 #include <utility>
8 
9 #include "common.hpp"
10 #include "settings.hpp"
11 
12 #ifndef STDOUT_FILENO
13 #define STDOUT_FILENO 1
14 #endif
15 #ifndef STDERR_FILENO
16 #define STDERR_FILENO 2
17 #endif
18 
19 POLYBAR_NS
20 
21 enum class loglevel {
22   NONE = 0,
23   ERROR,
24   WARNING,
25   NOTICE,
26   INFO,
27   TRACE,
28 };
29 
30 class logger {
31  public:
32   using make_type = const logger&;
33   static make_type make(loglevel level = loglevel::NONE);
34 
35   explicit logger(loglevel level);
36 
37   static loglevel parse_verbosity(const string& name, loglevel fallback = loglevel::NONE);
38 
39   void verbosity(loglevel level);
40 
41 #ifdef DEBUG_LOGGER  // {{{
42   template <typename... Args>
trace(const string & message,Args &&...args) const43   void trace(const string& message, Args&&... args) const {
44     output(loglevel::TRACE, message, std::forward<Args>(args)...);
45   }
46 #ifdef DEBUG_LOGGER_VERBOSE
47   template <typename... Args>
trace_x(const string & message,Args &&...args) const48   void trace_x(const string& message, Args&&... args) const {
49     output(loglevel::TRACE, message, std::forward<Args>(args)...);
50   }
51 #else
52   template <typename... Args>
trace_x(Args &&...) const53   void trace_x(Args&&...) const {}
54 #endif
55 #else
56   template <typename... Args>
trace(Args &&...) const57   void trace(Args&&...) const {}
58   template <typename... Args>
trace_x(Args &&...) const59   void trace_x(Args&&...) const {}
60 #endif  // }}}
61 
62   /**
63    * Output an info message
64    */
65   template <typename... Args>
info(const string & message,Args &&...args) const66   void info(const string& message, Args&&... args) const {
67     output(loglevel::INFO, message, std::forward<Args>(args)...);
68   }
69 
70   /**
71    * Output a notice
72    */
73   template <typename... Args>
notice(const string & message,Args &&...args) const74   void notice(const string& message, Args&&... args) const {
75     output(loglevel::NOTICE, message, std::forward<Args>(args)...);
76   }
77 
78   /**
79    * Output a warning message
80    */
81   template <typename... Args>
warn(const string & message,Args &&...args) const82   void warn(const string& message, Args&&... args) const {
83     output(loglevel::WARNING, message, std::forward<Args>(args)...);
84   }
85 
86   /**
87    * Output an error message
88    */
89   template <typename... Args>
err(const string & message,Args &&...args) const90   void err(const string& message, Args&&... args) const {
91     output(loglevel::ERROR, message, std::forward<Args>(args)...);
92   }
93 
94  protected:
95   template <typename T>
convert(T && arg) const96   decltype(auto) convert(T&& arg) const {
97     return forward<T>(arg);
98   }
99 
100   /**
101    * Convert string
102    */
103   const char* convert(string& arg) const;
104   const char* convert(const string& arg) const;
105 
106   /**
107    * Convert thread id
108    */
109   size_t convert(std::thread::id arg) const;
110 
111   /**
112    * Write the log message to the output channel
113    * if the defined verbosity level allows it
114    */
115   template <typename... Args>
output(loglevel level,const string & format,Args &&...values) const116   void output(loglevel level, const string& format, Args&&... values) const {
117     if (level > m_level) {
118       return;
119     }
120 
121 #if defined(__clang__)  // {{{
122 #pragma clang diagnostic push
123 #pragma clang diagnostic ignored "-Wformat-security"
124 #elif defined(__GNUC__)
125 #pragma GCC diagnostic push
126 #pragma GCC diagnostic ignored "-Wformat-security"
127 #endif  // }}}
128 
129     dprintf(m_fd, (m_prefixes.at(level) + format + m_suffixes.at(level) + "\n").c_str(), convert(values)...);
130 
131 #if defined(__clang__)  // {{{
132 #pragma clang diagnostic pop
133 #elif defined(__GNUC__)
134 #pragma GCC diagnostic pop
135 #endif  // }}}
136   }
137 
138  private:
139   /**
140    * Logger verbosity level
141    */
142   loglevel m_level{loglevel::TRACE};
143 
144   /**
145    * File descriptor used when writing the log messages
146    */
147   int m_fd{STDERR_FILENO};
148 
149   /**
150    * Loglevel specific prefixes
151    */
152   std::map<loglevel, string> m_prefixes;
153 
154   /**
155    * Loglevel specific suffixes
156    */
157   std::map<loglevel, string> m_suffixes;
158 };
159 
160 POLYBAR_NS_END
161