Логирование исключений
От: csharper  
Дата: 27.10.05 09:41
Оценка:
Hi

Вот захотелось сделать автоматическое логирование исключений. Есть базовый класс исключения, все от него наследуются. Но тут не совсем понятно когда вызвать метод log() чтобы записать все параметры. Функцию сделать виртуальной нельзя, потому что в конструкторе виртуальные функции не работают. Передавать дополнительные параметры в конструктор (параметры логирования) по иерархии до базового класса тоже не очень красиво. Есть какие-то идеи?

Спасибо!
... << RSDN@Home 1.1.4 beta 6a rev. 444>>
Re: Логирование исключений
От: Aera Беларусь  
Дата: 27.10.05 10:21
Оценка:
Здравствуйте, csharper, Вы писали:

Может оно?
struct my_log_exception : log_exception
{
  void log(const char*);
}

#define HERE __FILE__ "(" __LINE__ ")"

template<typename T> myassert(bool x, char const* placement)
{
  T ex; ex.log(placement);
  throw ex;
}

int main()
{
  int a=0;
  myassert<my_log_exception>(a==0, HERE);
}

--
Aera
--
RedApe
Re: Логирование исключений
От: Кодт Россия  
Дата: 27.10.05 10:22
Оценка: 16 (3)
Здравствуйте, csharper, Вы писали:

C>Вот захотелось сделать автоматическое логирование исключений. Есть базовый класс исключения, все от него наследуются. Но тут не совсем понятно когда вызвать метод log() чтобы записать все параметры. Функцию сделать виртуальной нельзя, потому что в конструкторе виртуальные функции не работают. Передавать дополнительные параметры в конструктор (параметры логирования) по иерархии до базового класса тоже не очень красиво. Есть какие-то идеи?


Кидай исключение не голой инструкцией throw YourClass, а обёрткой:
template<class Ex>
enable_if< is_base_and_derived<YourExceptionBase,Ex>, void > // чтобы пресечь кидание неправильных исключений
do_throw(const Ex& ex
       , const char* file, int line // приятный бонус: можно узнать, откуда кинуто
        )
{
  do_log(ex,file,line);
  throw ex;
}
#define DO_THROW(ex) do_throw((ex),__FILE__,__LINE__)
Перекуём баги на фичи!
Re: Логирование исключений
От: swamper  
Дата: 27.10.05 10:22
Оценка:
Здравствуйте, csharper, Вы писали:

C>Hi


C>Вот захотелось сделать автоматическое логирование исключений. Есть базовый класс исключения, все от него наследуются. Но тут не совсем понятно когда вызвать метод log() чтобы записать все параметры. Функцию сделать виртуальной нельзя, потому что в конструкторе виртуальные функции не работают. Передавать дополнительные параметры в конструктор (параметры логирования) по иерархии до базового класса тоже не очень красиво. Есть какие-то идеи?


Например так...


/**
    @ingroup Support
    @brief Базовый класс исключения.
*/

//=====================================================================================//
//                                   class Exception                                   //
//=====================================================================================//
class Exception : public std::exception
{
private:

    std::string m_msg;            // строка, с сообщением об ошибке

public:
    Exception();
    Exception(const char* msg);
    Exception(const std::string& msg);
    Exception(const exception& another);
    virtual ~Exception();
public:
    ///    получить строку с сообщением об ошибке
    virtual const char* what() const;

private:
    ///    выводит сообщение об ошибке в отладочный поток
    void writeDebugOut() const;

};

inline Exception::Exception() : m_msg("Unknown error.")
{
    writeDebugOut();
}

inline Exception::Exception(const char* msg) : m_msg(msg)
{
    writeDebugOut();
}

inline Exception::Exception(const std::string& msg) : m_msg(msg)
{
    writeDebugOut();
}

inline Exception::Exception(const std::exception& another) : m_msg(another.what())
{
}

inline Exception::~Exception()
{
}
//    получить строку с сообщением об ошибке
inline const char* Exception::what() const
{
    return m_msg.c_str();
}
//    выводит сообщение об ошибке в отладочный поток
inline void Exception::writeDebugOut() const
{
    DEBUG_OSTREAM("Exception [" << m_msg << "]\n");
}

/**    
    @ingroup Support
    @def MAKE_EXCEPTION(Name,Parent)     
        Сгенерировать новый тип исключения.
*/    

//=====================================================================================//
//                              #define MAKE_EXCEPTION()                               //
//=====================================================================================//
#define MAKE_EXCEPTION(Name,Parent)                                            \
class Name : public Parent                                                    \
{                                                                            \
public:                                                                        \
    Name() {}                                                                \
    Name(const char* msg) : Parent(msg) {}                                    \
    Name(const std::string& msg) : Parent(msg) {}                            \
    Name(const Name& another) : Parent(another) {}                            \
}


Использование:


MAKE_EXCEPTION(FileSystemFailure,Exception);
MAKE_EXCEPTION(FileSystemOpenFileFailure,FileSystemFailure);

//  где-то в теле функции
   ...
   throw FileSystemOpenFileFailure("Не удалось открыть файл ["+name+"]");
   ...



... макрос DEBUG_OSTREAM выводит сообщение об исключении в отладочный поток (окно Output под MSVS).
Re: Логирование исключений
От: Pavel Chikulaev Россия  
Дата: 27.10.05 10:22
Оценка:
Здравствуйте, csharper, Вы писали:

C>Hi


C>Вот захотелось сделать автоматическое логирование исключений. Есть базовый класс исключения, все от него наследуются. Но тут не совсем понятно когда вызвать метод log() чтобы записать все параметры. Функцию сделать виртуальной нельзя, потому что в конструкторе виртуальные функции не работают. Передавать дополнительные параметры в конструктор (параметры логирования) по иерархии до базового класса тоже не очень красиво. Есть какие-то идеи?


Может пригодится http://boost.org/libs/utility/base_from_member.html
Re: Логирование исключений
От: -MyXa- Россия  
Дата: 27.10.05 10:24
Оценка:
Здравствуйте, csharper, Вы писали:

C>Hi


C>Вот захотелось сделать автоматическое логирование исключений. Есть базовый класс исключения, все от него наследуются. Но тут не совсем понятно когда вызвать метод log() чтобы записать все параметры. Функцию сделать виртуальной нельзя, потому что в конструкторе виртуальные функции не работают. Передавать дополнительные параметры в конструктор (параметры логирования) по иерархии до базового класса тоже не очень красиво. Есть какие-то идеи?


C>Спасибо!


Самому интересно чем это грозит:
class base_exc
{
public:
    virtual ~base_exc(void) = 0 {};
};

template<typename Derived>
class basic_exc : 
    public base_exc
{
public:
    basic_exc()
    {
        std::cout << typeid(Derived).name() << std::endl;
    }
};

class my_exc1 : 
    public basic_exc<my_exc1>
{
};
Если не поможет, будем действовать током... 600 Вольт (C)
Re: Логирование исключений
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 27.10.05 10:32
Оценка:
Здравствуйте, csharper, Вы писали:

C>Вот захотелось сделать автоматическое логирование исключений....Есть какие-то идеи?


Отказаться от этого желания.

Если уж очень хочется залогировать что-нибудь во время порождения исключения, то подумай о макросе RAISE:
#define RAISE(exception_type, exception_params ) \
    do { exception_type ex__ exception_params ; \
      some_logging_object << ex__.what(); \
        throw ex__; \
    } while( 0 )


И использовать его так:
RAISE( std::invalid_argiment, ( "some ptr == NULL" ) );
RAISE( my_very_detailed_ragne_error_exception, ( module_name, "some_function", "range error", min, max ) );

только параметре исключения тебе всегда придется в дополнительные скобки заключать.

Не нравятся макросы, можно какую-нибудь шаблонную функцию придумать.

Но по мне, код для логирования должен быть отделен от кода по порождению исключений.

Кстати, вводя собственный корень для иерархии исключений, ты лишаешься возможности сделать часть исключений производными от std::logic_error, а часть -- от std::runtime_error. Хотя в большинстве случаев это и не важно.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re: Логирование исключений
От: Paranoik  
Дата: 27.10.05 12:14
Оценка: :)
Здравствуйте, csharper, Вы писали:

C>Hi


C>Вот захотелось сделать автоматическое логирование исключений. Есть базовый класс исключения, все от него наследуются. Но тут не совсем понятно когда вызвать метод log() чтобы записать все параметры. Функцию сделать виртуальной нельзя, потому что в конструкторе виртуальные функции не работают. Передавать дополнительные параметры в конструктор (параметры логирования) по иерархии до базового класса тоже не очень красиво. Есть какие-то идеи?


C>Спасибо!


Раз конструктор не подходит, можно попробовать воспользоватся деструктором...
Дружба не наследуется и не транзитивна.
©Бьерн Страуструп
Re[2]: Логирование исключений
От: Кодт Россия  
Дата: 27.10.05 12:21
Оценка:
Здравствуйте, Paranoik, Вы писали:

P>Раз конструктор не подходит, можно попробовать воспользоватся деструктором...

Какая разница? На момент вызова деструктора базы всё остальное разрушено, а vfptr настроен на vtbl базы.
Перекуём баги на фичи!
Re[3]: Логирование исключений
От: Paranoik  
Дата: 27.10.05 12:32
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Paranoik, Вы писали:


P>>Раз конструктор не подходит, можно попробовать воспользоватся деструктором...

К>Какая разница? На момент вызова деструктора базы всё остальное разрушено, а vfptr настроен на vtbl базы.

Можно оставить в базе полностью сформированное сообщение для логгирования...
Дружба не наследуется и не транзитивна.
©Бьерн Страуструп
Re[4]: Логирование исключений
От: Кодт Россия  
Дата: 27.10.05 12:34
Оценка:
Здравствуйте, Paranoik, Вы писали:

P>Можно оставить в базе полностью сформированное сообщение для логгирования...

В том месте, где это сообщение "оставляется", и можно записать его в лог.
Перекуём баги на фичи!
Re[3]: Логирование исключений
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 27.10.05 12:35
Оценка:
Здравствуйте, Кодт, Вы писали:

P>>Раз конструктор не подходит, можно попробовать воспользоватся деструктором...

К>Какая разница? На момент вызова деструктора базы всё остальное разрушено, а vfptr настроен на vtbl базы.

Например, базовый класс может содержать указатель на динамический созданный объект с описанием исключения. Каждый производный класс формирует этот объект в своем конструкторе, а базовый логирует информацию из него в своем деструкторе.

Только вот мне интересно, что произойдет, если логировать в деструкторе, вот в этом случае:
void f()
    {
        ...
        // По идее, запись в лог нужно сделать здесь.
        throw my_detailed_exception( ... );
        ...
    }

void g()
    {
        try
            {
                f();
            }
        catch( const my_exception_base & x )
            {
                log << "Shit happens!" << std::endl;
            }
    }


По идее, в лог сначала попадет сообщение "Shit happens!", а уже затем описание самого исключения (т.к. на момент работы блока catch объект исключения еще жив).

Еще интереснее дела могут идти в многопоточном приложении. Например, выборос исключения в f() снял блокировку (освободился mutex в деструкторе какого-нибудь scope_guard-а, к примеру) с параллельной нити. Она записала что-нибудь в лог. Затем управление опять получила нить с f(), возвратились в g() и записали что-то в лог. Хотя, по замыслу, в лог запись о появлении проблем должна была попасть еще внутри f(), пока параллельная нить была блокрирована.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re: Логирование исключений
От: MaximE Великобритания  
Дата: 27.10.05 13:55
Оценка:
On Thu, 27 Oct 2005 13:41:38 +0400, csharper <37239@users.rsdn.ru> wrote:

> Вот захотелось сделать автоматическое логирование исключений. Есть базовый класс исключения, все от него наследуются. Но тут не совсем понятно когда вызвать метод log() чтобы записать все параметры. Функцию сделать виртуальной нельзя, потому что в конструкторе виртуальные функции не работают. Передавать дополнительные параметры в конструктор (параметры логирования) по иерархии до базового класса тоже не очень красиво. Есть какие-то идеи?


Можешь аккуратно "перегрузить" throw. http://rsdn.ru/Forum/?mid=1029176
Автор: MaximE
Дата: 16.02.05


--
Maxim Yegorushkin
Posted via RSDN NNTP Server 2.0 beta
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.