rogue
Loading...
Searching...
No Matches
Logging.cpp
Go to the documentation of this file.
1
17#include "rogue/Directives.h"
18
19#include "rogue/Logging.h"
20#include "rogue/ScopedGil.h"
21
22#include <inttypes.h>
23#include <stdarg.h>
24#include <sys/time.h>
25#include <unistd.h>
26
27#include <cstdio>
28#include <cstring>
29#include <memory>
30#include <string>
31#include <vector>
32
33#if defined(__linux__)
34 #include <sys/syscall.h>
35#elif defined(__APPLE__) && defined(__MACH__)
36 #include <pthread.h>
37#endif
38
39#ifndef NO_PYTHON
40 #include <boost/python.hpp>
41namespace bp = boost::python;
42#endif
43
44namespace {
45uint32_t currentThreadId() {
46#if defined(__linux__)
47 return syscall(SYS_gettid);
48#elif defined(__APPLE__) && defined(__MACH__)
49 uint64_t tid64;
50 pthread_threadid_np(NULL, &tid64);
51 return static_cast<uint32_t>(tid64);
52#else
53 return 0;
54#endif
55}
56
57std::string loggerComponent(const std::string& name) {
58 const std::string prefix = "pyrogue.";
59 size_t start = 0;
60 size_t end;
61
62 if (name.rfind(prefix, 0) == 0) start = prefix.size();
63 end = name.find('.', start);
64 if (end == std::string::npos) return name.substr(start);
65 return name.substr(start, end - start);
66}
67} // namespace
68
69const uint32_t rogue::Logging::Critical;
70const uint32_t rogue::Logging::Error;
71const uint32_t rogue::Logging::Thread;
72const uint32_t rogue::Logging::Warning;
73const uint32_t rogue::Logging::Info;
74const uint32_t rogue::Logging::Debug;
75
76// Default Logging level Is Error
77uint32_t rogue::Logging::gblLevel_ = rogue::Logging::Error;
78
79// Logging level lock
80std::mutex rogue::Logging::levelMtx_;
81
82// Filter list
83std::vector<rogue::LogFilter*> rogue::Logging::filters_;
84
85// Active loggers
86std::vector<rogue::Logging*> rogue::Logging::loggers_;
87
88// Python forwarding enable
89bool rogue::Logging::forwardPython_ = false;
90
91// Stdout emission enable
92bool rogue::Logging::emitStdout_ = true;
93
94// Crate logger
95rogue::LoggingPtr rogue::Logging::create(const std::string& name, bool quiet) {
96 rogue::LoggingPtr log = std::make_shared<rogue::Logging>(name, quiet);
97 return log;
98}
99
100std::string rogue::Logging::normalizeName(const std::string& name) {
101 if (name.rfind("pyrogue.", 0) == 0) return name;
102 if (name == "pyrogue") return name;
103 return "pyrogue." + name;
104}
105
106rogue::Logging::Logging(const std::string& name, bool quiet) {
107 name_ = normalizeName(name);
108
109 levelMtx_.lock();
110 updateLevelLocked();
111 loggers_.push_back(this);
112 levelMtx_.unlock();
113
114 if (!quiet) warning("Starting logger with level = %" PRIu32, level_.load());
115}
116
118 std::vector<rogue::Logging*>::iterator it;
119
120 levelMtx_.lock();
121 for (it = loggers_.begin(); it < loggers_.end(); ++it) {
122 if (*it == this) {
123 loggers_.erase(it);
124 break;
125 }
126 }
127 levelMtx_.unlock();
128}
129
130void rogue::Logging::updateLevelLocked() {
131 std::vector<rogue::LogFilter*>::iterator it;
132 uint32_t level = gblLevel_;
133
134 for (it = filters_.begin(); it < filters_.end(); ++it) {
135 if (name_.find((*it)->name_) == 0) {
136 if ((*it)->level_ < level) level = (*it)->level_;
137 }
138 }
139
140 level_.store(level);
141}
142
143void rogue::Logging::setLevel(uint32_t level) {
144 std::vector<rogue::Logging*>::iterator it;
145
146 levelMtx_.lock();
147 gblLevel_ = level;
148 for (it = loggers_.begin(); it < loggers_.end(); ++it) (*it)->updateLevelLocked();
149 levelMtx_.unlock();
150}
151
152void rogue::Logging::setFilter(const std::string& name, uint32_t level) {
153 std::vector<rogue::Logging*>::iterator it;
154
155 levelMtx_.lock();
156
157 rogue::LogFilter* flt = new rogue::LogFilter(normalizeName(name), level);
158
159 filters_.push_back(flt);
160
161 for (it = loggers_.begin(); it < loggers_.end(); ++it) (*it)->updateLevelLocked();
162
163 levelMtx_.unlock();
164}
165
167 levelMtx_.lock();
168 forwardPython_ = enable;
169 levelMtx_.unlock();
170}
171
173 bool enable;
174 levelMtx_.lock();
175 enable = forwardPython_;
176 levelMtx_.unlock();
177 return enable;
178}
179
181 levelMtx_.lock();
182 emitStdout_ = enable;
183 levelMtx_.unlock();
184}
185
187 bool enable;
188 levelMtx_.lock();
189 enable = emitStdout_;
190 levelMtx_.unlock();
191 return enable;
192}
193
194void rogue::Logging::intLog(uint32_t level, const char* fmt, va_list args) {
195 if (level < level_.load()) return;
196
197 struct timeval tme;
198 char buffer[1000];
199 vsnprintf(buffer, sizeof(buffer), fmt, args);
200 gettimeofday(&tme, NULL);
201 if (emitStdout()) {
202 printf("%" PRIi64 ".%06" PRIi64 ":%s: %s\n",
203 static_cast<int64_t>(tme.tv_sec),
204 static_cast<int64_t>(tme.tv_usec),
205 name_.c_str(),
206 buffer);
207 }
208
209#ifndef NO_PYTHON
210 if (forwardPython()) {
212 try {
213 bp::object logging = bp::import("logging");
214 bp::object logger = logging.attr("getLogger")(name_);
215
216 if (bp::extract<bool>(logger.attr("isEnabledFor")(level))) {
217 bp::dict record;
218 uint32_t tid = currentThreadId();
219 uint32_t pid = static_cast<uint32_t>(getpid());
220 double created = static_cast<double>(tme.tv_sec) + (static_cast<double>(tme.tv_usec) / 1000000.0);
221 std::string component = loggerComponent(name_);
222
223 record["name"] = name_;
224 record["msg"] = buffer;
225 record["args"] = bp::tuple();
226 record["levelno"] = level;
227 record["levelname"] = logging.attr("getLevelName")(level);
228 record["pathname"] = "<rogue>";
229 record["filename"] = "<rogue>";
230 record["module"] = "rogue";
231 record["exc_info"] = bp::object();
232 record["exc_text"] = bp::object();
233 record["stack_info"] = bp::object();
234 record["lineno"] = 0;
235 record["funcName"] = "<rogue>";
236 record["created"] = created;
237 record["msecs"] = static_cast<double>(tme.tv_usec) / 1000.0;
238 record["relativeCreated"] = 0.0;
239 record["thread"] = tid;
240 record["threadName"] = "rogue";
241 record["process"] = pid;
242 record["processName"] = "rogue";
243 record["rogue_cpp"] = true;
244 record["rogue_tid"] = tid;
245 record["rogue_pid"] = pid;
246 record["rogue_logger"] = name_;
247 record["rogue_timestamp"] = created;
248 record["rogue_component"] = component;
249
250 logger.attr("handle")(logging.attr("makeLogRecord")(record));
251 }
252 } catch (const bp::error_already_set&) {
253 PyErr_Print();
254 }
255 }
256#endif
257}
258
259void rogue::Logging::log(uint32_t level, const char* fmt, ...) {
260 va_list arg;
261 va_start(arg, fmt);
262 intLog(level, fmt, arg);
263 va_end(arg);
264}
265
266void rogue::Logging::critical(const char* fmt, ...) {
267 va_list arg;
268 va_start(arg, fmt);
269 intLog(rogue::Logging::Critical, fmt, arg);
270 va_end(arg);
271}
272
273void rogue::Logging::error(const char* fmt, ...) {
274 va_list arg;
275 va_start(arg, fmt);
276 intLog(rogue::Logging::Error, fmt, arg);
277 va_end(arg);
278}
279
280void rogue::Logging::warning(const char* fmt, ...) {
281 va_list arg;
282 va_start(arg, fmt);
283 intLog(rogue::Logging::Warning, fmt, arg);
284 va_end(arg);
285}
286
287void rogue::Logging::info(const char* fmt, ...) {
288 va_list arg;
289 va_start(arg, fmt);
290 intLog(rogue::Logging::Info, fmt, arg);
291 va_end(arg);
292}
293
294void rogue::Logging::debug(const char* fmt, ...) {
295 va_list arg;
296 va_start(arg, fmt);
297 intLog(rogue::Logging::Debug, fmt, arg);
298 va_end(arg);
299}
300
302 uint32_t tid = currentThreadId();
303 this->log(Thread, "PID=%" PRIu32 ", TID=%" PRIu32, getpid(), tid);
304}
305
306const std::string& rogue::Logging::name() const {
307 return name_;
308}
309
311#ifndef NO_PYTHON
312 bp::class_<rogue::Logging, rogue::LoggingPtr, boost::noncopyable>("Logging", bp::no_init)
313 .def("setLevel", &rogue::Logging::setLevel)
314 .staticmethod("setLevel")
315 .def("setFilter", &rogue::Logging::setFilter)
316 .staticmethod("setFilter")
317 .def("setForwardPython", &rogue::Logging::setForwardPython)
318 .staticmethod("setForwardPython")
319 .def("forwardPython", &rogue::Logging::forwardPython)
320 .staticmethod("forwardPython")
321 .def("setEmitStdout", &rogue::Logging::setEmitStdout)
322 .staticmethod("setEmitStdout")
323 .def("emitStdout", &rogue::Logging::emitStdout)
324 .staticmethod("emitStdout")
325 .def("normalizeName", &rogue::Logging::normalizeName)
326 .staticmethod("normalizeName")
327 .def_readonly("Critical", &rogue::Logging::Critical)
328 .def_readonly("Error", &rogue::Logging::Error)
329 .def_readonly("Thread", &rogue::Logging::Thread)
330 .def_readonly("Warning", &rogue::Logging::Warning)
331 .def_readonly("Info", &rogue::Logging::Info)
332 .def_readonly("Debug", &rogue::Logging::Debug)
333 .def("name", &rogue::Logging::name, bp::return_value_policy<bp::copy_const_reference>());
334#endif
335}
Per-logger level override filter entry.
Definition Logging.h:34
~Logging()
Destroys the logger instance.
Definition Logging.cpp:117
void info(const char *fmt,...)
Emits a formatted message at Info level.
Definition Logging.cpp:287
static const uint32_t Thread
Thread-trace severity level constant.
Definition Logging.h:94
static void setEmitStdout(bool enable)
Enables or disables direct stdout emission of Rogue C++ logs.
Definition Logging.cpp:180
static bool forwardPython()
Returns whether Rogue C++ logs are currently forwarded to Python logging.
Definition Logging.cpp:172
void logThreadId()
Emits the current thread id through this logger.
Definition Logging.cpp:301
static void setup_python()
Registers Python bindings for Logging.
Definition Logging.cpp:310
Logging(const std::string &name, bool quiet=false)
Constructs a logger.
Definition Logging.cpp:106
static std::shared_ptr< rogue::Logging > create(const std::string &name, bool quiet=false)
Creates a logger instance.
Definition Logging.cpp:95
static void setForwardPython(bool enable)
Enables or disables forwarding Rogue C++ logs into Python logging.
Definition Logging.cpp:166
static bool emitStdout()
Returns whether Rogue C++ logs are currently emitted to stdout.
Definition Logging.cpp:186
static void setFilter(const std::string &filter, uint32_t level)
Sets name-based filter level override.
Definition Logging.cpp:152
void warning(const char *fmt,...)
Emits a formatted message at Warning level.
Definition Logging.cpp:280
const std::string & name() const
Returns the fully-qualified emitted logger name.
Definition Logging.cpp:306
static const uint32_t Debug
Debug severity level constant.
Definition Logging.h:100
void log(uint32_t level, const char *fmt,...)
Emits a formatted log message at a specified level.
Definition Logging.cpp:259
static const uint32_t Error
Error severity level constant.
Definition Logging.h:92
static const uint32_t Info
Informational severity level constant.
Definition Logging.h:98
static std::string normalizeName(const std::string &name)
Normalizes logger names to the emitted Rogue namespace.
Definition Logging.cpp:100
static const uint32_t Warning
Warning severity level constant.
Definition Logging.h:96
static void setLevel(uint32_t level)
Sets the global default logging level.
Definition Logging.cpp:143
void critical(const char *fmt,...)
Emits a formatted message at Critical level.
Definition Logging.cpp:266
void debug(const char *fmt,...)
Emits a formatted message at Debug level.
Definition Logging.cpp:294
static const uint32_t Critical
Critical severity level constant.
Definition Logging.h:90
void error(const char *fmt,...)
Emits a formatted message at Error level.
Definition Logging.cpp:273
RAII helper that acquires the Python GIL for a scope.
Definition ScopedGil.h:35
std::shared_ptr< rogue::Logging > LoggingPtr
Shared pointer alias for Logging.
Definition Logging.h:205