Программное отслеживание событий в журнале Event Viewer
Предистория: Есть файл, из которого на прибор идет подача команд. Когда прибор виснет или появляется ошибка, то в журнале ошибок Event Viewer появляется соответствующая запись. Мне нужно отследить момент появления этого сообщения и прекратить подачу команд в прибор. Но не просто прекратить, а и зафиксировать то, какая команда передалась последней, чтобы дальше прогонять предыдущие несколько команд, приближаясь к комбинации, вызвавшей вылет программы или ошибку. Таким образом, научившись программно реагировать на факт добавления сообщения о вылете основной программы в журнал событий, можно вовремя остановить ПО тестирование, и отметить в логе этого ПО, примерно после каких воздействий произошёл вылет.
А теперь сам вопрос: Как программно отслеживать факт добавления сообщения о вылете основной программы в журнал событий? Подскажите, пожалуйста! :confused::confused::confused:
Увы, автор об этом не пишет. Так же, как не пишат о том, сколько программ у него запущено, и как они взаимодействуют между собой, т.к. мне сложно представить, как программа что-то может писать в лог после того, как она вылетела по ошибке.
Если же нужно лишь отследить момент окончания программы, то это делается очень просто.
В общем, неясна постановка.
А перехват записи в журнал–интересная тема,на мой взгляд.Хотелось бы узнать,как это делается,причём желательно с помощью API
Не совсем. Просто иногда каждая команда в отдельности является правильной и приемлемой, а вот некоторая их комбмнация заводит прибор в тупик и он виснет.
Поэтому трудно отловить ошибки, тестируя и обрабатывая ошибки в самом коде (как предложил, например, andriano). Нужно работать с прибором и регистрировать его вылеты.
Нет, как раз исходники мне доступны, только вот там 170 тыс. строк. Так что это даже не иголка в стоге сена!:)
Для чтения записей из журнала используеться функция ReadEventLog. Предварительно журнал открывается функцией OpenEventLog вот их описание:
HANDLE OpenEventLog(
LPCTSTR lpUNCServerName , // server name
LPCTSTR lpSourceName // file name
);
HANDLE hEventLog , // handle to event log
DWORD dwReadFlags,, // how to read log
DWORD dwRecordOffset, // offset of first record
LPVOID lpBuffer, // buffer for read data
DWORD nNumberOfBytesToRead,// bytes to read
DWORD * pnBytesRead, // number of bytes read
DWORD * pnMinNumberOfBytesNeeded // bytes required
);
А еще я нашла интересную программу, осуществляющую т.н. мониторанг и слежение за журналом событий. Вот что о ней написано:
"EventMeister - это средство для чтения журнала событий Windows с обширными возможностями мониторинга и формирования предупреждений. Установленный на одном компьютере EventMeister может собирать данные со всех компьютеров сети, не требуя большого количества лицензий. EventMeister может собирать информацию о журнале событий Windows на вашем компьютере и на любом компьютере внутри сети. Данные из всех журналов представляются для вас в последовательном формате. С помощью фильтров вы можете получить лишь интересующую вас информацию, а также, группировать данные из различных журналов для облегчения анализа. вы можете фильтровать, сортировать и реорганизовывать столбцы для упрощения анализа и представления, создавать различные проекции одних и тех же данных. Вы можете экспортировать журнал, переводит журналы в различные форматы, включая text, csv, xml, форматированный html и RSS. Это позволяет импортировать отфильтрованные данные в базы данных или приложения для анализа, такие как Excel. Вы можете даже опубликовать ваши данные в формате RSS. EventMeister размещается в system tray и выполняет мониторинг ваших журналов 24 часа в сутки 7 дней в неделю в соответствии с определенными шаблонами. При обнаружении интересующего события он реагирует формированием звукового или визуального предупреждения, посылает электронные письма, записывает в журнал и даже запускает ваши собственные скрипты."
Правда мне нужен *.log. Только как вот ее встроить в программу? Ведь как раз исходники EventMeister мне недоступны.
Поэтому трудно отловить ошибки, тестируя и обрабатывая ошибки в самом коде (как предложил, например, andriano). Нужно работать с прибором и регистрировать его вылеты.
Мне по-прежнему непонятно, почему это не делать в одной программе.
И я так и не получил ответа на вопрос: сколько программ взаимодействуют с прибором и какова логика распределения работы между ними?
И я так и не получил ответа на вопрос: сколько программ взаимодействуют с прибором и какова логика распределения работы между ними?
На первую часть вопроса я вроде бы уже ответила :) (см. выше). А насчет числа программ, то их очень и очень много (самыми большими являются те, которые обеспечивают работу самого прибора, база данных (архив) и многие-многие другие). Все они объединены в один большой Setup.
Кстати, некоторые ошибки, те, что можно предугадать, и так обрабатываются в самой программе. Когда они происходят, то прибор защищен от вылета и пользователь получает сообщение об ошибке. Но вот беда: не все можно предугадать. Поэтому прибор и вылетает, поэтому и создаются записи в журнале сообщений. И нужно дальше работать уже с ними, чтобы понять причину выдета. :confused:
OpenEventLog();
NotifyChangeEventLog();
У меня к вам есть вопрос.
Как мне посоветовал Phodopus, я нашла информацию про NotifyChangeEventLog. Это действительно именно то, что мне нужно. Эта функция позволяет получать уведомления о событиях. Ее описание:
BOOL NotifyChangeEventLog(
HANDLE hEventLog, // описатель, полученный с помощью функции OpenEventLog
HANDLE hEvent // описатель ранее созданного объекта ядра события
);
Определив, что регистрационный файл изменен, система автоматически генерирует объект ядра события. Поток приложения определяет это и запускает все необходимые ему обработчики.
Я нашла несколько примеров применения функции NotifyChangeEventLog, но все они "вырваны" из больших программ и очень громоздки. Может ли кто-нибудь привести т.н. "компактный"пример, чтобы было ясно просто как работает функция.
Спасибо Вам за ответ! Я только немного не ориентируюсь в сленге. Вы предложили:
"Открываем журнал событий - получаем HANDLE. Создаем событие - получаем HANDLE. Создаем поток команд (как вариант) - усыпляем на событии. Даем оба HANDLE-ла функции. Все, теперь как получено событие проснется наш поток команд."
Извините, что я заменила некоторые слова, просто пытаюсь осознать смысл написанного. И еще уточните, пожалуйста, что значит "усыпляем на событии"?
Т.е. функции NotijyChangeEventLog передается 2 HANDLE-ла: один - лога событий, другой - самого события? Когда событие происходит и записывается в лог, то начинает работать NotijyChangeEventLog. А как это выглядит на примере?
OpenEventLog() - получаем HANDLE.
CreateEvent() - получаем HANDLE.
Создаем поток (как вариант) CreateThread()
WaitForSingleObject() в функции потока - усыпляем на событии.
Даем оба HANDLE-ла функции.
Т.е. функции NotijyChangeEventLog передается 2 HANDLE-ла
Да.
один - лога событий, другой - самого события?
Объект сихронизации event не имеет ничего общего с событием в журнале, это разные вещи. Возникновение записи в журнале порождает установку объекта синхронизации, как-то так.
А как это выглядит на примере?
Извините, код писать нет никакого желания. Может кто-нибудь и..
#include <stdio.h>
void __cdecl wmain(int argc, LPWSTR *argv)
{
wchar_t *logName = L"Application";// Имя event log.
wchar_t *sourceName = L"SampleEventSourceName"; // Event Source name.
BOOL bSuccess;
HANDLE hEventLog;
HANDLE hEvent;
DWORD dwWaitResult;
hEventLog = OpenEventLogW( //открытие журнала событий
NULL, //server name
sourceName // Event log source name.
);
if (hEventLog == NULL)
{
printf("Could not open event log."); //если не удалось открыть журнал
return;
}
hEvent = CreateEvent //Создание объекта события
(NULL, // атрибут защиты
FALSE, // тип сброса FALSE – автоматический
FALSE, // начальное состояние FALSE – не сигнальное
NULL); // без имени обьекта
NotifyChangeEventLog(hEventLog, hEvent); //получение уведомления о событии
dwWaitResult = WaitForSingleObject //ожидание события
(hEvent, //идентификатор объекта
INFINITE); // время ожидания в миллисекундах
if (dwWaitResult == WAIT_FAILED)
printf("Could not wait for an event to occur.");
else
printf("An event has been logged.\n");
CloseHandle(hEvent);
CloseEventLog(hEventLog);
return;
}
Но это только самое начало. Дело в том, что мне нужно фиксировать не просто наличие добавления новой записи в журнад событий, а и отмечать в др. месте (некотором log-файле) список последних, например, 10-ти отосланных кодов нажатия пульта. Это поможет выявить комбинацию, привеждую к вылету прибора. Но тут море вопросов.
Например, получили мы сообщение "An event has been logged". И что с этим делать? Ведь мне нужно понять не то, что был сбой, а какие отсылаемые коды команд к этому сбою привели. Если я беру пересылаемые коды из какого-то файла, то может нужно писать какой-то счетчик, который будет фиксировать порядковый номер кодов?В том смысле, чтобы по вылету можно было в огромном массиве данных файла и кодами выделить именно ту команду, после которой произошел вылет. И как это организовать? Есть ли идеи?
Т.е. я беру из файла массив с кодами команд, передаю их прибору, параллельно (или после передачи, но тогда время уже будет искажено) фиксируя отосланные команды в некотором log-файле c указанием времени их отправления. Потом сравниваю времена из журнала ошибок и из log-файла, определяя код "ошибочной" команды.
В принципе конечно это было бы неплохо, но вот только скорость передачи данных, установленная для пульта прибора составляет 38400 bps, т.е. я наверно буду проганять свой массив с такой же скоростью, чтобы максимально приблизить условия тестирования к реальным. Можно ли в случае таких времен адакватно следить за временем вылета, ведь наверняка время отправления кода, время записи в журнал, и время добавления кода отправленной команды в log-файл не будут идентичными. Или будут?
Чаще всего "вылет" происходит на неверной команде, то есть - последней в логах.
Нет. ПО прибора работает само по себе. Дополнительная программа, которую я надеюсь все-таки написать, будет работать уже с фактическими имеющимися вылетами. Т.е.
1. передавать коды из одного файла в прибор;
2. записывать переданные коды в log-файл;
3. регистрировать появление записи в Event Viewer;
Прекращение передачи кодов будет происходить (наверно) автоматически после вылета ПО (опять же с такими временами посылки может быть компьютер еще будет "жить" и пересылать данные, а программа прибора уже вылетит). Тогда уже я вручную буду смотреть на файл с переданными кодами и вычислять ошибку.
А действительно, не получится ли так, что ПО прибора (являющееся частью общего ПО компьютера) вылетело, а вцелом компьютер работает и пересылает все коды команд вплоть до последнего. Ведь Setup прибора - это одна программа, и если она дала сбой, то почему не должен тут же работать и выполнять другие программы сам компьютер? Так может быть? Просто тогда в моей программе сработает функция NotifyChangeEventLog() и нужно будет по флагу ее срабатывания тут же прекращать посылку команд.