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 
37 namespace fawkes {
38 
39 void
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 
69 void
70 NetworkLogger::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 
98 void
99 NetworkLogger::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 
126 void
127 NetworkLogger::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 
136 void
137 NetworkLogger::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 
146 void
147 NetworkLogger::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 
156 void
157 NetworkLogger::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 
166 void
167 NetworkLogger::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 
175 void
176 NetworkLogger::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 
184 void
185 NetworkLogger::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 
193 void
194 NetworkLogger::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 
202 void
203 NetworkLogger::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 
214 void
215 NetworkLogger::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 
226 void
227 NetworkLogger::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 
238 void
239 NetworkLogger::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 
250 void
251 NetworkLogger::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 
260 void
261 NetworkLogger::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 
270 void
271 NetworkLogger::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 
280 void
281 NetworkLogger::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 
290 void
291 NetworkLogger::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 
299 void
300 NetworkLogger::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 
308 void
309 NetworkLogger::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 
317 void
318 NetworkLogger::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 
326 void
327 NetworkLogger::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 
338 void
339 NetworkLogger::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 
350 void
351 NetworkLogger::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 
362 void
363 NetworkLogger::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 
374 void
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 
386 void
388 {
389 }
390 
391 void
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 {
454  _payload_size =
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 
503  _payload = payload;
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  */
522 struct timeval
523 NetworkLoggerMessageContent::get_time() const
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  */
534 const char *
536 {
537  return component_;
538 }
539 
540 /** Get message.
541  * @return message string
542  */
543 const 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  */
561 bool
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 begin()
Get iterator for messages.
Definition: exception.cpp:676
iterator end()
Get end iterator for messages.
Definition: exception.cpp:692
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