惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tenable Blog
H
Heimdal Security Blog
K
Kaspersky official blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
S
Schneier on Security
G
GRAHAM CLULEY
U
Unit 42
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
C
CERT Recently Published Vulnerability Notes
Google DeepMind News
Google DeepMind News
罗磊的独立博客
Stack Overflow Blog
Stack Overflow Blog
阮一峰的网络日志
阮一峰的网络日志
Simon Willison's Weblog
Simon Willison's Weblog
C
Cisco Blogs
Cyberwarzone
Cyberwarzone
T
The Exploit Database - CXSecurity.com
Project Zero
Project Zero
Security Archives - TechRepublic
Security Archives - TechRepublic
www.infosecurity-magazine.com
www.infosecurity-magazine.com
博客园 - 司徒正美
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
V
Visual Studio Blog
博客园 - Franky
Engineering at Meta
Engineering at Meta
WordPress大学
WordPress大学
Jina AI
Jina AI
P
Proofpoint News Feed
P
Proofpoint News Feed
有赞技术团队
有赞技术团队
L
LINUX DO - 最新话题
宝玉的分享
宝玉的分享
N
News and Events Feed by Topic
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
博客园 - 聂微东
T
The Blog of Author Tim Ferriss
Spread Privacy
Spread Privacy
Application and Cybersecurity Blog
Application and Cybersecurity Blog
IT之家
IT之家
S
Security Affairs
博客园 - 叶小钗
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
小众软件
小众软件
N
News | PayPal Newsroom
Cloudbric
Cloudbric
AWS News Blog
AWS News Blog
W
WeLiveSecurity
The Last Watchdog
The Last Watchdog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
NISL@THU
NISL@THU

博客园 - 海阔天

【原创】Self-Contained Container(自包含容器) Kindle 转换器 Win32 多线程学习笔记 海天软件自动安装工具 cd /d %~dp0是什么意思啊? (转)STL vector 容器介绍 . 【转】在VC++下实现高彩色工具条2011-05-19 14:35引言 vc编译错误pass it through SDKPAINT的处理方法 [转]修改SDI主窗口Title (转)VC中让CListBox带有复选框 (转)电脑程序员才能看懂的笑话 (转)专业的程序员需要具备的思考能力:写一个程序需要注意多少细节问题 (转)另一篇:VC导出数据到EXCEL (转)我的10个开发原则 [转]STL中map用法详解 [转]创业前应先做出一个好的非盈利产品 单元测试 版本控制 VC编程心得
(原创)日志处理(修改)
海阔天 · 2011-08-13 · via 博客园 - 海阔天

日志处理

日志可能有多种形式,比如以文件存储,显示到控制台屏幕上,或者在程序的一个列表框中……我们可以定义一个日志基类,然后继承之,针对不同的情况设计不同的子类。但如果程序中要求既在程序列表里显示日志,又要记录到文件或者还要记录到数据库等等吧,那么写日志的代码就非常麻烦,要几个日志类重复同样的动作。

利用下面的思路可以解决这个问题,在代码中只需要一个类的一个方法,就可以搞定所有日志类写日志的动作,同时又能起到一定的注释作用,是不是非常好!

OK! Let's go!

首先,定义一个日志类接口,主要给不同情况下生成日志的时候用。比如有的程序在自己的界面列表上输出日志,那么就可以实现这个接口,然后把实现的类传递到CLogHelper对象中,CLogHelper负责用日志接口列表中的日志接口写日志操作,而实现ILog接口的类负责实现日志的真实写入操作。

以下(核心)代码在VC6下编译并测试通过。代码中使用了STL技术。下同。

MyInterface ILog  
{
public:
    ILog();
    
virtual ~ILog();virtual void write(string logMsg);
    
virtual void writeLn(string logMsg);void debugWrite(string logMsg);
    
void debugWriteLn(string logMsg);
};

MyInterface 是自己定义的一个接口,按照园子里的方法如下:

#define MyInterface class __declspec(novtable)

CLogHelper类是日志类的助手,可以添加日志对象(ILog类型),提供每个日志对象的写日志功能。它也可以继承ILog接口。

class CLogHelper : public ILog  
{
public:
    CLogHelper();
    
virtual ~CLogHelper();void write(string logMsg);
    
void writeLn(string logMsg);// 下面的方法用于DEBUG环境
    void debugWrite(string logMsg);
    
void debugWriteLn(string logMsg);
    
    
void add(ILog *log);
    
private:
    list
<ILog *> logs;
};

CLogHelper::CLogHelper()
{

}

CLogHelper::

~CLogHelper()
{
    logs.clear();
}
void CLogHelper::write(string logMsg)
{
    list
<ILog *>::iterator logi;
    
for(logi=logs.begin();logi!=logs.end();logi++)
        (
*logi)->write(logMsg);
}
void CLogHelper::writeLn(string logMsg)
{
    
string msg=logMsg+"\n";
    write(msg);
}
void CLogHelper::add(ILog *log)
{
    logs.push_back(log);
}
void CLogHelper::debugWrite(string logMsg)
{
#ifdef _DEBUG
    write(logMsg);
#endif
}
void CLogHelper::debugWriteLn(string logMsg)
{
    
string msg=logMsg+"\n";
    debugWrite(msg);
}

下面是具体的日志类,它们都继承ILog接口。包括写入文件的日志类,控制台显示的日志类、程序列表中用到的日志类等等。

比如定义写入文件的日志类CLog继承ILog接口,代码略。

然后提供一个Log构建器(CLogBuilder),里面包括所有的具体日志类,在构造函数里把具体的日志类添加到CLogHelper中。构造函数提供一个文件路径的参数,表示文件日志要写到什么地方。这个参数默认为mylog.log文件,表示写到程序所在目录下,文件名默认为"mylog.log"。构造函数提供另一个参数为CLogHelper,就是说CLogHelper类是从外部传入的。

class CLogBuilder  
{
public:
    CLogBuilder(CLogHelper 
*logHelper,string path="mylog.log");
    
virtual ~CLogBuilder();string m_Path;
    
    CLog 
*fileLog;
};

CLogBuilder::CLogBuilder(CLogHelper 

*logHelper,string path)
:fileLog(
0),m_Path(path)
{
    fileLog
=new CLog(m_Path.c_str());
    
    
// 向LogHelper中添加日志类
    logHelper->add((ILog *)fileLog);
}

CLogBuilder::

~CLogBuilder()
{
    
if(fileLog)
    {
        delete(fileLog);
        fileLog
=NULL;
    }
}

然后定义一个职责转义类,在其它的类中需要提供写日志的时候,用这个类(定名为CRemark)。如果每个类的每个方法里都有写日志的代码,会把代码搞的很混乱,不突出方法的主题,也好像这个方法完成多项任务似的,代码不简明。记得VC的注释代码中有“// todo :”,所以这个类提供一个方法叫toDo(),其参数就是toDO()语句以下代码所完成工作的内容描述。看起来,这个方法好像是在给代码作注释。这样既起到了注释的作用,同时在toDo()方法中还可以调用日志类去写日志,岂不是一举两得。因为这个类在代码中看只是起到注释的作用,而在它的方法中却转义成了写日志,所以称其为职责转义类。当然,如果你发现这个类还可以干其它的事情,请你一定告诉我。

class CRemark  
{
public:
    CRemark();
    
virtual ~CRemark();

    CLogHelper 

*logHelper;
    CLogBuilder 
*logBuilder;
    
    
void toDo(string comment,BOOL isDebug=FALSE);
};

CRemark::CRemark()
:logHelper(

0),logBuilder(0)
{
    logHelper
=new CLogHelper();
    logBuilder
=new CLogBuilder(logHelper);
}

CRemark::

~CRemark()
{
    
if(logHelper)
    {
        delete(logHelper);
        logHelper
=NULL;
    }
    
if(logBuilder)
    {
        delete(logBuilder);
        logBuilder
=NULL;
    }
}
void CRemark::toDo(string comment,BOOL isDebug)
{
    
if(isDebug)
        logHelper
->debugWriteLn(comment);
    
else
        logHelper
->writeLn(comment);
}

代码比较完美和优雅了,就像C#那样,嘻嘻!

可以这样使用:

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    CRemark mark;
    mark.toDo(
"嘻嘻哈哈吼吼!");

  //这里是程序中实际的代码


    mark.toDo(
"DEBUG版本显示。。。",TRUE);

  //这里是程序中实际的代码

    mark.toDo("GOOD JOB!");

  //这里是程序中实际的代码

    system(
"pause");

}


程序会在所在目录下创建(默认)mylog.log文件,并在其中显示三行文本;如果改成Release,则只输出两行文本。