| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > отчет об ошибках |
| Автор: NYX 13.6.2012, 19:19 |
| Всем привет. Не так давно возникла потребность (личная, не коммерческая) в создании простой, но эффективной системы отчета о событиях. Сначала задался писать простенькие процедуры и функции, затем все переросло в класс, потом в два класса, которые в целом позволяют делать отчеты с описанием и без описания + разные навороты с версиями и прочее прочее. В общем в итоге все обросло таким мусором, что хочется плюнуть на это все и... растереть! В общем, после недолгих мозговых потугов до меня дошла определенная идея. Может идея и бредовая (так полагаю в плане производительности она не айс), но наверно это то, что вполне может меня удовлетворить Вот некоторая концепция: * Система отчета является базовым классом, который методом простеньких и не очень хаков, позволит произвести протоколирование маршрутов вызовов * Каждая вызываемая функция дает знать о том что ее вызвали * В итоге, не сильно сложный класс, занимающийся отловом известных ошибок, в случае возникновения ошибки класс как то хитро выдергивает МАРШРУТ вызовов и соответственно вставляет соответствующую информацию в лог ошибок. Дабы не раскрывать секреты исходных кодов, можно например записывать маршрут вызовов на подобии такого: 00-12-46-03-11 ERROR #1039 "Произошло что то ужасное!" Вот. За коим фигом я обращаюсь на форум? Хотелось бы услышать: 1) Какие средства мне могут ваще поспособствовать написанию подобного бреда 2) Не в коем случае не интересуюсь иными методами, и посты типа - оставь свой велосипед и goto КАКАЯ_ТО_ЛИБА 3) Как можно реализовать базовый класс, позволяющий произвести отчет о вызовах? Ну грубо говоря - обертка, дает определенный номер (для начала int 4 байта) каждой функции, и при вызовах\завершению функции, пихать\извлекать номер вызываемой функции (как в стек прям!). Вот. В общем, добрые человеки, у кого возникнет свободное время, было бы интересно пообсуждать, потрепаться об ентом (!) может даже можно поразмышлять о бинарных деревьях |
| Автор: NYX 13.6.2012, 21:16 |
| Наверно нужна посредственность вызовов функций. Что то вроди оболочки, которая своевременно делала бы отпечаток в анналах при вызове и завершении. Чисто вот гепотетически... да-не, даже практически, на асме это реализуемо. Вот как бы блин вывернуть сустав компилятору (и самое главное какой из них) чтоб такое заделать...? Не у кого мыслишек нет? |
| Автор: alexvs11 13.6.2012, 21:51 |
| NYX, если речь идет про gcc, то там есть backtrace http://www.gnu.org/software/libc/manual/html_node/Backtraces.html http://www.linuxjournal.com/article/6391 используется во многих линуксовых программах для диагностики все что собственно делает - распечатывает стек вызовов я видел и более экзотическое решение - с аттачем gdb и выводом его бектрейса |
| Автор: NYX 13.6.2012, 21:58 | ||
| Ща зафигурим.... интересно... Я никогда не философствовал для себя на тему отчета об ошибках, но счас реально внапряг стало выискивать ошибки через дебаггер, да и система отчета типо ->
<- дает посредственное описание. Один фиг все через дебаггер прогонять приходится. Если пользователь вышлет лог с такими ошибками, это ооочень долго разбираться |
| Автор: Randajad 13.6.2012, 22:10 |
| backtrace под виндами не работает, что увы. Добавлено через 1 минуту и 5 секунд Под виндами можно заюзать StackWalk. Только название функций через него не получить, ибо гцц не умеет пдбшки делать. Но основная задача - адреса функций - вполне. |
| Автор: NYX 13.6.2012, 22:17 |
| Под виндузятину бэктрейс походу отсутствует по крайней мере не инклудится <execinfo.h> как бы я его не взывал! По причине отсутствия.... эх! Прощайте мечты о светлом будущем! |
| Автор: Randajad 13.6.2012, 22:17 |
| Афтар не успел. Я выше как раз написал об этом. |
| Автор: NYX 13.6.2012, 22:17 |
| тока тока гугль меня на StackWalk послал... тока с пометкой об MSVC |
| Автор: Randajad 13.6.2012, 22:19 | ||
Кусочек из моего логгера:
Так сказать псевдокод. Чистое winapi. |
| Автор: NYX 13.6.2012, 22:28 | ||
| Блин под gcc (MinGW) такого нет. Но смысл примерно ясен. А вот еще, тут про ANSI дефолты прочел, что типо можно так:
Можно заместо throw что то свое подставить? не знаю как сформилуровать мыслю на счет throw. Да и ваще если бы можно было бы обойтись без постоянной реализации однотогоже кода в теле функции было бы круто... потому что throw как бы... в общем эт так, мысли в слух... |
| Автор: Randajad 13.6.2012, 22:30 |
| Что за блин? Это винапи и писалось под гцц. Работает на любом компиляторе. Добавлено через 1 минуту и 53 секунды Нельзя так, увы. |
| Автор: NYX 13.6.2012, 22:35 |
| Окей, тогда по порядку. STACKFRAME - не нашлось не в одном хидере, искал по содержимому. StackWalk - аналогично. Да к тому же под MinGW не одного засвета. Тока под VC нашлось типо... у гугля нет ассоциаций таких с этими двумя весчами |
| Автор: Randajad 13.6.2012, 22:41 | ||
У меня заинклюдены:
Где-то тут. И еще бы я посоветовал уделять внимание не только логгерам, но и качеству кода, дабы меньше ошибок было. |
| Автор: NYX 13.6.2012, 22:43 |
| Черт побери. Есть такие. Не уж то винда 7я в корень оскотинилась ищет кое как :( дать бы поддых тому кто виндус придумал Работает... Поторопился. StackWalk по прежнему не работает... |
| Автор: Randajad 13.6.2012, 22:48 |
| Поиск в вянде всегда был неадекватным, это да. Кстати, чтобы функции Sym* работали нужно делать до вызова сий выше приведенной функции это: SymInitialize(hProc, 0, TRUE); И после надо бы: SymCleanup(hProc); Везде, где hProc - хэндл текущего процесса. Хотя на другие тоже можно натравить... Добавлено @ 22:52 Я с планшета в кроватке, мне тяжело искать. Завтра поищу, если не разберешься. Может WINVER=0x501 забыл или еще что? |
| Автор: NYX 13.6.2012, 23:04 | ||
Это само собой |
| Автор: Randajad 14.6.2012, 09:06 | ||
А у гцц оказывается есть милый параметр!
|
| Автор: NYX 14.6.2012, 15:33 | ||
| Это практически то, что я и искал! Счас буду ковырять! Randajad, честь и хвала тебе! Очень здорово помог! Так! Нашел вполне себе компилируемый экземпляр...
Результат скомпилился, но вывода нет. Полагаю надо какие то дополнительные параметры компилятору кинуть? Нашел вроди бы установку параметров в виде: -finstrument-fnctions для g++ однако с такими параметрами отказывается компилить, типо unrecognized и все такое ВСЕ! РАБОТАЕТ! Я ща помру от радости! ВАХ-ВАХ-ВАХ! Randajad, спасибо тебе огромное еще раз! Очень здорово помог. Теперь буду ковыряться с найденными тобой декларациями, что да как. Думаю весьма мощная штуковина, можно не только отчет для стека вызовов делать, но и еще какие то навороты, например подготовка объектов и зачистка всякого рода. В общем и в целом одним слово ВЕЩЬ! |
| Автор: NYX 14.6.2012, 17:28 |
| Интересно, а можно ли сделать это не для всех функций, а например только для функций класса или модуля или namespace? |
| Автор: Randajad 14.6.2012, 19:15 |
| Можно. Там ключики есть. StackWalk - разобрался? Днем руки его объявление найти не дошли. |
| Автор: NYX 14.6.2012, 20:08 |
| to Со StackWalk так и не разобрался. По дефолту у меня винвер 0x400 редефайнил на 501 ничего не дало O_o Если честно я даже не знал что его стоит передефайнить. Я думал установщик сам проставляет нужные дефайны исходя из системы на которую ставит... В общем не удалось мне запустить тот самый код и твоего примера. Я как за комп сяду напишу какие траблы возникли, попробую расковыряться в чем дело. А можно подробнее про ключики? Ваще где их глянуть можно (в каком разделе gcc мануала)? |
| Автор: Randajad 14.6.2012, 21:19 | ||
Я - волшебник?
Работает. Это весь код main.cpp. С целью проверить компиляцию воткнул. Добавлено через 25 секунд Ключики смотреть в гуглике. Этот я именно там нашел. |
| Автор: NYX 14.6.2012, 22:57 | ||
| удивительный день волшебства! еще на подходе красным подчеркивает нетбинс. Ну ради прикола попытался откомпилить... выдал ругачку undefined reference to `__imp__StackWalk@36' зачит всеж имеется онное (ну онное имеется безусловно, видел я это в хидере). Но что самое удивительное, именно такую ругачку вижу впервые при попытке откомпилить. Значит судя по сему надобно: * либо статически чота прилинковать * либо создать какой то объект * либо переобъявить Что из трех надо сделать буду ковырять в гугле
В этом даже сомнений не возникало понять других людей, при всей сложности собеседника (в лице меня дубалома-любителя) |
| Автор: Randajad 14.6.2012, 23:09 |
| Ну да, прилинковать надо, как бы ругается и на что. imagehlp либа, к сведению. |
| Автор: NYX 15.6.2012, 02:53 |
| Работает прилинковал соответвтующий *.a Счас бошка не соображает мальца. Я утром протестирую, хотя в общем то примерно я понял как оно работает |
| Автор: NYX 15.6.2012, 18:05 | ||
Тока я чот не совсем понял, там судя по всему перечисляются не имена функций и имена файлов, в которых списком обозначены имена функций (дабы что бы не брахлить опшенцы длиннющими списками. Наверно так... А, кстати! Для исключения функций указывается аттрибут __attribute__((no_instrument_function)), собственно если убрать строки деклараций с атрибутами для _cyg_profile_func_* то получается вечная рекурсия. Соответственно для всех функций входящих в состав "пользовательских \ объявленных пользователем" можно установить такой аттрибут и функция будет исключена. Так что нафиг списки в опциях. Все пользовательские функции которые являются подвызовом _cyg_profile_function_* надо изолировать аттрибутом. Иначе будет вечная рекурсия. Кстати если использовать например внутри *_enter и *_exit векторы с их push_back \ pop_back, то получается так же самая рекурсия. Так что выход наверно такой, не заморачиваться с вектором и сделать свой стек простенький для протоколирования вызовов. В общем под это дело можно целый-отдельный модуль выделить, где первоначально объявляются все эти дебаггерские дела и функции "страдающие" производительностью (напр. рендеры или функции связанные со временем или может даже потоки... всех их можно заблаговременно изолироваться от инструментария функционала простым аттрибутом. Это просто грандиозно! |
| Автор: NYX 1.8.2012, 20:47 |
| Товарищи, а как на ваш взгляд, имеет ли смысл реализовывать такую стратегию отчета об ошибках? Программа реализована в виде двух модулей. Первый модуль исполняемый, второй модуль отчетный. В исполняемом модуле имеется некий класс-прокси, который отвечает за вызов модуля отчета, в т.ч. обеспечение ожидания в случае множественных вызовов из разных потоков. Класс-прокси является так же синглтоном и имеет в своем теле функцию __stdcall предназначеную для переопределения SetUnhandledExceptionFilter. Далее, для определения логической ошибки, производится вызов функции класса-прокси с указанием базовых данных в виде __FUNCTION__ и кода ошибки. В случае runtime ошибки так же производится вызов модуля отчета, но уже с более полной информацией о сбое. Производится вызов модуля отчета под средством CreateProcess. Модуль отчета имеет обработку аргументов из cmd строки, которые позволяют: очистить лог записать лог Далее, для чего такой костыль? Я вот так подумал, я же ведь могу получить доступ из одного процесса к другому процессу? Может быть мне будет проще сделать дамп слетевшего процесса из внешнего + это будут два раздельных процесса и у каждого своя виртуальная память, не разделяемая. В случае тотального пипца модуль отчета будет жив как не крути. В случае если надо будет просмотреть стек вызовов, то в том же олли могу поставить брейкпоинт на вызове функции прокси-класса и в момент завершения\слета посмотреть в олльге стек вызовов. Этого будет достаточно думаю. А дамп и прочее можно будет потом дописать в модуле отчета, как бы со временем дополняя функционал. А модуль исполняемый как есть, так и есть. Все что он может сделать, так это выполнять код. Модуль отчета можно например отдать на рабработку члену группы, какому нибудь системщику которые с асмом дружит как пчела с цветком ВАХ! Самый прикол в том, что я написал уже некую заготовку такой штуковины, вполне работает, модуль отчетности занимает копейки и прежде чем полностью повесить проц, надо запустить ну что то около нцати сотен экземпляров близкому к тыщячи Есть ли где нибудь описание опдобного метода? Насколько взрослым является такой метод? |