如何将boost :: log :: expressions格式化程序对象插入流以格式化时间戳记 或者

问题描述

我正在遵循有关Boost.log记录格式的教程,并且我试图格式化时间戳以仅在小数秒部分显示2位数字。 9年前在这里how to customize "TimeStamp" format of Boost.Log提出了相同的问题,但是该解决方案似乎不适用于更新版本的Boost。这是我尝试过的与上述解决方案类似的方法,但是使用的是format_date_time< boost::posix_time::ptime >而不是date_time<boost::posix_time::ptime>

namespace expr = boost::log::expressions;

auto ts = expr::format_date_time< boost::posix_time::ptime >("TimeStamp","%Y-%m-%d %H:%M:%s.");
auto ts_fractional = expr::format_date_time< boost::posix_time::ptime >("TimeStamp","%f");
auto ts_fractional_short = (expr::format("%.2s") % ts_fractional);
  
auto strm = expr::stream
    << '[' << ts << '.'
    << ts_fractional_short << ']'   //error here. ts_fractional would work
    << '[' << logging::trivial::severity << ']'
    << " " << expr::smessage;

sink->set_formatter(strm);

似乎相关的错误是:

/path/to/boost_1_73_0/boost/log/utility/formatting_ostream.hpp:921:19: note:   'boost::log::v2s_mt_posix::basic_formatting_ostream<char>::ostream_type {aka std::basic_ostream<char>}' is not derived from 'boost::log::v2s_mt_posix::basic_formatting_ostream<CharT,TraitsT,AllocatorT>'
     strm.stream() << value;
...
/path/to/boost_1_73_0/boost/log/utility/formatting_ostream.hpp:921:19: note:   cannot convert 'value' (type 'const boost::log::v2s_mt_posix::aux::basic_format<char>::pump') to type 'const id& {aka const boost::log::v2s_mt_posix::aux::id<boost::log::v2s_mt_posix::aux::process>&}'
     strm.stream() << value;

是否可以将expr::format()返回的对象转换为可以注入expr::stream的对象?

更新

我找到了一个解决方案,该解决方案是使用使用formatting_ostreamrecord_view自定义格式器,并从记录中提取时间戳。然后,我使用local_date_time对象和output_facet s进行格式化,最后使用小数秒字符串上的boost::format将其写回到ostream。这很丑。必须有更好的方法

void formatter(const boost::log::record_view &rec,boost::log::formatting_ostream &os)
{
  auto pt = logging::extract< boost::posix_time::ptime >("TimeStamp",rec);

  using namespace boost::local_time;
  using namespace boost::gregorian;

  stringstream ss;
  auto output_facet = new local_time_facet();
  auto input_facet = new local_time_input_facet();
  ss.imbue(locale(locale::classic(),output_facet));
  ss.imbue(locale(ss.getloc(),input_facet));

  local_date_time ldt(not_a_date_time);
  ss << pt;
  ss >> ldt;    //yuck...

  output_facet->format("%Y-%m-%d %H:%M:%s");
  ss.str("");
  ss << ldt;
  auto ts = ss.str();
  output_facet->format("%f");
  ss.str("");
  ss << ldt;
  auto ts_fractional = ss.str();

  os << boost::format("[%1%.%2%][%3%] %4%")
        % ts
        % (boost::format("%.3s") % ts_fractional)
        % logging::extract< boost::log::trivial::severity_level >("Severity",rec)
        % rec[expr::smessage];
}

int main(int argc,char *argv[]) {
...
  sink->set_formatter(&formatter);
...
}

更新2

以防万一有人偶然发现这个问题并想在C ++ 11编译器中使用@sehe的format_f

struct format_f {
  std::string format_str;

  template<typename T1,typename... Ts>
  string operator()(T1 const& t1,Ts const&... ts) const {
    return consume_arg((boost::format(format_str) % t1),ts...).str();
  }
  template<typename T1>
  T1 consume_arg(T1 &t1) const {
    return t1;
  }
  template<typename T1,typename T2,typename... Ts>
  T1 consume_arg(T1 &t1,T2 const& t2,Ts const&... ts) const {
    return consume_arg(t1 % t2,ts...);
  }
};

解决方法

您想延期使用应收帐款。

this older answer of mine轻松地借用Xfrm,我建议做一个完整日期时间的子字符串:

static constexpr Xfrm Left24 { [](std::string const& s) { return s.substr(0,24); } };

logging::formatter formatter = expr::stream
    << line_id
    << " | "
    << Left24 [ expr::stream << expr::format_date_time(timestamp,"%Y-%m-%d,%H:%M:%S.%f") ]
    << " [" << logging::trivial::severity << "]"
    << " - " << expr::smessage;

打印 Live On Wandbox

3 | 2020-08-15,11:37:30.128 [warning] - this is a warning message
4 | 2020-08-15,11:37:30.129 [error] - this is an error message
5 | 2020-08-15,11:37:30.129 [fatal] - this is a fatal error message

提取值

您可能希望提取真实数据,而不是进行文本后处理。我发现这比我希望的要难,但无论如何都要展示,以防万一:

boost::phoenix::function<milliseconds_f> milliseconds;

logging::formatter formatter = expr::format(
        "%1% | %2%.%3% [ %4% ] - %5%")
    % line_id
    % expr::format_date_time(timestamp,%H:%M:%S")
    % milliseconds(expr::attr<boost::posix_time::ptime>("TimeStamp").or_throw())
    % logging::trivial::severity
    % expr::smessage;

现在,milliseconds_f被定义为:

struct milliseconds_f {
    auto operator()(logging::value_ref<boost::posix_time::ptime> const& v) const {
        auto f = v.get().time_of_day().fractional_seconds();
        std::string s = std::to_string(f / 1000);
        while (s.length()<3) s += '0';
        return s;
    }
};

查看 Live On Wandbox

3 | 2020-08-15,12:27:38.870 [ warning ] - this is a warning message
4 | 2020-08-15,12:27:38.870 [ error ] - this is an error message
5 | 2020-08-15,12:27:38.870 [ fatal ] - this is a fatal error message

替代:更接近您的期望

您可以创建一个惰性函数来进行有效的格式化:

boost::phoenix::function<format_ex> format;

logging::formatter formatter = expr::format(
        "%1% | %2%.%3% [ %4% ] - %5%")
    % line_id
    % expr::format_date_time(timestamp,%H:%M:%S")
    % format(std::string("%.3s"),expr::format_date_time(timestamp,"%f"))
    % logging::trivial::severity
    % expr::smessage;

哪里

struct format_ex {
    template<typename... T>
    auto operator()(std::string const& format_str,T const&... v) const {
        return (boost::format(format_str) % ... % v);
    }
};

由于渗漏的抽象,您需要通过引用确保format-string不是char []文字。您还可以强制衰减(难看,但较不冗长):

    % format(+"%.3s","%f"))

要避开整个问题,可以将Phoenix Bind与格式化程序分开使用:

using boost::phoenix::bind;

logging::formatter formatter = expr::format(
        "%1% | %2%.%3% [ %4% ] - %5%")
    % line_id
    % expr::format_date_time(timestamp,%H:%M:%S")
    % bind(format_f{"%.3s"},"%f"))
    % logging::trivial::severity
    % expr::smessage;

使用

struct format_f {
    std::string format_str;
    
    template<typename... T>
    std::string operator()(T const&... v) const {
        return (boost::format(format_str) % ... % v).str();
    }
};

同时看到这两个 Live On Wandbox

混合

尝试通过以下方式将expr::streamformat混合:

boost::phoenix::function<format_f> left24 = format_f{"%.24s"};

logging::formatter formatter = expr::stream
    << line_id << " | "
    << left24(expr::format_date_time(timestamp,%H:%M:%S.%f"))
    << " [ " << logging::trivial::severity
    << " ] - " << expr::smessage;

使用与上面相同的format_f Live On Wandbox ,打印:

3 | 2020-08-15,12:55:39.426 [ warning ] - this is a warning message
4 | 2020-08-15,12:55:39.426 [ error ] - this is an error message
5 | 2020-08-15,12:55:39.426 [ fatal ] - this is a fatal error message

或者

boost::phoenix::function<format_ex> format;

logging::formatter formatter = expr::stream
    << line_id << " | "
    << format(+"%.24s",%H:%M:%S.%f"))
    << " [ " << logging::trivial::severity
    << " ] - " << expr::smessage;

Live On Wandbox

3 | 2020-08-15,12:59:35.964 [ warning ] - this is a warning message
4 | 2020-08-15,12:59:35.965 [ error ] - this is an error message
5 | 2020-08-15,12:59:35.965 [ fatal ] - this is a fatal error message

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...