network_logger.cpp

00001 
00002 /***************************************************************************
00003  *  network_logger.cpp - Fawkes network logger
00004  *
00005  *  Created: Sat Dec 15 00:48:52 2007 (after I5 xmas party)
00006  *  Copyright  2006-2007  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023 
00024 #include <netcomm/utils/network_logger.h>
00025 
00026 #include <core/threading/mutex.h>
00027 #include <netcomm/fawkes/component_ids.h>
00028 #include <netcomm/fawkes/hub.h>
00029 #include <netcomm/utils/ntoh64.h>
00030 
00031 #include <sys/time.h>
00032 #include <time.h>
00033 #include <netinet/in.h>
00034 #include <cstring>
00035 #include <cstdlib>
00036 #include <cstdio>
00037 
00038 namespace fawkes {
00039 
00040 void
00041 NetworkLoggerMessageContent::serialize()
00042 {
00043 }
00044 
00045 
00046 /** @class NetworkLogger <netcomm/utils/network_logger.h>
00047  * Interface for logging to network clients.
00048  * The NetwokLogger will pipe all output to clients that subscribed for log
00049  * messages.
00050  * @author Tim Niemueller
00051  */
00052 
00053 /** Constructor.
00054  * @param hub FawkesNetworkHub to use to send and receive messages
00055  * @param log_level minimum level to log
00056  */
00057 NetworkLogger::NetworkLogger(FawkesNetworkHub *hub, LogLevel log_level)
00058   : Logger(log_level),
00059     FawkesNetworkHandler(FAWKES_CID_NETWORKLOGGER)
00060 {
00061   this->hub = hub;
00062 
00063   hub->add_handler(this);
00064 }
00065 
00066 
00067 /** Destructor. */
00068 NetworkLogger::~NetworkLogger()
00069 {
00070   hub->remove_handler(this);
00071 }
00072 
00073 
00074 void
00075 NetworkLogger::send_message(Logger::LogLevel level, struct timeval *t,
00076                             const char *component, bool is_exception,
00077                             const char *format, va_list va)
00078 {
00079   struct timeval now;
00080   if ( t == NULL ) {
00081     gettimeofday(&now, NULL);
00082     t = &now;
00083   }
00084 
00085   NetworkLoggerMessageContent *content = new NetworkLoggerMessageContent(level, t,
00086                                                                          component,
00087                                                                          is_exception,
00088                                                                          format, va);
00089 
00090   for ( __ssit = __subscribers.begin(); __ssit != __subscribers.end(); ++__ssit) {
00091     NetworkLoggerMessageContent *content_copy = new NetworkLoggerMessageContent(content);
00092     try {
00093       hub->send(*__ssit, FAWKES_CID_NETWORKLOGGER, MSGTYPE_LOGMESSAGE, content_copy);
00094     } catch (Exception &e) {
00095       // Boom, can't do anything about it, logging could cause infinite loop...
00096     }
00097   }
00098   
00099   delete content;
00100 }
00101 
00102 
00103 void
00104 NetworkLogger::send_message(Logger::LogLevel level, struct timeval *t,
00105                             const char *component, bool is_exception,
00106                             const char *message)
00107 {
00108   struct timeval now;
00109   if ( t == NULL ) {
00110     gettimeofday(&now, NULL);
00111     t = &now;
00112   }
00113 
00114   NetworkLoggerMessageContent *content = new NetworkLoggerMessageContent(level, t,
00115                                                                          component,
00116                                                                          is_exception,
00117                                                                          message);
00118   
00119   for ( __ssit = __subscribers.begin(); __ssit != __subscribers.end(); ++__ssit) {
00120     NetworkLoggerMessageContent *content_copy = new NetworkLoggerMessageContent(content);
00121     try {
00122       hub->send(*__ssit, FAWKES_CID_NETWORKLOGGER, MSGTYPE_LOGMESSAGE, content_copy);
00123     } catch (Exception &e) {
00124       // Boom, can't do anything about it, logging could cause infinite loop...
00125     }
00126   }
00127 
00128   delete content;
00129 }
00130 
00131 
00132 void
00133 NetworkLogger::vlog_debug(const char *component, const char *format, va_list va)
00134 {
00135   if ((log_level <= LL_DEBUG) && (! __subscribers.empty()) ) {
00136     __subscribers.lock();
00137     send_message(LL_DEBUG, NULL, component, /* exception? */ false, format, va);
00138     __subscribers.unlock();
00139   }
00140 }
00141 
00142 
00143 void
00144 NetworkLogger::vlog_info(const char *component, const char *format, va_list va)
00145 {
00146   if ((log_level <= LL_INFO) && (! __subscribers.empty()) ) {
00147     __subscribers.lock();
00148     send_message(LL_INFO, NULL, component, /* exception? */ false, format, va);
00149    __subscribers.unlock();
00150   }
00151 }
00152 
00153 
00154 void
00155 NetworkLogger::vlog_warn(const char *component, const char *format, va_list va)
00156 {
00157   if ((log_level <= LL_WARN) && (! __subscribers.empty()) ) {
00158     __subscribers.lock();
00159     send_message(LL_WARN, NULL, component, /* exception? */ false, format, va);
00160    __subscribers.unlock();
00161   }
00162 }
00163 
00164 
00165 void
00166 NetworkLogger::vlog_error(const char *component, const char *format, va_list va)
00167 {
00168   if ((log_level <= LL_ERROR) && (! __subscribers.empty()) ) {
00169     __subscribers.lock();
00170     send_message(LL_ERROR, NULL, component, /* exception? */ false, format, va);
00171    __subscribers.unlock();
00172   }
00173 }
00174 
00175 
00176 void
00177 NetworkLogger::log_debug(const char *component, const char *format, ...)
00178 {
00179   va_list arg;
00180   va_start(arg, format);
00181   vlog_debug(component, format, arg);
00182   va_end(arg);
00183 }
00184 
00185 
00186 void
00187 NetworkLogger::log_info(const char *component, const char *format, ...)
00188 {
00189   va_list arg;
00190   va_start(arg, format);
00191   vlog_info(component, format, arg);
00192   va_end(arg);
00193 }
00194 
00195 
00196 void
00197 NetworkLogger::log_warn(const char *component, const char *format, ...)
00198 {
00199   va_list arg;
00200   va_start(arg, format);
00201   vlog_warn(component, format, arg);
00202   va_end(arg);
00203 }
00204 
00205 
00206 void
00207 NetworkLogger::log_error(const char *component, const char *format, ...)
00208 {
00209   va_list arg;
00210   va_start(arg, format);
00211   vlog_error(component, format, arg);
00212   va_end(arg);
00213 }
00214 
00215 
00216 void
00217 NetworkLogger::log_debug(const char *component, Exception &e)
00218 {
00219   if ((log_level <= LL_DEBUG) && (! __subscribers.empty()) ) {
00220     __subscribers.lock();
00221     for (Exception::iterator i = e.begin(); i != e.end(); ++i) {
00222       send_message(LL_DEBUG, NULL, component, /* exception? */ true, *i);
00223     } 
00224    __subscribers.unlock();
00225   }
00226 }
00227 
00228 void
00229 NetworkLogger::log_info(const char *component, Exception &e)
00230 {
00231   if ((log_level <= LL_INFO) && (! __subscribers.empty()) ) {
00232     __subscribers.lock();
00233     for (Exception::iterator i = e.begin(); i != e.end(); ++i) {
00234       send_message(LL_INFO, NULL, component, /* exception? */ true, *i);
00235     } 
00236    __subscribers.unlock();
00237   }
00238 }
00239 
00240 
00241 void
00242 NetworkLogger::log_warn(const char *component, Exception &e)
00243 {
00244   if ((log_level <= LL_WARN) && (! __subscribers.empty()) ) {
00245     __subscribers.lock();
00246     for (Exception::iterator i = e.begin(); i != e.end(); ++i) {
00247       send_message(LL_WARN, NULL, component, /* exception? */ true, *i);
00248     } 
00249    __subscribers.unlock();
00250   }
00251 }
00252 
00253 
00254 void
00255 NetworkLogger::log_error(const char *component, Exception &e)
00256 {
00257   if ((log_level <= LL_ERROR) && (! __subscribers.empty()) ) {
00258     __subscribers.lock();
00259     for (Exception::iterator i = e.begin(); i != e.end(); ++i) {
00260       send_message(LL_ERROR, NULL, component, /* exception? */ true, *i);
00261     }
00262    __subscribers.unlock();
00263   }
00264 }
00265 
00266 
00267 
00268 
00269 void
00270 NetworkLogger::vtlog_debug(struct timeval *t, const char *component,
00271                            const char *format, va_list va)
00272 {
00273   if ((log_level <= LL_DEBUG) && (! __subscribers.empty()) ) {
00274     __subscribers.lock();
00275     send_message(LL_DEBUG, t, component, /* exception? */ false, format, va);
00276     __subscribers.unlock();
00277   }
00278 }
00279 
00280 
00281 void
00282 NetworkLogger::vtlog_info(struct timeval *t, const char *component, const char *format, va_list va)
00283 {
00284   if ((log_level <= LL_INFO) && (! __subscribers.empty()) ) {
00285     __subscribers.lock();
00286     send_message(LL_INFO, t, component, /* exception? */ false, format, va);
00287    __subscribers.unlock();
00288   }
00289 }
00290 
00291 
00292 void
00293 NetworkLogger::vtlog_warn(struct timeval *t, const char *component, const char *format, va_list va)
00294 {
00295   if ((log_level <= LL_WARN) && (! __subscribers.empty()) ) {
00296     __subscribers.lock();
00297     send_message(LL_WARN, t, component, /* exception? */ false, format, va);
00298    __subscribers.unlock();
00299   }
00300 }
00301 
00302 
00303 void
00304 NetworkLogger::vtlog_error(struct timeval *t, const char *component, const char *format, va_list va)
00305 {
00306   if ((log_level <= LL_ERROR) && (! __subscribers.empty()) ) {
00307     __subscribers.lock();
00308     send_message(LL_ERROR, t, component, /* exception? */ false, format, va);
00309    __subscribers.unlock();
00310   }
00311 }
00312 
00313 
00314 void
00315 NetworkLogger::tlog_debug(struct timeval *t, const char *component, const char *format, ...)
00316 {
00317   va_list arg;
00318   va_start(arg, format);
00319   vtlog_debug(t, component, format, arg);
00320   va_end(arg);
00321 }
00322 
00323 
00324 void
00325 NetworkLogger::tlog_info(struct timeval *t, const char *component, const char *format, ...)
00326 {
00327   va_list arg;
00328   va_start(arg, format);
00329   vtlog_info(t, component, format, arg);
00330   va_end(arg);
00331 }
00332 
00333 
00334 void
00335 NetworkLogger::tlog_warn(struct timeval *t, const char *component, const char *format, ...)
00336 {
00337   va_list arg;
00338   va_start(arg, format);
00339   vtlog_warn(t, component, format, arg);
00340   va_end(arg);
00341 }
00342 
00343 
00344 void
00345 NetworkLogger::tlog_error(struct timeval *t, const char *component, const char *format, ...)
00346 {
00347   va_list arg;
00348   va_start(arg, format);
00349   vtlog_error(t, component, format, arg);
00350   va_end(arg);
00351 }
00352 
00353 
00354 void
00355 NetworkLogger::tlog_debug(struct timeval *t, const char *component, Exception &e)
00356 {
00357   if ((log_level <= LL_DEBUG) && (! __subscribers.empty()) ) {
00358     __subscribers.lock();
00359     for (Exception::iterator i = e.begin(); i != e.end(); ++i) {
00360       send_message(LL_DEBUG, t, component, /* exception? */ true, *i);
00361     } 
00362    __subscribers.unlock();
00363   }
00364 }
00365 
00366 void
00367 NetworkLogger::tlog_info(struct timeval *t, const char *component, Exception &e)
00368 {
00369   if ((log_level <= LL_INFO) && (! __subscribers.empty()) ) {
00370     __subscribers.lock();
00371     for (Exception::iterator i = e.begin(); i != e.end(); ++i) {
00372       send_message(LL_INFO, t, component, /* exception? */ true, *i);
00373     } 
00374    __subscribers.unlock();
00375   }
00376 }
00377 
00378 
00379 void
00380 NetworkLogger::tlog_warn(struct timeval *t, const char *component, Exception &e)
00381 {
00382   if ((log_level <= LL_WARN) && (! __subscribers.empty()) ) {
00383     __subscribers.lock();
00384     for (Exception::iterator i = e.begin(); i != e.end(); ++i) {
00385       send_message(LL_WARN, t, component, /* exception? */ true, *i);
00386     } 
00387    __subscribers.unlock();
00388   }
00389 }
00390 
00391 
00392 void
00393 NetworkLogger::tlog_error(struct timeval *t, const char *component, Exception &e)
00394 {
00395   if ((log_level <= LL_ERROR) && (! __subscribers.empty()) ) {
00396     __subscribers.lock();
00397     for (Exception::iterator i = e.begin(); i != e.end(); ++i) {
00398       send_message(LL_ERROR, t, component, /* exception? */ true, *i);
00399     } 
00400    __subscribers.unlock();
00401   }
00402 }
00403 
00404 
00405 void
00406 NetworkLogger::handle_network_message(FawkesNetworkMessage *msg)
00407 {
00408   if ( (msg->cid() == FAWKES_CID_NETWORKLOGGER) &&
00409        (msg->msgid() == MSGTYPE_SUBSCRIBE) ) {
00410     __subscribers.lock();
00411     __subscribers.push_back(msg->clid());
00412     __subscribers.sort();
00413     __subscribers.unique();
00414     __subscribers.unlock();
00415   }
00416 }
00417 
00418 void
00419 NetworkLogger::client_connected(unsigned int clid)
00420 {
00421 }
00422 
00423 
00424 void
00425 NetworkLogger::client_disconnected(unsigned int clid)
00426 {
00427   __subscribers.remove_locked(clid);
00428 }
00429 
00430 
00431 /** @class NetworkLoggerMessageContent <netcomm/utils/network_logger.h>
00432  * Message sent over the network with a log message.
00433  * Contains a buffer with a small header and two null-terminated strings, the first
00434  * being the component and the second being the real message.
00435  * @author Tim Niemueller
00436  */
00437 
00438 
00439 /** Constructor.
00440  * @param log_level Log level
00441  * @param t time
00442  * @param component component string
00443  * @param is_exception true if this message originates from an exception, false otherwise
00444  * @param format message string format
00445  * @param va va_list containing the arguments for the given format
00446  */
00447 NetworkLoggerMessageContent::NetworkLoggerMessageContent(Logger::LogLevel log_level,
00448                                                          struct timeval *t,
00449                                                          const char *component,
00450                                                          bool is_exception,
00451                                                          const char *format, va_list va)
00452 {
00453   char *tmp = NULL;
00454   int tmplen;
00455   if ( (tmplen = vasprintf(&tmp, format, va)) != -1 ) {
00456     _payload_size = sizeof(NetworkLogger::network_logger_header_t) + strlen(component) + tmplen + 2;
00457     _payload = calloc(1, _payload_size);
00458     __own_payload = true;
00459     header = (NetworkLogger::network_logger_header_t *)_payload;
00460     header->log_level    = log_level;
00461     header->exception    = is_exception ? 1 : 0;
00462     header->time_sec     = hton64(t->tv_sec);
00463     header->time_usec    = htonl(t->tv_usec);
00464     copy_payload(sizeof(NetworkLogger::network_logger_header_t), component, strlen(component));
00465     copy_payload(sizeof(NetworkLogger::network_logger_header_t) + strlen(component) + 1, tmp, tmplen);
00466     __component = (char *)_payload + sizeof(NetworkLogger::network_logger_header_t);
00467     __message   = (char *)_payload + sizeof(NetworkLogger::network_logger_header_t) + strlen(component) + 1;
00468     free(tmp);
00469   }
00470 }
00471 
00472 
00473 /** Constructor.
00474  * @param log_level Log level
00475  * @param t time
00476  * @param component component string
00477  * @param is_exception true if this message originates from an exception, false otherwise
00478  * @param message message string.
00479  */
00480 NetworkLoggerMessageContent::NetworkLoggerMessageContent(Logger::LogLevel log_level,
00481                                                          struct timeval *t,
00482                                                          const char *component,
00483                                                          bool is_exception,
00484                                                          const char *message)
00485 {
00486   _payload_size = sizeof(NetworkLogger::network_logger_header_t) + strlen(component) + strlen(message) + 2;
00487   _payload = calloc(1, _payload_size);
00488   __own_payload = true;
00489   header = (NetworkLogger::network_logger_header_t *)_payload;
00490   header->log_level    = log_level;
00491   header->exception    = is_exception ? 1 : 0;
00492   header->time_sec     = hton64(t->tv_sec);
00493   header->time_usec    = htonl(t->tv_usec);
00494   copy_payload(sizeof(NetworkLogger::network_logger_header_t), component, strlen(component));
00495   copy_payload(sizeof(NetworkLogger::network_logger_header_t) + strlen(component) + 1, message, strlen(message));
00496   __component = (char *)_payload + sizeof(NetworkLogger::network_logger_header_t);
00497   __message   = (char *)_payload + sizeof(NetworkLogger::network_logger_header_t) + strlen(component) + 1;
00498 }
00499 
00500 
00501 /** Copy constructor.
00502  * @param content content to copy
00503  */
00504 NetworkLoggerMessageContent::NetworkLoggerMessageContent(const NetworkLoggerMessageContent *content)
00505 {
00506   _payload_size = content->_payload_size;
00507   _payload = malloc(_payload_size);
00508   __own_payload = true;
00509   memcpy(_payload, content->_payload, _payload_size);
00510   header = (NetworkLogger::network_logger_header_t *)_payload;
00511   __component = (char *)_payload + sizeof(NetworkLogger::network_logger_header_t);
00512   __message   = (char *)_payload + sizeof(NetworkLogger::network_logger_header_t) + strlen(__component) + 1;
00513 }
00514 
00515 
00516 /** Message parsing constructor.
00517  * To be used with FawkesNetworkMessage::msgc().
00518  * @param component_id component ID
00519  * @param msg_id message ID
00520  * @param payload payload
00521  * @param payload_size payload size
00522  */
00523 NetworkLoggerMessageContent::NetworkLoggerMessageContent(unsigned int component_id,
00524                                                          unsigned int msg_id,
00525                                                          void *payload, size_t payload_size)
00526 {
00527   if ( component_id != FAWKES_CID_NETWORKLOGGER ) {
00528     throw TypeMismatchException("Wrong CID, expected FAWKES_CID_NETWORKLOGGER");
00529   }
00530 
00531   _payload = payload;
00532   _payload_size = payload_size;
00533   __own_payload = false;
00534   header = (NetworkLogger::network_logger_header_t *)_payload;
00535   __component = (char *)_payload + sizeof(NetworkLogger::network_logger_header_t);
00536   __message   = (char *)_payload + sizeof(NetworkLogger::network_logger_header_t) + strlen(__component) + 1;
00537 }
00538 
00539 /** Destructor. */
00540 NetworkLoggerMessageContent::~NetworkLoggerMessageContent()
00541 {
00542   if (__own_payload)  free(_payload);
00543 }
00544 
00545 /** Get time.
00546  * @return time of the log message
00547  */
00548 struct timeval
00549 NetworkLoggerMessageContent::get_time() const
00550 {
00551   struct timeval rv;
00552   rv.tv_sec  = (time_t)ntoh64(header->time_sec);
00553   rv.tv_usec = ntohl(header->time_usec);
00554   return rv;
00555 }
00556 
00557 
00558 /** Get component.
00559  * @return component string
00560  */
00561 const char *
00562 NetworkLoggerMessageContent::get_component() const
00563 {
00564   return __component;
00565 }
00566 
00567 
00568 /** Get message.
00569  * @return message string
00570  */
00571 const char *
00572 NetworkLoggerMessageContent::get_message() const
00573 {
00574   return __message;
00575 }
00576 
00577 
00578 /** Log level.
00579  * @return log level.
00580  */
00581 Logger::LogLevel
00582 NetworkLoggerMessageContent::get_loglevel() const
00583 {
00584   return (Logger::LogLevel)header->log_level;
00585 }
00586 
00587 
00588 /** Check if message was generated by exception.
00589  * @return true if message was generated by exception, false otherwise
00590  */
00591 bool
00592 NetworkLoggerMessageContent::is_exception() const
00593 {
00594   return (header->exception == 1);
00595 }
00596 
00597 } // end namespace fawkes