Symbian中日志文件的使用

来源:互联网 发布:毁坏的冬眠者数据库 编辑:程序博客网 时间:2024/04/29 17:34

 我包装了一下RFileLogger ,个人感觉好用多了,分享一下省得大家为了日志文件发愁。

.h

#ifndef __RLOG_H__
#define __RLOG_H__
#include <e32base.h>
class RLog : public CBase
{
public:
 static void Log(const TDesC &aErrTypeName, const TDesC &aErrMsg);
static  void Log(const TDesC & aErrMsg,const TInt aErrCode);
static void Log(const TDesC& aMsg);
private:
/*!
  @function NewL
  
  @discussion Create a RLog object
  @result a pointer to the created instance of RLog
  */
    static RLog* NewL();
/*!
  @function NewLC
  
  @discussion Create a RLog object
  @result a pointer to the created instance of RLog
  */
    static RLog* NewLC();
/*!
  @function ~RLog
 
  @discussion Destroy the object and release all memory objects
  */
    ~RLog();
private:
/*!
  @function RLog
  @discussion Constructs this object
  */
    RLog();
/*!
  @function ConstructL
  @discussion Performs second phase construction of this object
  */
    void ConstructL();
private:
    // Member variables
};
#endif // __RLOG_H__

 

.cpp

#include "RLog.h"
#include "flogger.h"
RLog* RLog::NewL()
    {
    RLog* self = NewLC();
    CleanupStack::Pop(self);
    return self;
    }
   
RLog* RLog::NewLC()
    {
    RLog* self = new (ELeave) RLog();
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }

RLog::RLog()
    {
    }

RLog::~RLog()
    {
    }

void RLog::ConstructL()
    {
    }
 
void RLog::Log(const TDesC &aMsg)
{
 RFileLogger iLog;
 iLog.Connect();
 iLog.CreateLog(_L("mylogDir"),_L("MyLogFile.txt"),EFileLoggingModeAppend);
 
 iLog.Write(aMsg);
 
 // Close the log file and the connection to the server.
 iLog.CloseLog();
 iLog.Close();
}
void RLog::Log(const TDesC &aErrMsg, const TInt aErrCode)
{
 HBufC* buf=HBufC::New(aErrMsg.Length()+20);
 buf->Des().Append(aErrMsg);
 buf->Des().Append(_L(":"));
 buf->Des().AppendNum(aErrCode);
 Log(*buf);
 delete buf;
}
void RLog::Log(const TDesC &aErrTypeName, const TDesC &aErrMsg)
{
 HBufC* buf=HBufC::New(aErrMsg.Length()+2+aErrMsg.Length());
 buf->Des().Append(aErrTypeName);
 buf->Des().Append(_L(":"));
 buf->Des().Append(aErrMsg);
 Log(*buf);
 delete buf;
}

mpp里面添加

LIBRARY flogger.lib//loggerfile

example

#include "RLog.h"

 HBufC * buf=HBufC::New(50);
 buf->Des().Append(_L("MoChEv:"));
 buf->Des().Append(_L("P="));
 buf->Des().AppendNum(aPreviousState);
 buf->Des().Append(_L("C="));
 buf->Des().AppendNum(aCurrentState);
 buf->Des().Append(_L("E="));
 buf->Des().AppendNum(aErrorCode);
 RLog::Log(*buf);//可以直接写消息
delete buf;

 TRAPD(errc,this->CleanAmrFileL(aBarFileName));
 if(errc)
 {
  RLog::Log(_L("CleanAmrFileL:"),errc);//消息+错误码
  User::Leave(errc);
 }
 else{
  RLog::Log(_L("CleanAmrFileL:OK"));
 }


TDesC* aFullFileName=GetFullFileName(aBarFileName);

  RLog::Log(_L("fullfile"),*aFullFileName);//消息+描述符

 

 

 

注意要使用RFileLogger 必须先创建文件夹,因为这个类无法创建新文件夹。

模拟器上使用log

在目录/epoc32/wins/c/logs下创建目录mylogDir,并在下面创建文件MyLogFile.txt

在手机上使用log

1在pkg文件的同级目录创建文件MyLogFile.txt

2需要在pkg文件中加入".MyLogFile.txt"-"c:/logs/mylogDir/MyLogFile.txt"-目的是创建一个文件夹.

你可以用fileman等工具打开查看这个文件。或者将它传到pc上分析。

 

我这样包装的目的是为了获得两不同版本的日志函数,既有静态函数以方便临时调试使用。

又有成员函数以避免反复连接日志服务器,以提高效率。

但是有一个很明显的缺点就是当我的项目结束测试需要发布的时候,我需要把这些打印的日志语句都注释掉。

进行下一轮迭代开发时,有些日志又需要再打开以前注释的日志语句。

smart man给我提供了一个很好的解决方法他是这样做的:

 
在使用这个头文件的时候不是直接使用debug函数而是使用DEBUG宏。
这样当我在mmp文件里面加入Macro __UNLOG__ 语句后,整个工程的所有cpp里面的形如
DEBUG(0,"abc:%s",abc); 都会被宏替换为(0,"abc:%s",abc); 这样就不会输出任何日志了。
在发布和测试状态之间的日志切换变得异常轻松,哪怕有成百上千的日志语句也不畏惧。
而且通过使用VA_LIST 这个日志继承了RFileLogger的可变参数。这个头文件我用了很长时间感觉很方便。
但是当我在处理通讯报文的时候有的时候我希望打印一下xml文本的内容或者其他内容很长的文本。
这个时候就暴露出了RFileLogger的致命伤--有最大长度的限制。
RFileLogger
首先我们看到的是一个R,也就实说这个类要用到资源,甚么资源呢,从成员函数Connect上我们可以看出需要用到服务器的资源.
为什么要用服务器呢.有的时候我们需要多个进程同时往一个日志文件里面写日志,我们不希望出现进程A覆盖了B刚写入的日志也不希望在B些日志的时候等B写完再让A写.
怎么办呢?按照symbian的标准套路就是C/S模式.只有服务器可以往文件里面写东西而客户端必须连接服务器把要写的东西交给服务器.
做过cs的人都知道,服务器和客户端之间进行通讯的时候可以传递描述符,并且是定长的.
由于这个限制因此就产生了RFileLogger的缺点不能写任意长的数据.
这个定长的长度是多少呢?
通过头文件 flogger.h 我们可以看到 RFileFlog有一个常量 const TInt KLogBufferSize=150;
我们用Write()写一个很长的字符串就可以看出来,日志被截断了.而且算上日期刚好是150个字符.如果是中文一个汉字要用到两个字符的位置。也就是说大概能支持每行128个字母或者是64个汉字。
WriteFormat()和Write()是RFileLogger的两个重要函数.
symbian还没有开源,现在我只能凭借经验推断一下这里面都做了什么。
WriteFormat-首先这是个支持可变参数的函数,我们可以写入任意个参数进行类似printf的操作。
(1) 分配一个HBuf最大长度为150 (KLogBufferSize)
(2) 取出当前时间格式化后写入字符串的开始。
(3) 将可变参数记录到VA_LIST类型的一个变量里面,对buf进行appendFormatList操作,如果超长就停止format
(4) 然后加换行。
(5) 将buf传递给服务器,由服务器进行记录
另外RFileLogger的成员TLogFormatter iFormatter;
TLogFormatter又有两个成员:
TLogFormatter16Overflow iOverflow16;
TLogFormatter8Overflow iOverflow8;
定义如下:
NONSHARABLE_CLASS(TLogFormatter16Overflow) :public TDes16Overflow
/** Unicode overflow handler.
@internalComponent */
{
public:
virtual void Overflow(TDes16& aDes);
};
它的实现应该在flogger.lib对应的dll里面.
这很显然是在用户传入字符串format后如果超长就进行截断处理用的。
Write 是不用支持可变参数的,只需要上述(3)的地方进行超长判断,如果超长就截断。(1),(2),(4),(5)都一样。
这两个函数还有静态函数版本,应该是对上述两个成员函数版本的封装。前后各增加了connect 和close的操作。
如果是对中文操作上述的(3)如果失败后会发生意想不到的效果。并且有可能导致不执行(4)
一般来讲日期和时间在日志里面占用了20~22个字节。如下:
17/03/20097:08:31KTestDesc()len=13,buf=Test Desc log
17/03/20097:16:51A1234567890B1234567890C1234567890D12345
2009/01/1211:27:35CPropertyObserver::ConstructL(){
2009/01/1211:27:35subscribe (0x2001d651,0xa)
一个有趣的现象是当你打印一串纯中文的unicode时候中文部分最大长度是43而不是128 也不是128/2=64.
文件中的编码格式是utf8,这说明在写日志前进行了utf8转换。
这个转换应该是在服务器端进行的,或者是在客户端将时间串和文本连接完成后进行的。
要显示多余150字节的日志内容,并且能够支持ucs2的unicode输入的日志。就需要自己动手了。
大体思路是先看长度是否有可能超出150,如果超出的话就按照uncode转为utf8后占用的字节数进行截断。
保证每次打印的内容转换成utf8后不超过150.并且用尽量少的行数打印尽量多的内容。经过反复试验模式终于形成了下面的日志。
这个日志不但解决了内容超长的问题。还提供了一些便于使用的工具。可以快捷的随手打印一个变量。整形或者描述符都可以。
同时也吸收了smart man的日志里面的优点。
 下面是主要的代码片段,完整的代码http://download.csdn.net/source/1145570。
头文件:

 

实现:

例子: