add function,1.limit log freq 2.realtime log control
This commit is contained in:
@@ -17,6 +17,8 @@
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <fnmatch.h>
|
||||
#include <unordered_map>
|
||||
#include <chrono>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#include "log4cplus/logger.h"
|
||||
@@ -48,9 +50,35 @@ extern std::string subdir;
|
||||
|
||||
//日志主题
|
||||
extern std::string G_LOG_TOPIC;
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const int LOGTYPE_DEFAULT = LOG_CODE_OTHER;
|
||||
|
||||
static const int LOGTYPE_WILDCARD = 999; // logtype 通配号码
|
||||
static const char* ID_WILDCARD = "all"; // id 通配字段
|
||||
|
||||
std::map<std::string, TypedLogger> logger_map;
|
||||
DebugSwitch g_debug_switch;
|
||||
|
||||
|
||||
|
||||
//用来控制日志上送的结构
|
||||
struct LOGEntry {
|
||||
std::string id; //测点和装置需要的id
|
||||
std::string level; // terminal / measurepoint /process
|
||||
int logtype; // 日志类型
|
||||
int min_grade; // DEBUG / INFO / WARN / ERROR
|
||||
int countdown; // 倒计时,单位秒
|
||||
};
|
||||
|
||||
//日志上送map管理
|
||||
std::map<std::string, LOGEntry> g_log_entries;
|
||||
pthread_mutex_t g_log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
std::string build_debug_key(const std::string& id, const std::string& level, int logtype);
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
/* log4.cpp 顶部 */
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
thread_local int g_log_code_tls = 0;
|
||||
#else
|
||||
@@ -122,8 +150,7 @@ bool DebugSwitch::match(const std::string& logger_name, int level, int logtype)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<std::string, TypedLogger> logger_map;
|
||||
DebugSwitch g_debug_switch;
|
||||
|
||||
|
||||
/*class SendAppender : public Appender {
|
||||
protected:
|
||||
@@ -201,7 +228,7 @@ private:
|
||||
std::chrono::steady_clock::time_point::min();
|
||||
};
|
||||
|
||||
static std::unordered_map<std::string, RateState> s_rate_map;
|
||||
static std::unordered_map<std::string, RateState> s_rate_map; //频率map
|
||||
static std::mutex s_rate_mutex;
|
||||
|
||||
// 定义“同一条日志”的规则:logger + level + code + msg //原来只区分了日志登记名和等级,现在具体到每一条日志
|
||||
@@ -218,9 +245,19 @@ private:
|
||||
|
||||
std::lock_guard<std::mutex> lk(s_rate_mutex);
|
||||
RateState& st = s_rate_map[key];
|
||||
|
||||
// 超过恢复时间,重置计数
|
||||
const int RESET_SEC = 3600; // 一小时
|
||||
if (st.last_emit != steady_clock::time_point::min()) {
|
||||
auto idle = duration_cast<seconds>(now - st.last_emit).count();
|
||||
if (idle >= RESET_SEC) {
|
||||
st.hit_count = 0; // 恢复为“新日志”
|
||||
}
|
||||
}
|
||||
|
||||
st.hit_count++;
|
||||
|
||||
const int period_sec = (st.hit_count > 5) ? 300 : 1;
|
||||
const int period_sec = (st.hit_count > 3) ? 300 : 1;
|
||||
|
||||
if (st.last_emit == steady_clock::time_point::min()) {
|
||||
st.last_emit = now;
|
||||
@@ -236,6 +273,48 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool find_entry_allow(const std::string& key, int level_val) { //通配方式查找
|
||||
std::map<std::string, LOGEntry>::iterator it = g_log_entries.find(key);
|
||||
if (it == g_log_entries.end() || it->second.countdown <= 0) return false;
|
||||
return level_val >= it->second.min_grade;
|
||||
}
|
||||
|
||||
static bool allow_low_level_send(const std::string& id,
|
||||
const std::string& level_str,//层级
|
||||
int logtype,
|
||||
int level_val) {//告警等级
|
||||
pthread_mutex_lock(&g_log_mutex);
|
||||
|
||||
// 1) 精确匹配:id + level + logtype
|
||||
if (find_entry_allow(build_debug_key(id, level_str, logtype), level_val)) {
|
||||
pthread_mutex_unlock(&g_log_mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2) logtype 通配:id + level + -1
|
||||
if (find_entry_allow(build_debug_key(id, level_str, LOGTYPE_WILDCARD), level_val)) {
|
||||
pthread_mutex_unlock(&g_log_mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 3) id 通配:* + level + logtype
|
||||
if (find_entry_allow(build_debug_key(ID_WILDCARD, level_str, logtype), level_val)) {
|
||||
pthread_mutex_unlock(&g_log_mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 4) 双通配:* + level + -1
|
||||
if (find_entry_allow(build_debug_key(ID_WILDCARD, level_str, LOGTYPE_WILDCARD), level_val)) {
|
||||
pthread_mutex_unlock(&g_log_mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&g_log_mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
void append(const spi::InternalLoggingEvent& event) override {
|
||||
std::string logger_name = event.getLoggerName();
|
||||
@@ -253,11 +332,33 @@ protected:
|
||||
// TLS code
|
||||
int code = g_log_code_tls;
|
||||
|
||||
const int safe_logtype = 0;
|
||||
const int safe_logtype = code; // 使用 code 作为 logtype
|
||||
|
||||
if (!(level == ERROR_LOG_LEVEL ||
|
||||
level == WARN_LOG_LEVEL ||
|
||||
g_debug_switch.match(logger_name, level, safe_logtype))) {
|
||||
bool allow_send = false;
|
||||
|
||||
if (level >= WARN_LOG_LEVEL) {
|
||||
allow_send = true;
|
||||
} else {
|
||||
// NORMAL/DEBUG 默认不上送,必须命令打开
|
||||
std::string ctrl_level = level_str; // "process" / "terminal" / "measurepoint"
|
||||
|
||||
std::string ctrl_id;
|
||||
if (ctrl_level == "process") {
|
||||
ctrl_id = "process"; // process 用固定 id
|
||||
} else {
|
||||
ctrl_id = extract_logger_id(logger_name); // terminal.<id> / monitor.<id>
|
||||
if (ctrl_id.empty()) {
|
||||
// 没解析出 id,就不给低等级上送(避免误发)
|
||||
allow_send = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ctrl_id.empty()) {
|
||||
allow_send = allow_low_level_send(ctrl_id, ctrl_level, safe_logtype, level);
|
||||
}
|
||||
}
|
||||
|
||||
if (!allow_send) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -318,22 +419,11 @@ public:
|
||||
std::unordered_map<std::string, SendAppender::RateState> SendAppender::s_rate_map;
|
||||
std::mutex SendAppender::s_rate_mutex;
|
||||
|
||||
//用来控制日志上送的结构
|
||||
struct LOGEntry {
|
||||
std::string id; //测点和装置需要的id
|
||||
std::string level; // terminal / measurepoint /process
|
||||
|
||||
int min_grade; // DEBUG / INFO / WARN / ERROR
|
||||
int countdown; // 倒计时,单位秒
|
||||
};
|
||||
|
||||
//日志上送map管理
|
||||
std::map<std::string, LOGEntry> g_log_entries;
|
||||
pthread_mutex_t g_log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// 生成唯一 key
|
||||
std::string build_debug_key(const std::string& id, const std::string& level) {
|
||||
return id + "|" + level + "|";
|
||||
std::string build_debug_key(const std::string& id, const std::string& level, int logtype) {
|
||||
std::ostringstream oss;
|
||||
oss << id << "|" << level << "|" << logtype;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// 外部线程中调用:每秒更新所有倒计时,0 则删除
|
||||
@@ -354,19 +444,19 @@ void update_log_entries_countdown() {
|
||||
pthread_mutex_unlock(&g_log_mutex);
|
||||
}
|
||||
|
||||
void process_log_command(const std::string& id, const std::string& level, const std::string& grade, const std::string& logtype_str) {
|
||||
if (level != "terminal" && level != "measurepoint") return;
|
||||
void process_log_command(const std::string& id, const std::string& level, const std::string& grade, int logtype) {
|
||||
if (level != "terminal" && level != "measurepoint" && level != "process") return;
|
||||
|
||||
int grade_level = (grade == "DEBUG") ? DEBUG_LOG_LEVEL : INFO_LOG_LEVEL;
|
||||
|
||||
std::string key = build_debug_key(id, level);
|
||||
std::string key = build_debug_key(id, level, logtype);
|
||||
|
||||
pthread_mutex_lock(&g_log_mutex);
|
||||
|
||||
LOGEntry& entry = g_log_entries[key]; // 会自动 insert 或取已有
|
||||
entry.id = id;
|
||||
entry.level = level;
|
||||
|
||||
entry.logtype = logtype;
|
||||
entry.min_grade = grade_level;
|
||||
entry.countdown = 60; // 重置倒计时
|
||||
|
||||
@@ -405,7 +495,7 @@ log4cplus::Logger init_logger(const std::string& full_name,
|
||||
//进程的日志
|
||||
void init_logger_process() {
|
||||
std::string base_dir = FRONT_PATH + "/" + subdir + "/processNo" + std::to_string(g_front_seg_index) + "/log";
|
||||
logger_map["process"] = TypedLogger(init_logger(std::string("process"), base_dir, std::string("process")), LOGTYPE_DATA);
|
||||
logger_map["process"] = TypedLogger(init_logger(std::string("process"), base_dir, std::string("process")), LOGTYPE_DEFAULT);
|
||||
std::cout << "process log init ok" << std::endl;
|
||||
}
|
||||
|
||||
@@ -444,7 +534,7 @@ void init_loggers_bydevid(const std::string& dev_id)
|
||||
device_appender->setLayout(std::unique_ptr<Layout>(new PatternLayout("%D{%Y-%m-%d %H:%M:%S} [%p] [%c] %m%n")));
|
||||
|
||||
Logger device_logger = init_logger(device_key, device_dir, dev_id, device_appender);
|
||||
logger_map[device_key] = TypedLogger(device_logger, LOGTYPE_DATA);
|
||||
logger_map[device_key] = TypedLogger(device_logger, LOGTYPE_DEFAULT);
|
||||
|
||||
|
||||
}
|
||||
@@ -469,7 +559,7 @@ void init_loggers_bydevid(const std::string& dev_id)
|
||||
monitor_appender->setLayout(std::unique_ptr<Layout>(new PatternLayout("%D{%Y-%m-%d %H:%M:%S} [%p] [%c] %m%n")));
|
||||
|
||||
Logger mon_logger = init_logger(mon_key.str(), mon_path.str(), mon_name.str(), monitor_appender);
|
||||
logger_map[mon_key.str()] = TypedLogger(mon_logger, LOGTYPE_DATA);
|
||||
logger_map[mon_key.str()] = TypedLogger(mon_logger, LOGTYPE_DEFAULT);
|
||||
|
||||
|
||||
}
|
||||
@@ -509,7 +599,7 @@ void init_loggers()
|
||||
|
||||
Logger device_logger = init_logger(device_key, device_dir, term.terminal_id, device_appender);
|
||||
|
||||
logger_map[device_key] = TypedLogger(device_logger, LOGTYPE_DATA);
|
||||
logger_map[device_key] = TypedLogger(device_logger, LOGTYPE_DEFAULT);
|
||||
|
||||
|
||||
|
||||
@@ -532,7 +622,7 @@ void init_loggers()
|
||||
|
||||
Logger mon_logger = init_logger(mon_key.str(), mon_path.str(), mon_name.str(), monitor_appender);
|
||||
|
||||
logger_map[mon_key.str()] = TypedLogger(mon_logger, LOGTYPE_DATA);
|
||||
logger_map[mon_key.str()] = TypedLogger(mon_logger, LOGTYPE_DEFAULT);
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user