Fawkes API Fawkes Development Version
network_logger.cpp
1
2/***************************************************************************
3 * network_logger.cpp - Fawkes network logger
4 *
5 * Created: Sat Dec 15 00:48:52 2007 (after I5 xmas party)
6 * Copyright 2006-2017 Tim Niemueller [www.niemueller.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. A runtime exception applies to
14 * this software (see LICENSE.GPL_WRE file mentioned below for details).
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22 */
23
24#include <core/threading/mutex.h>
25#include <netcomm/fawkes/component_ids.h>
26#include <netcomm/fawkes/hub.h>
27#include <netcomm/utils/ntoh64.h>
28#include <netinet/in.h>
29#include <network_logger/network_logger.h>
30#include <sys/time.h>
31
32#include <cstdio>
33#include <cstdlib>
34#include <cstring>
35#include <time.h>
36
37namespace fawkes {
38
39void
41{
42}
43
44/** @class NetworkLogger <network_logger/network_logger.h>
45 * Interface for logging to network clients.
46 * The NetwokLogger will pipe all output to clients that subscribed for log
47 * messages.
48 * @author Tim Niemueller
49 */
50
51/** Constructor.
52 * @param hub FawkesNetworkHub to use to send and receive messages
53 * @param log_level minimum level to log
54 */
56: Logger(log_level), FawkesNetworkHandler(FAWKES_CID_NETWORKLOGGER)
57{
58 this->hub = hub;
59
60 hub->add_handler(this);
61}
62
63/** Destructor. */
65{
66 hub->remove_handler(this);
67}
68
69void
70NetworkLogger::send_message(Logger::LogLevel level,
71 struct timeval * t,
72 const char * component,
73 bool is_exception,
74 const char * format,
75 va_list va)
76{
77 struct timeval now;
78 if (t == NULL) {
79 gettimeofday(&now, NULL);
80 t = &now;
81 }
82
83 NetworkLoggerMessageContent *content =
84 new NetworkLoggerMessageContent(level, t, component, is_exception, format, va);
85
86 for (ssit_ = subscribers_.begin(); ssit_ != subscribers_.end(); ++ssit_) {
87 NetworkLoggerMessageContent *content_copy = new NetworkLoggerMessageContent(content);
88 try {
89 hub->send(*ssit_, FAWKES_CID_NETWORKLOGGER, MSGTYPE_LOGMESSAGE, content_copy);
90 } catch (Exception &e) {
91 // Boom, can't do anything about it, logging could cause infinite loop...
92 }
93 }
94
95 delete content;
96}
97
98void
99NetworkLogger::send_message(Logger::LogLevel level,
100 struct timeval * t,
101 const char * component,
102 bool is_exception,
103 const char * message)
104{
105 struct timeval now;
106 if (t == NULL) {
107 gettimeofday(&now, NULL);
108 t = &now;
109 }
110
111 NetworkLoggerMessageContent *content =
112 new NetworkLoggerMessageContent(level, t, component, is_exception, message);
113
114 for (ssit_ = subscribers_.begin(); ssit_ != subscribers_.end(); ++ssit_) {
115 NetworkLoggerMessageContent *content_copy = new NetworkLoggerMessageContent(content);
116 try {
117 hub->send(*ssit_, FAWKES_CID_NETWORKLOGGER, MSGTYPE_LOGMESSAGE, content_copy);
118 } catch (Exception &e) {
119 // Boom, can't do anything about it, logging could cause infinite loop...
120 }
121 }
122
123 delete content;
124}
125
126void
127NetworkLogger::vlog_debug(const char *component, const char *format, va_list va)
128{
129 if ((log_level <= LL_DEBUG) && (!subscribers_.empty())) {
130 subscribers_.lock();
131 send_message(LL_DEBUG, NULL, component, /* exception? */ false, format, va);
132 subscribers_.unlock();
133 }
134}
135
136void
137NetworkLogger::vlog_info(const char *component, const char *format, va_list va)
138{
139 if ((log_level <= LL_INFO) && (!subscribers_.empty())) {
140 subscribers_.lock();
141 send_message(LL_INFO, NULL, component, /* exception? */ false, format, va);
142 subscribers_.unlock();
143 }
144}
145
146void
147NetworkLogger::vlog_warn(const char *component, const char *format, va_list va)
148{
149 if ((log_level <= LL_WARN) && (!subscribers_.empty())) {
150 subscribers_.lock();
151 send_message(LL_WARN, NULL, component, /* exception? */ false, format, va);
152 subscribers_.unlock();
153 }
154}
155
156void
157NetworkLogger::vlog_error(const char *component, const char *format, va_list va)
158{
159 if ((log_level <= LL_ERROR) && (!subscribers_.empty())) {
160 subscribers_.lock();
161 send_message(LL_ERROR, NULL, component, /* exception? */ false, format, va);
162 subscribers_.unlock();
163 }
164}
165
166void
167NetworkLogger::log_debug(const char *component, const char *format, ...)
168{
169 va_list arg;
170 va_start(arg, format);
171 vlog_debug(component, format, arg);
172 va_end(arg);
173}
174
175void
176NetworkLogger::log_info(const char *component, const char *format, ...)
177{
178 va_list arg;
179 va_start(arg, format);
180 vlog_info(component, format, arg);
181 va_end(arg);
182}
183
184void
185NetworkLogger::log_warn(const char *component, const char *format, ...)
186{
187 va_list arg;
188 va_start(arg, format);
189 vlog_warn(component, format, arg);
190 va_end(arg);
191}
192
193void
194NetworkLogger::log_error(const char *component, const char *format, ...)
195{
196 va_list arg;
197 va_start(arg, format);
198 vlog_error(component, format, arg);
199 va_end(arg);
200}
201
202void
203NetworkLogger::log_debug(const char *component, Exception &e)
204{
205 if ((log_level <= LL_DEBUG) && (!subscribers_.empty())) {
206 subscribers_.lock();
207 for (Exception::iterator i = e.begin(); i != e.end(); ++i) {
208 send_message(LL_DEBUG, NULL, component, /* exception? */ true, *i);
209 }
210 subscribers_.unlock();
211 }
212}
213
214void
215NetworkLogger::log_info(const char *component, Exception &e)
216{
217 if ((log_level <= LL_INFO) && (!subscribers_.empty())) {
218 subscribers_.lock();
219 for (Exception::iterator i = e.begin(); i != e.end(); ++i) {
220 send_message(LL_INFO, NULL, component, /* exception? */ true, *i);
221 }
222 subscribers_.unlock();
223 }
224}
225
226void
227NetworkLogger::log_warn(const char *component, Exception &e)
228{
229 if ((log_level <= LL_WARN) && (!subscribers_.empty())) {
230 subscribers_.lock();
231 for (Exception::iterator i = e.begin(); i != e.end(); ++i) {
232 send_message(LL_WARN, NULL, component, /* exception? */ true, *i);
233 }
234 subscribers_.unlock();
235 }
236}
237
238void
239NetworkLogger::log_error(const char *component, Exception &e)
240{
241 if ((log_level <= LL_ERROR) && (!subscribers_.empty())) {
242 subscribers_.lock();
243 for (Exception::iterator i = e.begin(); i != e.end(); ++i) {
244 send_message(LL_ERROR, NULL, component, /* exception? */ true, *i);
245 }
246 subscribers_.unlock();
247 }
248}
249
250void
251NetworkLogger::vtlog_debug(struct timeval *t, const char *component, const char *format, va_list va)
252{
253 if ((log_level <= LL_DEBUG) && (!subscribers_.empty())) {
254 subscribers_.lock();
255 send_message(LL_DEBUG, t, component, /* exception? */ false, format, va);
256 subscribers_.unlock();
257 }
258}
259
260void
261NetworkLogger::vtlog_info(struct timeval *t, const char *component, const char *format, va_list va)
262{
263 if ((log_level <= LL_INFO) && (!subscribers_.empty())) {
264 subscribers_.lock();
265 send_message(LL_INFO, t, component, /* exception? */ false, format, va);
266 subscribers_.unlock();
267 }
268}
269
270void
271NetworkLogger::vtlog_warn(struct timeval *t, const char *component, const char *format, va_list va)
272{
273 if ((log_level <= LL_WARN) && (!subscribers_.empty())) {
274 subscribers_.lock();
275 send_message(LL_WARN, t, component, /* exception? */ false, format, va);
276 subscribers_.unlock();
277 }
278}
279
280void
281NetworkLogger::vtlog_error(struct timeval *t, const char *component, const char *format, va_list va)
282{
283 if ((log_level <= LL_ERROR) && (!subscribers_.empty())) {
284 subscribers_.lock();
285 send_message(LL_ERROR, t, component, /* exception? */ false, format, va);
286 subscribers_.unlock();
287 }
288}
289
290void
291NetworkLogger::tlog_debug(struct timeval *t, const char *component, const char *format, ...)
292{
293 va_list arg;
294 va_start(arg, format);
295 vtlog_debug(t, component, format, arg);
296 va_end(arg);
297}
298
299void
300NetworkLogger::tlog_info(struct timeval *t, const char *component, const char *format, ...)
301{
302 va_list arg;
303 va_start(arg, format);
304 vtlog_info(t, component, format, arg);
305 va_end(arg);
306}
307
308void
309NetworkLogger::tlog_warn(struct timeval *t, const char *component, const char *format, ...)
310{
311 va_list arg;
312 va_start(arg, format);
313 vtlog_warn(t, component, format, arg);
314 va_end(arg);
315}
316
317void
318NetworkLogger::tlog_error(struct timeval *t, const char *component, const char *format, ...)
319{
320 va_list arg;
321 va_start(arg, format);
322 vtlog_error(t, component, format, arg);
323 va_end(arg);
324}
325
326void
327NetworkLogger::tlog_debug(struct timeval *t, const char *component, Exception &e)
328{
329 if ((log_level <= LL_DEBUG) && (!subscribers_.empty())) {
330 subscribers_.lock();
331 for (Exception::iterator i = e.begin(); i != e.end(); ++i) {
332 send_message(LL_DEBUG, t, component, /* exception? */ true, *i);
333 }
334 subscribers_.unlock();
335 }
336}
337
338void
339NetworkLogger::tlog_info(struct timeval *t, const char *component, Exception &e)
340{
341 if ((log_level <= LL_INFO) && (!subscribers_.empty())) {
342 subscribers_.lock();
343 for (Exception::iterator i = e.begin(); i != e.end(); ++i) {
344 send_message(LL_INFO, t, component, /* exception? */ true, *i);
345 }
346 subscribers_.unlock();
347 }
348}
349
350void
351NetworkLogger::tlog_warn(struct timeval *t, const char *component, Exception &e)
352{
353 if ((log_level <= LL_WARN) && (!subscribers_.empty())) {
354 subscribers_.lock();
355 for (Exception::iterator i = e.begin(); i != e.end(); ++i) {
356 send_message(LL_WARN, t, component, /* exception? */ true, *i);
357 }
358 subscribers_.unlock();
359 }
360}
361
362void
363NetworkLogger::tlog_error(struct timeval *t, const char *component, Exception &e)
364{
365 if ((log_level <= LL_ERROR) && (!subscribers_.empty())) {
366 subscribers_.lock();
367 for (Exception::iterator i = e.begin(); i != e.end(); ++i) {
368 send_message(LL_ERROR, t, component, /* exception? */ true, *i);
369 }
370 subscribers_.unlock();
371 }
372}
373
374void
376{
377 if ((msg->cid() == FAWKES_CID_NETWORKLOGGER) && (msg->msgid() == MSGTYPE_SUBSCRIBE)) {
378 subscribers_.lock();
379 subscribers_.push_back(msg->clid());
380 subscribers_.sort();
381 subscribers_.unique();
382 subscribers_.unlock();
383 }
384}
385
386void
388{
389}
390
391void
393{
394 subscribers_.remove_locked(clid);
395}
396
397/** @class NetworkLoggerMessageContent <network_logger/network_logger.h>
398 * Message sent over the network with a log message.
399 * Contains a buffer with a small header and two null-terminated strings, the first
400 * being the component and the second being the real message.
401 * @author Tim Niemueller
402 */
403
404/** Constructor.
405 * @param log_level Log level
406 * @param t time
407 * @param component component string
408 * @param is_exception true if this message originates from an exception, false otherwise
409 * @param format message string format
410 * @param va va_list containing the arguments for the given format
411 */
413 struct timeval * t,
414 const char * component,
415 bool is_exception,
416 const char * format,
417 va_list va)
418{
419 char *tmp = NULL;
420 int tmplen;
421 if ((tmplen = vasprintf(&tmp, format, va)) != -1) {
422 _payload_size = sizeof(NetworkLogger::network_logger_header_t) + strlen(component) + tmplen + 2;
423 _payload = calloc(1, _payload_size);
424 own_payload_ = true;
426 header->log_level = log_level;
427 header->exception = is_exception ? 1 : 0;
428 header->time_sec = hton64(t->tv_sec);
429 header->time_usec = htonl(t->tv_usec);
430 copy_payload(sizeof(NetworkLogger::network_logger_header_t), component, strlen(component));
431 copy_payload(sizeof(NetworkLogger::network_logger_header_t) + strlen(component) + 1,
432 tmp,
433 tmplen);
434 component_ = (char *)_payload + sizeof(NetworkLogger::network_logger_header_t);
435 message_ =
436 (char *)_payload + sizeof(NetworkLogger::network_logger_header_t) + strlen(component) + 1;
437 free(tmp);
438 }
439}
440
441/** Constructor.
442 * @param log_level Log level
443 * @param t time
444 * @param component component string
445 * @param is_exception true if this message originates from an exception, false otherwise
446 * @param message message string.
447 */
449 struct timeval * t,
450 const char * component,
451 bool is_exception,
452 const char * message)
453{
455 sizeof(NetworkLogger::network_logger_header_t) + strlen(component) + strlen(message) + 2;
456 _payload = calloc(1, _payload_size);
457 own_payload_ = true;
459 header->log_level = log_level;
460 header->exception = is_exception ? 1 : 0;
461 header->time_sec = hton64(t->tv_sec);
462 header->time_usec = htonl(t->tv_usec);
463 copy_payload(sizeof(NetworkLogger::network_logger_header_t), component, strlen(component));
464 copy_payload(sizeof(NetworkLogger::network_logger_header_t) + strlen(component) + 1,
465 message,
466 strlen(message));
467 component_ = (char *)_payload + sizeof(NetworkLogger::network_logger_header_t);
468 message_ =
469 (char *)_payload + sizeof(NetworkLogger::network_logger_header_t) + strlen(component) + 1;
470}
471
472/** Copy constructor.
473 * @param content content to copy
474 */
476{
477 _payload_size = content->_payload_size;
478 _payload = malloc(_payload_size);
479 own_payload_ = true;
480 memcpy(_payload, content->_payload, _payload_size);
482 component_ = (char *)_payload + sizeof(NetworkLogger::network_logger_header_t);
483 message_ =
484 (char *)_payload + sizeof(NetworkLogger::network_logger_header_t) + strlen(component_) + 1;
485}
486
487/** Message parsing constructor.
488 * To be used with FawkesNetworkMessage::msgc().
489 * @param component_id component ID
490 * @param msg_id message ID
491 * @param payload payload
492 * @param payload_size payload size
493 */
495 unsigned int msg_id,
496 void * payload,
497 size_t payload_size)
498{
499 if (component_id != FAWKES_CID_NETWORKLOGGER) {
500 throw TypeMismatchException("Wrong CID, expected FAWKES_CID_NETWORKLOGGER");
501 }
502
505 own_payload_ = false;
507 component_ = (char *)_payload + sizeof(NetworkLogger::network_logger_header_t);
508 message_ =
509 (char *)_payload + sizeof(NetworkLogger::network_logger_header_t) + strlen(component_) + 1;
510}
511
512/** Destructor. */
514{
515 if (own_payload_)
516 free(_payload);
517}
518
519/** Get time.
520 * @return time of the log message
521 */
522struct timeval
524{
525 struct timeval rv;
526 rv.tv_sec = (time_t)ntoh64(header->time_sec);
527 rv.tv_usec = ntohl(header->time_usec);
528 return rv;
529}
530
531/** Get component.
532 * @return component string
533 */
534const char *
536{
537 return component_;
538}
539
540/** Get message.
541 * @return message string
542 */
543const char *
545{
546 return message_;
547}
548
549/** Log level.
550 * @return log level.
551 */
554{
555 return (Logger::LogLevel)header->log_level;
556}
557
558/** Check if message was generated by exception.
559 * @return true if message was generated by exception, false otherwise
560 */
561bool
563{
564 return (header->exception == 1);
565}
566
567} // end namespace fawkes
Message iterator for exceptions.
Definition: exception.h:73
Base class for exceptions in Fawkes.
Definition: exception.h:36
iterator end() noexcept
Get end iterator for messages.
Definition: exception.cpp:692
iterator begin() noexcept
Get iterator for messages.
Definition: exception.cpp:676
Network handler abstract base class.
Definition: handler.h:32
Fawkes Network Hub.
Definition: hub.h:34
virtual void send(FawkesNetworkMessage *msg)=0
Method to send a message to a specific client.
virtual void remove_handler(FawkesNetworkHandler *handler)=0
Remove a message handler.
virtual void add_handler(FawkesNetworkHandler *handler)=0
Add a message handler.
void copy_payload(size_t offset, const void *buf, size_t len)
Copy payload into payload buffer to a specified offset.
virtual size_t payload_size()
Return payload size.
void * _payload
Pointer to payload.
virtual void * payload()
Return pointer to payload.
Representation of a message that is sent over the network.
Definition: message.h:77
unsigned short int msgid() const
Get message type ID.
Definition: message.cpp:294
unsigned short int cid() const
Get component ID.
Definition: message.cpp:285
unsigned int clid() const
Get client ID.
Definition: message.cpp:276
virtual void unlock() const
Unlock list.
Definition: lock_list.h:138
virtual void lock() const
Lock list.
Definition: lock_list.h:124
void remove_locked(const Type &x)
Remove element from list with lock protection.
Definition: lock_list.h:163
Interface for logging.
Definition: logger.h:42
LogLevel
Log level.
Definition: logger.h:51
@ LL_INFO
informational output about normal procedures
Definition: logger.h:53
@ LL_WARN
warning, should be investigated but software still functions, an example is that something was reques...
Definition: logger.h:54
@ LL_ERROR
error, may be recoverable (software still running) or not (software has to terminate).
Definition: logger.h:57
@ LL_DEBUG
debug output, relevant only when tracking down problems
Definition: logger.h:52
LogLevel log_level
Minimum log level.
Definition: logger.h:126
Message sent over the network with a log message.
NetworkLoggerMessageContent(Logger::LogLevel log_level, struct timeval *t, const char *component, bool is_exception, const char *message)
Constructor.
virtual ~NetworkLoggerMessageContent()
Destructor.
Logger::LogLevel get_loglevel() const
Log level.
virtual void serialize()
Serialize message content.
const char * get_message() const
Get message.
const char * get_component() const
Get component.
bool is_exception() const
Check if message was generated by exception.
virtual void client_disconnected(unsigned int clid)
Called when a client disconnected.
virtual void log_error(const char *component, const char *format,...)
Log error message.
virtual void vlog_error(const char *component, const char *format, va_list va)
Log error message.
virtual void log_warn(const char *component, const char *format,...)
Log warning message.
virtual void vtlog_error(struct timeval *t, const char *component, const char *format, va_list va)
Log error message for specific time.
virtual void vtlog_debug(struct timeval *t, const char *component, const char *format, va_list va)
Log debug message for specific time.
virtual void tlog_debug(struct timeval *t, const char *component, const char *format,...)
Log debug message for specific time.
virtual void vtlog_warn(struct timeval *t, const char *component, const char *format, va_list va)
Log warning message for specific time.
virtual void tlog_warn(struct timeval *t, const char *component, const char *format,...)
Log warning message for specific time.
virtual void tlog_info(struct timeval *t, const char *component, const char *format,...)
Log informational message for specific time.
virtual void vlog_info(const char *component, const char *format, va_list va)
Log informational message.
virtual void vlog_debug(const char *component, const char *format, va_list va)
Log debug message.
virtual void client_connected(unsigned int clid)
Called when a new client connected.
virtual void log_info(const char *component, const char *format,...)
Log informational message.
NetworkLogger(FawkesNetworkHub *hub, LogLevel log_level=LL_DEBUG)
Constructor.
@ MSGTYPE_SUBSCRIBE
Subscribe for logging messages.
@ MSGTYPE_LOGMESSAGE
Log message.
virtual void vlog_warn(const char *component, const char *format, va_list va)
Log warning message.
virtual void vtlog_info(struct timeval *t, const char *component, const char *format, va_list va)
Log informational message for specific time.
virtual void log_debug(const char *component, const char *format,...)
Log debug message.
virtual void handle_network_message(FawkesNetworkMessage *msg)
Called for incoming messages that are addressed to the correct component ID.
virtual void tlog_error(struct timeval *t, const char *component, const char *format,...)
Log error message for specific time.
virtual ~NetworkLogger()
Destructor.
Fawkes library namespace.
uint32_t time_usec
addition to time in usec, encoded in network byte order
uint64_t time_sec
time in seconds since the epoch, encoded in network byte order