Back to index

nux  3.0.0
LoggingWriter.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /*
00003  * Copyright 2011 Inalogic® Inc.
00004  *
00005  * This program is free software: you can redistribute it and/or modify it
00006  * under the terms of the GNU Lesser General Public License, as
00007  * published by the  Free Software Foundation; either version 2.1 or 3.0
00008  * of the License.
00009  *
00010  * This program is distributed in the hope that it will be useful, but
00011  * WITHOUT ANY WARRANTY; without even the implied warranties of
00012  * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
00013  * PURPOSE.  See the applicable version of the GNU Lesser General Public
00014  * License for more details.
00015  *
00016  * You should have received a copy of both the GNU Lesser General Public
00017  * License along with this program. If not, see <http://www.gnu.org/licenses/>
00018  *
00019  * Authored by: Tim Penhey <tim.penhey@canonical.com>
00020  *
00021  */
00022 
00023 //#if defined(NUX_OS_WINDOWS)
00024 #include "NuxCore.h"
00025 //#endif
00026 
00027 #include "System.h"
00028 #include "LoggingWriter.h"
00029 
00030 #include <cstdlib>
00031 #include <iostream>
00032 #include <sstream>
00033 #include <vector>
00034 
00035 namespace nux {
00036 namespace logging {
00037 
00038 namespace {
00039 
00040 Writer* pInstance;
00041 
00042 void cleanup_writer_instance()
00043 {
00044   delete pInstance;
00045   pInstance = 0;
00046 }
00047 
00048 struct StreamWrapper
00049 {
00050   typedef boost::shared_ptr<StreamWrapper> Ptr;
00051 
00052   StreamWrapper(std::ostream& output) : out(output) {}
00053   std::ostream& out;
00054 };
00055 
00056 const char* severity_string(Level severity)
00057 {
00058   // The return value is always padded out here.
00059   switch (severity)
00060   {
00061   case Critical:
00062     return "CRIT ";
00063   case Error:
00064     return "ERROR";
00065   case Warning:
00066     return "WARN ";
00067   case Info:
00068     return "INFO ";
00069   case Debug:
00070     return "DEBUG";
00071   case Trace:
00072     return "TRACE";
00073   default:
00074     // We technically shouldn't get this.
00075     return "     ";
00076   }
00077 }
00078 
00079 std::string TimestampString(std::time_t timestamp)
00080 {
00081   // return an ISO format string: YYYY-MM-DD HH:MM:SS
00082   static const char* format = "%Y-%m-%d %H:%M:%S";
00083   const int buf_size = 20;
00084   char buffer[buf_size];
00085   tm local_time;
00086 
00087 #if defined(NUX_OS_WINDOWS)
00088   static const char* invalid_time_stamp = "invalid_time_stamp";
00089 
00090   if (localtime_s(&local_time, &timestamp) == 0)
00091     std::strftime(buffer, buf_size, format, &local_time);
00092   else
00093     memcpy_s(buffer, sizeof(buffer), invalid_time_stamp, strnlen(invalid_time_stamp, 30));
00094 #else
00095   std::strftime(buffer, buf_size, format, ::localtime_r(&timestamp, &local_time));
00096 #endif
00097 
00098   return buffer;
00099 }
00100 
00101 std::string ShortenedFilename(std::string const& filename)
00102 {
00103   std::string::size_type pos = filename.rfind('/');
00104   if (pos == std::string::npos)
00105     return filename;
00106 
00107   return filename.substr(pos+1);
00108 }
00109 
00110 } // anon namespace
00111 
00112 class Writer::Impl
00113 {
00114 public:
00115   Impl();
00116 
00117   void WriteMessage(Level severity,
00118                     std::string const& module,
00119                     std::string const& filename,
00120                     int line_number,
00121                     std::time_t timestamp,
00122                     std::string const& message);
00123 
00124   void SetOutputStream(std::ostream& out);
00125 
00126 private:
00127   typedef std::vector<StreamWrapper::Ptr> OutputStreams;
00128   OutputStreams output_streams_;
00129 };
00130 
00131 Writer::Impl::Impl()
00132 {
00133   output_streams_.push_back(StreamWrapper::Ptr(new StreamWrapper(std::cout)));
00134 }
00135 
00136 void Writer::Impl::SetOutputStream(std::ostream& out)
00137 {
00138   output_streams_.clear();
00139   output_streams_.push_back(StreamWrapper::Ptr(new StreamWrapper(out)));
00140 }
00141 
00142 void Writer::Impl::WriteMessage(Level severity,
00143                                 std::string const& module,
00144                                 std::string const& filename,
00145                                 int line_number,
00146                                 std::time_t timestamp,
00147                                 std::string const& message)
00148 {
00149   // If we want to have some form of custom formatter, here is where we do it.
00150   // Right now, format the line independently, and then write it to each
00151   // output stream.
00152   std::stringstream sout;
00153   sout << severity_string(severity)
00154        << " " << TimestampString(timestamp)
00155        << " " << module
00156        << " " << ShortenedFilename(filename)
00157        << ":" << line_number
00158        << " " << message;
00159   for (OutputStreams::iterator i = output_streams_.begin(), end = output_streams_.end();
00160        i != end; ++i)
00161   {
00162     std::ostream& out = (*i)->out;
00163     out << sout.rdbuf() << std::endl;
00164   }
00165 
00166 #if defined(NUX_OS_WINDOWS) && defined(NUX_DEBUG)
00167   // Quick hack to print messages to Visual Studio output.
00168   // Should create a Visual Studio StreamWrapper instead!
00169   OutputDebugString (sout.str().c_str());
00170 #endif
00171 
00172 }
00173 
00174 
00175 Writer::Writer()
00176   : pimpl(new Impl())
00177 {
00178 #ifdef NUX_DEBUG
00179   std::cerr << "nux::logging::Writer::Writer()\n";
00180 #endif
00181 }
00182 
00183 Writer::~Writer()
00184 {
00185   delete pimpl;
00186 #ifdef NUX_DEBUG
00187   std::cerr << "nux::logging::Writer::~Writer()\n";
00188 #endif
00189 }
00190 
00191 Writer& Writer::Instance()
00192 {
00193   if (pInstance == 0)
00194   {
00195     pInstance = new Writer();
00196     std::atexit(cleanup_writer_instance);
00197   }
00198   return *pInstance;
00199 }
00200 
00201 void Writer::WriteMessage(Level severity,
00202                           std::string const& module,
00203                           std::string const& filename,
00204                           int line_number,
00205                           std::time_t timestamp,
00206                           std::string const& message)
00207 {
00208   pimpl->WriteMessage(severity, module, filename, line_number,
00209                       timestamp, message);
00210 }
00211 
00212 void Writer::SetOutputStream(std::ostream& out)
00213 {
00214   pimpl->SetOutputStream(out);
00215 }
00216 
00217 }
00218 }