Mage小组 著
Email: [email protected]
QQ: 18725262
http://www.173d8.com
http://blog.csdn.net/pizi0475
用文件来记录Ogre系统初始化、运行、结束以及调试信息。使用日志便于我们调试程序。
Ogre日志系统由两个类组成:Log类与LogManager。下面我们分别来看这两个类。
代表用于记录信息的日志。Log类的一个对象对应于一个日志文件。
Log类提供了向日志文件写信息的函数logMessage,其定义如下:
void logMessage(const String& message, LogMessageLevel lml = LML_NORMAL);
参数message,String类型的变量,存储要写入的信息。
参数lml,指定传入信息的级别,来衡量一条信息的重要程度。
参数值 |
信息的重要程度 |
LML_TRIVIAL |
最低 |
LML_NORMAL |
一般 |
LML_CRITIAL |
最高 |
为了判断一条信息的重要性,从而决定是否将该信息写入日志文件。我们不光要衡量信息的重要程度,还应该同时考虑日志文件的重要程度。Log类提供了一个函数setLogDetail来设置日志文件的重要程度,其定义如下:
void setLogDetail(LoggingLevel ll);
参数ll,指定该日志文件的级别,来衡量日志文件的重要程度。
参数值 |
代表日志文件的重要程度 |
LL_LOW |
最低 |
LL_NORMAL |
一般 |
LL_BOREME |
最高 |
管理所有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指定默认日志文件的重要程度,它可以是:
参数值 |
信息的重要程度 |
LML_TRIVIAL |
最不重要 |
LML_NORMAL |
一般 |
LML_CRITIAL |
最重要 |
成员函数getDefaultLog返回默认的Log对象
Log* getDefaultLog();
成员函数logMessage向默认的日志文件中写入信息,它有两种形式:
void logMessage( const String& message, LogMessageLevel lml = LML_NORMAL);
void logMessage( LogMessageLevel lml, const char* szMessage, ... );
参数lml指定传入的信息的重要程度。
第一个logMessage可以向日志文件中写入一条信息。第二个logMessage可以写入接收的多条信息。
重载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会抛出这个类型的异常,并把这个异常记录的错误信息写入到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 ) )
// 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.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的日志系统与异常处理,我们可以迅速的查看系统运行的信息,快速定位错误发生的位置,并动态地处理错误。