eis/TestProject/play_gruond/time_jump_detector.cc000

167 lines
5.0 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <atomic>
#include <chrono>
#include <csignal>
#include <fstream>
#include <iostream>
#include <sys/stat.h>
#include <thread>
#include <ctime> // 添加用于localtime_r和时间函数
#include <iomanip> // 添加用于std::setw和std::setfill
#include <sstream> // 添加用于std::ostringstream
std::atomic<bool> stop_logging(false);
void signalHandler(int signum) { stop_logging = true; }
class HighPrecisionTimeLogger {
private:
std::ofstream log_file;
int log_interval_ms;
std::string filename;
uint64_t last_timestamp_us;
uint64_t second_last_timestamp_us;
bool selective_logging;
bool in_jump_mode;
int jump_remaining;
// 获取当前时间戳(微秒)
uint64_t getCurrentTimestampUs() {
auto now = std::chrono::system_clock::now();
auto duration = now.time_since_epoch();
return std::chrono::duration_cast<std::chrono::microseconds>(duration)
.count();
}
// 格式化时间戳为可读字符串
std::string formatTimestamp(uint64_t timestamp_us) {
time_t seconds = timestamp_us / 1000000;
suseconds_t microseconds = timestamp_us % 1000000;
struct tm tm_info;
localtime_r(&seconds, &tm_info);
char buffer[64];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm_info);
std::ostringstream oss;
oss << buffer << "." << std::setw(6) << std::setfill('0') << microseconds;
return oss.str();
}
// 检查是否需要日志轮转
void checkLogRotation() {
struct stat stat_buf;
if (stat(filename.c_str(), &stat_buf) == 0) {
// 如果文件超过50MB进行轮转
if (static_cast<size_t>(stat_buf.st_size) >= 50 * 1024 * 1024) {
log_file.close();
std::string old_filename = filename + ".old";
rename(filename.c_str(), old_filename.c_str());
log_file.open(filename, std::ios::out);
}
}
}
public:
HighPrecisionTimeLogger(const std::string &fname = "timestamps.log",
int interval_ms = 50, bool selective = true)
: filename(fname), log_interval_ms(interval_ms),
selective_logging(selective), last_timestamp_us(0),
second_last_timestamp_us(0), in_jump_mode(false), jump_remaining(0) {
log_file.open(filename, std::ios::out);
if (!log_file.is_open()) {
throw std::runtime_error("无法打开日志文件");
}
// 写入表头
log_file << "timestamp,formatted_time,time_jump_detected,interval_us,note"
<< std::endl;
}
void startLogging() {
signal(SIGINT, signalHandler);
signal(SIGTERM, signalHandler);
std::cout << "开始记录时间戳,间隔: " << log_interval_ms << "ms"
<< std::endl;
std::cout << "按Ctrl+C停止记录" << std::endl;
auto next_log_time = std::chrono::steady_clock::now();
uint64_t expected_interval_us = log_interval_ms * 1000;
while (!stop_logging) {
uint64_t current_timestamp_us = getCurrentTimestampUs();
std::string formatted_time = formatTimestamp(current_timestamp_us);
bool time_jump_detected = false;
std::string note = "";
// 时间跳变检测逻辑
if (last_timestamp_us != 0 && second_last_timestamp_us != 0) {
// 检测时间回退
if (current_timestamp_us < last_timestamp_us) {
time_jump_detected = true;
note = "TIME_REGESSION";
}
// 检测异常大的间隔超过预期1.5倍)
else {
uint64_t actual_interval_us =
current_timestamp_us - second_last_timestamp_us;
uint64_t threshold_us = expected_interval_us * 1.5;
if (actual_interval_us > threshold_us) {
time_jump_detected = true;
note = "LONG_INTERVAL";
}
}
}
// 更新历史时间戳
if (last_timestamp_us != 0) {
second_last_timestamp_us = last_timestamp_us;
}
last_timestamp_us = current_timestamp_us;
// 记录到文件
uint64_t interval =
(second_last_timestamp_us == 0)
? 0
: (current_timestamp_us - second_last_timestamp_us);
log_file << current_timestamp_us << "," << formatted_time << ","
<< (time_jump_detected ? "YES" : "NO") << "," << interval << ","
<< note << std::endl;
// 检查日志轮转
checkLogRotation();
// 计算下一个日志时间点
next_log_time += std::chrono::milliseconds(log_interval_ms);
std::this_thread::sleep_until(next_log_time);
}
log_file.close();
std::cout << "记录已停止,数据保存在: " << filename << std::endl;
}
};
int main(int argc, char *argv[]) {
std::string filename = "time_log.csv";
int interval_ms = 50;
if (argc >= 2) {
interval_ms = std::stoi(argv[1]);
}
if (argc >= 3) {
filename = argv[2];
}
try {
HighPrecisionTimeLogger logger(filename, interval_ms);
logger.startLogging();
} catch (const std::exception &e) {
std::cerr << "错误: " << e.what() << std::endl;
return 1;
}
return 0;
}