Ogre 异常处理和日志

 平:我改一点错误。就是枚举类型前后的表格写错了

日志管理

用文件来记录Ogre系统初始化、运行、结束以及调试信息。使用日志便于我们调试程序。

Ogre日志系统的组成

Ogre日志系统由两个类组成:Log类LogManager。下面我们分别来看这两个类。

Log类

代表用于记录信息的日志。Log类的一个对象对应于一个日志文件。

Log类提供了向日志文件写信息的函数logMessage,其定义如下:

   void logMessage(const String& message, LogMessageLevel lml = LML_NORMAL);
              参数message,String类型的变量,存储要写入的信息。
              参数lml,指定传入信息的级别,来衡量一条信息的重要程度。
     

参数值

信息的重要程度

LML_TRIVIAL

最低

LML_NORMAL

一般

LML_CRITIAL

最高

 平:LogMessageLevel 定义源码在 OgreLog.h 中,

enum LogMessageLevel
    {
        LML_TRIVIAL = 1,
        LML_NORMAL = 2,
        LML_CRITICAL = 3
    };

为了判断一条信息的重要性,从而决定是否将该信息写入日志文件。我们不光要衡量信息的重要程度,还应该同时考虑日志文件的重要程度。Log类提供了一个函数setLogDetail来设置日志文件的重要程度,其定义如下: 

   void setLogDetail(LoggingLevel ll);
              参数ll,指定该日志文件的级别,来衡量日志文件的重要程度


参数值

代表日志文件的重要程度

LL_LOW

最低

LL_NORMAL

一般

LL_BOREME

最高

平:LoggingLevel 定义源码在 OgreLog.h 中

enum LoggingLevel
    {
        LL_LOW = 1,
        LL_NORMAL = 2,
        LL_BOREME = 3
    };


LogManager类

管理所有Log类的对象,也就是管理所有的日志文件。并负责向日志文件中输出信息。

LogManager类提供了创建Log对象的成员函数createLog。

注意,不要用Log类直接创建对象,而要用LogManager的createLog函数来创建Log对象。因为这保证了:使LogManager维护所有的Log对象,通过LogManager可以方便地进行查找等操作。createLog定义如下:

 Log* createLog( const String& name, bool defaultLog = false, bool debuggerOutput = true );
     参数name是String类型的,它指定所创建日志文件的文件名,如Ogre.log。
     参数defaultLog是布尔类型的,如果为true,则把当前创建的日志文件设置为LogManager默认的日志文件。调用LogManager的接口函数都对此文件生效。
     参数debuggerOutput是布尔类型的,如果为true,则不只向日志文件中输出信息,还向调试窗口中输出信息。

成员函数

     成员函数getLog可以通过文件名得到其代表的Log对象。它的定义如下:

     Log* getLog( const String& name);
     参数name指定了要查找的日志文件名。

     设置默认Log文件级别的成员函数:

     void setLogDetail(LoggingLevel ll);

     参数ll指定默认日志文件的重要程度,它见前面。

  

     成员函数getDefaultLog返回默认的Log对象 

    Log* getDefaultLog();

     成员函数logMessage向默认的日志文件中写入信息,它有两种形式:

     void logMessage( const String& message, LogMessageLevel lml = LML_NORMAL);
     void logMessage( LogMessageLevel lml, const char* szMessage, ... );
     参数lml指定传入的信息的重要程度。

     第一个logMessage可以向日志文件中写入一条信息。第二个logMessage可以写入接收的多条信息。

Ogre日志系统的使用举例

程序概述

重载ExampleApplication内的createScene函数,在函数内创建一个名为Test.log的日志文件,并向该文件中写入一段信息。

部分代码

   void createScene(void)
    {
         Log *p_Log = LogManager::getSingleton().createLog( "test.log" );
         p_Log->logMessage( "I write a message to test.log" );
}

     在createScene函数中,首先调用LogManager的createLog成员函数来创建一个名为test.log的日志文件,并用p_Log保存此日志文件的指针。然后,我们通过Log的成员函数logMessage向test.log中写入一句话。

     执行一遍程序后,你会发现程序可执行文件所在的目录下多了一个名为test.log的文件,接着打开test.log,你会看见一行字:I write a message to test.log。

当然,这个程序所做的并没有什么意义。它的目的只是演示一下Ogre日志系统的使用方法,

 

关于Ogre日志系统的应用,在下一部分异常处理中还有介绍。


异常处理

Ogre用C++内建的异常处理机制来处理错误。

使用异常处理的好处

首先,使用异常处理,可以使C++程序的两个部分相互通信(这两部分通常是分别开发的)。检测到异常的部分可以抛出异常,而另一部分可以捕获异常并做进行处理。

其次,使用异常处理,可以避免用返回值来定义错误。当有错误发生时,一个异常就会被抛出,这个异常里面封装了发生错误的详细信息。

 

Ogre中使用异常的例子:

 

   try {
        app.go();
} catch( Ogre::Exception& e ) {
   // 处理异常
    }

首先,这段代码分为两部分,分别由try与catch包围起来,如果app.go()有错误产生,则Ogre::Exception类型的异常会被抛出,catch部分捕获并处理这个异常。

 

其次,如果没有异常,这段代码可能会是这样的:   

     if( !app.go() )
     {
        // 处理错误
     }

       我们不得不用函数的返回值来定义错误。这样,不但错误信息不准确,而且导致程序的错误处理代码与应用代码混在一起,不易于维护。

 

Ogre对异常处理的支持    

Ogre::Exception

Ogre定义了自己的异常类型Ogre::Exception,它记录了错误的详细信息(错误编号、详细描述、错误发生的文件名、行数等)。当有错误发生时,Ogre会抛出这个类型的异常,并把这个异常记录的错误信息写入到LogManager的默认日志文件中。

Ogre::Exception提供了一个成员函数getFullDescription,它的返回值是String类型的,保存了对错误的详细描述。

Ogre::Exception维护了一个函数名称堆栈。提供了一个入栈函数_pushFunction,它接收一个String类型的参数。和一个出栈函数_popFunction。我们需要在每个函数的起始位置调用_pushFunction,并把该函数的函数名当作参数传入。在结束位置调用_popFunction。

 

几个辅助宏

Except(num, desc, src ) 相当于throw( Exception( num, desc, src, __FILE__, __LINE__ ) )。a, b, c分别代表错误编号,错误描述与错误发生所在的函数。__FILE__和__LINE__是系统变量,它们的意思是错误发生时的代码文件和行数。

OgreGuard( a ) 相当于Exception::_pushFunction( ( a ) )
OgreUnguard( a ) 相当于Exception::_popFunction( ( a ) )

Ogre异常处理的例子

部分代码:

// Log.cpp
    MaterialApplication app;
 
try {
    app.go();
} catch( Exception& e ) {
#if OGRE_PLATFORM == PLATFORM_WIN32
// 如果是Win32平台,则弹出一个错误对话框,显示错误的详细信息。
MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
       // 如果不是Win32平台,则直接输出错误的详细信息。
    fprintf(stderr, "An exception has occured: %s/n",
            e.getFullDescription().c_str());
 
// Log.h
// 定义一个函数Wudi1,在内部武断地抛出一个异常
void Wudi1()
{
       OgreGuard( "Wudi1" );                // 将函数名称压入堆栈
       Except( 888, "wudi", "Wudi1" );    // 抛出一个异常
       OgreUnguard();                           // 弹出栈顶元素
}
 
// 定义一个函数Wudi2,在内部调用Wudi1
void Wudi2()
{
       OgreGuard( "Wudi2" );                // 将函数名称压入堆栈
       Wudi1();                                     // 调用Wudi1
       OgreUnguard();                           // 弹出栈顶元素
}
 
class MaterialApplication : public ExampleApplication
{
public:
    MaterialApplication() {}
 
protected:
// 重载createScene函数
void createScene(void)
{
       Wudi2();                // 调用Wudi2函数
    }
};
 


执行结果

运行程序,会弹出一个错误对话框:

 Ogre 异常处理和日志_第1张图片

在默认的日志文件Ogre.log中也记录了同样的错误信息:

5:49:48: An exception has been thrown!

 

-----------------------------------

Details:

-----------------------------------

Error #: 888

Function: Wudi1

Description: wudi.

File: d:/programming exercises/ogre例子/ogre99f/renwind_log/log.h

Line: 32

Stack unwinding: Wudi1()<-Wudi2()<-<<beginning of stack>>

最后一行,显示了函数名称队列的展开。我们可以看出,栈底的函数是Wudi2(),异常发生在栈顶Wudi1()函数内。

 

通过Ogre的日志系统与异常处理,我们可以迅速的查看系统运行的信息,快速定位错误发生的位置,并动态地处理错误。

转载: http://blog.csdn.net/pizi0475/article/details/5451267

你可能感兴趣的:(Ogre 异常处理和日志)