【问题标题】:How do I write a message timestamp to a log file?如何将消息时间戳写入日志文件?
【发布时间】:2019-03-14 16:47:43
【问题描述】:

我正在尝试为我的 C++ 程序创建一个日志文件。我的目标是在我的程序的两个点放置两个时间戳,并在文件中打印这两个点之间的 CPU 时间段。我这样做是因为我想知道我的代码的哪些部分是最耗时的,以便我可以进行改进(所以可能有几块我想要测量的代码)。到目前为止,我已经制作了一个函数,当调用它时,它会将我作为参数传递的字符串打印到文件中:

#define LOGFILE "myprog.log"
void Log (std::string message){
    std::ofstream ofs;
    ofs.open(LOGFILE, std::ofstream::out | std::ios::app);
    ofs << message << std::endl;
    ofs.close();
}

但是,我很难弄清楚如何打印 CPU 时间戳。首先,我不知道我应该使用什么时间测量格式(我应该使用 chrono 还是 time_t 类型?)我正在尝试打印一个时间段,所以如果有一个持续时间类型会很有帮助(我我试过 chrono::duration 但它似乎需要 C++11 支持)。其次,鉴于我知道要使用什么类型,如何将其打印到文件中?有没有办法将该类型转换为字符串?或者我可以将它直接传递给我的函数并以某种方式打印吗?

在过去的几天里,这一直困扰着我,我似乎无法弄清楚,所以任何意见都会非常有帮助。提前致谢!

【问题讨论】:

  • 一个很好的起点,直到它进入 C++ 标准,是Howard Hinnant's Date library
  • 如果你真的想分析你的程序,为什么不使用为此目的设计的传统工具呢?
  • 注意:在胡乱处理日志文件之前花点时间。您花在打开文件等上的时间会影响您的结果。
  • @LIghtnessRacesinOrbit 需要解释一下吗?你到底怎么认为我知道你在说什么?
  • @user4581301 感谢您的提示!

标签: c++ logging time timestamp chrono


【解决方案1】:

获取 CPU 时间戳

您需要使用std::chrono::system_clock 来获取此时间戳。 请勿使用std::chrono::steady_clockstd::chrono::high_resolution_clock,因为它们用于进行高精度计时测量,并且不保证对挂钟时间的保真度或准确性。

auto now = std::chrono::system_clock::now();
//now is a time_point object describing the instant it was recorded according to your system clock

以可读格式打印此 CPU 时间戳

在 C++20 中,这很简单。

std::string formatted_time = std::format("{0:%F_%T}", now);
ofs << formatted_time << ": " << message << std::endl;
  • %F%Y-%m-%D 的替代品,它将以 ISO 格式输出年-月-日,即2018-10-09
  • %T%H:%M:%S 相同,都会输出一个时间,即17:55:34.786

有关如何指定这些参数的详细信息,请参阅 std::formatstd::formatter 的规范。

截至 2020 年 12 月,尚无主要编译器支持 &lt;format&gt; 库,因此您可以使用 fmt 作为替代方案,这是该库的独立实现。

C++20 之前

考虑Howard Hinnant's date library,其中大部分都作为chrono 库的新部分并入C++20。在该库中找到的 format 函数使用与上面建议的 C++20 版本相同的语法,但没有与 std::format 集成。

【讨论】:

  • 非常感谢您的回答。我怎样才能使用 C++20 的特性呢?我正在使用 CMakeLists.txt 文件来制作我的项目。
  • error: ‘format’ is not a member of ‘std::chrono’
  • @Cerin 从我写这个答案到现在,他们将std::chrono::format 功能集成到更通用的std::formatstd::formatter 功能中。我已经更新了答案以反映他们所做的更改,但我不得不对格式字符串吐口水,因为我查看的编译器都不支持 C++20 中的 &lt;format&gt; 库功能。
【解决方案2】:

记录在案:

如果 C++20 功能不可用,例如我的情况,您可以使用以下内容:

#include <ctime>
#include <iomanip>
#include <iostream>

using namespace std ;

time_t now = time(nullptr) ;
cout << put_time(localtime(&now), "%T") << endl ;

put_time是在iomanip库中定义的,看https://en.cppreference.com/w/cpp/io/manip/put_time,time_t和localtime都来自ctime,https://en.cppreference.com/w/cpp/chrono/c/ctime

【讨论】:

    【解决方案3】:

    如果您想要更手动的方法,这是我之前使用的方法

    char buffer[MAX_BUFFER_SIZE];
    
    time_t t = time(NULL);
    struct tm *lt = localtime(&t);
    
    snprintf(buffer, MAX_BUFFER_SIZE, "%02d/%02d/%02d %02d:%02d:%02d", lt->tm_mon+1, lt->tm_mday, lt->tm_year%100, lt->tm_hour, lt->tm_min, lt->tm_sec);
    

    然后将 buffer(现在包含时间的字符串表示)输出到您的文件。

    【讨论】:

      【解决方案4】:

      我通常将我的实现用于此类事情。

      #include <chrono>
      #include <ctime>
      
      
      // strftime format
      #define LOGGER_PRETTY_TIME_FORMAT "%Y-%m-%d %H:%M:%S"
      
      // printf format
      #define LOGGER_PRETTY_MS_FORMAT ".%03d"
      
      
      // convert current time to milliseconds since unix epoch
      template <typename T>
      static int to_ms(const std::chrono::time_point<T>& tp)
      {
          using namespace std::chrono;
      
          auto dur = tp.time_since_epoch();
          return static_cast<int>(duration_cast<milliseconds>(dur).count());
      }
      
      
      // format it in two parts: main part with date and time and part with milliseconds
      static std::string pretty_time()
      {
          auto tp = std::chrono::system_clock::now();
          std::time_t current_time = std::chrono::system_clock::to_time_t(tp);
      
          // this function use static global pointer. so it is not thread safe solution
          std::tm* time_info = std::localtime(&current_time);
      
          char buffer[128];
      
          int string_size = strftime(
              buffer, sizeof(buffer),
              LOGGER_PRETTY_TIME_FORMAT,
              time_info
          );
      
          int ms = to_ms(tp) % 1000;
      
          string_size += std::snprintf(
              buffer + string_size, sizeof(buffer) - string_size,
              LOGGER_PRETTY_MS_FORMAT, ms
          );
      
          return std::string(buffer, buffer + string_size);
      }
      

      返回当前时间,格式为:2018-09-23 21:58:52.642

      是的,它需要--std=c++11 或更高版本。

      【讨论】:

      • 感谢您的回答。如何使用 C++11 功能? (我使用的是 CMakeLists.txt 文件)
      • @ekter15 TARGET_COMPILE_FEATURES(${MyProject} PRIVATE cxx_std_11)SET(CMAKE_CXX_STANDARD 11)
      猜你喜欢
      • 2020-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-19
      • 2021-12-19
      • 2015-08-10
      • 1970-01-01
      相关资源
      最近更新 更多