libmoost
|
00001 /* vim:set ts=3 sw=3 sts=3 et: */ 00028 #include <string> 00029 #include <algorithm> 00030 00031 #include <boost/shared_ptr.hpp> 00032 #include <boost/asio/ip/host_name.hpp> 00033 00034 #include <log4cxx/appenderskeleton.h> 00035 #include <log4cxx/helpers/synchronized.h> 00036 #include <log4cxx/patternlayout.h> 00037 #include <log4cxx/helpers/stringhelper.h> 00038 #include <log4cxx/helpers/loglog.h> 00039 #include <log4cxx/helpers/optionconverter.h> 00040 #include <log4cxx/helpers/synchronized.h> 00041 #include <log4cxx/helpers/pool.h> 00042 #include <log4cxx/helpers/fileoutputstream.h> 00043 #include <log4cxx/helpers/outputstreamwriter.h> 00044 #include <log4cxx/helpers/bufferedwriter.h> 00045 #include <log4cxx/helpers/bytebuffer.h> 00046 #include <log4cxx/helpers/synchronized.h> 00047 00048 #include "../../include/moost/nagios/nsca_client.hpp" 00049 00050 #include "../../include/moost/logging/global.hpp" 00051 #include "../../include/moost/logging/nsca_appender.hpp" 00052 #include "../../include/moost/logging/pseudo_ostream.hpp" 00053 00054 using namespace log4cxx; 00055 using namespace log4cxx::helpers; 00056 using namespace moost; 00057 using namespace moost::nagios; 00058 00059 IMPLEMENT_LOG4CXX_OBJECT(NscaAppender) 00060 00061 namespace log4cxx 00062 { 00063 NscaAppender::NscaAppender() 00064 : AppenderSkeleton(LayoutPtr(new PatternLayout(LOG4CXX_STR("%m")))) 00065 , out_(moost::logging::global_singleton::instance().get_ostream()) 00066 { 00067 activateOptions(); 00068 } 00069 00070 NscaAppender::NscaAppender( 00071 std::string const & this_host, 00072 nsca_config const & cfg 00073 ) 00074 : AppenderSkeleton(LayoutPtr(new PatternLayout(LOG4CXX_STR("%m")))) 00075 , this_host_(this_host) 00076 , this_host_desc_(this_host) 00077 , nsca_config_(cfg) 00078 , out_(moost::logging::global_singleton::instance().get_ostream()) 00079 { 00080 activateOptions(); 00081 } 00082 00083 NscaAppender::NscaAppender( 00084 std::string const & this_host, 00085 std::string const & nsca_svr_host 00086 ) 00087 : AppenderSkeleton(LayoutPtr(new PatternLayout(LOG4CXX_STR("%m")))) 00088 , this_host_(this_host) 00089 , this_host_desc_(this_host) 00090 , nsca_config_(nsca_svr_host) 00091 , out_(moost::logging::global_singleton::instance().get_ostream()) 00092 { 00093 activateOptions(); 00094 } 00095 00096 NscaAppender::NscaAppender( 00097 std::string const & this_host, 00098 std::string const & this_host_desc, 00099 nsca_config const & cfg 00100 ) 00101 : AppenderSkeleton(LayoutPtr(new PatternLayout(LOG4CXX_STR("%m")))) 00102 , this_host_(this_host) 00103 , this_host_desc_(this_host_desc) 00104 , nsca_config_(cfg) 00105 , out_(moost::logging::global_singleton::instance().get_ostream()) 00106 { 00107 activateOptions(); 00108 } 00109 00110 NscaAppender::NscaAppender( 00111 std::string const & this_host, 00112 std::string const & this_host_desc, 00113 std::string const & nsca_svr_host 00114 ) 00115 : AppenderSkeleton(LayoutPtr(new PatternLayout(LOG4CXX_STR("%m")))) 00116 , this_host_(this_host) 00117 , this_host_desc_(this_host_desc) 00118 , nsca_config_(nsca_svr_host) 00119 , out_(moost::logging::global_singleton::instance().get_ostream()) 00120 { 00121 } 00122 00123 NscaAppender::NscaAppender(LayoutPtr & layout) 00124 : log4cxx::AppenderSkeleton(layout) 00125 , out_(moost::logging::global_singleton::instance().get_ostream()) 00126 { 00127 activateOptions(); 00128 } 00129 00130 NscaAppender::NscaAppender( 00131 LayoutPtr & layout, 00132 std::string const & this_host, 00133 nsca_config const & cfg 00134 ) 00135 : AppenderSkeleton(layout) 00136 , this_host_(this_host) 00137 , this_host_desc_(this_host) 00138 , nsca_config_(cfg) 00139 , out_(moost::logging::global_singleton::instance().get_ostream()) 00140 { 00141 activateOptions(); 00142 } 00143 00144 NscaAppender::NscaAppender( 00145 LayoutPtr & layout, 00146 std::string const & this_host, 00147 std::string const & nsca_svr_host 00148 ) 00149 : AppenderSkeleton(layout) 00150 , this_host_(this_host) 00151 , this_host_desc_(this_host) 00152 , nsca_config_(nsca_svr_host) 00153 , out_(moost::logging::global_singleton::instance().get_ostream()) 00154 { 00155 activateOptions(); 00156 } 00157 00158 NscaAppender::NscaAppender( 00159 LayoutPtr & layout, 00160 std::string const & this_host, 00161 std::string const & this_host_desc, 00162 nsca_config const & cfg 00163 ) 00164 : AppenderSkeleton(layout) 00165 , this_host_(this_host) 00166 , this_host_desc_(this_host_desc) 00167 , nsca_config_(cfg) 00168 , out_(moost::logging::global_singleton::instance().get_ostream()) 00169 { 00170 activateOptions(); 00171 } 00172 00173 NscaAppender::NscaAppender( 00174 LayoutPtr & layout, 00175 std::string const & this_host, 00176 std::string const & this_host_desc, 00177 std::string const & nsca_svr_host 00178 ) 00179 : AppenderSkeleton(layout) 00180 , this_host_(this_host) 00181 , this_host_desc_(this_host_desc) 00182 , nsca_config_(nsca_svr_host) 00183 , out_(moost::logging::global_singleton::instance().get_ostream()) 00184 { 00185 activateOptions(); 00186 } 00187 00188 void NscaAppender::setNscaHost(std::string const & host) 00189 { 00190 nsca_config_.nsca_svr_host = host; 00191 out_ << "NscaHost: " << host << std::endl; 00192 } 00193 00194 void NscaAppender::setNscaPort(std::string const & port) 00195 { 00196 nsca_config_.nsca_svr_port = port; 00197 out_ << "NscaPort: " << port << std::endl; 00198 } 00199 00200 void NscaAppender::setRecvTimeoutMs(boost::uint16_t timeout) 00201 { 00202 nsca_config_.recv_timeout = timeout; 00203 out_ << "RecvTimeout: " << timeout << std::endl; 00204 } 00205 00206 void NscaAppender::setSendTimeoutMs(boost::uint16_t timeout) 00207 { 00208 nsca_config_.send_timeout = timeout; 00209 out_ << "SendTimeout: " << timeout << std::endl; 00210 } 00211 00212 void NscaAppender::setEncType(std::string const & enctype) 00213 { 00214 nsca_config_.enctype = enctype; 00215 out_ << "EncType: " << enctype << std::endl; 00216 } 00217 00218 void NscaAppender::setEncPass(std::string const & encpass) 00219 { 00220 nsca_config_.encpass = encpass; 00221 out_ << "EncPass: " << encpass << std::endl; 00222 } 00223 00224 void NscaAppender::setThisHost(std::string const & host) 00225 { 00226 this_host_ = host; 00227 out_ << "ThisHost: " << host << std::endl; 00228 } 00229 00230 void NscaAppender::setThisHostDesc(std::string const & desc) 00231 { 00232 this_host_desc_ = desc; 00233 out_ << "ThisHostDesc: " << desc << std::endl; 00234 } 00235 00236 void NscaAppender::setOption(const LogString& option, const LogString& value) 00237 { 00238 if (StringHelper::equalsIgnoreCase(option, 00239 LOG4CXX_STR("NSCAHOST"), LOG4CXX_STR("nscahost"))) 00240 { 00241 setNscaHost(value); 00242 } 00243 else 00244 if (StringHelper::equalsIgnoreCase(option, 00245 LOG4CXX_STR("NSCAPORT"), LOG4CXX_STR("nscaport"))) 00246 { 00247 setNscaPort(value); 00248 } 00249 else 00250 if (StringHelper::equalsIgnoreCase(option, 00251 LOG4CXX_STR("RECVTIMEOUTMS"), LOG4CXX_STR("recvtimeoutms"))) 00252 { 00253 setRecvTimeoutMs(OptionConverter::toInt(value, 00254 nsca_const::DEFAULT_RECV_TIMEOUT_MS)); 00255 } 00256 else 00257 if (StringHelper::equalsIgnoreCase(option, 00258 LOG4CXX_STR("SENDTIMEOUTMS"), LOG4CXX_STR("sendtimeoutms"))) 00259 { 00260 setSendTimeoutMs(OptionConverter::toInt(value, 00261 nsca_const::DEFAULT_SEND_TIMEOUT_MS)); 00262 } 00263 else 00264 if (StringHelper::equalsIgnoreCase(option, 00265 LOG4CXX_STR("ENCTYPE"), LOG4CXX_STR("enctype"))) 00266 { 00267 setEncType(value); 00268 } 00269 else 00270 if (StringHelper::equalsIgnoreCase(option, 00271 LOG4CXX_STR("ENCPASS"), LOG4CXX_STR("encpass"))) 00272 { 00273 setEncPass(value); 00274 } 00275 else 00276 if (StringHelper::equalsIgnoreCase(option, 00277 LOG4CXX_STR("THISHOST"), LOG4CXX_STR("thishost"))) 00278 { 00279 setThisHost(value); 00280 } 00281 else 00282 if (StringHelper::equalsIgnoreCase(option, 00283 LOG4CXX_STR("THISHOSTDESC"), LOG4CXX_STR("thishostdesc"))) 00284 { 00285 setThisHostDesc(value); 00286 } 00287 else 00288 { 00289 AppenderSkeleton::setOption(option, value); 00290 } 00291 } 00292 00293 void NscaAppender::activateOptions() 00294 { 00295 Pool p; 00296 activateOptions(p); 00297 } 00298 00299 void NscaAppender::activateOptions(Pool& p ) 00300 { 00301 nsca_client_.reset(new nsca_client(nsca_config_)); 00302 out_ << "Nagios client activated" << std::endl; 00303 00304 // Ensure any base class options get activated 00305 AppenderSkeleton::activateOptions(p); 00306 } 00307 00308 void NscaAppender::close() 00309 { 00310 nsca_client_.reset(); 00311 out_ << "Nagios client terminated" << std::endl; 00312 } 00313 00314 bool NscaAppender::requiresLayout() const 00315 { 00316 return false; 00317 } 00318 00319 void NscaAppender::append ( 00320 spi::LoggingEventPtr const & event, 00321 helpers::Pool & p 00322 ) 00323 { 00324 try 00325 { 00326 if(!nsca_client_) 00327 { 00328 // fail silently, logging error should not take down application! 00329 out_ 00330 << "ERROR: append failed (nsca_client not activated)" 00331 << std::endl; 00332 return; 00333 } 00334 00335 std::string const & thost = 00336 this_host_.empty() ? 00337 boost::asio::ip::host_name(): 00338 this_host_; 00339 00340 std::string const & tdesc = 00341 this_host_desc_.empty() ? 00342 "unknown": // open to suggestions on how we can improve on this! 00343 this_host_desc_; 00344 00345 out_ 00346 << "Sending alert to Nagios" << std::endl 00347 << "- host: " << thost << std::endl 00348 << "- desc: " << tdesc << std::endl 00349 << "- type: "; 00350 00351 int service_state = 0; 00352 00353 switch(get_level(event->getLevel()->toInt())) 00354 { 00355 // it doesn't make sense why these would be logged to nagios so map to unknown 00356 case Level::ALL_INT: 00357 case Level::DEBUG_INT: 00358 case Level::TRACE_INT: 00359 out_ << "unknown" << std::endl; 00360 service_state = nsca_client::service_state::UNKNOWN; 00361 break; 00362 00363 // map a logger info state to a nagios ok state 00364 case Level::INFO_INT: 00365 out_ << "ok" << std::endl; 00366 service_state = nsca_client::service_state::OK; 00367 break; 00368 00369 // map a logger warning state to a nagios warning state 00370 case Level::WARN_INT: 00371 out_ << "warning" << std::endl; 00372 service_state = nsca_client::service_state::WARNING; 00373 break; 00374 00375 // map a logger error or fatal state to a nagios critical state 00376 case Level::ERROR_INT: 00377 case Level::FATAL_INT: 00378 out_ << "critical" << std::endl; 00379 service_state = nsca_client::service_state::CRITICAL; 00380 break; 00381 00382 // the logger is turned off -- do nothing! 00383 case Level::OFF_INT: 00384 default: // no action 00385 out_ << "none" << std::endl; 00386 return; 00387 } 00388 00389 // format and send the message to the nsca server 00390 LogString msg; 00391 layout->format(msg, event, p); 00392 { 00393 helpers::synchronized sync(mutex); 00394 00395 // this is a bit of a fudge to convert from wide to narrow but 00396 // since we're generally only using ASCII it's good enough. 00397 std::string narrow(msg.begin(), msg.end()); 00398 00399 out_ 00400 << "- mesg: " 00401 << narrow 00402 << std::endl; 00403 00404 nsca_client_->send( 00405 thost, 00406 tdesc, 00407 service_state, 00408 narrow); 00409 } 00410 } 00411 catch(std::exception const & e) 00412 { 00413 out_ 00414 << "append failed: " << e.what() << std::endl; 00415 } 00416 catch(...) 00417 { 00418 out_ 00419 << "append failed." << std::endl; 00420 } 00421 } 00422 00423 int NscaAppender::get_level(int const level) // static 00424 { 00425 int const level_range[] = { 00426 Level::OFF_INT, 00427 Level::FATAL_INT, 00428 Level::ERROR_INT, 00429 Level::WARN_INT, 00430 Level::INFO_INT, 00431 Level::DEBUG_INT, 00432 Level::TRACE_INT, 00433 Level::ALL_INT, 00434 }; 00435 00436 int const * end = level_range + sizeof(level_range) / sizeof(level_range[0]); 00437 int const * plevel = std::lower_bound(level_range, end, level, std::greater<int>()); 00438 00439 if(plevel == end) throw std::invalid_argument("invalid level"); // this should not be possible 00440 00441 return *plevel; 00442 } 00443 }