Logging Boost Log:设置属性使日志条目消失

Logging Boost Log:设置属性使日志条目消失,logging,boost,boost-log,Logging,Boost,Boost Log,我有一个跟踪程序,它应该记录函数的进出: class Tracer { public: Tracer(Logger logger, std::string function, std::string file) : _logger(logger), _function(function), _file(file) {} ~Tracer() { using namespace boost::log; // attribute_c

我有一个跟踪程序,它应该记录函数的进出:

class Tracer
{
public:  
  Tracer(Logger logger, std::string function, std::string file)
    :
    _logger(logger),
    _function(function),
    _file(file)
  {}

  ~Tracer()
  {
    using namespace boost::log;
    // attribute_cast<attributes::mutable_constant<int>>(core::get()->get_global_attributes()["Line"]).set(1);
    attribute_cast<attributes::mutable_constant<std::string>>(core::get()->get_global_attributes()["File"]).set(_file);
    attribute_cast<attributes::mutable_constant<std::string>>(core::get()->get_global_attributes()["Function"]).set(_function);
    BOOST_LOG_SEV(_logger, trivial::severity_level::trace) << "Leaving " << _function;
  }

private:
  Logger _logger;
  std::string _function;
  std::string _file;
};
这很好,但是一旦我取消设置行属性的行的注释,我就不会再收到任何留言了

属性是预先添加的,如下所示:

using namespace boost::log;
add_common_attributes();
core::get()->add_global_attribute("Scope", attributes::named_scope());
core::get()->add_global_attribute("Rank", attributes::constant<int>(5));
core::get()->add_global_attribute("Line", attributes::mutable_constant<int>(5));
core::get()->add_global_attribute("File", attributes::mutable_constant<std::string>(""));
core::get()->add_global_attribute("Function", attributes::mutable_constant<std::string>(""));
设置所有其他属性后,类似于Line的属性就可以了。我感到困惑,因为Line似乎不是一个保留名称,它在其他地方工作,boost::log源代码没有透露该名称的相关用法


这里有什么问题?我很乐意向任何人发送总共约150行的SPULTE代码

您的代码的主要问题是get_global_attributes返回全局属性集的副本。对副本所做的任何更改都不会影响附加到日志记录的属性。如果代码是多线程的,那么使用全局属性首先是错误的,因为执行上下文是线程特定的。此外,假设属性_cast成功,即不返回空属性,则假定该属性在程序中的任何位置都不会更改。您至少应该检查属性_cast的结果

更好的方法是将行和函数属性添加到跟踪构造函数中的线程特定属性集,而不是日志初始化代码,并在析构函数中恢复它们以前的状态。恢复部分很重要,因为您计划嵌套用Tracer标记的调用

using namespace boost::log;

class Tracer
{
  enum restore_action
  {
    noop,
    restore_prev,
    remove
  };

public:  
  Tracer(
    Logger const& logger,
    std::string const& function,
    std::string const& file,
    int line)
    :
    _logger(logger),
    _function_name(function),
    _prev_line_number(0),
    _function(set_attribute("Function", function, _prev_function_name)),
    _file(set_attribute("File", file, _prev_file_name)),
    _line(set_attribute("Line", line, _prev_line_number))
  {
    BOOST_LOG_SEV(_logger, trivial::severity_level::trace)
      << "Entering " << _function_name;
  }

  ~Tracer()
  {
    BOOST_LOG_SEV(_logger, trivial::severity_level::trace)
      << "Leaving " << _function_name;

    restore_attribute(_function, _prev_function_name);
    restore_attribute(_file, _prev_file_name);
    restore_attribute(_line, _prev_line_number);
  }

private:
  template< typename T >
  static std::pair< attribute_set::iterator, restore_action >
    set_attribute(attribute_name name, T const& value, T& prev_value)
  {
    typedef attributes::mutable_constant< T > mutable_constant_t;
    core_ptr p = core::get();

    std::pair< attribute_set::iterator, bool > res =
      p->add_thread_attribute(name, mutable_constant_t(value));
    if (res.second)
      return std::make_pair(res.first, remove);

    mutable_constant_t prev =
      attribute_cast< mutable_constant_t >(res.first->second);
    if (!prev)
      return std::make_pair(res.first, noop);

    prev_value = prev.get();
    prev.set(value);
    return std::make_pair(res.first, restore_prev);
  }

  template< typename T >
  static void restore_attribute(
    std::pair< attribute_set::iterator, restore_action > const& state,
    T const& prev_value)
  {
    typedef attributes::mutable_constant< T > mutable_constant_t;

    switch (state.second)
    {
    case restore_prev:
      {
        mutable_constant_t attr =
          attribute_cast< mutable_constant_t >(state.first->second);
        if (attr)
          attr.set(prev_value);
      }
      break;

    case remove:
      core::get()->remove_thread_attribute(state.first);
      break;

    case noop:
    default:
      break;
    }
  }

private:
  Logger _logger;
  std::string _function_name;
  std::string _prev_function_name, _prev_file_name;
  int _prev_line_number;
  std::pair< attribute_set::iterator, restore_action > _function;
  std::pair< attribute_set::iterator, restore_action > _file;
  std::pair< attribute_set::iterator, restore_action > _line;
};
请注意,此代码将使用跟踪程序设置的函数、文件和行属性标记此线程生成的所有记录。如果这不是您真正想要的,并且您只需要标记有关输入和离开函数的消息,那么您应该将函数、文件和行添加到记录器属性,而不是特定于线程的属性。这将大大简化代码,因为您不必费心恢复属性的先前状态

我还要补充的是,有更好的工具来维护调用堆栈,特别是标记当前执行上下文。允许您以比上面写的更便宜的方式标记当前范围或函数。标记不会生成日志记录,但添加起来很简单

class Tracer
{
public:  
  Tracer(
    Logger const& logger,
    string_literal const& function,
    string_literal const& file,
    unsigned int line)
    :
    _logger(logger),
    _function_name(function),
    _scope_sentry(function, file, line)
  {
    BOOST_LOG_SEV(_logger, trivial::severity_level::trace)
      << "Entering " << _function_name;
  }

  ~Tracer()
  {
    BOOST_LOG_SEV(_logger, trivial::severity_level::trace)
      << "Leaving " << _function_name;
  }

private:
  Logger _logger;
  string_literal _function_name;
  attributes::named_scope::sentry _scope_sentry;
};

与原始代码相比,此版本具有额外的限制,即函数名和文件名必须是字符串文字,而不仅仅是任意字符串。您还必须以不同的方式进行设置。

谢谢您的回复,抱歉,我没有完全理解。我的完整代码是在我最初的意图是添加行号和文件日志消息。Scopes只提供我打开scope时的行号,而不是实际的BOOST_LOG_SEV调用。我认为这应该是日志库中的标准内容,并从用户那里被黑客入侵。为了实现这一点,我在第70行使用了宏。下一步,我想有这个跟踪器,它不能使用行和文件,所以我想手动设置它。在这种情况下,我不理解你的问题。如果要标记每个日志语句的位置,那么最好的方法是使用add_值操纵器。要自动使用它,您可以定义自己的日志宏,该宏将包装BOOST_LOG_SEV并添加值,并在整个代码中使用它。不可能将其作为一个特殊属性或记录器来实现。这个地方,因为它的消息长度非常有限,似乎不适合讨论这个问题。能在别的地方找到你吗?