libmoost
/home/mhx/git/github/libmoost/src/logging/nsca_appender.cpp
Go to the documentation of this file.
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 }