nux-1.14.0
|
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, ×tamp) == 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(×tamp, &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 }