add fun in log4
This commit is contained in:
@@ -125,14 +125,13 @@ bool DebugSwitch::match(const std::string& logger_name, int level, int logtype)
|
||||
std::map<std::string, TypedLogger> logger_map;
|
||||
DebugSwitch g_debug_switch;
|
||||
|
||||
class SendAppender : public Appender {
|
||||
/*class SendAppender : public Appender {
|
||||
protected:
|
||||
void append(const spi::InternalLoggingEvent& event) {
|
||||
std::string logger_name = event.getLoggerName();
|
||||
int level = event.getLogLevel();
|
||||
std::string msg = event.getMessage();
|
||||
|
||||
int logtype = (logger_name.find(".COM") != std::string::npos) ? LOGTYPE_COM : LOGTYPE_DATA;
|
||||
std::string level_str;
|
||||
if (logger_name.find("process") == 0)
|
||||
level_str = "process";
|
||||
@@ -193,15 +192,139 @@ public:
|
||||
virtual ~SendAppender() {
|
||||
destructorImpl(); // 重要!释放 log4cplus 基类资源
|
||||
}
|
||||
};*/
|
||||
class SendAppender : public Appender {
|
||||
private:
|
||||
struct RateState {
|
||||
uint64_t hit_count = 0; // 同一条日志累计命中次数
|
||||
std::chrono::steady_clock::time_point last_emit =
|
||||
std::chrono::steady_clock::time_point::min();
|
||||
};
|
||||
|
||||
static std::unordered_map<std::string, RateState> s_rate_map;
|
||||
static std::mutex s_rate_mutex;
|
||||
|
||||
// 定义“同一条日志”的规则:logger + level + code + msg //原来只区分了日志登记名和等级,现在具体到每一条日志
|
||||
static std::string make_key(const std::string& logger_name, int level, int code, const std::string& msg) {
|
||||
std::ostringstream oss;
|
||||
oss << logger_name << "|" << level << "|" << code << "|" << msg;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// 前 5 次:1 秒一次;第 6 次起:300 秒一次
|
||||
static bool should_emit(const std::string& key) {
|
||||
using namespace std::chrono;
|
||||
const auto now = steady_clock::now();
|
||||
|
||||
std::lock_guard<std::mutex> lk(s_rate_mutex);
|
||||
RateState& st = s_rate_map[key];
|
||||
st.hit_count++;
|
||||
|
||||
const int period_sec = (st.hit_count > 5) ? 300 : 1;
|
||||
|
||||
if (st.last_emit == steady_clock::time_point::min()) {
|
||||
st.last_emit = now;
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto elapsed = duration_cast<seconds>(now - st.last_emit).count();
|
||||
if (elapsed >= period_sec) {
|
||||
st.last_emit = now;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
void append(const spi::InternalLoggingEvent& event) override {
|
||||
std::string logger_name = event.getLoggerName();
|
||||
int level = event.getLogLevel();
|
||||
std::string msg = event.getMessage();
|
||||
|
||||
std::string level_str;
|
||||
if (logger_name.find("process") == 0)
|
||||
level_str = "process";
|
||||
else if (logger_name.find("monitor") != std::string::npos)
|
||||
level_str = "measurepoint";
|
||||
else
|
||||
level_str = "terminal";
|
||||
|
||||
// TLS code
|
||||
int code = g_log_code_tls;
|
||||
|
||||
const int safe_logtype = 0;
|
||||
|
||||
if (!(level == ERROR_LOG_LEVEL ||
|
||||
level == WARN_LOG_LEVEL ||
|
||||
g_debug_switch.match(logger_name, level, safe_logtype))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ★新增:限频判断(同一条日志前 5 次 1 秒一次;之后 300 秒一次)
|
||||
const std::string key = make_key(logger_name, level, code, msg);
|
||||
if (!should_emit(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "{\"processNo\":\"" << std::to_string(g_front_seg_index)
|
||||
<< "\",\"nodeId\":\"" << FRONT_INST
|
||||
<< "\",\"businessId\":\"" << extract_logger_id(logger_name)
|
||||
<< "\",\"level\":\"" << level_str
|
||||
<< "\",\"time\":\"" << now_yyyy_mm_dd_hh_mm_ss()
|
||||
<< "\",\"grade\":\"" << get_level_str(level)
|
||||
// ★建议:code 用数字(不是字符串)
|
||||
<< "\",\"code\":" << code
|
||||
<< ",\"log\":\"" << escape_json(msg) << "\"}";
|
||||
|
||||
queue_data_t connect_info;
|
||||
connect_info.strTopic = G_LOG_TOPIC;
|
||||
connect_info.strText = oss.str();
|
||||
connect_info.tag = G_LOG_TAG;
|
||||
connect_info.key = G_LOG_KEY;
|
||||
|
||||
std::lock_guard<std::mutex> lock(queue_data_list_mutex);
|
||||
queue_data_list.push_back(connect_info);
|
||||
}
|
||||
|
||||
std::string escape_json(const std::string& input) {
|
||||
std::ostringstream ss;
|
||||
for (size_t i = 0; i < input.size(); ++i) {
|
||||
switch (input[i]) {
|
||||
case '\\': ss << "\\\\"; break;
|
||||
case '"': ss << "\\\""; break;
|
||||
case '\n': ss << "\\n"; break;
|
||||
case '\r': ss << "\\r"; break;
|
||||
case '\t': ss << "\\t"; break;
|
||||
default: ss << input[i]; break;
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void close() override {
|
||||
// 可空实现
|
||||
}
|
||||
|
||||
public:
|
||||
SendAppender() {}
|
||||
virtual ~SendAppender() {
|
||||
destructorImpl();
|
||||
}
|
||||
};
|
||||
|
||||
//用来控制日志上送的静态变量定义
|
||||
std::unordered_map<std::string, SendAppender::RateState> SendAppender::s_rate_map;
|
||||
std::mutex SendAppender::s_rate_mutex;
|
||||
|
||||
//用来控制日志上送的结构
|
||||
struct LOGEntry {
|
||||
std::string id;
|
||||
std::string level; // terminal / measurepoint
|
||||
int logtype; // com / data
|
||||
int min_grade;
|
||||
int countdown;
|
||||
std::string id; //测点和装置需要的id
|
||||
std::string level; // terminal / measurepoint /process
|
||||
|
||||
int min_grade; // DEBUG / INFO / WARN / ERROR
|
||||
int countdown; // 倒计时,单位秒
|
||||
};
|
||||
|
||||
//日志上送map管理
|
||||
@@ -209,8 +332,8 @@ 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, int logtype) {
|
||||
return id + "|" + level + "|" + (logtype == 1 ? "COM" : "DATA");
|
||||
std::string build_debug_key(const std::string& id, const std::string& level) {
|
||||
return id + "|" + level + "|";
|
||||
}
|
||||
|
||||
// 外部线程中调用:每秒更新所有倒计时,0 则删除
|
||||
@@ -234,17 +357,16 @@ void update_log_entries_countdown() {
|
||||
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;
|
||||
|
||||
int type = (logtype_str == "com") ? LOGTYPE_COM : LOGTYPE_DATA;
|
||||
int grade_level = (grade == "DEBUG") ? DEBUG_LOG_LEVEL : INFO_LOG_LEVEL;
|
||||
|
||||
std::string key = build_debug_key(id, level, type);
|
||||
std::string key = build_debug_key(id, level);
|
||||
|
||||
pthread_mutex_lock(&g_log_mutex);
|
||||
|
||||
LOGEntry& entry = g_log_entries[key]; // 会自动 insert 或取已有
|
||||
entry.id = id;
|
||||
entry.level = level;
|
||||
entry.logtype = type;
|
||||
|
||||
entry.min_grade = grade_level;
|
||||
entry.countdown = 60; // 重置倒计时
|
||||
|
||||
|
||||
@@ -32,8 +32,6 @@ extern LOG_TLS_SPEC int g_log_code_tls;
|
||||
|
||||
#include "appender.h"
|
||||
|
||||
#define LOGTYPE_COM 1
|
||||
#define LOGTYPE_DATA 2
|
||||
/////////////////////////////////////////////入参验证
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
# define PRINTF_LIKE(fmt_index, first_arg) __attribute__((format(printf, fmt_index, first_arg)))
|
||||
|
||||
@@ -497,7 +497,7 @@ void Front::OnTimerThread()
|
||||
|
||||
while (!m_IsTimerCancel)
|
||||
{
|
||||
update_log_entries_countdown();
|
||||
update_log_entries_countdown();//日志上送倒计时
|
||||
|
||||
//业务超时检查
|
||||
check_device_busy_timeout();
|
||||
|
||||
@@ -1036,11 +1036,14 @@ rocketmq::ConsumeStatus myMessageCallbackrtdata(const rocketmq::MQMessageExt& ms
|
||||
|
||||
// 消息解析
|
||||
std::string devid;
|
||||
std::string devname;
|
||||
ushort line;
|
||||
bool realData = false, soeData = false;
|
||||
int limit = 0;
|
||||
int idx = 0;
|
||||
|
||||
get_terminal_name_by_terminal_id(devid, devname);
|
||||
|
||||
if (!parseJsonMessageRT(body, devid, line, realData, soeData, limit,idx)) {
|
||||
std::cerr << "Failed to parse the JSON message." << std::endl;
|
||||
DIY_ERRORLOG_CODE("process",0,LOG_CODE_JSON, "主题:%s - tag:%s的实时触发消息失败", G_MQCONSUMER_TOPIC_RT.c_str(), FRONT_INST.c_str());
|
||||
@@ -1057,7 +1060,7 @@ rocketmq::ConsumeStatus myMessageCallbackrtdata(const rocketmq::MQMessageExt& ms
|
||||
if (ClientManager::instance().get_dev_status(devid) != 1) {
|
||||
std::cout << "devid对应装置不在线: " << devid << std::endl;
|
||||
// 记录日志不响应 web 端
|
||||
DIY_ERRORLOG_CODE("process",0,LOG_CODE_COMM,"主题:%s - tag:%s的实时数据触发消息失败,装置%s不在线", G_MQCONSUMER_TOPIC_RT.c_str(),FRONT_INST.c_str(),devid.c_str());
|
||||
DIY_ERRORLOG_CODE("process",0,LOG_CODE_COMM,"主题:%s - tag:%s的实时数据触发消息失败,装置%s不在线", G_MQCONSUMER_TOPIC_RT.c_str(),FRONT_INST.c_str(),devname.c_str());
|
||||
return rocketmq::CONSUME_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user