00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "MsgLogger/MsgFormatter.h"
00023
00024
00025
00026
00027 #include <algorithm>
00028 extern "C" {
00029 #include <time.h>
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <sys/types.h>
00034 #include <unistd.h>
00035 }
00036
00037
00038
00039
00040
00041
00042
00043
00044 #include "MsgLogger/MsgLogRecord.h"
00045
00046
00047
00048
00049
00050 namespace {
00051
00052 using namespace MsgLogger ;
00053
00054
00055 void formattedTime ( std::string fmt, std::ostream& out ) ;
00056
00057
00058 const std::string s_defFmt = "%(time) [%(LVL)] {%(logger)} %(file):%(line) - %(message)" ;
00059
00060
00061 std::string s_appFmtMap [MsgLogLevel::LAST_LEVEL+1] ;
00062
00063
00064 std::string s_envFmtMap [MsgLogLevel::LAST_LEVEL+1] ;
00065
00066 void initFmtMap() {
00067
00068 static bool initDone = false ;
00069 if ( not initDone ) {
00070 initDone = true ;
00071
00072
00073 if ( const char* env = getenv ( "MSGLOGFMT" ) ) {
00074 std::fill_n ( s_envFmtMap, MsgLogLevel::LAST_LEVEL+1, env ) ;
00075 }
00076
00077
00078
00079 for ( int i = 0 ; i < MsgLogLevel::LAST_LEVEL+1 ; ++ i ) {
00080 MsgLogLevel lvl(i) ;
00081 std::string envname = "MSGLOGFMT_" ;
00082 envname += lvl.level3() ;
00083 if ( const char* env = getenv ( envname.c_str() ) ) {
00084 s_envFmtMap[i] = env ;
00085 }
00086 }
00087
00088 }
00089 }
00090
00091 }
00092
00093 namespace MsgLogger {
00094
00095
00096
00097
00098
00099
00100 MsgFormatter::MsgFormatter( const std::string& afmt, const std::string& timefmt )
00101 : _timefmt(timefmt)
00102 {
00103
00104 ::initFmtMap() ;
00105
00106 if ( _timefmt.empty() ) {
00107 if ( const char* env = getenv ( "MSGLOGTIMEFMT" ) ) {
00108 _timefmt = env ;
00109 } else {
00110 _timefmt = "%Y-%m-%d %H:%M:%S.%f" ;
00111 }
00112 }
00113 }
00114
00115
00116 MsgFormatter::~MsgFormatter()
00117 {
00118 }
00119
00120
00121 void
00122 MsgFormatter::addGlobalFormat ( const std::string& fmt )
00123 {
00124 std::fill_n ( ::s_appFmtMap, MsgLogLevel::LAST_LEVEL+1, fmt ) ;
00125 }
00126
00127 void
00128 MsgFormatter::addGlobalFormat ( MsgLogLevel level, const std::string& fmt )
00129 {
00130 ::s_appFmtMap[level.code()] = fmt ;
00131 }
00132
00133
00134 void
00135 MsgFormatter::addFormat ( MsgLogLevel level, const std::string& fmt )
00136 {
00137 _fmtMap[level.code()] = fmt ;
00138 }
00139
00140
00141 void
00142 MsgFormatter::format ( const MsgLogRecord& rec, std::ostream& out )
00143 {
00144 const std::string& fmt = getFormat( rec.level() );
00145
00146
00147 for ( std::string::const_iterator i = fmt.begin() ; i != fmt.end() ; ++ i ) {
00148
00149 if ( *i != '%' ) {
00150 out.put( *i ) ;
00151 continue ;
00152 }
00153
00154 std::string::const_iterator j = i ;
00155 if ( ++j == fmt.end() ) {
00156 out.put( *i ) ;
00157 continue ;
00158 }
00159
00160
00161 if ( *j == '%' ) {
00162 out.put( '%' ) ;
00163 i = j ;
00164 continue ;
00165 }
00166
00167
00168 if ( *j != '(' ) {
00169 out.put( *i ) ;
00170 continue ;
00171 }
00172
00173
00174 j = std::find ( j, fmt.end(), ')' ) ;
00175 if ( j == fmt.end() ) {
00176 out.put( *i ) ;
00177 continue ;
00178 }
00179
00180
00181 std::string name ( i+2, j ) ;
00182 bool known = true ;
00183 if ( name == "logger" ) {
00184 if ( rec.logger().empty() ) {
00185 out << "/root/" ;
00186 } else {
00187 out << rec.logger() ;
00188 }
00189 } else if ( name == "level" ) {
00190 out << rec.level() ;
00191 } else if ( name == "L" ) {
00192 out << rec.level().levelLetter() ;
00193 } else if ( name == "LVL" ) {
00194 out << rec.level().level3() ;
00195 } else if ( name == "message" ) {
00196
00197 rec.msgbuf()->pubseekoff ( 0, std::ios_base::beg, std::ios_base::in ) ;
00198 out << rec.msgbuf() ;
00199 } else if ( name == "path" ) {
00200 const char* path = rec.fileName() ;
00201 out << ( path ? path : "<empty>" ) ;
00202 } else if ( name == "file" ) {
00203 const char* path = rec.fileName() ;
00204 if ( path ) {
00205 const char* p = strrchr ( path, '/' ) ;
00206 if ( ! p ) p = path ;
00207 out << p+1 ;
00208 } else {
00209 out << "<empty>" ;
00210 }
00211 } else if ( name == "line" ) {
00212 out << rec.lineNum() ;
00213 } else if ( name == "time" ) {
00214 formattedTime ( _timefmt, out ) ;
00215 } else if ( name == "pid" ) {
00216 out << (unsigned long)getpid() ;
00217 } else {
00218 known = false ;
00219 }
00220
00221
00222 if ( known ) {
00223 i = j ;
00224 }
00225
00226 }
00227
00228
00229 }
00230
00231
00232 const std::string&
00233 MsgFormatter::getFormat ( MsgLogLevel level ) const
00234 {
00235 int lvl = level.code() ;
00236 if ( not _fmtMap[lvl].empty() ) {
00237 return _fmtMap[lvl] ;
00238 } else if ( not ::s_envFmtMap[lvl].empty() ) {
00239 return ::s_envFmtMap[lvl] ;
00240 } else if ( not ::s_appFmtMap[lvl].empty() ) {
00241 return ::s_appFmtMap[lvl] ;
00242 } else {
00243 return ::s_defFmt ;
00244 }
00245 }
00246
00247
00248
00249 }
00250
00251 namespace {
00252
00253
00254 void formattedTime ( std::string fmt, std::ostream& out )
00255 {
00256
00257 struct timespec ts;
00258 clock_gettime( CLOCK_REALTIME, &ts );
00259
00260
00261 struct tm tms ;
00262 localtime_r( &ts.tv_sec, &tms );
00263
00264
00265 std::string::size_type n = fmt.find("%f") ;
00266 if ( n != std::string::npos ) {
00267 char subs[4] ;
00268 snprintf ( subs, 4, "%03d", int(ts.tv_nsec/1000000) ) ;
00269 while ( n != std::string::npos ) {
00270 fmt.replace ( n, 2, subs ) ;
00271 n = fmt.find("%f") ;
00272 }
00273 }
00274
00275 char buf[1024] ;
00276 strftime(buf, 1024, fmt.c_str(), &tms );
00277 out << buf ;
00278
00279 }
00280
00281 }