Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Технология ведения лога (диагностика) 
:(
    Опции темы
_Tanatos_
Дата 21.11.2007, 11:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 28
Регистрация: 20.11.2007

Репутация: нет
Всего: нет



Благодарю всех за активное участие и ценные советы.

В силу обстоятельств на начальной стадии проекта буду писать на C++ Builder а он не знает не __func__, __FUNCTION__ и __PRETTY_FUNCTION__. Ну да ладно, меня не ломает скопировать название функции и класса, и потом можно написать простую тулзу которая перебирая перед компиляцией все исходники будет править имя класса и функции - так что это решаемо.

Отказаться от использования ООП думаю не оправданно. Конечно остаются некоторые вероятности, но отказать может почти все. Например от отключения питания не спасут никакие технологии программирования (кстати ИБП тоже подыхают периодически).

Однозначно простой лог меня не устроит. Нужно дерево. Кстати необязательно его при этом хранить целиком в память, достаточно точно знать номер записи родителя или как еще более простой вариант номер уровня (и не надо заводить стек для родителей) если номер меньше чем номер предыдущей записи - значит дочерний, если больше значит выхоим на уровень выше. Недостаток - парсить действительно надо будет все. Но никто не мешает этот-же лог просмотреть и как текст просто отфильтровав по типу записи и классу.

По поводу сброса буффера на диск, надо постараться отловить крах системы (может даже вынести ведение лога в независимый процесс - пока не думал над этим) а в штатном режиме делать сброс буввера например, каждые 10 секунд.

Будут результаты отпишусь, может и правда совместными усилиями сделаем конфетку.

Еще один момент, уважаемые форумчане!
Подскажите как быть с ведением лога в многопоточном приложении? Пока предполагаю вести независимые логи в разные файлы, чтобы каждый из них можно было просматривать и как дерево и в развернутом виде.

Это сообщение отредактировал(а) _Tanatos_ - 21.11.2007, 11:20
PM MAIL   Вверх
Lazin
Дата 21.11.2007, 11:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



О чем то похожем говорил bsa, можно вынести часть функционала в отдельный класс и использовать raii

Код

//класс - лог-файл - записывает данные в файл в каком-то формате
class Log
{
 static long node;
 void write(long n, LPCSTR msg);
};

//класс - непосредственно для записи сообщений пользовательским кодом
class Logger
{
friend class Log;
static Log s_log;
long current_node;
public:
 Logger() : current_node(Log::node)
 {
    ++Log::node;//здесь нужна синхронизация
 }

 ~Logger()
 {
   s_log.write(current_node, "return");
 }

 void Write(LPCSTR str)
 {
    s_log.write(current_node, str);
 }
};


принцип такой, впри входе в ф-ю создается объект Logger. Через который производится запись в лог, каждый такой объект имеет свой номер, по которому можно определить порядок вызовов, в деструкторе, в лог также записывается информация о том что ф-я завершила выполнение.


Это сообщение отредактировал(а) Lazin - 21.11.2007, 11:55
PM MAIL Skype GTalk   Вверх
archimed7592
Дата 21.11.2007, 12:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 58
Всего: 93



Цитата(Lazin @  21.11.2007,  11:54 Найти цитируемый пост)
 ~Logger()
 {
   s_log.write(current_node, "return");
 }

Я бы ещё добавил
Код
s_log.write(current_node, std::uncaught_exception() ? "return(stack unwinding)" : "return");



--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
SaDFromSpb
Дата 21.11.2007, 12:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 263
Регистрация: 5.4.2006
Где: Санкт-Петербург

Репутация: 3
Всего: 3



А вот, кстати, содержимое boost/current_function.hpp:
Код

namespace boost
{

namespace detail
{

inline void current_function_helper()
{

#if defined(__GNUC__) || (defined(__MWERKS__) && (__MWERKS__ >= 0x3000)) || (defined(__ICC) && (__ICC >= 600))

# define BOOST_CURRENT_FUNCTION __PRETTY_FUNCTION__

#elif defined(__FUNCSIG__)

# define BOOST_CURRENT_FUNCTION __FUNCSIG__

#elif (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 600)) || (defined(__IBMCPP__) && (__IBMCPP__ >= 500))

# define BOOST_CURRENT_FUNCTION __FUNCTION__

#elif defined(__BORLANDC__) && (__BORLANDC__ >= 0x550)

# define BOOST_CURRENT_FUNCTION __FUNC__

#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)

# define BOOST_CURRENT_FUNCTION __func__

#else

# define BOOST_CURRENT_FUNCTION "(unknown)"

#endif

}

} // namespace detail

} // namespace boost


Все весьма банально =)



--------------------
"За исключением части, касающейся потоков, библиотека Loki написана на стандартном языке С++. Увы, это означает, что многие современные компиляторы не смогут работать с ней в полном объеме." (А. Александреску. Modern C++ design. 2001)
PM   Вверх
dumb
Дата 21.11.2007, 14:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


sceloglauxalbifacies
****


Профиль
Группа: Экс. модератор
Сообщений: 2929
Регистрация: 16.6.2006

Репутация: 8
Всего: 158



Цитата(_Tanatos_ @  21.11.2007,  11:13 Найти цитируемый пост)
буду писать на C++ Builder а он не знает не __func__, __FUNCTION__ и __PRETTY_FUNCTION__
он знает __FUNC__smile
PM MAIL   Вверх
JackYF
Дата 21.11.2007, 17:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


полуавантюрист
****


Профиль
Группа: Участник
Сообщений: 5814
Регистрация: 28.8.2004
Где: страна тысячи озё р

Репутация: 18
Всего: 162



Цитата(Mayk @  21.11.2007,  04:37 Найти цитируемый пост)
в бусте есть boost/current_function.hpp  

* ушёл смотреть *

ну вот, уже выложили smile
ну так, в принципе, и предполагалось.

Буст подруливает.
Maykу однозначно плюс.


--------------------
Пожаловаться на меня как модератора можно здесь.
PM MAIL Jabber   Вверх
_Tanatos_
Дата 22.11.2007, 13:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 28
Регистрация: 20.11.2007

Репутация: нет
Всего: нет



Подскажите какой тип лучше использовать для хранения времени события и заодно какие функции для работы с ним.
PM MAIL   Вверх
Lazin
Дата 22.11.2007, 13:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



структура FILETIME, функции GetLocalTyme SystemTimeToFileTime
PM MAIL Skype GTalk   Вверх
SaDFromSpb
Дата 22.11.2007, 15:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 263
Регистрация: 5.4.2006
Где: Санкт-Петербург

Репутация: 3
Всего: 3



Цитата(_Tanatos_ @  22.11.2007,  13:41 Найти цитируемый пост)
Подскажите какой тип лучше использовать для хранения времени события и заодно какие функции для работы с ним. 

А что, в <ctime> большой выбор для этого?  smile  Или что-то нестандартное хочешь использовать? Время события системное хочешь использовать, или считая от запуска программы?



--------------------
"За исключением части, касающейся потоков, библиотека Loki написана на стандартном языке С++. Увы, это означает, что многие современные компиляторы не смогут работать с ней в полном объеме." (А. Александреску. Modern C++ design. 2001)
PM   Вверх
StarikanMan
Дата 22.11.2007, 16:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 22.11.2007

Репутация: нет
Всего: нет



bsa, он написал очень хороший пример
PM MAIL   Вверх
dumb
Дата 22.11.2007, 16:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


sceloglauxalbifacies
****


Профиль
Группа: Экс. модератор
Сообщений: 2929
Регистрация: 16.6.2006

Репутация: 8
Всего: 158



всем, кто пытается осмыслить посты StarikansBack'а - этот убогий является каким-то обгашенным куском недоразума, генерирующим случайные наборы слов.
PM MAIL   Вверх
Lazin
Дата 22.11.2007, 16:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Цитата(dumb @  22.11.2007,  16:32 Найти цитируемый пост)
всем, кто пытается осмыслить посты StarikansBack'а - этот убогий является каким-то обгашенным куском недоразума, генерирующим случайные наборы слов. 

Кстати пример кода взят из одного из недавних постов на форуме))
PM MAIL Skype GTalk   Вверх
Lazin
Дата 22.11.2007, 17:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Цитата(Alexeis @  22.11.2007,  16:55 Найти цитируемый пост)
[offtop]Это по ходу обиженный на Гуеду RinOSPro, который мстит за то что его банили.[/offtop] 

точнее множество его клонов))
PM MAIL Skype GTalk   Вверх
_Tanatos_
Дата 23.11.2007, 14:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 28
Регистрация: 20.11.2007

Репутация: нет
Всего: нет



Вот что у меня получилось на данный момент 
Привожу фрагмент кода с описанием структуры данных одной записи:

Код

typedef struct
{
    unsigned long   m_RowID;    // Порядковый номер строки
    int             m_Level;    // Уровень вложенности
    int             m_ProcID;   // Идентификатор процесса
    int             m_UnitID;   // Идентификатор модуля
    char            m_Type;     // Тип сообщенияы
    int             m_Error;    // Код ошибки
    char*           m_Msg;      // Текст сообщения
    char*           m_Data;     // Дополнительные данные
    char*           m_Function; // Имя функции
    char*           m_File;     // Имя файла
    int             m_Line;     // Номер строки
    SYSTEMTIME      m_Time;     // Время события
}
TtLibLogRecord;


Какие есть мысли и соображения?
Изначально буду реализовывать функцию регистрации записи с полным перечнем 
Поля m_Level и m_Time обрабатываются автоматически внутри класса.
Предполагаю, что использование полей m_Type, m_File и m_Line будет внутри макроса, тем самым сократиться общая длина записи
Макрос __FUNC__ пока не буду использовать, так как нет гарантий, что при смене компилятора работоспособность кода сохранится.
Для времени пока остановился на SYSTEMTIME, дабы не вызывать лишние функции преобразования, да и при записи в текстовый файл не надо будетзаниматься обратной конвертацией для форматирования.

далее приведено определение обработчика для регистрации новой записи
Код

typedef void (__closure *TtLibOnLogAdd)(CtLibLogEngine& LogEngine);
typedef std::vector<TtLibOnLogAdd> TtLibLogSubscribers;


Вот и сам класс журналирования
Код

class CtLibLogEngine
{
private:
    TtLibLogRecord      m_Record;
    unsigned long       m_RowID;
    TtLibLogSubscribers m_Subscribers;
protected:
public:
   ~CtLibLogEngine();
    CtLibLogEngine();

    inline const TtLibLogRecord& getRecord() const;

    inline void SubscriberAdd(TtLibOnLogAdd OnLogAdd);
    inline void SubscriberRemove(TtLibOnLogAdd OnLogAdd);

    inline void RegisterMsg(int ProcID, int UnitID, char Type, int Error, const char* Msg, const char* Data, const char* Function, const char* File, int Line);
};


Предполагается следующий сценарий использования
- имеется глобальная переменная g_LogEngine через нее происходит регистрация всех событий
- В данному классу подключаются обработчики выполняющие одну из следующих функций:
         - запись в файл
         - отправка лога по почте (например пересылает только критические сообщения)
         - отображение сообщений в окне отладки (если таковое имеется в программе)
- Далее при входе в журналируюмую функцию объявляем вспомогательный класс (экземпляр), через него обеспечивается запись в журнал с увеличением уровня вложенности
- используем подготовленные макросы для ведения лога в пределах функции.
- вызываем функцию Complete() в вспомогательном классе
- при завершении функции вспомогательный класс в деструкторе фиксирует уменьшение уровня вложенности и делает запись либо об успешном выполнении либо об аварийном завершении (если небыло вызова Complete() )

примерно так.
Вспомогательный класс опишу чуть позже.

Поддержка многопоточности на последний этап, так как это на перспективу и мне пока не нужно.

Из актуальных вопросов это регистрация условий обработки - ограничение по минимальному и максимальному уровню для m_Type для каждого отдельного m_UnitID, что позволит сократить объем сохраняемых записей.

Пока планирую сделать так:
Код

typedef struct
{
    int     m_UnitID;   // Идентификатор модуля
    char    m_Min;      // Минимальное значение для m_Type
    char    m_Max;      // Максимальное значение для m_Type
}
TtLibLogCondition;


Соответственно делаем массив таких записей и при регистрации новой записи сначала пробегаемся по этому массиву и проверяем на выполнимость условий, если разрешающего условия не найдено, то завершаем обработку, иначе поочередно вызываем все обработчики.

При необходимости задавать условия для каждого обработчика отдельно, это уже реализуется внутри конкретного обработчика.

Какие есть мысли, пожелания, предложения?
По ходу дела буду выкладывать готовые фрагменты и по результату скину все целиком.

Это сообщение отредактировал(а) _Tanatos_ - 23.11.2007, 14:27
PM MAIL   Вверх
Lazin
Дата 23.11.2007, 14:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Цитата(_Tanatos_ @  23.11.2007,  14:17 Найти цитируемый пост)

Код

typedef struct
{
    unsigned long   m_RowID;    // Порядковый номер строки
    int             m_Level;    // Уровень вложенности
    int             m_ProcID;   // Идентификатор процесса
    int             m_UnitID;   // Идентификатор модуля
    char            m_Type;     // Тип сообщенияы
    int             m_Error;    // Код ошибки
    char*           m_Msg;      // Текст сообщения
    char*           m_Data;     // Дополнительные данные
    char*           m_Function; // Имя функции
    char*           m_File;     // Имя файла
    int             m_Line;     // Номер строки
    SYSTEMTIME      m_Time;     // Время события
}
TtLibLogRecord;

Мне кажется эта структура сильно избыточна, если знаешь имя ф-ии, то имя файла и номер строки знать не обязательно. И имя ф-ии можно указывать только при входе в ф-ию, с другой стороны нет идентификатора потока, в многопоточном приложении записи из разных потоков смешаются, и получится хаос. Уровень вложенности нужно расчитывать для каждого потока отдельно. Еще можно расчитывать m_Level в зависимости от степени вложенности.
PM MAIL Skype GTalk   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1016 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.