65.9K
CodeProject 正在变化。 阅读更多。
Home

调试技术:用于同时以多种方式生成日志的日志记录器

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.14/5 (8投票s)

2004年12月29日

3分钟阅读

viewsIcon

41233

downloadIcon

512

这个记录器可以被配置成使用各种输出类型来生成日志输出。

引言

这篇文章对于那些想要看到优秀设计实现的人很有用。 这篇文章使用设计模式来有效地解决日志记录的问题。 日志记录是我们开发工作的重要组成部分。 通常,我们不知道作为参数传递给 API/调用的是哪种类型的输入。 这可能会导致应用程序出现意外行为。 因此,为了检查/验证,我们必须以各种方式记录详细信息,例如我们可以将其存储在 XML文本 文件、电子邮件 中,在控制台上 打印 等。 在这里,我只提供了基于文本的实现,因为它很容易做到。 您可以派生您的类来实现其他记录器。

背景

如果您真的想了解幕后情况,那么请选择任何简单的书,其中给出了带有示例的设计模式。 通过这个例子,你也会真正学到一些东西。

Using the Code

下面给出了代码的简要说明。 不要忘记将示例配置文件复制到演示应用程序源代码中的给定目录中。

我们有一个主类,它是所有记录器的父类,CLogger

class  CLogger
{
public:
    virtual void MakeLog( enum EnumLogType enumType ,string sData ) = 0;
    virtual void AddDate() = 0;
    virtual ~CLogger(){ }
protected:
    friend class CLoggerManager;
    virtual BOOL UpLoadSettings( ifstream &in_confile ){ return 0; }
};

提供了两个主要函数MakeLogAddDate,它们可以是任何记录器的基本或最小函数。 现在,从它派生的任何类都必须实现这两个。 第三个函数UpLoadSettings稍后解释。 请参见下面的部分

class  CLoggerManager : public CLogger
{
    string m_sConfigFile;
    CLogResolver*    m_pResolver;
    void set_members( string &sConfigFile ,CLogResolver* pResolver );
    CLoggerManager(){}
    CLoggerManager( const CLoggerManager& );
    CLoggerManager& operator = ( const CLoggerManager& );
    vector<CLogger*> m_vOutput;
public:
    static CLoggerManager& instantiate( string sConfigFile ,
                    CLogResolver* pResolver );
    ~CLoggerManager();
private:
    BOOL LoadConfig();
public:
    void MakeLog( enum EnumLogType enumType ,string sData );
};

CLoggerManager 类是日志记录的重要组成部分。 它从 CLogger 获取接口,但也充当管理器,允许各种记录器使用它们各自所需的数据进行初始化。

首先,了解配置文件的格式。Config 文件包含以下内容

  • 类名
  • 特定数据
  • 再次是类名和特定数据....

Resolver 返回类名中指定的类的新对象的地址。 然后,UpLoadSettings 加载特定数据。 在这里,添加 Resolver 是因为我们不需要使配置文件的读取复杂化。 关于 resolver 最重要的是要记住你可以拥有 Resolver 的派生类来处理更多的 Logger。 在这里,在代码中,LoadConfig 函数将记录器逐个加载到指定的向量中。

BOOL LoadConfig()
{
    try
    {
        if ( !m_pResolver )
            return FALSE;

        ifstream in_confile; 
        in_confile.open( m_sConfigFile.c_str() );
        if ( !in_confile.is_open() )
            return FALSE;


        // Now Read Settings
        while ( 1 )
        {
            string sClassName;
            in_confile >> sClassName;

            if ( !sClassName.length() )
                break;

            CLogger* pLogger = m_pResolver->Resolve( sClassName );

            if ( pLogger )
            {
                if ( !pLogger->UpLoadSettings( in_confile ) )
                    break;
            }
            else
                break;

            m_vOutput.push_back( pLogger );
        }
    }
    catch(...)
    {
        // Catch any exception
    }
    return TRUE;
}

现在,如果我们调用 CLoggerManager 进行日志记录,那么它将被路由到内部的所有记录器,如下所示

void MakeLog( enum EnumLogType enumType ,string sData )
{
   for (vector<CLogger *>::const_iterator iter_output = m_vOutput.begin();
                                            iter_output != m_vOutput.end() ; 
                                            ++iter_output )
   {
        CLogger* p_output = *iter_output;

        if ( p_output )
        {
            p_output->MakeLog( enumType ,sData );
        }
   }
}

下面是创建 Logger 的单个实例的代码,因为我们不想复制我们的 CLoggerManager 对象(我们不需要它)。

static CLoggerManager& instantiate(string sConfigFile ,CLogResolver* pResolver)
{
    static CLoggerManager m_Manager;
    m_Manager.set_members( sConfigFile ,pResolver );
    m_Manager.LoadConfig();
    return m_Manager;
}

查看源代码文件中的 CFileLogger 代码,了解它的工作原理。 这非常容易理解。

历史

这是我发布的第一篇文章。 我还有很多可以增强知识的新想法。 我也是一个学习者。 我会等待你的回复。 如果您有任何建议,欢迎提出。

许可证

本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。

作者可能使用的许可证列表可以在此处找到。

© . All rights reserved.