ztsdb
logging.hpp
1 // (C) 2016 Leonardo Silvestri
2 //
3 // This file is part of ztsdb.
4 //
5 // ztsdb is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // ztsdb is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with ztsdb. If not, see <http://www.gnu.org/licenses/>.
17 
18 
19 #ifndef LOGGING_HPP
20 #define LOGGING_HPP
21 
22 
23 #include <cstdio>
24 #include <cstdarg>
25 #include <mutex>
26 #include "timezone/ztime.hpp"
27 
28 
29 extern tz::Zones tzones;
30 
31 
32 using namespace std::string_literals;
33 
34 
35 namespace zlog {
36 
37  enum Severity {
38  SV_TRACE,
39  SV_DEBUG,
40  SV_INFO,
41  SV_WARN,
42  SV_ERROR,
43  SV_FATAL
44  };
45 
46 
47  inline const char* to_string(Severity sv) {
48  static const char* svstr[] = {
49  "TRACE",
50  "DEBUG",
51  "INFO",
52  "WARN",
53  "ERROR",
54  "FATAL"
55  };
56  return static_cast<std::size_t>(sv) < sizeof(svstr)/sizeof(svstr[0]) ?
57  svstr[static_cast<int>(sv)] : "unknown";
58  }
59 
60  inline Severity from_string(const std::string& s) {
61  if (s == "TRACE"s) return SV_TRACE;
62  if (s == "DEBUG"s) return SV_DEBUG;
63  if (s == "INFO"s) return SV_INFO;
64  if (s == "WARN"s) return SV_WARN;
65  if (s == "ERROR"s) return SV_ERROR;
66  if (s == "FATAL"s) return SV_FATAL;
67  throw std::range_error("unknown severity string");
68  }
69 
70  // Besides severity filtering, we could also implement tag
71  // filtering, so we then have the possibility to enable logging only
72  // for specific (tagged) modules. For the moment we rely on local
73  // '#define" for debug information (which gets compiled out).
74 
77  struct Logger {
78  Logger() : f(nullptr), level(SV_TRACE), tz("GMT") { }
79  Logger(const std::string& s, const std::string& tz_p) : level(SV_TRACE) {
80  init(s, tz_p);
81  }
82 
83  inline void init(const std::string& s, const std::string& tz_p) {
84  f = fopen(s.c_str(), "a");
85  if (f == nullptr) {
86  throw std::system_error(std::error_code(errno, std::system_category()),
87  "cannot open log file");
88  }
89  tz = tz_p;
90  }
91 
92  inline void uninit() {
93  if (f) {
94  fflush(f);
95  fclose(f);
96  f = nullptr;
97  }
98  tz = "GMT";
99  }
100 
103  inline int changeFile(const std::string& s) {
104  if (f) {
105  fclose(f);
106  f = nullptr;
107  }
108  if (!s.empty()) {
109  f = fopen(s.c_str(), "a");
110  if (f == nullptr) {
111  return errno;
112  }
113  }
114  return 0;
115  }
116 
117  inline int log(Severity sv, const char* fmt, ...) {
118  if (sv >= level) {
119  va_list ap;
120  va_start(ap, fmt);
121  std::string tm = tz::to_string(std::chrono::system_clock::now(),
122  "", tzones.find(tz), tz, true);
123  static char str[BUFLEN];
124  mx.lock(); // to protect 'str'
125  vsnprintf(str, BUFLEN, fmt, ap);
126  int res = f ?
127  fprintf(f, "%s [%s]: %s\n", tm.c_str(), to_string(sv), str) :
128  printf("%s [%s]: %s\n", tm.c_str(), to_string(sv), str);
129  if (f) fflush(f); // because apparently, in C++ with
130  // gcc/CLANG, flush doesn't
131  // automatically occur after newline
132  mx.unlock();
133  va_end(ap);
134  return res;
135  }
136  else {
137  return 0;
138  }
139  }
140 
141  inline void setLevel(Severity sv) { level = sv; }
142 
143  ~Logger() {
144  uninit();
145  }
146 
147  inline Severity from_string(const std::string& s) {
148  if (s == "TRACE"s) return SV_TRACE;
149  if (s == "DEBUG"s) return SV_DEBUG;
150  if (s == "INFO"s) return SV_INFO;
151  if (s == "WARN"s) return SV_WARN;
152  if (s == "ERROR"s) return SV_ERROR;
153  if (s == "FATAL"s) return SV_FATAL;
154  throw std::range_error("unknown severity string");
155  }
156 
157  private:
158  FILE* f;
159  Severity level;
160  std::mutex mx;
161  std::string tz;
162  static const int BUFLEN = 512;
163  };
164 
165 
166 }
167 
168 #endif
zlog::Logger
Definition: logging.hpp:77
tz
Timezone handling and temporal types and functions depending on timezones.
Definition: period.hpp:28
zlog::Logger::changeFile
int changeFile(const std::string &s)
Definition: logging.hpp:103
tz::Zones
Definition: zone.hpp:66