source: nscp/modules/CheckEventLog/CheckEventLog.cpp @ 465866c

0.4.10.4.2
Last change on this file since 465866c was 465866c, checked in by Michael Medin <michael@…>, 12 months ago

2012-06-05 MickeM

  • Tweaked all servers to use the new internals and added first testcase for NSCP socket

2012-05-24 MickeM

  • Reworked real time event log support to be a lot more flexible You can now specify all options on a "filter" level.
  • WARNING* Old syntax NOT supported (and will not upgrade) but hopefully not to many will be affected.
  • Added support for ipv6 allowed hosts validation

2012-05-21 MickeM

  • Sofia Born (My second daughter)
  • Property mode set to 100644
File size: 25.7 KB
Line 
1/**************************************************************************
2*   Copyright (C) 2004-2007 by Michael Medin <michael@medin.name>         *
3*                                                                         *
4*   This code is part of NSClient++ - http://trac.nakednuns.org/nscp      *
5*                                                                         *
6*   This program is free software; you can redistribute it and/or modify  *
7*   it under the terms of the GNU General Public License as published by  *
8*   the Free Software Foundation; either version 2 of the License, or     *
9*   (at your option) any later version.                                   *
10*                                                                         *
11*   This program is distributed in the hope that it will be useful,       *
12*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14*   GNU General Public License for more details.                          *
15*                                                                         *
16*   You should have received a copy of the GNU General Public License     *
17*   along with this program; if not, write to the                         *
18*   Free Software Foundation, Inc.,                                       *
19*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
20***************************************************************************/
21
22#include "stdafx.h"
23#include "CheckEventLog.h"
24#include <filter_framework.hpp>
25#include <boost/foreach.hpp>
26
27#include <time.h>
28#include <utils.h>
29#include <error.hpp>
30#include <map>
31#include <vector>
32//#include <config.h>
33
34#include <boost/bind.hpp>
35#include <boost/assign.hpp>
36#include <boost/program_options.hpp>
37
38#include "filter.hpp"
39#include "filters.hpp"
40
41#include <nscapi/nscapi_protobuf_functions.hpp>
42#include <nscapi/nscapi_core_helper.hpp>
43
44#include <parsers/where/unary_fun.hpp>
45#include <parsers/where/list_value.hpp>
46#include <parsers/where/binary_op.hpp>
47#include <parsers/where/unary_op.hpp>
48#include <parsers/where/variable.hpp>
49
50#include <simple_timer.hpp>
51#include <settings/client/settings_client.hpp>
52namespace sh = nscapi::settings_helper;
53
54#include "simple_registry.hpp"
55#include "eventlog_record.hpp"
56
57CheckEventLog::CheckEventLog() {
58}
59CheckEventLog::~CheckEventLog() {
60}
61struct parse_exception {
62        parse_exception(std::wstring) {}
63};
64
65
66bool CheckEventLog::loadModule() {
67        return false;
68}
69
70
71void real_time_thread::process_no_events(const filters::filter_config_object &object) {
72        std::wstring response;
73        if (!nscapi::core_helper::submit_simple_message(object.target, object.alias, NSCAPI::returnOK, object.ok_msg, object.perf_msg, response)) {
74                NSC_LOG_ERROR(_T("Failed to submit evenhtlog result: ") + response);
75        }
76}
77
78void real_time_thread::process_record(const filters::filter_config_object &object, const EventLogRecord &record) {
79        std::wstring response;
80        std::wstring message = record.render(true, object.syntax, object.date_format, object.dwLang);
81        if (!nscapi::core_helper::submit_simple_message(object.target, object.alias, object.severity, message, object.perf_msg, response)) {
82                NSC_LOG_ERROR(_T("Failed to submit evenhtlog result: ") + response);
83        }
84
85        if (cache_) {
86                boost::unique_lock<boost::timed_mutex> lock(cache_mutex_, boost::get_system_time() + boost::posix_time::seconds(5));
87                if (!lock.owns_lock()) {
88                        NSC_LOG_ERROR(_T("ERROR: Could not get CheckEventLogCache mutex."));
89                        return;
90                }
91                hit_cache_.push_back(message);
92        }
93}
94bool real_time_thread::check_cache(unsigned long &count, std::wstring &messages) {
95        if (!cache_) {
96                messages = _T("ERROR: Cache is not enabled!");
97                NSC_LOG_ERROR(messages);
98                return false;
99        }
100        boost::unique_lock<boost::timed_mutex> lock(cache_mutex_, boost::get_system_time() + boost::posix_time::seconds(5));
101        if (!lock.owns_lock()) {
102                messages = _T("ERROR: Could not get CheckEventLogCache mutex.");
103                NSC_LOG_ERROR(messages);
104                return false;
105        }
106        BOOST_FOREACH(const std::wstring &s, hit_cache_) {
107                if (!messages.empty())
108                        messages += _T(", ");
109                messages += s;
110        }
111        count = hit_cache_.size();
112        hit_cache_.clear();
113        return true;
114}
115void real_time_thread::debug_miss(const EventLogRecord &record) {
116        std::wstring message = record.render(true, _T("%type% %source%: %message%"), DATE_FORMAT, LANG_NEUTRAL);
117        NSC_DEBUG_MSG_STD(_T("No filter matched: ") + message);
118}
119
120void real_time_thread::thread_proc() {
121
122        std::list<filters::filter_config_object> filters;
123        BOOST_FOREACH(filters::filter_config_object object, filters_.get_object_list()) {
124                eventlog_filter::filter_argument fargs = eventlog_filter::factories::create_argument(object.syntax, object.date_format);
125                fargs->filter = object.filter;
126                fargs->debug = object.debug;
127                fargs->alias = object.alias;
128                fargs->bShowDescriptions = true;
129                // eventlog_filter::filter_engine
130                object.engine = eventlog_filter::factories::create_engine(fargs);
131
132                if (!object.engine) {
133                        NSC_LOG_ERROR_STD(_T("Invalid filter: ") + object.filter);
134                        continue;
135                }
136
137                if (!object.engine->boot()) {
138                        NSC_LOG_ERROR_STD(_T("Error booting filter: ") + object.filter);
139                        continue;
140                }
141
142                std::wstring message;
143                if (!object.engine->validate(message)) {
144                        NSC_LOG_ERROR_STD(_T("Error validating filter: ") + message);
145                        continue;
146                }
147                filters.push_back(object);
148        }
149
150
151
152        typedef boost::shared_ptr<eventlog_wrapper> eventlog_type;
153        typedef std::vector<eventlog_type> eventlog_list;
154        eventlog_list list;
155
156        BOOST_FOREACH(std::wstring l, lists_) {
157                eventlog_type el = eventlog_type(new eventlog_wrapper(l));
158                if (!el->seek_end()) {
159                        NSC_LOG_ERROR_STD(_T("Failed to find the end of eventlog: ") + l);
160                } else {
161                        list.push_back(el);
162                }
163        }
164       
165        // TODO: add support for scanning "missed messages" at startup
166
167        HANDLE *handles = new HANDLE[1+list.size()];
168        handles[0] = stop_event_;
169        for (int i=0;i<list.size();i++) {
170                list[i]->notify(handles[i+1]);
171        }
172
173        DWORD dwWaitTime = max_age_;
174        if (dwWaitTime > 0 && dwWaitTime < 5000)
175                dwWaitTime = 5000;
176        unsigned int errors = 0;
177        while (true) {
178                DWORD dwWaitReason = WaitForMultipleObjects(list.size()+1, handles, FALSE, dwWaitTime==0?INFINITE:dwWaitTime);
179                if (dwWaitReason == WAIT_TIMEOUT) {
180                        BOOST_FOREACH(const filters::filter_config_object &object, filters) {
181                                process_no_events(object);
182                        }
183                } else if (dwWaitReason == WAIT_OBJECT_0) {
184                        delete [] handles;
185                        return;
186                } else if (dwWaitReason > WAIT_OBJECT_0 && dwWaitReason <= (WAIT_OBJECT_0 + list.size())) {
187
188                        eventlog_type el = list[dwWaitReason-WAIT_OBJECT_0-1];
189                        DWORD status = el->read_record(0, EVENTLOG_SEQUENTIAL_READ|EVENTLOG_FORWARDS_READ);
190                        if (ERROR_SUCCESS != status && ERROR_HANDLE_EOF != status) {
191                                delete [] handles;
192                                return;
193                        }
194
195                        __time64_t ltime;
196                        _time64(&ltime);
197
198                        EVENTLOGRECORD *pevlr = el->read_record_with_buffer();
199                        while (pevlr != NULL) {
200                                EventLogRecord elr(el->get_name(), pevlr, ltime);
201                                boost::shared_ptr<eventlog_filter::filter_obj> arg = boost::shared_ptr<eventlog_filter::filter_obj>(new eventlog_filter::filter_obj(elr));
202                                bool matched = false;
203
204                                BOOST_FOREACH(const filters::filter_config_object &object, filters) {
205                                        if (object.engine->match(arg)) {
206                                                process_record(object, elr);
207                                                matched = true;
208                                        }
209                                }
210                                if (debug_ && !matched)
211                                        debug_miss(elr);
212
213                                pevlr = el->read_record_with_buffer();
214                        }
215                } else {
216                        NSC_LOG_ERROR(_T("Error failed to wait for eventlog message: ") + error::lookup::last_error());
217                        if (errors++ > 10) {
218                                NSC_LOG_ERROR(_T("To many errors giving up"));
219                                delete [] handles;
220                                return;
221                        }
222                }
223        }
224        delete [] handles;
225        return;
226}
227
228
229bool real_time_thread::start() {
230        if (!enabled_)
231                return true;
232
233        stop_event_ = CreateEvent(NULL, TRUE, FALSE, _T("EventLogShutdown"));
234
235        thread_ = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&real_time_thread::thread_proc, this)));
236        return true;
237}
238bool real_time_thread::stop() {
239        SetEvent(stop_event_);
240        if (thread_)
241                thread_->join();
242        return true;
243}
244
245void real_time_thread::add_realtime_filter(boost::shared_ptr<nscapi::settings_proxy> proxy, std::wstring key, std::wstring query) {
246        try {
247                filters_.add(proxy, filters_path_, key, query, key == _T("default"));
248        } catch (const std::exception &e) {
249                NSC_LOG_ERROR_STD(_T("Failed to add command: ") + key + _T(", ") + utf8::to_unicode(e.what()));
250        } catch (...) {
251                NSC_LOG_ERROR_STD(_T("Failed to add command: ") + key);
252        }
253}
254
255
256bool CheckEventLog::loadModuleEx(std::wstring alias, NSCAPI::moduleLoadMode mode) {
257        try {
258                register_command(_T("CheckEventLog"), _T("Check for errors in the event logger!"));
259                register_command(_T("check_eventlog"), _T("Check for errors in the event logger!"));
260                register_command(_T("checkeventlogcache"), _T("Check for errors in the event logger!"));
261                register_command(_T("check_eventlog_cache"), _T("Check for errors in the event logger!"));
262
263                sh::settings_registry settings(get_settings_proxy());
264                settings.set_alias(alias, _T("eventlog"));
265               
266                thread_.filters_path_ = settings.alias().get_settings_path(_T("real-time/filters"));
267
268
269                settings.alias().add_path_to_settings()
270                        (_T("EVENT LOG SECTION"), _T("Section for the EventLog Checker (CheckEventLog.dll)."))
271
272                        (_T("real-time"), _T("CONFIGURE REALTIME CHECKING"), _T("A set of options to configure the real time checks"))
273
274                        (_T("real-time/filters"), sh::fun_values_path(boost::bind(&real_time_thread::add_realtime_filter, &thread_, get_settings_proxy(), _1, _2)), 
275                        _T("REALTIME FILTERS"), _T("A set of filters to use in real-time mode"))
276                        ;
277
278                settings.alias().add_key_to_settings()
279                        (_T("debug"), sh::bool_key(&debug_, false),
280                        _T("DEBUG"), _T("Log more information when filtering (usefull to detect issues with filters) not usefull in production as it is a bit of a resource hog."))
281
282                        (_T("lookup names"), sh::bool_key(&lookup_names_, true),
283                        _T("LOOKUP NAMES"), _T("Lookup the names of eventlog files"))
284
285                        (_T("syntax"), sh::wstring_key(&syntax_),
286                        _T("SYNTAX"), _T("Set this to use a specific syntax string for all commands (that don't specify one)."))
287
288                        (_T("buffer size"), sh::int_key(&buffer_length_, 128*1024),
289                        _T("BUFFER_SIZE"), _T("The size of the buffer to use when getting messages this affects the speed and maximum size of messages you can recieve."))
290
291                        ;
292
293                settings.alias().add_key_to_settings(_T("real-time"))
294
295                        (_T("enabled"), sh::bool_fun_key<bool>(boost::bind(&real_time_thread::set_enabled, &thread_, _1), false),
296                        _T("REAL TIME CHECKING"), _T("Spawns a backgrounnd thread which detects issues and reports them back instantly."))
297
298                        (_T("startup age"), sh::string_fun_key<std::wstring>(boost::bind(&real_time_thread::set_start_age, &thread_, _1), _T("30m")),
299                        _T("STARTUP AGE"), _T("The initial age to scan when starting NSClient++"))
300
301                        (_T("maximum age"), sh::string_fun_key<std::wstring>(boost::bind(&real_time_thread::set_max_age, &thread_, _1), _T("5m")),
302                        _T("MAGIMUM AGE"), _T("How long before reporting \"ok\" (if this is set to off no ok will be reported only errors)"))
303
304                        (_T("log"), sh::string_fun_key<std::wstring>(boost::bind(&real_time_thread::set_eventlog, &thread_, _1), _T("application")),
305                        _T("LOGS TO CHECK"), _T("Coma separated list of logs to check"))
306
307                        (_T("debug"), sh::bool_key(&thread_.debug_, false),
308                        _T("DEBUG"), _T("Log missed records (usefull to detect issues with filters) not usefull in production as it is a bit of a resource hog."))
309
310                        (_T("enable active"), sh::bool_key(&thread_.cache_, false),
311                        _T("ENABLE ACTIVE MONITORING"), _T("This will store all matches so you can use real-time filters from active monitoring (use CheckEventlogCache)."))
312                        ;
313
314                settings.register_all();
315                settings.notify();
316
317                if (mode == NSCAPI::normalStart) {
318                        if (!thread_.start())
319                                NSC_LOG_ERROR_STD(_T("Failed to start collection thread"));
320                }
321
322        } catch (nscapi::nscapi_exception &e) {
323                NSC_LOG_ERROR_STD(_T("Failed to register command: ") + utf8::cvt<std::wstring>(e.what()));
324                return false;
325        } catch (std::exception &e) {
326                NSC_LOG_ERROR_STD(_T("Exception: ") + utf8::cvt<std::wstring>(e.what()));
327                return false;
328        } catch (...) {
329                NSC_LOG_ERROR_STD(_T("Failed to register command."));
330                return false;
331        }
332        return true;
333}
334bool CheckEventLog::unloadModule() {
335        if (!thread_.stop())
336                NSC_LOG_ERROR_STD(_T("Failed to start collection thread"));
337        return true;
338}
339
340bool CheckEventLog::hasCommandHandler() {
341        return true;
342}
343bool CheckEventLog::hasMessageHandler() {
344        return false;
345}
346
347class uniq_eventlog_record {
348        DWORD ID;
349        WORD type;
350        WORD category;
351public:
352        std::wstring message;
353        uniq_eventlog_record(EVENTLOGRECORD *pevlr) : ID(pevlr->EventID&0xffff), type(pevlr->EventType), category(pevlr->EventCategory) {}
354        bool operator< (const uniq_eventlog_record &other) const {
355                return (ID < other.ID) || ((ID==other.ID)&&(type < other.type)) || (ID==other.ID&&type==other.type)&&(category < other.category);
356        }
357        std::wstring to_string() const {
358                return _T("id=") + strEx::itos(ID) + _T("type=") + strEx::itos(type) + _T("category=") + strEx::itos(category);
359        }
360};
361typedef std::map<uniq_eventlog_record,unsigned int> uniq_eventlog_map;
362
363struct event_log_buffer {
364        BYTE *bBuffer;
365        DWORD bufferSize_;
366        event_log_buffer(DWORD bufferSize) : bufferSize_(bufferSize) {
367                bBuffer = new BYTE[bufferSize+10];
368        }
369        ~event_log_buffer() {
370                delete [] bBuffer;
371        }
372        EVENTLOGRECORD* getBufferUnsafe() {
373                return reinterpret_cast<EVENTLOGRECORD*>(bBuffer);
374        }
375        DWORD getBufferSize() {
376                return bufferSize_;
377        }
378};
379typedef checkHolders::CheckContainer<checkHolders::MaxMinBoundsULongInteger> EventLogQuery1Container;
380typedef checkHolders::CheckContainer<checkHolders::ExactBoundsULongInteger> EventLogQuery2Container;
381
382NSCAPI::nagiosReturn CheckEventLog::checkCache(std::list<std::wstring> &arguments, std::wstring &message, std::wstring &perf) {
383
384        EventLogQuery1Container query1;
385        EventLogQuery2Container query2;
386        bool bPerfData = true;
387        unsigned int truncate = 0;
388        NSCAPI::nagiosReturn returnCode = NSCAPI::returnOK;
389
390        try {
391                MAP_OPTIONS_BEGIN(arguments)
392                        MAP_OPTIONS_NUMERIC_ALL(query1, _T(""))
393                        MAP_OPTIONS_EXACT_NUMERIC_ALL(query2, _T(""))
394                        MAP_OPTIONS_STR2INT(_T("truncate"), truncate)
395                        MAP_OPTIONS_BOOL_FALSE(IGNORE_PERFDATA, bPerfData)
396                        MAP_OPTIONS_MISSING(message, _T("Unknown argument: "))
397                MAP_OPTIONS_END()
398        } catch (checkHolders::parse_exception e) {
399                message = e.getMessage();
400                return NSCAPI::returnUNKNOWN;
401        } catch (...) {
402                message = _T("Invalid command line!");
403                return NSCAPI::returnUNKNOWN;
404        }
405
406        unsigned long count = 0;
407        if (!thread_.check_cache(count, message)) {
408                return NSCAPI::returnUNKNOWN;
409        }
410
411        if (!bPerfData) {
412                query1.perfData = false;
413                query2.perfData = false;
414        }
415        if (query1.alias.empty())
416                query1.alias = _T("eventlog");
417        if (query2.alias.empty())
418                query2.alias = _T("eventlog");
419        if (query1.hasBounds())
420                query1.runCheck(count, returnCode, message, perf);
421        else if (query2.hasBounds())
422                query2.runCheck(count, returnCode, message, perf);
423        else {
424                message = _T("No bounds specified!");
425                return NSCAPI::returnUNKNOWN;
426        }
427        if ((truncate > 0) && (message.length() > (truncate-4)))
428                message = message.substr(0, truncate-4) + _T("...");
429        if (message.empty())
430                message = _T("Eventlog check ok");
431        return returnCode;
432}
433
434NSCAPI::nagiosReturn CheckEventLog::handleCommand(const std::wstring &target, const std::wstring &command, std::list<std::wstring> &arguments, std::wstring &message, std::wstring &perf) {
435        if (command == _T("checkeventlogcache") || command == _T("check_eventlog_cache"))
436                return checkCache(arguments, message, perf);
437        if (command != _T("checkeventlog") && command != _T("check_eventlog"))
438                return NSCAPI::returnIgnored;
439        simple_timer time;
440       
441        NSCAPI::nagiosReturn returnCode = NSCAPI::returnOK;
442
443        std::list<std::wstring> files;
444        EventLogQuery1Container query1;
445        EventLogQuery2Container query2;
446
447
448        eventlog_filter::filter_argument fargs = eventlog_filter::factories::create_argument(syntax_, DATE_FORMAT);
449
450        bool bPerfData = true;
451        bool unique = false;
452        unsigned int truncate = 0;
453        event_log_buffer buffer(buffer_length_);
454        //bool bPush = true;
455
456        try {
457                MAP_OPTIONS_BEGIN(arguments)
458                        MAP_OPTIONS_NUMERIC_ALL(query1, _T(""))
459                        MAP_OPTIONS_EXACT_NUMERIC_ALL(query2, _T(""))
460                        MAP_OPTIONS_STR2INT(_T("truncate"), truncate)
461                        MAP_OPTIONS_BOOL_TRUE(_T("unique"), unique)
462                        MAP_OPTIONS_BOOL_TRUE(_T("descriptions"), fargs->bShowDescriptions)
463                        MAP_OPTIONS_PUSH(_T("file"), files)
464                        MAP_OPTIONS_BOOL_FALSE(IGNORE_PERFDATA, bPerfData)
465                        MAP_OPTIONS_BOOL_EX(_T("filter"), fargs->bFilterIn, _T("in"), _T("out"))
466                        MAP_OPTIONS_BOOL_EX(_T("filter"), fargs->bFilterAll, _T("all"), _T("any"))
467                        MAP_OPTIONS_BOOL_EX(_T("debug"), fargs->debug, _T("true"), _T("false"))
468                        MAP_OPTIONS_STR(_T("syntax"), fargs->syntax)
469                        MAP_OPTIONS_STR(_T("filter"), fargs->filter)
470                        MAP_OPTIONS_MISSING(message, _T("Unknown argument: "))
471                        MAP_OPTIONS_END()
472        } catch (filters::parse_exception e) {
473                message = e.getMessage();
474                return NSCAPI::returnUNKNOWN;
475        } catch (filters::filter_exception e) {
476                message = e.getMessage();
477                return NSCAPI::returnUNKNOWN;
478                } catch (checkHolders::parse_exception e) {
479                message = e.getMessage();
480                return NSCAPI::returnUNKNOWN;
481        } catch (...) {
482                message = _T("Invalid command line!");
483                return NSCAPI::returnUNKNOWN;
484        }
485
486        unsigned long int hit_count = 0;
487        if (files.empty()) {
488                message = _T("No file specified try adding: file=Application");
489                return NSCAPI::returnUNKNOWN;
490        }
491        bool buffer_error_reported = false;
492
493
494        eventlog_filter::filter_engine impl = eventlog_filter::factories::create_engine(fargs);
495
496        if (!impl) {
497                message = _T("Failed to initialize filter subsystem.");
498                return NSCAPI::returnUNKNOWN;
499        }
500
501        impl->boot();
502
503        __time64_t ltime;
504        _time64(&ltime);
505
506        if (!impl->validate(message)) {
507                return NSCAPI::returnUNKNOWN;
508        }
509
510
511        NSC_DEBUG_MSG_STD(_T("Boot time: ") + strEx::itos(time.stop()));
512
513        for (std::list<std::wstring>::const_iterator cit2 = files.begin(); cit2 != files.end(); ++cit2) {
514                std::wstring name = *cit2;
515                if (lookup_names_) {
516                        name = eventlog_wrapper::find_eventlog_name(*cit2);
517                        if ((*cit2) != name) {
518                                NSC_DEBUG_MSG_STD(_T("Opening alternative log: ") + name);
519                        }
520                }
521                HANDLE hLog = OpenEventLog(NULL, name.c_str());
522                if (hLog == NULL) {
523                        message = _T("Could not open the '") + (*cit2) + _T("' event log: ") + error::lookup::last_error();
524                        return NSCAPI::returnUNKNOWN;
525                }
526                uniq_eventlog_map uniq_records;
527
528                DWORD dwRead, dwNeeded;
529                while (true) {
530                        BOOL bStatus = ReadEventLog(hLog, EVENTLOG_FORWARDS_READ|EVENTLOG_SEQUENTIAL_READ,
531                                0, buffer.getBufferUnsafe(), buffer.getBufferSize(), &dwRead, &dwNeeded);
532                        if (bStatus == FALSE) {
533                                DWORD err = GetLastError();
534                                if (err == ERROR_INSUFFICIENT_BUFFER) {
535                                        if (!buffer_error_reported) {
536                                                NSC_LOG_ERROR_STD(_T("EvenlogBuffer is too small change the value of buffer_length=") + strEx::itos(dwNeeded+1) + _T(": ") + error::lookup::last_error(err));
537                                                buffer_error_reported = true;
538                                        }
539                                } else if (err == ERROR_HANDLE_EOF) {
540                                        break;
541                                } else {
542                                        NSC_LOG_ERROR_STD(_T("Failed to read from eventlog: ") + error::lookup::last_error(err));
543                                        message = _T("Failed to read from eventlog: ") + error::lookup::last_error(err);
544                                        CloseEventLog(hLog);
545                                        return NSCAPI::returnUNKNOWN;
546                                }
547                        }
548                        EVENTLOGRECORD *pevlr = buffer.getBufferUnsafe();
549                        while (dwRead > 0) {
550                                EventLogRecord record((*cit2), pevlr, ltime);
551                                boost::shared_ptr<eventlog_filter::filter_obj> arg = boost::shared_ptr<eventlog_filter::filter_obj>(new eventlog_filter::filter_obj(record));
552                                bool match = impl->match(arg);
553                                if (match&&unique) {
554                                        match = false;
555                                        uniq_eventlog_record uniq_record = pevlr;
556                                        uniq_eventlog_map::iterator it = uniq_records.find(uniq_record);
557                                        if (it != uniq_records.end()) {
558                                                (*it).second ++;
559                                        }
560                                        else {
561                                                if (!fargs->syntax.empty()) {
562                                                        uniq_record.message = record.render(fargs->bShowDescriptions, fargs->syntax);
563                                                } else if (!fargs->bShowDescriptions) {
564                                                        uniq_record.message = record.get_source();
565                                                } else {
566                                                        uniq_record.message = record.get_source();
567                                                        uniq_record.message += _T("(") + EventLogRecord::translateType(record.eventType()) + _T(", ") +
568                                                                strEx::itos(record.eventID()) + _T(", ") + EventLogRecord::translateSeverity(record.severity()) + _T(")");
569                                                        uniq_record.message += _T("[") + record.enumStrings() + _T("]");
570                                                        uniq_record.message += _T("{%count%}");
571                                                }
572                                                uniq_records[uniq_record] = 1;
573                                        }
574                                        hit_count++;
575                                } else if (match) {
576                                        if (!fargs->syntax.empty()) {
577                                                strEx::append_list(message, record.render(fargs->bShowDescriptions, fargs->syntax));
578                                        } else if (!fargs->bShowDescriptions) {
579                                                strEx::append_list(message, record.get_source());
580                                        } else {
581                                                strEx::append_list(message, record.get_source());
582                                                message += _T("(") + EventLogRecord::translateType(record.eventType()) + _T(", ") +
583                                                        strEx::itos(record.eventID()) + _T(", ") + EventLogRecord::translateSeverity(record.severity()) + _T(")");
584                                                message += _T("[") + record.enumStrings() + _T("]");
585                                        }
586                                        hit_count++;
587                                }
588                                dwRead -= pevlr->Length;
589                                pevlr = reinterpret_cast<EVENTLOGRECORD*>((LPBYTE)pevlr + pevlr->Length);
590                        }
591                }
592                CloseEventLog(hLog);
593                for (uniq_eventlog_map::const_iterator cit = uniq_records.begin(); cit != uniq_records.end(); ++cit) {
594                        std::wstring msg = (*cit).first.message;
595                        strEx::replace(msg, _T("%count%"), strEx::itos((*cit).second));
596                        strEx::append_list(message, msg);
597                }
598        }
599        NSC_DEBUG_MSG_STD(_T("Evaluation time: ") + strEx::itos(time.stop()));
600
601        if (!bPerfData) {
602                query1.perfData = false;
603                query2.perfData = false;
604        }
605        if (query1.alias.empty())
606                query1.alias = _T("eventlog");
607        if (query2.alias.empty())
608                query2.alias = _T("eventlog");
609        if (query1.hasBounds())
610                query1.runCheck(hit_count, returnCode, message, perf);
611        else if (query2.hasBounds())
612                query2.runCheck(hit_count, returnCode, message, perf);
613        else {
614                message = _T("No bounds specified!");
615                return NSCAPI::returnUNKNOWN;
616        }
617        if ((truncate > 0) && (message.length() > (truncate-4)))
618                message = message.substr(0, truncate-4) + _T("...");
619        if (message.empty())
620                message = _T("Eventlog check ok");
621        return returnCode;
622}
623NSCAPI::nagiosReturn CheckEventLog::commandRAWLineExec(const wchar_t* char_command, const std::string &request, std::string &response) {
624        std::wstring command = char_command;
625        if (command == _T("insert-eventlog-message") || command == _T("insert-eventlog") || command == _T("insert-message") || command == _T("insert")) {
626                nscapi::functions::decoded_simple_command_data data = nscapi::functions::parse_simple_exec_request(char_command, request);
627                std::wstring message;
628                std::vector<std::wstring> args(data.args.begin(), data.args.end());
629                bool ok = insert_eventlog(args, message);
630                nscapi::functions::create_simple_exec_response(command, ok?NSCAPI::isSuccess:NSCAPI::hasFailed, message, response);
631                return ok?NSCAPI::isSuccess:NSCAPI::hasFailed;
632        } else if (command == _T("help")) {
633                std::vector<std::wstring> args;
634                args.push_back(_T("--help"));
635                std::wstring message;
636                insert_eventlog(args, message);
637                nscapi::functions::create_simple_exec_response(command, NSCAPI::isSuccess, message, response);
638                return NSCAPI::isSuccess;
639        }
640        return NSCAPI::returnIgnored;
641}
642
643
644
645NSCAPI::nagiosReturn CheckEventLog::insert_eventlog(std::vector<std::wstring> arguments, std::wstring &message) {
646        try {
647                namespace po = boost::program_options;
648
649                bool help = false;
650                std::wstring type, severity, source_name;
651                std::vector<std::wstring> strings;
652                WORD wEventID = 0, category = 0, customer = 0;
653                WORD facility = 0;
654                po::options_description desc("Allowed options");
655                desc.add_options()
656                        ("help,h", po::bool_switch(&help), "Show help screen")
657                        ("source,s", po::wvalue<std::wstring>(&source_name)->default_value(_T("Application Error")), "source to use")
658                        ("type,t", po::wvalue<std::wstring>(&type), "Event type")
659                        ("level,l", po::wvalue<std::wstring>(&type), "Event level (type)")
660                        ("facility,f", po::value<WORD>(&facility), "Facility/Qualifier")
661                        ("qualifier,q", po::value<WORD>(&facility), "Facility/Qualifier")
662                        ("severity", po::wvalue<std::wstring>(&severity), "Event severity")
663                        ("category,c", po::value<WORD>(&category), "Event category")
664                        ("customer", po::value<WORD>(&customer), "Customer bit 0,1")
665                        ("arguments,a", po::wvalue<std::vector<std::wstring> >(&strings), "Message arguments (strings)")
666                        ("eventlog-arguments", po::wvalue<std::vector<std::wstring> >(&strings), "Message arguments (strings)")
667                        ("event-arguments", po::wvalue<std::vector<std::wstring> >(&strings), "Message arguments (strings)")
668                        ("id,i", po::value<WORD>(&wEventID), "Event ID")
669                        ;
670
671                boost::program_options::variables_map vm;
672
673                po::wparsed_options parsed = po::basic_command_line_parser<wchar_t>(arguments).options(desc).run();
674                po::store(parsed, vm);
675                po::notify(vm);
676
677                if (help) {
678                        std::stringstream ss;
679                        ss << "CheckEventLog Command line syntax:" << std::endl;
680                        ss << desc;
681                        message = utf8::cvt<std::wstring>(ss.str());
682                        return NSCAPI::isSuccess;
683                } else {
684                        event_source source(source_name);
685                        WORD dwType = EventLogRecord::translateType(type);
686                        WORD wSeverity = EventLogRecord::translateSeverity(severity);
687                        DWORD tID = (wEventID&0xffff) | ((facility&0xfff)<<16) | ((customer&0x1)<<29) | ((wSeverity&0x3)<<30);
688
689                        int size = 0;
690                        BOOST_FOREACH(const std::wstring &s, strings) {
691                                size += s.size()+1;
692                        }
693                        LPCWSTR *string_data = new LPCWSTR[strings.size()];
694                        int i=0;
695                        BOOST_FOREACH(const std::wstring &s, strings) {
696                                string_data[i++] = s.c_str();
697                        }
698
699                        if (!ReportEvent(source, dwType, category, tID, NULL, strings.size(), 0, string_data, NULL)) {
700                                message = _T("Could not report the event");
701                                return NSCAPI::hasFailed;
702                        } else {
703                                message = _T("Message reported successfully");
704                        }
705                        delete [] string_data;
706                }
707        } catch (const std::exception &e) {
708                NSC_LOG_ERROR_STD(_T("Failed to parse command line: ") + utf8::cvt<std::wstring>(e.what()));
709        }
710        return NSCAPI::returnIgnored;
711}
712
713NSC_WRAP_DLL();
714NSC_WRAPPERS_MAIN_DEF(CheckEventLog);
715NSC_WRAPPERS_IGNORE_MSG_DEF();
716NSC_WRAPPERS_HANDLE_CMD_DEF();
717NSC_WRAPPERS_CLI_DEF();
Note: See TracBrowser for help on using the repository browser.