S3FC project page S3FC home page

Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

s3_logger.h

Go to the documentation of this file.
00001 /*
00002  * Stone Three Foundation Class (s3fc) provides a number of utility classes.
00003  * Copyright (C) 2001 by Stone Three Signal Processing (Pty) Ltd.
00004  *
00005  * Authored by Stone Three Signal Processing (Pty) Ltd.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  * 
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  * 
00021  * Please see the file 'COPYING' in the source root directory.
00022  */
00023 
00033 #ifndef S3_LOGGER__H
00034 #define S3_LOGGER__H
00035 
00079 #include <iostream>
00080 #include <string>
00081 #include <sstream>
00082 #include <fstream>
00083 #include <list>
00084 #include <iomanip>
00085 #include <syslog.h>
00086 #include <s3fc/s3_message.h>
00087 #include <s3fc/s3_exception.h>
00088 #include <s3fc/s3_thread_base.h>
00089 #include <s3fc/s3_conversion.h>
00090 #include <s3fc/s3_mutex.h>
00091 
00092 
00094 #define S3_LOG_DEFAULT_IDENT   "s3_log"
00095 
00096 #define S3_DEFAULT_OSTREAM_BUF_SIZE 1024
00097 //------------------------------------------------------------------------------
00106 class s3_file_buffer : public std::filebuf 
00107 {
00108 public:
00109    
00118    s3_file_buffer( const std::string& filename, bool append = true ) 
00119       throw( s3_generic_exception )
00120    {
00121       if ( std::filebuf::open(
00122          filename.c_str(),
00123          append ? (std::ios::app | std::ios::out) :
00124          (std::ios::out) ) == 0) 
00125       {
00126          throw s3_generic_exception( "s3_file_buffer::s3_file_buffer()", 
00127                                      "file open error" );
00128       }
00129    }
00130 
00131    virtual ~s3_file_buffer() {}
00132 };
00133 
00134 //------------------------------------------------------------------------------
00144 class s3_generic_streambuf : public std::streambuf
00145 {
00146 private:
00147 
00149    std::vector<char> putbuffer;
00150 
00155    virtual void write_to_device() = 0;
00156 
00157 public:
00158    
00164    s3_generic_streambuf( const unsigned int put_buffer_len = 
00165                          S3_DEFAULT_OSTREAM_BUF_SIZE ) :
00166       putbuffer( put_buffer_len + 1 )
00167    {
00168       setp( &putbuffer[0], &putbuffer[put_buffer_len] );   
00169    }
00170 
00175    virtual ~s3_generic_streambuf() 
00176    {
00177       // We may not sync() here because this will indirectly do a call
00178       // to s3_generic_streambuf::write_to_device() (which is pure virtual).
00179       // This is very much not a good thing to do.
00180       // This implies that the destructors of the derived classes MUST call
00181       // sync().
00182    }
00183 
00185    virtual int overflow( int ch )
00186    {
00187       sync();
00188       if ( ch != EOF )
00189       {
00190          *pptr() = static_cast<char>( ch );
00191          pbump( 1 );
00192       }
00193       return ch;
00194    }
00195 
00197    virtual int sync( void )
00198    {
00199       if ( pptr() > pbase() )
00200       {
00201          *pptr() = static_cast<char>('\0');
00202          write_to_device();
00203          setp( &putbuffer[0], &putbuffer[putbuffer.size()] );   
00204       }
00205       return 0;
00206    }
00207 };
00208 
00209 //------------------------------------------------------------------------------
00218 class s3_syslog_buffer : public s3_generic_streambuf
00219 {
00220 private:
00221 
00222    std::string remainder_string;
00223 
00225    virtual void write_to_device()
00226    {
00227       // We want to do a call to syslog everytime there is a '\n'
00228       // character.
00229       std::string pbase_str( pbase() );
00230       std::string::size_type start_i = 0;
00231       std::string::size_type idx;
00232 
00233       while ( ( idx = pbase_str.find( "\n", start_i ) ) != std::string::npos )
00234       {
00235          syslog( LOG_ERR, (remainder_string + pbase_str.substr( start_i, idx - start_i )).c_str() );
00236          start_i = idx + 1;
00237          remainder_string = "";
00238       }
00239       remainder_string = remainder_string +
00240          pbase_str.substr( start_i, pbase_str.length() - start_i );
00241    }
00242 
00243 public:
00244    
00248    s3_syslog_buffer( const unsigned int put_buffer_len = 
00249                      S3_DEFAULT_OSTREAM_BUF_SIZE ) :
00250       s3_generic_streambuf( put_buffer_len ),
00251       remainder_string( "" ) {}
00252 
00254    virtual ~s3_syslog_buffer() 
00255    {
00256       sync(); 
00257    }
00258 };
00259 
00260 //------------------------------------------------------------------------------
00268 class s3_syslogger : public std::ostream 
00269 {
00270  protected:
00271    
00273    s3_syslog_buffer logbuf;
00274 
00275  public:
00276 
00280     s3_syslogger() :
00281        std::ostream( &logbuf ), 
00282        logbuf() {}
00283 
00284     virtual ~s3_syslogger() {}
00285 };
00286 
00287 //------------------------------------------------------------------------------
00296 class s3_msgb_log_buffer : public s3_generic_streambuf
00297 {
00298 private:
00299    
00301    virtual void write_to_device()
00302    {
00303       msg_box.send_msg( dest_box_name, std::string( pbase() ) );
00304    }
00305 
00309    s3_message_box msg_box;
00310 
00312    const std::string dest_box_name;
00313 
00314 public:
00315    
00334    s3_msgb_log_buffer( const std::string &my_box_name,
00335                        const std::string &dst_box_name,
00336                        const std::string po_ip = "",
00337                        const unsigned int po_port = 0 ) :
00338       msg_box(),
00339       dest_box_name( dst_box_name )
00340    {
00341       if ( ( po_ip != "" ) && ( po_port !=0 ) )
00342       {
00343          if ( s3_message_box::initialised() == false )
00344          {
00345             s3_message_box::init( po_ip, po_port );
00346          }
00347       }
00348 
00349       unsigned int try_cnt = 0;
00350       while ( true )
00351       {
00352          try
00353          {
00354             msg_box.set_name( my_box_name + "_" + 
00355                               s3_conversion::to_string( try_cnt ) );
00356             msg_box.connect();
00357             break;
00358          }
00359          catch ( s3_generic_exception e )
00360          {
00361             if ( std::string( e.what() ).
00362                  find( "Name clash" ) != std::string::npos )
00363             {
00364                try_cnt++;
00365             }
00366             else
00367             {
00368                throw e;
00369             }
00370          }
00371       }
00372    }
00373 
00375    virtual ~s3_msgb_log_buffer() 
00376    {
00377       msg_box.disconnect();
00378       sync();
00379    }
00380 };
00381 
00382 //------------------------------------------------------------------------------
00390 class s3_msgb_logger : public std::ostream 
00391 {
00392  protected:
00393    
00395    s3_msgb_log_buffer logbuf;
00396 
00397  public:
00398 
00415     s3_msgb_logger( const std::string &my_box_name,
00416                     const std::string &dst_box_name,
00417                     const std::string po_ip = "",
00418                     const unsigned int po_port = 0 ) :
00419        std::ostream( &logbuf ), 
00420        logbuf( my_box_name, dst_box_name, po_ip, po_port ) {}
00421 };
00422 
00423 //------------------------------------------------------------------------------
00431 class s3_filelogger : public std::ostream 
00432 {
00433  private:
00434    
00436     s3_file_buffer logbuf;
00437 
00438  public:
00439 
00447     s3_filelogger( const std::string& filename,
00448                    const bool append = true ) :
00449        std::ostream( &logbuf ), 
00450        logbuf( filename, append ) {}
00451 };
00452 
00453 //------------------------------------------------------------------------------
00468 class s3_log_buffer : 
00469    public s3_generic_streambuf, 
00470    public std::list<std::ostream*> 
00471 {
00472 private:
00473 
00475    std::string ident;
00476 
00478    int priority;
00479 
00481    std::string priority_str;
00482 
00484    s3_mutex write_lock;
00485 
00487    virtual void write_to_device()
00488    {
00489       write_lock.lock();
00490 
00491       // Distribute to all registered ostreams.
00492       for ( std::list<std::ostream*>::iterator it = begin(); 
00493            it != end(); it++ )
00494       {
00495          **it << ident << priority_str << pbase();
00496       }
00497 
00498       write_lock.unlock();
00499    }
00500 
00501    bool b_append_info;
00502 
00503 public:
00504    
00515    s3_log_buffer( const std::string ident_arg,
00516                   std::ostream *def_out = 0,
00517                   const bool b_append_info_arg = true ) :
00518       ident( ident_arg ),
00519       b_append_info( b_append_info_arg )
00520    {
00521       if ( def_out == 0 )
00522       {
00523          push_back( &std::cerr );
00524       }
00525       else
00526       {
00527          push_back( def_out );
00528       }
00529 
00530       s3_log_buffer::set_priority( LOG_ERR );
00531 
00532       set_ident( ident_arg );
00533    }
00534 
00536    virtual ~s3_log_buffer() 
00537    {
00538       sync();
00539    }
00540 
00542    void set_ident( const std::string &new_ident )
00543    {
00544       if ( ! b_append_info )
00545       {
00546          ident = "";
00547          return;
00548       }
00549       ident =  new_ident;
00550    }
00551 
00553    int get_priority( void )
00554    {
00555       return priority;
00556    }
00557 
00573    void set_priority( const int new_priority )
00574    {
00575 
00576       if ( ! b_append_info )
00577       {
00578          priority_str = "";
00579          return;
00580       }
00581 
00582       switch( new_priority )
00583       {
00584       case LOG_EMERG:
00585          priority = new_priority;
00586          priority_str = " [emergency] ";
00587          break;
00588       case LOG_ALERT:
00589          priority = new_priority;
00590          priority_str = " [alert] ";
00591          break;
00592       case LOG_CRIT:
00593          priority = new_priority;
00594          priority_str = " [critical] ";
00595          break;
00596       case LOG_ERR:
00597          priority = new_priority;
00598          priority_str = " [error] ";
00599          break;
00600       case LOG_WARNING:
00601          priority = new_priority;
00602          priority_str = " [warning] ";
00603          break;
00604       case LOG_NOTICE:
00605          priority = new_priority;
00606          priority_str = " [notice] ";
00607          break;
00608       case LOG_INFO:
00609          priority = new_priority;
00610          priority_str = " [info] ";
00611          break;
00612       case LOG_DEBUG:
00613          priority = new_priority;
00614          priority_str = " [debug] ";
00615          break;
00616       }
00617    }
00618 }; 
00619 
00620 
00621 class s3_logger;
00622 
00623 template<class TP> class s3_smanip; // TP = Type Param
00624  
00625 template<class TP>
00626 inline std::ostream& operator<<( s3_logger& o, const s3_smanip<TP>& m )
00627 {
00628    return m._f( o, m._a );
00629 }
00630  
00631 template<class TP> 
00632 class s3_smanip 
00633 {
00634     std::ostream& (*_f)( s3_logger&, TP );
00635     TP _a;
00636 public:
00637     s3_smanip( std::ostream& (*f)(s3_logger&, TP), TP a ) : 
00638        _f( f ), 
00639        _a( a ) {}
00640     //
00641    friend
00642    std::ostream& operator<< <TP>( s3_logger& o, const s3_smanip<TP>& m );
00643 };
00644 
00645 //------------------------------------------------------------------------------
00653 class s3_logger : public std::ostream 
00654 {
00655  private:
00656 
00658    s3_log_buffer logbuf;   
00659 
00660  public:
00661 
00672     s3_logger( const std::string& ident_arg = S3_LOG_DEFAULT_IDENT,
00673                std::ostream *def_out = 0,
00674                const bool b_append_info_arg = true ) : 
00675        std::ostream( &logbuf ),
00676        logbuf( ident_arg, def_out, b_append_info_arg ) {}
00677 
00678     s3_logger(const bool b_append_info_arg) : 
00679        std::ostream( &logbuf ),
00680        logbuf( S3_LOG_DEFAULT_IDENT, 0, b_append_info_arg ) {}
00681 
00682 
00684     ~s3_logger() {}
00685 
00690     std::list<std::ostream*> &ostream_list( void )
00691     {
00692        return logbuf;
00693     }
00694 
00696     std::ostream& setident( const std::string &new_ident )
00697     {
00698        logbuf.set_ident( new_ident );
00699        return *this;
00700     }
00701 
00706     std::ostream& setpriority( const int new_priority )
00707     {
00708        logbuf.set_priority( new_priority );
00709        return *this;
00710     }
00711 
00713     int getpriority( void )
00714     {
00715        return logbuf.get_priority();
00716     }
00717 };
00718 
00719 inline extern std::ostream& __iomanip_setpriority ( s3_logger& s, int n )
00720 {
00721    return s.setpriority( n );
00722 }
00723 
00724 inline s3_smanip<int> setpriority( int n )           
00725 { 
00726    return s3_smanip<int>( __iomanip_setpriority, n ); 
00727 }
00728 
00729 inline extern std::ostream& __iomanip_setident ( s3_logger& s, std::string n )
00730 {
00731    return s.setident( n );
00732 }
00733 
00734 inline s3_smanip<std::string> setident( std::string n )           
00735 { 
00736    return s3_smanip<std::string>( __iomanip_setident, n ); 
00737 }
00738 
00739 //------------------------------------------------------------------------------
00753 class s3_msgb_log_rx_thread : public s3_thread_base
00754 {
00755 protected:
00756   
00760    s3_message_box msg_box;
00761 
00763    std::ostream *ostr;
00764 
00765 public:
00766 
00785    s3_msgb_log_rx_thread( const std::string &my_box_name,
00786                           std::ostream *ostream_arg = 0,
00787                           const std::string &po_ip = "",
00788                           const unsigned int po_port = 0 ) :
00789       msg_box( my_box_name )
00790    {
00791       if ( ostream_arg == 0 )
00792       {
00793          ostr = &std::cerr;
00794       }
00795       else
00796       {
00797          ostr = ostream_arg;
00798       }
00799 
00800       if ( ( po_ip != "" ) && ( po_port !=0 ) )
00801       {
00802          if ( s3_message_box::initialised() == false )
00803          {
00804             s3_message_box::init( po_ip, po_port );
00805          }
00806       }
00807       msg_box.connect();
00808       msg_box.subscribe_arrival( state_changed );
00809    }
00810        
00814    virtual ~s3_msgb_log_rx_thread() 
00815    {
00816       msg_box.disconnect();
00817    }
00818 
00822    void main_loop()
00823    {
00824       // The main while loop will exit when this flag is set to true.   
00825       bool b_terminate = false;
00826       while ( b_terminate == false )
00827       { 
00828          test_cancel();
00829          wait_on_state_changed();
00830 
00831          // Check msg_box for any messages.
00832          s3_message msg = msg_box.get_msg();
00833          if ( msg.is_empty() == false )
00834          {
00835             if ( ostr)
00836             {
00837                *ostr << msg.get_body() << std::flush;
00838             }
00839          }
00840       }
00841    }
00842 };
00843 
00844 extern s3_logger s3_log;
00845 
00846 #endif // S3_LOGGER__H
00847 
00848 

Send comments to: s3fc@stonethree.com SourceForge Logo