【问题标题】:Verbosity level in simple Logger implemenation C++简单 Logger 实现 C++ 中的详细级别
【发布时间】:2011-12-24 12:45:47
【问题描述】:

由于我学习 C++,我目前正在为一个项目实现一个简单的 Logger。

我已经有了一个 Logger 基类,作为一些不同的附加程序,下一步是实现详细级别。 问题是我不确定我是否正确理解了详细程度的概念,所以我想在开始实施它们之前得到一些反馈。 因此,据我了解,一般工作的详细程度如下:

用户首先创建两个 Logger: f.e.:

FileLogger fl; 
VSLogger vl;

之后他可以设置详细级别,例如:

fl.setLoggerLevel(DEBUG);
vl.setLoggerLevel(FATAL_ERROR);

之后他可以随心所欲地登录,例如:

fl.logg("New Object of Type .... created");
ASSERT(1,2, "1==2");

虽然断言写入具有致命错误级别的 VSLogger

在输出文件中它可能看起来像这样:

13:36 Msg: New Object of Type .... created (LEVEL:DEBUG);

在 Visual Studio 中它可能看起来像这样:

13:36 Msg: Assert (1==2) failed (LEVEL:FATAL_ERROR)

这是详细程度的含义还是我误解了详细程度的一般概念?

【问题讨论】:

  • 详细程度通常会告诉您的记录器实际记录了 多少。您在这里描述的是日志级别。通常你有一个记录器,在每个日志的基础上指定日志级别,并且可以设置实际记录的日志级别。
  • 谢谢。我想我理解你的意思(我实际上在研究时在其他一些网站上发现了几乎相同的定义)但我不明白的是:记录器不能自己记录东西(至少如果它没有以某种方式硬编码) .因此,如果用户想要记录某些内容并为其提供日志级别,则始终必须调用 logg 函数。那么记录器如何区分他记录的内容和不记录的内容呢?我必须说只记录至少 ERROR 级别的内容吗?如果是这样,我为什么还要记录与 INFO 级别相关的内容,而不是记录器从不记录它们?
  • 例如,您调用logger.verbosity(INFO | WARNING | DEBUG);,只有这三个级别被实际记录,您只需检查log 函数中的详细程度标志:void log(unsigned level, char const* msg){ if(!(verbosity_flag & level)) return; /* else log it */ }
  • 啊,我明白了。谢谢你。我现在将尝试首先实现所有内容,如果仍有不清楚的地方或我认为可能可以做得更好,可能会在几天后返回代码
  • @Xeo:我会避免使用掩码来表示详细程度。记录器中的常见实现是每个日志级别包括更高级别。也就是说,如果您将日志级别设置为INFO,您会自动期望看到任何WARNERROR 消息,但不会看到DEBUG,而这通常通过将级别映射到数字和比较:if (log_level >= msg_level ) return;(如果我们配置为记录 WARN(比如 2)并获得级别为 INFO(比如 3)的消息,则不要记录)

标签: c++ logging verbosity


【解决方案1】:

我不明白为什么用户必须使用两个记录器。消费代码不应该关心日志目标。

另一个问题是您的消费代码不会在任何地方传递严重性。每当您调用日志记录功能时,您都会传递严重性。消费代码不关心当前的详细程度是多少,它只是传入一个严重性并依赖于记录器的实现来了解严重性是否超过了详细程度。 (此规则有一个例外,您可以检查详细级别以避免在高性能代码中创建日志消息的开销)

我宁愿有一个记录器作为用户,带有两个附加输出,它们可能具有不同的详细级别。

在最简单的情况下,我会创建一个全局函数 Logger& GetLogger(),它会导致像 GetLogger().LogDebug("New Object of Type .... created"); 这样的用户代码

首先创建一个接口:

public class ILogger
{
  public:
    virtual LogDebug(string message)=0;
    ...
}

然后创建一个支持订阅的实例:

public class DispatchingLogger:ILogger
{
  private:
    vector<ILogger*> loggers;
  public:
    override LogDebug(string message)
    {
      foreach(ILogger logger in loggers)
      {
        logger.LogDebug(message);
      }
    }

    void Subscribe(ILogger* logger)
    {
      loggers.add(logger);
    }
}

然后全局GetLogger() 函数返回DispatchingLogger 的单个实例。您可以订阅几个具有不同详细级别的实现。实现ILogger的用户类也可以注册。

(我知道我的 C++ 语法不正确,自从我使用 C++ 以来一直有一点)

【讨论】:

  • 首先感谢您的帖子。拥有两个或更多记录器的原因是用户可以定义自己的记录器。到目前为止,我只实现了 Visual Studio、File 或 Stdout Appends。例如,用户可能从我的 Logger 基类派生并添加一个 TCP Logger。但我也明白你的意思。
  • 拥有多个记录器实现,并且只将一个记录器实例暴露给消费代码是不同的问题。您可以同时拥有两者。在您的示例中,您将 VS 和文件记录器订阅到广播事件。
  • 这与我目前使用的几乎相同。我有一个 Logdispatch 命名空间,其中包含三个函数:addLogger()、removeLogger() 和 log()。每次实例化新的 Logger 时都会调用 addLogger() ,并在删除 Logger 时删除。我正在使用侵入性列表而不是向量。稍后我可能还会考虑基于策略的设计,但目前我想先让它发挥作用。
【解决方案2】:

详细级别显示要记录哪些消息(或者更确切地说,是什么严重性)。

例如

Set verbosity to INFO
Log a trace message  //the message will not be logged
Log a debug message  //the message will not be logged
Log an info message  //the message will be logged
Log a warning        //the message will be logged
Log an error or a fatal error.  // will be logged

【讨论】:

    猜你喜欢
    • 2016-07-05
    • 1970-01-01
    • 2016-12-09
    • 1970-01-01
    • 2021-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-21
    相关资源
    最近更新 更多