OpenRTM
1.0.0
|
00001 // -*- C++ -*- 00020 #ifndef LOGGER_H 00021 #define LOGGER_H 00022 00023 #include <limits.h> 00024 #include <iostream> 00025 #include <fstream> 00026 #include <vector> 00027 #include <string> 00028 00029 #include <coil/Mutex.h> 00030 #include <coil/Guard.h> 00031 00032 #ifndef LINE_MAX 00033 #define LINE_MAX 1024 00034 #endif 00035 00036 #define BUFFER_LEN LINE_MAX 00037 00038 namespace coil 00039 { 00053 template <typename _CharT, typename _Traits=std::char_traits<_CharT> > 00054 class log_streambuf 00055 : public ::std::basic_streambuf<_CharT, _Traits> 00056 { 00057 public: 00058 typedef _CharT char_type; 00059 typedef _Traits traits_type; 00060 typedef std::basic_streambuf<char_type, traits_type> streambuf_type; 00061 typedef coil::Mutex Mutex; 00062 typedef coil::Guard<coil::Mutex> Guard; 00063 00079 log_streambuf() 00080 : streambuf_type() 00081 { 00082 char *pStart = m_buf; 00083 char *pEnd = m_buf + (BUFFER_LEN - 1); 00084 this->setp(pStart, pEnd); 00085 this->setg(pStart, pStart, pEnd); 00086 } 00087 00103 virtual ~log_streambuf() 00104 { 00105 } 00106 00136 void addStream(streambuf_type* stream, bool cleanup = false) 00137 { 00138 m_streams.push_back(Stream(stream, cleanup)); 00139 } 00140 00163 bool removeStream(streambuf_type* stream) 00164 { 00165 std::vector<coil::log_streambuf<char>::Stream>::iterator it; 00166 for( it = m_streams.begin(); it != m_streams.end(); it++ ) 00167 { 00168 if (it->stream_ == stream) 00169 { 00170 m_streams.erase(it); 00171 return true; 00172 } 00173 } 00174 return false; 00175 } 00176 00196 std::vector<streambuf_type*> getBuffers() 00197 { 00198 std::vector<streambuf_type*> buffs; 00199 for (int i(0), len(m_streams.size()); i < len; ++i) 00200 { 00201 buffs.push_back(m_streams[i].stream_); 00202 } 00203 return buffs; 00204 } 00205 00206 protected: 00226 virtual std::streamsize xsputn(const char_type* s, std::streamsize n) 00227 { 00228 stream_sputn(); 00229 for (int i(0), len(m_streams.size()); i < len; ++i) 00230 { 00231 Guard gaurd(m_streams[i].mutex_); 00232 m_streams[i].stream_->sputn(s, n); 00233 } 00234 return n; 00235 } 00236 00252 virtual std::streamsize stream_sputn() 00253 { 00254 int bytes_to_write; 00255 bytes_to_write = this->pptr() - this->gptr(); 00256 if (bytes_to_write > 0) 00257 { 00258 for (int i(0), len(m_streams.size()); i < len; ++i) 00259 { 00260 Guard gaurd(m_streams[i].mutex_); 00261 m_streams[i].stream_->sputn(this->gptr(), bytes_to_write); 00262 } 00263 this->gbump(bytes_to_write); 00264 if (this->gptr() >= this->pptr()) 00265 { 00266 this->pbump(this->pbase() - this->pptr()); 00267 this->gbump(this->pbase() - this->gptr()); 00268 } 00269 } 00270 return bytes_to_write; 00271 } 00272 00293 virtual std::streamsize stream_sputn(const char_type* s, std::streamsize n) 00294 { 00295 00296 for (int i(0), len(m_streams.size()); i < len; ++i) 00297 { 00298 Guard gaurd(m_streams[i].mutex_); 00299 m_streams[i].stream_->sputn(s, n); 00300 m_streams[i].stream_->pubsync(); 00301 } 00302 return n; 00303 } 00322 virtual int overflow (int c = traits_type::eof()) 00323 { 00324 Guard guard(m_mutex); 00325 // if (traits_type::eq_int_type(c, traits_type::eof())) 00326 // return c; 00327 // 00328 // char_type last_char = traits_type::to_char_type(c); 00329 // if (sputn(&last_char, 1) != 1) 00330 // return traits_type::eof(); 00331 // else 00332 // return c; 00333 00334 if (this->pbase()) 00335 { 00336 if (this->pptr() > this->epptr() || this->pptr() < this->pbase()) 00337 return traits_type::eof(); 00338 // Add extra character to buffer if not EOF 00339 if (!traits_type::eq_int_type(c, traits_type::eof())) 00340 { 00341 this->pbump(-1); 00342 *(this->pptr()) = traits_type::to_char_type(c); 00343 this->pbump(1); 00344 } 00345 // Number of characters to write to file 00346 int bytes_to_write = this->pptr() - this->gptr(); 00347 // Overflow doesn't fail if nothing is to be written 00348 if (bytes_to_write > 0) 00349 { 00350 if (stream_sputn(this->gptr(), bytes_to_write) != bytes_to_write) 00351 return traits_type::eof(); 00352 // Reset next pointer to point to pbase on success 00353 this->pbump(this->pbase() - this->pptr()); 00354 this->gbump(this->pbase() - this->gptr()); 00355 } 00356 } 00357 // Write extra character to file if not EOF 00358 else if (!traits_type::eq_int_type(c, traits_type::eof())) 00359 { 00360 // Impromptu char buffer (allows "unbuffered" output) 00361 char_type last_char = traits_type::to_char_type(c); 00362 // If gzipped file won't accept this character, fail 00363 if (stream_sputn(&last_char, 1) != 1) 00364 return traits_type::eof(); 00365 } 00366 // If you got here, you have succeeded (even if c was EOF) 00367 // The return value should therefore be non-EOF 00368 if (traits_type::eq_int_type(c, traits_type::eof())) 00369 return traits_type::not_eof(c); 00370 else 00371 return c; 00372 } 00373 00389 virtual int sync() 00390 { 00391 if (this->pbase()) 00392 { 00393 Guard guard(m_mutex); 00394 if (this->pptr() > this->epptr() || this->pptr() < this->pbase()) 00395 return -1; 00396 00397 int bytes_to_write; 00398 bytes_to_write = this->pptr() - this->gptr(); 00399 if (bytes_to_write > 0) 00400 { 00401 if (stream_sputn(this->gptr(), bytes_to_write) != bytes_to_write) 00402 { 00403 return -1; 00404 } 00405 this->gbump(bytes_to_write); 00406 if (this->gptr() >= this->pptr()) 00407 { 00408 this->pbump(this->pbase() - this->pptr()); 00409 this->gbump(this->pbase() - this->gptr()); 00410 } 00411 } 00412 } 00413 else 00414 { 00415 this->overflow(); 00416 } 00417 return 0; 00418 } 00419 00420 public: 00421 00433 struct Stream 00434 { 00435 Stream(streambuf_type* stream, bool cleanup = false) 00436 : stream_(stream), cleanup_(cleanup) 00437 { 00438 } 00439 00440 virtual ~Stream() 00441 { 00442 } 00443 00444 Stream(const Stream& x) 00445 : stream_(x.stream_) 00446 { 00447 } 00448 00449 Stream& operator=(const Stream& x) 00450 { 00451 Stream tmp(x); 00452 tmp.swap(*this); 00453 return *this; 00454 } 00455 00456 void swap(Stream& x) 00457 { 00458 streambuf_type* stream = x.stream_; 00459 bool cleanup = x.cleanup_; 00460 00461 x.stream_ = this->stream_; 00462 x.cleanup_ = this->cleanup_; 00463 00464 this->stream_ = stream; 00465 this->cleanup_ = cleanup; 00466 } 00467 mutable Mutex mutex_; 00468 streambuf_type* stream_; 00469 bool cleanup_; 00470 }; 00471 00472 private: 00473 00493 log_streambuf(const log_streambuf& x); 00494 00518 log_streambuf& operator=(const log_streambuf& x); 00519 00520 std::vector<Stream> m_streams; 00521 Mutex m_mutex; 00522 char m_buf[BUFFER_LEN]; 00523 }; 00524 00525 00539 template <typename _CharT, typename _Traits=std::char_traits<_CharT> > 00540 class log_stream 00541 : public std::basic_ostream<_CharT, _Traits> 00542 { 00543 public: 00544 // Types: 00545 typedef _CharT char_type; 00546 typedef _Traits traits_type; 00547 typedef std::basic_ostream<char_type, traits_type> ostream_type; 00548 typedef std::basic_streambuf<char_type, traits_type> streambuf_type; 00549 typedef coil::Mutex Mutex; 00550 typedef coil::Guard<Mutex> Guard; 00551 00577 log_stream(streambuf_type* sb, int levelmin, int levelmax, int level) 00578 : ostream_type(sb), 00579 m_minLevel(levelmin), m_maxLevel(levelmax), m_logLevel(level) 00580 { 00581 if (m_minLevel >= m_maxLevel) throw std::bad_alloc(); 00582 this->init(sb); 00583 } 00584 00603 virtual void header(int level) 00604 { 00605 return; 00606 } 00607 00627 bool setLevel(int level) 00628 { 00629 if (m_minLevel <= level && level <= m_maxLevel) 00630 { 00631 m_logLevel = level; 00632 return true; 00633 } 00634 return false; 00635 } 00636 00656 int getLevel() const 00657 { 00658 return m_logLevel; 00659 } 00660 00676 void enableLock() 00677 { 00678 m_lockEnable = true; 00679 } 00680 00696 void disableLock() 00697 { 00698 m_lockEnable = false; 00699 } 00700 00732 ostream_type& level(int level) 00733 { 00734 if (m_minLevel <= level && level <= m_logLevel) 00735 { 00736 header(level); 00737 return *this; 00738 } 00739 else 00740 { 00741 return m_dummy; 00742 } 00743 } 00744 00769 bool isValid(int level) const 00770 { 00771 return m_minLevel <= level && level <= m_logLevel; 00772 } 00773 00787 inline void lock() 00788 { 00789 if (m_lockEnable) m_mutex.lock(); 00790 } 00791 00805 inline void unlock() 00806 { 00807 if (m_lockEnable) m_mutex.unlock(); 00808 } 00809 00810 00811 protected: 00812 00828 ~log_stream(){}; 00829 00845 log_stream(); 00846 00866 log_stream(const log_stream& x); 00867 00891 log_stream& operator=(const log_stream& x); 00892 00893 private: 00894 int m_minLevel, m_maxLevel; 00895 int m_logLevel; 00896 00904 std::ofstream m_dummy; 00905 public: 00906 00914 static bool m_lockEnable; 00915 00923 static Mutex m_mutex; 00924 }; 00925 00926 template <typename _CharT, typename _Traits > 00927 bool log_stream<_CharT,_Traits >::m_lockEnable = true; 00928 00929 template <typename _CharT, typename _Traits > 00930 coil::Mutex log_stream<_CharT,_Traits>::m_mutex("Mutex for Logger."); 00931 00932 typedef log_streambuf<char> LogStreamBuffer; 00933 typedef log_stream<char> LogStream; 00934 00935 }; 00936 #endif // LOGGER_H