mirror of https://github.com/gabime/spdlog.git
test
parent
486b55554f
commit
265de6186d
@ -0,0 +1,58 @@
|
||||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/desensitizer.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace spdlog {
|
||||
|
||||
desensitizer::desensitizer() : rules_() {
|
||||
// 添加默认的脱敏规则
|
||||
add_rule("phone", R"(1[3-9]\d{9})", "1****5678");
|
||||
add_rule("email", R"([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})", "***@***");
|
||||
add_rule("id_card", R"(\d{17}[\dXx])", "***********5678");
|
||||
}
|
||||
|
||||
desensitizer::desensitizer(details::desensitize_rules rules) : rules_(std::move(rules)) {
|
||||
}
|
||||
|
||||
void desensitizer::add_rule(const std::string &name, const std::string &pattern, const std::string &replacement) {
|
||||
try {
|
||||
rules_[name] = {std::regex(pattern), replacement};
|
||||
} catch (const std::regex_error &e) {
|
||||
throw std::invalid_argument(fmt::format("Invalid regex pattern '{}': {}", pattern, e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
void desensitizer::remove_rule(const std::string &name) {
|
||||
rules_.erase(name);
|
||||
}
|
||||
|
||||
void desensitizer::clear_rules() {
|
||||
rules_.clear();
|
||||
}
|
||||
|
||||
std::string desensitizer::desensitize(const std::string &msg) const {
|
||||
std::string result = msg;
|
||||
for (const auto &[name, rule] : rules_) {
|
||||
result = std::regex_replace(result, rule.pattern, rule.replacement);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void desensitizer::desensitize(details::log_msg &msg) const {
|
||||
if (msg.payload.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string desensitized = desensitize(std::string(msg.payload.data(), msg.payload.size()));
|
||||
msg.payload = spdlog::string_view_t(desensitized.data(), desensitized.size());
|
||||
}
|
||||
|
||||
} // namespace spdlog
|
||||
@ -0,0 +1,52 @@
|
||||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/details/log_msg.h>
|
||||
#include <spdlog/fmt/fmt.h>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
|
||||
struct desensitize_rule {
|
||||
std::regex pattern;
|
||||
std::string replacement;
|
||||
};
|
||||
|
||||
using desensitize_rules = std::unordered_map<std::string, desensitize_rule>;
|
||||
|
||||
} // namespace details
|
||||
|
||||
class SPDLOG_API desensitizer {
|
||||
public:
|
||||
desensitizer();
|
||||
explicit desensitizer(details::desensitize_rules rules);
|
||||
|
||||
// 添加脱敏规则
|
||||
void add_rule(const std::string &name, const std::string &pattern, const std::string &replacement);
|
||||
|
||||
// 移除脱敏规则
|
||||
void remove_rule(const std::string &name);
|
||||
|
||||
// 清空所有脱敏规则
|
||||
void clear_rules();
|
||||
|
||||
// 脱敏字符串
|
||||
std::string desensitize(const std::string &msg) const;
|
||||
|
||||
// 脱敏log_msg
|
||||
void desensitize(details::log_msg &msg) const;
|
||||
|
||||
private:
|
||||
details::desensitize_rules rules_;
|
||||
};
|
||||
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "desensitizer-inl.h"
|
||||
#endif
|
||||
@ -0,0 +1,89 @@
|
||||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/formatters/json_formatter.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/details/os.h>
|
||||
#include <spdlog/details/format_helper.h>
|
||||
|
||||
namespace spdlog {
|
||||
namespace formatters {
|
||||
|
||||
json_formatter::json_formatter(std::string eol)
|
||||
: eol_(std::move(eol))
|
||||
{}
|
||||
|
||||
std::unique_ptr<formatter> json_formatter::clone() const {
|
||||
return details::make_unique<json_formatter>(*this);
|
||||
}
|
||||
|
||||
void json_formatter::format(const details::log_msg &msg, memory_buf_t &dest) {
|
||||
fmt::format_to(std::back_inserter(dest), "{{");
|
||||
|
||||
// 添加时间字段
|
||||
std::tm tm_time;
|
||||
if (msg.time.time_since_epoch().count() == 0) {
|
||||
// 如果时间未设置,使用当前时间
|
||||
auto now = std::chrono::system_clock::now();
|
||||
tm_time = details::os::localtime(std::chrono::system_clock::to_time_t(now));
|
||||
} else {
|
||||
tm_time = details::os::localtime(std::chrono::system_clock::to_time_t(msg.time));
|
||||
}
|
||||
|
||||
char time_buf[128];
|
||||
std::strftime(time_buf, sizeof(time_buf), time_format_.c_str(), &tm_time);
|
||||
fmt::format_to(std::back_inserter(dest), "\"time\":\"{}\",", time_buf);
|
||||
|
||||
// 添加日志级别
|
||||
fmt::format_to(std::back_inserter(dest), "\"level\":{},", static_cast<int>(msg.level));
|
||||
|
||||
// 添加日志级别名称
|
||||
if (include_level_name_) {
|
||||
fmt::format_to(std::back_inserter(dest), "\"level_name\":\"{}\",", level::to_string_view(msg.level));
|
||||
}
|
||||
|
||||
// 添加日志名称
|
||||
fmt::format_to(std::back_inserter(dest), "\"logger_name\":\"{}\",", msg.logger_name);
|
||||
|
||||
// 添加线程ID
|
||||
if (include_thread_id_) {
|
||||
fmt::format_to(std::back_inserter(dest), "\"thread_id\":{},", msg.thread_id);
|
||||
}
|
||||
|
||||
// 添加日志消息
|
||||
fmt::format_to(std::back_inserter(dest), "\"message\":{}", fmt::format("{}", msg.payload));
|
||||
|
||||
// 添加源位置信息
|
||||
if (include_source_location_ && msg.source.filename != nullptr) {
|
||||
fmt::format_to(std::back_inserter(dest), ",\"source_location\":{{\"file\":\"{}\",\"line\":{},\"function\":\"{}\"}}",
|
||||
msg.source.filename,
|
||||
msg.source.line,
|
||||
msg.source.funcname);
|
||||
}
|
||||
|
||||
// 关闭JSON对象
|
||||
fmt::format_to(std::back_inserter(dest), "{}", eol_);
|
||||
}
|
||||
|
||||
void json_formatter::set_include_source_location(bool include) {
|
||||
include_source_location_ = include;
|
||||
}
|
||||
|
||||
void json_formatter::set_include_thread_id(bool include) {
|
||||
include_thread_id_ = include;
|
||||
}
|
||||
|
||||
void json_formatter::set_include_level_name(bool include) {
|
||||
include_level_name_ = include;
|
||||
}
|
||||
|
||||
void json_formatter::set_time_format(std::string format) {
|
||||
time_format_ = std::move(format);
|
||||
}
|
||||
|
||||
} // namespace formatters
|
||||
} // namespace spdlog
|
||||
@ -0,0 +1,48 @@
|
||||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/formatter.h>
|
||||
#include <spdlog/details/log_msg.h>
|
||||
#include <spdlog/fmt/fmt.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace spdlog {
|
||||
namespace formatters {
|
||||
|
||||
class SPDLOG_API json_formatter : public formatter {
|
||||
public:
|
||||
json_formatter(std::string eol = spdlog::details::os::default_eol);
|
||||
|
||||
std::unique_ptr<formatter> clone() const override;
|
||||
void format(const details::log_msg &msg, memory_buf_t &dest) override;
|
||||
|
||||
// 设置是否包含源位置信息
|
||||
void set_include_source_location(bool include);
|
||||
|
||||
// 设置是否包含线程ID
|
||||
void set_include_thread_id(bool include);
|
||||
|
||||
// 设置是否包含日志级别名称
|
||||
void set_include_level_name(bool include);
|
||||
|
||||
// 设置时间格式
|
||||
void set_time_format(std::string format);
|
||||
|
||||
private:
|
||||
std::string eol_;
|
||||
bool include_source_location_ = true;
|
||||
bool include_thread_id_ = true;
|
||||
bool include_level_name_ = true;
|
||||
std::string time_format_ = "%Y-%m-%dT%H:%M:%S.%eZ";
|
||||
};
|
||||
|
||||
} // namespace formatters
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "json_formatter-inl.h"
|
||||
#endif
|
||||
@ -0,0 +1,240 @@
|
||||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/log_aggregator.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/details/os.h>
|
||||
#include <spdlog/fmt/fmt.h>
|
||||
#include <regex>
|
||||
#include <chrono>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
namespace spdlog {
|
||||
|
||||
log_aggregator::log_aggregator(size_t max_buffer_size)
|
||||
: max_buffer_size_(max_buffer_size)
|
||||
, log_callback_([this](const details::log_msg &msg) {
|
||||
std::lock_guard<std::mutex> lock(buffer_mutex_);
|
||||
if (log_buffer_.size() >= max_buffer_size_) {
|
||||
log_buffer_.erase(log_buffer_.begin());
|
||||
}
|
||||
log_buffer_.push_back(msg);
|
||||
update_statistics(msg);
|
||||
update_latency_distribution(msg);
|
||||
})
|
||||
{
|
||||
// 初始化统计信息
|
||||
auto now = std::chrono::system_clock::now();
|
||||
statistics_.first_log_time = now;
|
||||
statistics_.last_log_time = now;
|
||||
}
|
||||
|
||||
log_aggregator::~log_aggregator() {
|
||||
// 注销所有日志记录器
|
||||
std::lock_guard<std::mutex> lock(loggers_mutex_);
|
||||
for (auto &[name, logger] : registered_loggers_) {
|
||||
logger->remove_callback(log_callback_);
|
||||
}
|
||||
}
|
||||
|
||||
void log_aggregator::register_logger(std::shared_ptr<logger> logger) {
|
||||
std::lock_guard<std::mutex> lock(loggers_mutex_);
|
||||
auto name = logger->name();
|
||||
if (registered_loggers_.find(name) == registered_loggers_.end()) {
|
||||
registered_loggers_[name] = logger;
|
||||
logger->add_callback(log_callback_);
|
||||
}
|
||||
}
|
||||
|
||||
void log_aggregator::unregister_logger(std::shared_ptr<logger> logger) {
|
||||
std::lock_guard<std::mutex> lock(loggers_mutex_);
|
||||
auto name = logger->name();
|
||||
auto it = registered_loggers_.find(name);
|
||||
if (it != registered_loggers_.end()) {
|
||||
logger->remove_callback(log_callback_);
|
||||
registered_loggers_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
query_result log_aggregator::query_logs(const query_filter &filter) const {
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
query_result result;
|
||||
std::vector<details::log_msg> filtered_logs;
|
||||
|
||||
std::lock_guard<std::mutex> lock(buffer_mutex_);
|
||||
result.total_logs = log_buffer_.size();
|
||||
|
||||
// 过滤日志
|
||||
for (const auto &msg : log_buffer_) {
|
||||
if (msg.time < filter.start_time || msg.time > filter.end_time) {
|
||||
continue;
|
||||
}
|
||||
if (msg.level < filter.min_level || msg.level > filter.max_level) {
|
||||
continue;
|
||||
}
|
||||
if (!filter.logger_name.empty() && msg.logger_name != filter.logger_name) {
|
||||
continue;
|
||||
}
|
||||
if (!filter.keyword.empty()) {
|
||||
std::string payload(msg.payload.data(), msg.payload.size());
|
||||
if (payload.find(filter.keyword) == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
filtered_logs.push_back(msg);
|
||||
}
|
||||
|
||||
result.total_matched = filtered_logs.size();
|
||||
|
||||
// 应用分页
|
||||
size_t start_idx = filter.offset;
|
||||
size_t end_idx = std::min(start_idx + filter.limit, filtered_logs.size());
|
||||
if (start_idx < filtered_logs.size()) {
|
||||
result.logs.insert(result.logs.end(), filtered_logs.begin() + start_idx, filtered_logs.begin() + end_idx);
|
||||
}
|
||||
|
||||
auto end_time = std::chrono::high_resolution_clock::now();
|
||||
result.query_duration = std::chrono::duration<double, std::milli>(end_time - start_time).count();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
log_statistics log_aggregator::get_statistics() const {
|
||||
std::lock_guard<std::mutex> lock(statistics_mutex_);
|
||||
return statistics_;
|
||||
}
|
||||
|
||||
latency_distribution log_aggregator::get_latency_distribution(const std::string &prefix) const {
|
||||
std::lock_guard<std::mutex> lock(latency_mutex_);
|
||||
auto it = latency_distributions_.find(prefix);
|
||||
if (it != latency_distributions_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return latency_distribution{};
|
||||
}
|
||||
|
||||
void log_aggregator::clean_old_logs(std::chrono::system_clock::time_point before_time) {
|
||||
std::lock_guard<std::mutex> lock(buffer_mutex_);
|
||||
auto it = std::remove_if(log_buffer_.begin(), log_buffer_.end(),
|
||||
[&before_time](const details::log_msg &msg) {
|
||||
return msg.time < before_time;
|
||||
});
|
||||
log_buffer_.erase(it, log_buffer_.end());
|
||||
}
|
||||
|
||||
void log_aggregator::set_max_buffer_size(size_t max_size) {
|
||||
std::lock_guard<std::mutex> lock(buffer_mutex_);
|
||||
max_buffer_size_ = max_size;
|
||||
// 如果当前缓存大小超过新的最大大小,删除旧的日志
|
||||
if (log_buffer_.size() > max_size) {
|
||||
size_t to_remove = log_buffer_.size() - max_size;
|
||||
log_buffer_.erase(log_buffer_.begin(), log_buffer_.begin() + to_remove);
|
||||
}
|
||||
}
|
||||
|
||||
size_t log_aggregator::get_current_buffer_size() const {
|
||||
std::lock_guard<std::mutex> lock(buffer_mutex_);
|
||||
return log_buffer_.size();
|
||||
}
|
||||
|
||||
void log_aggregator::add_custom_statistic(const std::string &name,
|
||||
std::function<void(const details::log_msg &, log_statistics &)> statistic_fn) {
|
||||
std::lock_guard<std::mutex> lock(custom_stats_mutex_);
|
||||
custom_statistics_[name] = std::move(statistic_fn);
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, double> log_aggregator::get_custom_statistics() const {
|
||||
std::lock_guard<std::mutex> lock(custom_stats_mutex_);
|
||||
std::unordered_map<std::string, double> result;
|
||||
for (const auto &[name, fn] : custom_statistics_) {
|
||||
// 这里可以根据需要实现自定义统计结果的获取
|
||||
// 目前只是返回0.0作为示例
|
||||
result[name] = 0.0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void log_aggregator::update_statistics(const details::log_msg &msg) {
|
||||
std::lock_guard<std::mutex> lock(statistics_mutex_);
|
||||
|
||||
statistics_.total_logs++;
|
||||
statistics_.last_log_time = msg.time;
|
||||
|
||||
// 更新级别计数
|
||||
statistics_.level_counts[msg.level]++;
|
||||
|
||||
// 调用自定义统计函数
|
||||
std::lock_guard<std::mutex> custom_lock(custom_stats_mutex_);
|
||||
for (auto &[name, fn] : custom_statistics_) {
|
||||
try {
|
||||
fn(msg, statistics_);
|
||||
} catch (const std::exception &ex) {
|
||||
// 忽略自定义统计函数的异常
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void log_aggregator::update_latency_distribution(const details::log_msg &msg) {
|
||||
std::string payload(msg.payload.data(), msg.payload.size());
|
||||
std::optional<double> latency = parse_latency(payload);
|
||||
if (!latency) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 提取延迟前缀(如果有的话)
|
||||
std::string prefix;
|
||||
size_t colon_pos = payload.find(":");
|
||||
if (colon_pos != std::string::npos) {
|
||||
prefix = payload.substr(0, colon_pos);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(latency_mutex_);
|
||||
auto &dist = latency_distributions_[prefix];
|
||||
|
||||
dist.count++;
|
||||
dist.min_latency = std::min(dist.min_latency, *latency);
|
||||
dist.max_latency = std::max(dist.max_latency, *latency);
|
||||
dist.average_latency = (dist.average_latency * (dist.count - 1) + *latency) / dist.count;
|
||||
|
||||
// 将延迟分到不同的桶中
|
||||
std::string bucket;
|
||||
if (*latency < 1.0) {
|
||||
bucket = "<1ms";
|
||||
} else if (*latency < 10.0) {
|
||||
bucket = "1-10ms";
|
||||
} else if (*latency < 100.0) {
|
||||
bucket = "10-100ms";
|
||||
} else if (*latency < 1000.0) {
|
||||
bucket = "100-1000ms";
|
||||
} else {
|
||||
bucket = ">1000ms";
|
||||
}
|
||||
dist.latency_buckets[bucket]++;
|
||||
}
|
||||
|
||||
std::optional<double> log_aggregator::parse_latency(const std::string &msg) const {
|
||||
// 尝试从日志消息中解析延迟信息
|
||||
// 支持的格式:
|
||||
// - latency: 123.45ms
|
||||
// - time: 123.45ms
|
||||
// - took: 123.45ms
|
||||
|
||||
std::regex latency_regex(R"((latency|time|took):\s*(\d+(?:\.\d+)?)ms)"s);
|
||||
std::smatch match;
|
||||
if (std::regex_search(msg, match, latency_regex)) {
|
||||
try {
|
||||
double latency = std::stod(match[2]);
|
||||
return latency;
|
||||
} catch (const std::exception &ex) {
|
||||
// 解析失败
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace spdlog
|
||||
@ -0,0 +1,135 @@
|
||||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <spdlog/details/log_msg.h>
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/logger.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
#include <functional>
|
||||
|
||||
namespace spdlog {
|
||||
|
||||
// 日志统计信息
|
||||
struct log_statistics {
|
||||
std::unordered_map<level::level_enum, size_t> level_counts;
|
||||
size_t total_logs = 0;
|
||||
std::chrono::system_clock::time_point first_log_time;
|
||||
std::chrono::system_clock::time_point last_log_time;
|
||||
};
|
||||
|
||||
// 延迟分布
|
||||
struct latency_distribution {
|
||||
size_t count = 0;
|
||||
double min_latency = 0.0;
|
||||
double max_latency = 0.0;
|
||||
double average_latency = 0.0;
|
||||
std::unordered_map<std::string, size_t> latency_buckets;
|
||||
};
|
||||
|
||||
// 查询结果
|
||||
struct query_result {
|
||||
std::vector<details::log_msg> logs;
|
||||
size_t total_matched = 0;
|
||||
size_t total_logs = 0;
|
||||
double query_duration = 0.0;
|
||||
};
|
||||
|
||||
// 查询过滤条件
|
||||
struct query_filter {
|
||||
std::chrono::system_clock::time_point start_time;
|
||||
std::chrono::system_clock::time_point end_time;
|
||||
level::level_enum min_level = level::trace;
|
||||
level::level_enum max_level = level::critical;
|
||||
std::string keyword;
|
||||
std::string logger_name;
|
||||
size_t limit = 100;
|
||||
size_t offset = 0;
|
||||
};
|
||||
|
||||
class SPDLOG_API log_aggregator {
|
||||
public:
|
||||
explicit log_aggregator(size_t max_buffer_size = 10000);
|
||||
~log_aggregator();
|
||||
|
||||
log_aggregator(const log_aggregator &) = delete;
|
||||
log_aggregator &operator=(const log_aggregator &) = delete;
|
||||
|
||||
// 注册日志记录器
|
||||
void register_logger(std::shared_ptr<logger> logger);
|
||||
|
||||
// 注销日志记录器
|
||||
void unregister_logger(std::shared_ptr<logger> logger);
|
||||
|
||||
// 查询日志
|
||||
query_result query_logs(const query_filter &filter) const;
|
||||
|
||||
// 获取日志统计信息
|
||||
log_statistics get_statistics() const;
|
||||
|
||||
// 获取延迟分布
|
||||
latency_distribution get_latency_distribution(const std::string &prefix = "") const;
|
||||
|
||||
// 清理指定时间之前的日志
|
||||
void clean_old_logs(std::chrono::system_clock::time_point before_time);
|
||||
|
||||
// 设置最大缓存大小
|
||||
void set_max_buffer_size(size_t max_size);
|
||||
|
||||
// 获取当前缓存大小
|
||||
size_t get_current_buffer_size() const;
|
||||
|
||||
// 添加自定义统计函数
|
||||
void add_custom_statistic(const std::string &name,
|
||||
std::function<void(const details::log_msg &, log_statistics &)> statistic_fn);
|
||||
|
||||
// 获取自定义统计结果
|
||||
std::unordered_map<std::string, double> get_custom_statistics() const;
|
||||
|
||||
private:
|
||||
// 日志缓存
|
||||
std::vector<details::log_msg> log_buffer_;
|
||||
size_t max_buffer_size_;
|
||||
mutable std::mutex buffer_mutex_;
|
||||
|
||||
// 注册的日志记录器
|
||||
std::unordered_map<std::string, std::shared_ptr<logger>> registered_loggers_;
|
||||
mutable std::mutex loggers_mutex_;
|
||||
|
||||
// 日志统计信息
|
||||
log_statistics statistics_;
|
||||
mutable std::mutex statistics_mutex_;
|
||||
|
||||
// 延迟分布
|
||||
std::unordered_map<std::string, latency_distribution> latency_distributions_;
|
||||
mutable std::mutex latency_mutex_;
|
||||
|
||||
// 自定义统计函数
|
||||
std::unordered_map<std::string, std::function<void(const details::log_msg &, log_statistics &)>> custom_statistics_;
|
||||
mutable std::mutex custom_stats_mutex_;
|
||||
|
||||
// 日志收集回调
|
||||
std::function<void(const details::log_msg &)> log_callback_;
|
||||
|
||||
// 更新统计信息
|
||||
void update_statistics(const details::log_msg &msg);
|
||||
|
||||
// 更新延迟分布
|
||||
void update_latency_distribution(const details::log_msg &msg);
|
||||
|
||||
// 解析延迟信息
|
||||
std::optional<double> parse_latency(const std::string &msg) const;
|
||||
};
|
||||
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "log_aggregator-inl.h"
|
||||
#endif
|
||||
Loading…
Reference in New Issue