LogOutputStream.cpp
Go to the documentation of this file.
00001 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
00002 //----------------------------------------------------------------------
00010 //----------------------------------------------------------------------
00011 #include "LogOutputStream.h"
00012 
00013 #include <assert.h>
00014 #include <cctype>
00015 #include <cstring>
00016 #include <iostream>
00017 
00018 #include <icl_core/internal_raw_debug.h>
00019 #include <icl_core/os.h>
00020 #include <icl_core/os_lxrt.h>
00021 #include <icl_core/os_string.h>
00022 #include <icl_core_config/Config.h>
00023 
00024 #include "LoggingManager.h"
00025 #include "ThreadStream.h"
00026 
00027 namespace icl_core {
00028 namespace logging {
00029 
00030 const icl_core::String LogOutputStream::m_default_log_format = "<~T.~3M> ~S(~L)~ C~(O~::D: ~E";
00031 const icl_core::ThreadPriority LogOutputStream::m_default_worker_thread_priority = 5;
00032 
00033 LogOutputStream::LogOutputStream(const icl_core::String& name,
00034                                  const icl_core::String& config_prefix,
00035                                  icl_core::logging::LogLevel log_level,
00036                                  bool use_worker_thread)
00037   : m_name(name),
00038     m_log_level(log_level),
00039     m_time_format("%Y-%m-%d %H:%M:%S"),
00040     m_use_worker_thread(use_worker_thread),
00041     m_no_worker_thread_push_mutex(1),
00042     m_format_mutex(1)
00043 {
00044   LoggingManager::instance().assertInitialized();
00045 
00046   icl_core::String log_format = m_default_log_format;
00047   icl_core::config::get<icl_core::String>(config_prefix + "/Format", log_format);
00048   changeLogFormat(log_format.c_str());
00049 
00050   if (m_use_worker_thread)
00051   {
00052     icl_core::ThreadPriority priority = m_default_worker_thread_priority;
00053     icl_core::config::get<icl_core::ThreadPriority>(config_prefix + "/ThreadPriority", priority);
00054 
00055 #ifdef ICL_CORE_LOG_OUTPUT_STREAM_USE_FIXED_QUEUE
00056     size_t message_queue_size = cDEFAULT_FIXED_OUTPUT_STREAM_QUEUE_SIZE;
00057     icl_core::config::get<size_t>(config_prefix + "/MesageQueueSize", message_queue_size);
00058 
00059     m_worker_thread = new WorkerThread(this, message_queue_size, priority);
00060 #else
00061     m_worker_thread = new WorkerThread(this, priority);
00062 #endif
00063   }
00064   else
00065   {
00066     m_worker_thread = NULL;
00067   }
00068 }
00069 
00070 LogOutputStream::LogOutputStream(const icl_core::String& name,
00071                                  icl_core::logging::LogLevel log_level,
00072                                  bool use_worker_thread)
00073   : m_name(name),
00074     m_log_level(log_level),
00075     m_time_format("%Y-%m-%d %H:%M:%S"),
00076     m_use_worker_thread(use_worker_thread),
00077     m_no_worker_thread_push_mutex(1),
00078     m_format_mutex(1)
00079 {
00080   LoggingManager::instance().assertInitialized();
00081   changeLogFormat(m_default_log_format.c_str());
00082   if (m_use_worker_thread)
00083   {
00084 #ifdef ICL_CORE_LOG_OUTPUT_STREAM_USE_FIXED_QUEUE
00085     m_worker_thread = new WorkerThread(this, cDEFAULT_FIXED_OUTPUT_STREAM_QUEUE_SIZE,
00086                                        m_default_worker_thread_priority);
00087 #else
00088     m_worker_thread = new WorkerThread(this, m_default_worker_thread_priority);
00089 #endif
00090   }
00091   else
00092   {
00093     m_worker_thread = NULL;
00094   }
00095 }
00096 
00097 LogOutputStream::~LogOutputStream()
00098 {
00099   if (m_use_worker_thread)
00100   {
00101     if (m_worker_thread->running())
00102     {
00103       std::cerr << "WARNING: Destroyed LogOutputStream while thread is still alive. "
00104                 << "Please call Shutdown() before destruction." << std::endl;
00105     }
00106 
00107     delete m_worker_thread;
00108     m_worker_thread = NULL;
00109   }
00110 }
00111 
00112 void LogOutputStream::changeLogFormat(const char *format)
00113 {
00114   // Stop processing at the end of the format string.
00115   if (format[0] != 0)
00116   {
00117     parseLogFormat(format);
00118 
00119     if (m_format_mutex.wait())
00120     {
00121       m_log_format.clear();
00122       m_log_format = m_new_log_format;
00123       m_new_log_format.clear();
00124 
00125       m_format_mutex.post();
00126     }
00127   }
00128 }
00129 
00130 void LogOutputStream::push(icl_core::logging::LogLevel log_level,
00131                            const char* log_stream_description, const char *filename,
00132                            int line, const char *classname, const char *objectname,
00133                            const char *function, const char *text)
00134 {
00135   if (log_level >= getLogLevel())
00136   {
00137     LogMessage new_entry(icl_core::TimeStamp::now(), log_level, log_stream_description,
00138                          filename, line, classname, objectname, function, text);
00139 
00140     if (m_use_worker_thread)
00141     {
00142       // Hand the log text over to the output implementation.
00143       if (m_worker_thread->m_mutex->wait())
00144       {
00145 #ifdef ICL_CORE_LOG_OUTPUT_STREAM_USE_FIXED_QUEUE
00146         if (!m_worker_thread->isMessageQueueFull())
00147         {
00148           m_worker_thread->m_message_queue[m_worker_thread->m_message_queue_write_index] = new_entry;
00149           m_worker_thread->incrementIndex(m_worker_thread->m_message_queue_write_index);
00150         }
00151 #else
00152         m_worker_thread->m_message_queue.push(new_entry);
00153 #endif
00154         m_worker_thread->m_mutex->post();
00155         m_worker_thread->m_fill_count->post();
00156       }
00157     }
00158     else
00159     {
00160       if (m_no_worker_thread_push_mutex.wait())
00161       {
00162         pushImpl(new_entry);
00163         m_no_worker_thread_push_mutex.post();
00164       }
00165     }
00166   }
00167 }
00168 
00169 void LogOutputStream::pushImpl(const LogMessage& log_message)
00170 {
00171   if (m_format_mutex.wait())
00172   {
00173     std::stringstream msg;
00174     for (icl_core::List<LogFormatEntry>::const_iterator it = m_log_format.begin();
00175          it != m_log_format.end(); ++it)
00176     {
00177       switch (it->type)
00178       {
00179       case LogFormatEntry::eT_TEXT:
00180       {
00181         msg << it->text;
00182         break;
00183       }
00184       case LogFormatEntry::eT_CLASSNAME:
00185       {
00186         if (std::strcmp(log_message.class_name, "") != 0)
00187         {
00188           msg << it->text << log_message.class_name;
00189         }
00190         break;
00191       }
00192       case LogFormatEntry::eT_OBJECTNAME:
00193       {
00194         if (std::strcmp(log_message.object_name, "") != 0)
00195         {
00196           msg << it->text << log_message.object_name << it->suffix;
00197         }
00198         break;
00199       }
00200       case LogFormatEntry::eT_FUNCTION:
00201       {
00202         if (std::strcmp(log_message.function_name, "") != 0)
00203         {
00204           msg << it->text << log_message.function_name;
00205         }
00206         break;
00207       }
00208       case LogFormatEntry::eT_MESSAGE:
00209       {
00210         msg << log_message.message_text;
00211         break;
00212       }
00213       case LogFormatEntry::eT_FILENAME:
00214       {
00215         msg << log_message.filename;
00216         break;
00217       }
00218       case LogFormatEntry::eT_LINE:
00219       {
00220         msg << log_message.line;
00221         break;
00222       }
00223       case LogFormatEntry::eT_LEVEL:
00224       {
00225         msg << logLevelDescription(log_message.log_level);
00226         break;
00227       }
00228       case LogFormatEntry::eT_STREAM:
00229       {
00230         msg << log_message.log_stream;
00231         break;
00232       }
00233       case LogFormatEntry::eT_TIMESTAMP:
00234       {
00235         char time_buffer[100];
00236         memset(time_buffer, 0, 100);
00237 
00238 #ifdef _SYSTEM_LXRT_
00239         // Don't use strfLocaltime() in a hard realtime LXRT task, because
00240         // it might use a POSIX mutex!
00241         if (icl_core::os::isThisLxrtTask() && icl_core::os::isThisHRT())
00242         {
00243           icl_core::os::snprintf(time_buffer, 99, "%d %02d:%02d:%02d(HRT)",
00244                                  int(log_message.timestamp.days()),
00245                                  int(log_message.timestamp.hours()),
00246                                  int(log_message.timestamp.minutes()),
00247                                  int(log_message.timestamp.seconds()));
00248         }
00249         else
00250 #endif
00251         {
00252           log_message.timestamp.strfLocaltime(time_buffer, 100, m_time_format);
00253         }
00254 
00255         msg << time_buffer;
00256         break;
00257       }
00258       case LogFormatEntry::eT_TIMESTAMP_MS:
00259       {
00260         int32_t msec = log_message.timestamp.tsNSec() / 1000000;
00261         size_t msec_len = 1;
00262         if (msec >= 10)
00263         {
00264           msec_len = 2;
00265         }
00266         if (msec >= 100)
00267         {
00268           msec_len = 3;
00269         }
00270         for (size_t i = it->width; i > msec_len; --i)
00271         {
00272           msg << "0";
00273         }
00274         msg << msec;
00275         break;
00276       }
00277       }
00278     }
00279     m_format_mutex.post();
00280 
00281     pushImpl(msg.str());
00282   }
00283 }
00284 
00285 void LogOutputStream::pushImpl(const icl_core::String&)
00286 {
00287   std::cerr << "LOG OUTPUT STREAM ERROR: pushImpl() is not implemented!!!" << std::endl;
00288 }
00289 
00290 void LogOutputStream::printConfiguration() const
00291 {
00292   std::cerr << "    " << name() << " : " << logLevelDescription(m_log_level) << std::endl;
00293 }
00294 
00295 
00297 #ifdef _IC_BUILDER_DEPRECATED_STYLE_
00298 
00302 void LogOutputStream::ChangeTimeFormat(const char* format)
00303 {
00304   changeTimeFormat(format);
00305 }
00306 
00310 void LogOutputStream::ChangeLogFormat(const char *format)
00311 {
00312   changeLogFormat(format);
00313 }
00314 
00318 void LogOutputStream::Push(icl_core::logging::LogLevel log_level,
00319                            const char *log_stream_description, const char *filename,
00320                            int line, const char *classname, const char *objectname,
00321                            const char *function, const char *text)
00322 {
00323   push(log_level, log_stream_description, filename, line, classname, objectname, function, text);
00324 }
00325 
00329 void LogOutputStream::Start()
00330 {
00331   start();
00332 }
00333 
00338 void LogOutputStream::Shutdown()
00339 {
00340   shutdown();
00341 }
00342 
00346 ICL_CORE_VC_DEPRECATE_STYLE_USE(LogOutputStream::getLogLevel)
00347 icl_core::logging::LogLevel LogOutputStream::LogLevel() const
00348 {
00349   return getLogLevel();
00350 }
00351 
00355 void LogOutputStream::SetLogLevel(icl_core::logging::LogLevel log_level)
00356 {
00357   setLogLevel(log_level);
00358 }
00359 
00363 icl_core::String LogOutputStream::Name() const
00364 {
00365   return name();
00366 }
00367 
00372 void LogOutputStream::PrintConfiguration() const
00373 {
00374   printConfiguration();
00375 }
00376 
00377 #endif
00378 
00379 
00380 void LogOutputStream::parseLogFormat(const char *format)
00381 {
00382   LogFormatEntry new_entry;
00383 
00384   // The format string starts with a field specifier.
00385   if (format[0] == '~')
00386   {
00387     ++format;
00388 
00389     // Read the field width.
00390     while (format[0] != 0 && std::isdigit(format[0]))
00391     {
00392       new_entry.width = 10 * new_entry.width + (format[0] - '0');
00393       ++format;
00394     }
00395 
00396     // Read optional prefix text.
00397     char *prefix_ptr = new_entry.text;
00398     while (format[0] != 0 && format[0] != 'C' && format[0] != 'O' && format[0] != 'D'
00399            && format[0] != 'E' && format[0] != 'F' && format[0] != 'G' && format[0] != 'L'
00400            && format[0] != 'S' && format[0] != 'T' && format[0] != 'M')
00401     {
00402       *prefix_ptr = format[0];
00403       ++prefix_ptr;
00404       ++format;
00405     }
00406 
00407     // Read the field type.
00408     if (format[0] == 'C')
00409     {
00410       new_entry.type = LogFormatEntry::eT_CLASSNAME;
00411     }
00412     else if (format[0] == 'O')
00413     {
00414       new_entry.type = LogFormatEntry::eT_OBJECTNAME;
00415       if (new_entry.text[0] == '(')
00416       {
00417         std::strncpy(new_entry.suffix, ")", 100);
00418       }
00419       else if (new_entry.text[0] == '[')
00420       {
00421         std::strncpy(new_entry.suffix, "]", 100);
00422       }
00423       else if (new_entry.text[0] == '{')
00424       {
00425         std::strncpy(new_entry.suffix, "}", 100);
00426       }
00427     }
00428     else if (format[0] == 'D')
00429     {
00430       new_entry.type = LogFormatEntry::eT_FUNCTION;
00431     }
00432     else if (format[0] == 'E')
00433     {
00434       new_entry.type = LogFormatEntry::eT_MESSAGE;
00435     }
00436     else if (format[0] == 'F')
00437     {
00438       new_entry.type = LogFormatEntry::eT_FILENAME;
00439     }
00440     else if (format[0] == 'G')
00441     {
00442       new_entry.type = LogFormatEntry::eT_LINE;
00443     }
00444     else if (format[0] == 'L')
00445     {
00446       new_entry.type = LogFormatEntry::eT_LEVEL;
00447     }
00448     else if (format[0] == 'S')
00449     {
00450       new_entry.type = LogFormatEntry::eT_STREAM;
00451     }
00452     else if (format[0] == 'T')
00453     {
00454       new_entry.type = LogFormatEntry::eT_TIMESTAMP;
00455     }
00456     else if (format[0] == 'M')
00457     {
00458       new_entry.type = LogFormatEntry::eT_TIMESTAMP_MS;
00459     }
00460 
00461     if (format[0] != 0)
00462     {
00463       m_new_log_format.push_back(new_entry);
00464     }
00465 
00466     ++format;
00467   }
00468   else
00469   {
00470     char *text_ptr = new_entry.text;
00471     while (format[0] != '~' && format[0] != 0)
00472     {
00473       *text_ptr = format[0];
00474       ++text_ptr;
00475       ++format;
00476     }
00477 
00478     if (new_entry.text[0] != 0)
00479     {
00480       m_new_log_format.push_back(new_entry);
00481     }
00482   }
00483 
00484   // Stop processing at the end of the format string.
00485   if (format[0] == 0)
00486   {
00487     return;
00488   }
00489   else
00490   {
00491     parseLogFormat(format);
00492   }
00493 }
00494 
00495 void LogOutputStream::start()
00496 {
00497   if (m_use_worker_thread)
00498   {
00499     m_worker_thread->start();
00500   }
00501 }
00502 
00503 void LogOutputStream::shutdown()
00504 {
00505   if (m_use_worker_thread)
00506   {
00507     if (m_worker_thread->running())
00508     {
00509       m_worker_thread->stop();
00510       m_worker_thread->m_fill_count->post();
00511       m_worker_thread->join();
00512     }
00513   }
00514 }
00515 
00516 #ifdef ICL_CORE_LOG_OUTPUT_STREAM_USE_FIXED_QUEUE
00517 LogOutputStream::WorkerThread::WorkerThread(LogOutputStream *output_stream, size_t message_queue_size,
00518                                             icl_core::ThreadPriority priority)
00519   : Thread(priority),
00520     m_output_stream(output_stream),
00521     m_message_queue_size(message_queue_size),
00522     m_message_queue_write_index(0),
00523     m_message_queue_read_index(0)
00524 {
00525   m_message_queue = new LogMessage[message_queue_size+1];
00526 
00527   m_mutex = new Semaphore(1);
00528   m_fill_count = new Semaphore(0);
00529 }
00530 #else
00531 LogOutputStream::WorkerThread::WorkerThread(LogOutputStream *output_stream, icl_core::ThreadPriority priority)
00532   : Thread(priority),
00533     m_output_stream(output_stream)
00534 {
00535   m_mutex = new Semaphore(1);
00536   m_fill_count = new Semaphore(0);
00537 }
00538 #endif
00539 
00540 LogOutputStream::WorkerThread::~WorkerThread()
00541 {
00542   delete m_mutex;
00543   delete m_fill_count;
00544 #ifdef ICL_CORE_LOG_OUTPUT_STREAM_USE_FIXED_QUEUE
00545   delete[] m_message_queue;
00546 #endif
00547 }
00548 
00549 void LogOutputStream::WorkerThread::run()
00550 {
00551   m_output_stream->onStart();
00552 
00553   // Wait for new messages to arrive.
00554   while (execute())
00555   {
00556     if (m_fill_count->wait())
00557     {
00558 #ifdef ICL_CORE_LOG_OUTPUT_STREAM_USE_FIXED_QUEUE
00559       if (!isMessageQueueEmpty())
00560 #else
00561       if (!m_message_queue.empty())
00562 #endif
00563       {
00564         if (m_mutex->wait())
00565         {
00566           LogMessage log_message;
00567           bool push = false;
00568 #ifdef ICL_CORE_LOG_OUTPUT_STREAM_USE_FIXED_QUEUE
00569           if (!isMessageQueueEmpty())
00570           {
00571             log_message = m_message_queue[m_message_queue_read_index];
00572             incrementIndex(m_message_queue_read_index);
00573             push = true;
00574           }
00575 #else
00576           if (!m_message_queue.empty())
00577           {
00578             log_message = m_message_queue.front();
00579             m_message_queue.pop();
00580             push = true;
00581           }
00582 #endif
00583 
00584           m_mutex->post();
00585 
00586           if (push)
00587           {
00588             m_output_stream->pushImpl(log_message);
00589           }
00590         }
00591       }
00592     }
00593     else if (execute())
00594     {
00595       PRINTF("LogOutputStream(%s)::run: semaphore wait failed\n", m_output_stream->m_name.c_str());
00596       icl_core::os::usleep(10000);
00597     }
00598   }
00599 
00600   // Write out all remaining log messages.
00601   if (m_mutex->wait())
00602   {
00603 #ifdef ICL_CORE_LOG_OUTPUT_STREAM_USE_FIXED_QUEUE
00604     while (!isMessageQueueEmpty())
00605     {
00606       LogMessage log_message = m_message_queue[m_message_queue_read_index];
00607       incrementIndex(m_message_queue_read_index);
00608       m_output_stream->pushImpl(log_message);
00609     }
00610 #else
00611     while (!m_message_queue.empty())
00612     {
00613       LogMessage log_message = m_message_queue.front();
00614       m_message_queue.pop();
00615       m_output_stream->pushImpl(log_message);
00616     }
00617 #endif
00618 
00619     m_mutex->post();
00620   }
00621 
00622   m_output_stream->onShutdown();
00623 }
00624 
00625 
00626 #ifdef ICL_CORE_LOG_OUTPUT_STREAM_USE_FIXED_QUEUE
00627 void LogOutputStream::WorkerThread::incrementIndex(size_t& index)
00628 {
00629   ++index;
00630   if (index >= m_message_queue_size)
00631   {
00632     index = 0;
00633   }
00634 }
00635 
00636 bool LogOutputStream::WorkerThread::isMessageQueueEmpty()
00637 {
00638   return m_message_queue_read_index == m_message_queue_write_index;
00639 }
00640 
00641 bool LogOutputStream::WorkerThread::isMessageQueueFull()
00642 {
00643   return ((m_message_queue_write_index == m_message_queue_read_index - 1)
00644           || (m_message_queue_write_index == m_message_queue_size - 1
00645               && m_message_queue_read_index == 0));
00646 }
00647 #endif
00648 
00649 LogOutputStream::LogMessage::LogMessage(const icl_core::TimeStamp& timestamp,
00650                                         icl_core::logging::LogLevel log_level,
00651                                         const char *log_stream, const char *filename,
00652                                         size_t line, const char *class_name,
00653                                         const char *object_name, const char *function_name,
00654                                         const char *message_text)
00655   : timestamp(timestamp),
00656     log_level(log_level),
00657     line(line)
00658 {
00659   std::strncpy(LogMessage::log_stream, log_stream, cMAX_IDENTIFIER_LENGTH+1);
00660   std::strncpy(LogMessage::filename, filename, cMAX_DESCRIPTION_LENGTH+1);
00661   std::strncpy(LogMessage::class_name, class_name, cMAX_IDENTIFIER_LENGTH+1);
00662   std::strncpy(LogMessage::object_name, object_name, cMAX_DESCRIPTION_LENGTH+1);
00663   std::strncpy(LogMessage::function_name, function_name, cMAX_IDENTIFIER_LENGTH+1);
00664   std::strncpy(LogMessage::message_text, message_text, cDEFAULT_LOG_SIZE+1);
00665 }
00666 
00667 }
00668 }


schunk_svh_driver
Author(s): Georg Heppner
autogenerated on Fri Aug 28 2015 12:59:19