
#include "../log4cplus/logger.h"
#include "../log4cplus/configurator.h"
#include "../log4cplus/fileappender.h"
#include "../log4cplus/layout.h"
#include "../log4cplus/ndc.h"
//#include "../log4cplus/log4.h"
#include "../log4cplus/spi/loggingevent.h"
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <ctime>
#include <sstream>
#include <pthread.h>
#include <unistd.h>
#include <cstring>
//目录创建
#include <sys/stat.h>
#include <sys/types.h>
#include "../json/mms_json_inter.h"
#include "../mms/rdb_client.h"
#include "../include/node.h"//lnk20241223

#include "../log4cplus/log4.h"//后移防止min/max定义冲突
///////////////////////////////////////////////lnk20260303添加日志上送控制
#include <unordered_map>
#include <chrono>
#include <mutex>
#include <atomic>
#include <memory>

struct LogLevelCache {      //记录日志等级的缓存，减少频繁访问全局map的开销
    std::unordered_map<std::string, int> term_min; // terminal_id -> min level
    std::unordered_map<std::string, int> mp_min;   // mp_id -> min level
};

// append线程只读，不加锁
static std::shared_ptr<LogLevelCache> g_level_cache_sp;

///////////////////////////////////////////////

//用来控制日志上送的结构
struct LOGEntry {
    std::string id;
    std::string level; // terminal / measurepoint
    int code;       //code
    int min_grade;  //允许上送的最低日志等级
    int countdown;  //自动关闭的倒计时，单位秒
};

//日志上送map管理
std::map<std::string, LOGEntry> g_log_entries;
pthread_mutex_t g_log_mutex = PTHREAD_MUTEX_INITIALIZER;
/////////////////////////////////////////////外部定义
extern unsigned int	g_node_id;
extern int          g_front_seg_index;
extern std::string  FRONT_INST;
extern char			subdir[128];
extern node_t*      g_node;

//mq
extern QMutex kafka_data_list_mutex; //Kafka发送数据锁
extern QList<Ckafka_data_t> kafka_data_list; //kafka发送数据链表

//辅助函数
extern std::string intToString(int number);

//日志主题
extern std::string G_LOG_TOPIC;

// 日志限流配置
extern int G_LOG_RATE_RESET_SEC;
extern int G_LOG_RATE_LIMIT_SEC;
extern int G_LOG_RATE_KEEP_ALL_MS;
extern int G_LOG_RATE_KEEP_BURST_MS;
extern int G_LOG_RATE_KEEP_BURST_COUNT;
extern int G_LOG_RATE_KEEP_HIGHFREQ_COUNT;

/////////////////////////////////////////////////////////
//log4命名空间
using namespace log4cplus;
using namespace log4cplus::helpers;
///////////////////////////////////////////////////////////////
static std::string extract_logger_id(const std::string& logger_name);

////////////////////////////////////////////////////////辅助函数



///////////////////////////////////////////////////////lnk20260303添加日志上送控制
//用于在台账中查询日志上送控制项的日志等级字符串转换为整数
static int int_to_loglevel(int v, int default_level = WARN_LOG_LEVEL)
{
    switch (v) {
        case 0: return ERROR_LOG_LEVEL;
        case 1: return WARN_LOG_LEVEL;
        case 2: return INFO_LOG_LEVEL;
        case 3: return DEBUG_LOG_LEVEL;
        default: return default_level;
    }
}
// 构建日志等级缓存，减少 append 线程访问全局 map 的开销
static LogLevelCache* build_cache_unlocked()
{
    LogLevelCache* nc = new LogLevelCache;

    // 没 node / 没 clients：返回空 cache（查不到会兜底 WARN）
    if (!g_node || g_node->n_clients <= 0 || !g_node->clients) {
        return nc;
    }

    // 你 LD_info 是固定 10 个就用 10；如果不是，改成实际长度
    const int MAX_LD = 10;

    for (int iedno = 0; iedno < g_node->n_clients; ++iedno) {
        ied_t* ied = g_node->clients[iedno];
        if (!ied || !ied->usr_ext) continue;

        ied_usr_t* ied_usr = (ied_usr_t*)ied->usr_ext;

        // terminal_id 必须有效
        const char* tid = ied_usr->terminal_id;
        if (!tid || tid[0] == '\0') continue;

        const std::string terminal_id(tid);

        // 装置级阈值：0~3 -> log4cplus level（默认 WARN）
        const int term_lv = int_to_loglevel(ied_usr->log_level, WARN_LOG_LEVEL);
        nc->term_min[terminal_id] = term_lv;

        // 监测点阈值：若非法/缺失，兜底用装置级 term_lv
        for (int i = 0; i < MAX_LD; ++i) {
            const char* mp = ied_usr->LD_info[i].mp_id;
            if (!mp || mp[0] == '\0') continue;

            const std::string mp_id(mp);

            // mp 的 log_level 优先；非法则用 term_lv
            const int mp_lv = int_to_loglevel(ied_usr->LD_info[i].log_level, term_lv);
            nc->mp_min[mp_id] = mp_lv;
        }
    }

    return nc;
}
//用于更新日志等级缓存的函数，获取最新的日志上送控制项并更新到缓存中，调用时需持锁
void refresh_log_level_cache_locked()
{
    std::shared_ptr<LogLevelCache> nc(build_cache_unlocked());
    std::atomic_store(&g_level_cache_sp, nc);
}
const int LOGTYPE_DEFAULT = LOG_CODE_OTHER; // 默认日志类型，表示不区分具体类型的日志上送控制
static const int LOGTYPE_WILDCARD = 999;    // 用于匹配任意日志类型的特殊值
static const char* ID_WILDCARD = "all";     // 用于匹配任意 ID 的特殊值

static std::string build_debug_key(const std::string& id,
                                   const std::string& level, // terminal/measurepoint/process
                                   int code)              // 日志类型
{
    std::ostringstream oss;
    oss << id << "|" << level << "|" << code;
    return oss.str();
}

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 code,
                                 int level_val)
{
    pthread_mutex_lock(&g_log_mutex);

    // 1) 精确
    if (find_entry_allow(build_debug_key(id, level_str, code), level_val)) {
        pthread_mutex_unlock(&g_log_mutex);
        return true;
    }
    // 2) logtype 通配
    if (find_entry_allow(build_debug_key(id, level_str, LOGTYPE_WILDCARD), level_val)) {
        pthread_mutex_unlock(&g_log_mutex);
        return true;
    }
    // 3) id 通配
    if (find_entry_allow(build_debug_key(ID_WILDCARD, level_str, code), level_val)) {
        pthread_mutex_unlock(&g_log_mutex);
        return true;
    }
    // 4) 双通配
    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;
}

static int get_min_send_level_cached(const std::string& level_str, const std::string& logger_name)
{
    const int DEFAULT_LEVEL = WARN_LOG_LEVEL;
    if (level_str == "process") return DEFAULT_LEVEL;

    const std::string id = extract_logger_id(logger_name); //terminal.<id> / monitor.<mp>
    if (id.empty()) return DEFAULT_LEVEL;

    std::shared_ptr<LogLevelCache> c = std::atomic_load(&g_level_cache_sp);
    if (!c) return DEFAULT_LEVEL;

    if (level_str == "terminal") {
        auto it = c->term_min.find(id);
        return (it != c->term_min.end()) ? it->second : DEFAULT_LEVEL;
    }
    if (level_str == "measurepoint") {
        auto it = c->mp_min.find(id);
        return (it != c->mp_min.end()) ? it->second : DEFAULT_LEVEL;
    }
    return DEFAULT_LEVEL;
}
///////////////////////////////////////////////////////lnk20260303添加日志上送控制
std::string get_front_type_from_subdir() {
    if (std::strstr(subdir, "cfg_3s_data") != NULL)
        return "realTime";
    else if (std::strstr(subdir, "cfg_soe_comtrade") != NULL)
        return "comtrade";
    else if (std::strstr(subdir, "cfg_pqdif_data") != NULL)
        return "PQDIF";
    else if (std::strstr(subdir, "cfg_recallhis_data") != NULL)
        return "recall";
    else if (std::strstr(subdir, "cfg_stat_data") != NULL)
        return "stat";
    else
        return "unknown";
}

// 递归创建目录
bool create_directory_recursive(const std::string& path) {
    size_t pos = 0;
    std::string current;
    while (pos != std::string::npos) {
        pos = path.find('/', pos + 1);
        current = path.substr(0, pos);
        if (!current.empty() && access(current.c_str(), F_OK) != 0) {
            if (mkdir(current.c_str(), 0755) != 0) {
                perror(("mkdir failed: " + current).c_str());
                return false;
            }
        }
    }
    return true;
}
//////////////////////////////////////////////////////////////////////
std::string extract_logger_id(const std::string& logger_name) {
    if (logger_name == "process") return "process";
    size_t pos = logger_name.find('.');
    if (pos == std::string::npos) return "";
    // 取第一个 '.' 后面的全部：terminal.<id> / monitor.<mp>
    return logger_name.substr(pos + 1);
}

std::string get_level_str(int level) {
    switch (level) {
        case 10000: return "DEBUG";
        case 20000: return "NORMAL";  // 或 "INFO" 根据你业务定义
        case 30000: return "WARN";
        case 40000: return "ERROR";
        default:    return "UNKNOWN";
    }
}
//////////////////////////////////////////////////////////////////////
TypedLogger::TypedLogger() {}
TypedLogger::TypedLogger(const Logger& l, int t) : logger(l), code(t) {}

DebugSwitch::DebugSwitch() : debug_open(false), min_level(WARN_LOG_LEVEL) {}
void DebugSwitch::open() { debug_open = true; }
void DebugSwitch::close() {
    debug_open = false;
    targets.clear();
    type_enable.clear();
}
void DebugSwitch::set_target(const std::string& name) { targets.insert(name); }
void DebugSwitch::set_level(int level) { min_level = level; }
void DebugSwitch::enable_type(int type) { type_enable[type] = true; }
void DebugSwitch::disable_type(int type) { type_enable[type] = false; }

bool DebugSwitch::match(const std::string& logger_name, int level, int logtype) {
    if (!debug_open) return false;
    if (level < min_level) return false;
    if (type_enable.count(logtype) && !type_enable[logtype]) return false;
    std::set<std::string>::iterator it;
    for (it = targets.begin(); it != targets.end(); ++it) {
        if (logger_name.find(*it) != std::string::npos)
            return true;
    }
    return false;
}

std::map<std::string, TypedLogger> logger_map;
DebugSwitch g_debug_switch;

// ★新增：定义 TLS 变量，默认 0
LOG_TLS int g_log_code_tls = 0;

class SendAppender : public Appender {
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 if (logger_name.find("terminal") != std::string::npos)
            level_str = "terminal";
        else
            level_str = "process";

        int code = g_log_code_tls;          // TLS code
        int safe_logtype = code;            // ★关键：用 code 当 logtype 维度

        bool allow_send = false;
        int min_send_level = get_min_send_level_cached(level_str, logger_name);

        // ① 高于台账阈值：直接上送
        if (level >= min_send_level) {
            allow_send = true;
        } else {
            // ② 低等级：默认不上送，除非命令打开
            std::string ctrl_id;
            if (level_str == "process") ctrl_id = "process";
            else ctrl_id = extract_logger_id(logger_name);

            if (!ctrl_id.empty()) {
                allow_send = allow_low_level_send(ctrl_id, level_str, safe_logtype, level);
            }
        }

        if (!allow_send) return;

        // ③ 限频：同一条日志
        const std::string rkey = make_key(logger_name, level, code, msg);
            
        uint64_t suppressed_before_emit = 0;
        if (!should_emit(rkey, suppressed_before_emit)) return;
            
        // 如果本次输出前压掉过日志，则在 log 文本后追加统计
        std::string final_msg = msg;
        if (suppressed_before_emit > 0) {
            std::ostringstream suppressed_oss;
            suppressed_oss << msg << " 【已过滤重复同类日志 "
                           << suppressed_before_emit
                           << " 条】";
            final_msg = suppressed_oss.str();
        }

        std::string business_id = extract_logger_id(logger_name);
        std::string front_type  = get_front_type_from_subdir();

        std::ostringstream oss;
        oss << "{\"processNo\":\"" << intToString(g_front_seg_index)
            << "\",\"nodeId\":\"" << escape_json(FRONT_INST)
            << "\",\"businessId\":\"" << escape_json(business_id)
            << "\",\"level\":\"" << escape_json(level_str)
            << "\",\"grade\":\"" << escape_json(get_level_str(level))
            << "\",\"logtype\":\"" << safe_logtype
            << "\",\"frontType\":\"" << escape_json(front_type)
            << "\",\"code\":" << code
            << ",\"log\":\"" << escape_json(final_msg) << "\"}";
            
        Ckafka_data_t connect_info;
        connect_info.strTopic = QString::fromStdString(G_LOG_TOPIC);
        connect_info.mp_id     = QString::fromStdString(business_id);
        connect_info.strText  = QString::fromStdString(oss.str());
            
        kafka_data_list_mutex.lock();
        kafka_data_list.append(connect_info);
        kafka_data_list_mutex.unlock();
    }

    std::string escape_json(const std::string& input) {
        std::ostringstream ss;
        for (unsigned int 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();
    }

    virtual void close() {
        // 可空实现
    }

public:
    SendAppender() {}
    virtual ~SendAppender() {
        destructorImpl();  // 重要！释放 log4cplus 基类资源
    }
//////////////////////////////////////////////////////////////////20260303添加日志上送控制 - 频率限制实现
private:
    struct RateState {
        uint64_t pass_count;          // 当前周期内已放行条数
        uint64_t suppressed_count;    // 当前被抑制条数
        std::chrono::steady_clock::time_point last_emit;
        std::chrono::steady_clock::time_point last_seen;
        std::chrono::steady_clock::time_point last_reset;
        bool has_emit;

        RateState()
            : pass_count(0),
              suppressed_count(0),
              last_emit(),
              last_seen(),
              last_reset(),
              has_emit(false) {}
    };

    static std::unordered_map<std::string, RateState> s_rate_map;
    static std::mutex s_rate_mutex;

    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();
    }

    static bool should_emit(const std::string& key, uint64_t& suppressed_before_emit) {
        using namespace std::chrono;

        const auto now = steady_clock::now();
        suppressed_before_emit = 0;

        std::lock_guard<std::mutex> lk(s_rate_mutex);
        RateState& st = s_rate_map[key];

        const int RESET_SEC = G_LOG_RATE_RESET_SEC ;   // 1小时重置
        const int LIMIT_SEC = G_LOG_RATE_LIMIT_SEC ;     // 进入限流后：多久发1条 主要控制中频和高频那些，低频的都直接放行了

        // 初始化 / 强制每小时重置
        if (st.last_reset.time_since_epoch().count() == 0) {
            st.last_reset = now;
        } else {
            auto since_reset = duration_cast<seconds>(now - st.last_reset).count();
            if (since_reset >= RESET_SEC) { //重置周期
                st = RateState();
                st.last_reset = now;
            }
        }

        // 计算当前频率档位（按“本次与上次看到该key的间隔”判断）
        // >=60秒/条：全部保留
        // [1秒, 60秒)：保留前60条，然后1分钟1条
        // <1秒：保留前10条，然后1分钟1条
        int allow_burst = 0;

        if (st.last_seen.time_since_epoch().count() == 0) {
            // 第一次看到，先按“全部保留”处理
            allow_burst = -1;
        } else {
            auto gap_ms = duration_cast<milliseconds>(now - st.last_seen).count();

            if (gap_ms >= G_LOG_RATE_KEEP_ALL_MS) { //什么时候不需要限流    //低频  //如果这里设置的很低，就不会限流
                allow_burst = -1;     // 全部保留
            } else if (gap_ms >= G_LOG_RATE_KEEP_BURST_MS) {
                allow_burst = G_LOG_RATE_KEEP_BURST_COUNT;     // 前60条    //中频  //如果这里设置的比低频低，也不会生效
            } else {
                allow_burst = G_LOG_RATE_KEEP_HIGHFREQ_COUNT;      // 前10条 //高频
            }
        }

        st.last_seen = now;

        // 档位1：全部保留
        if (allow_burst == -1) {
            suppressed_before_emit = st.suppressed_count;
            st.suppressed_count = 0;
            st.pass_count++;
            st.last_emit = now;
            st.has_emit = true;
            return true;
        }

        // 档位2/3：先放前N条
        if (st.pass_count < (uint64_t)allow_burst) {
            suppressed_before_emit = st.suppressed_count;
            st.suppressed_count = 0;
            st.pass_count++;
            st.last_emit = now;
            st.has_emit = true;
            return true;
        }

        // 超过前N条后：进入 1分钟1条
        if (!st.has_emit) {
            suppressed_before_emit = st.suppressed_count;
            st.suppressed_count = 0;
            st.pass_count++;
            st.last_emit = now;
            st.has_emit = true;
            return true;
        }

        auto elapsed = duration_cast<seconds>(now - st.last_emit).count();
        if (elapsed >= LIMIT_SEC) {
            suppressed_before_emit = st.suppressed_count;
            st.suppressed_count = 0;
            st.pass_count++;
            st.last_emit = now;
            st.has_emit = true;
            return true;
        }

        // 本条被抑制
        st.suppressed_count++;
        return false;
    }
};
//////////////////////////////////////////////////////////////////20260303添加日志上送控制 - 频率限制实现
std::unordered_map<std::string, SendAppender::RateState> SendAppender::s_rate_map;
std::mutex SendAppender::s_rate_mutex;

// 外部线程中调用：每秒更新所有倒计时，0 则删除
void update_log_entries_countdown() {
    pthread_mutex_lock(&g_log_mutex);
    std::map<std::string, LOGEntry>::iterator it = g_log_entries.begin();
    while (it != g_log_entries.end()) {
        if (it->second.countdown > 0) {
            it->second.countdown--;
            if (it->second.countdown == 0) {
                std::cout << "[LOG] debug日志上送自动关闭: " << it->first << std::endl;
                it = g_log_entries.erase(it);
                continue;
            }
        }
        ++it;
    }
    pthread_mutex_unlock(&g_log_mutex);
}

void process_log_command(const std::string& id,
                         const std::string& level,
                         const std::string& grade,
                         int code)
{
    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, code);

    pthread_mutex_lock(&g_log_mutex);
    LOGEntry& entry = g_log_entries[key];
    entry.id = id;
    entry.level = level;
    entry.code = code;
    entry.min_grade = grade_level;
    entry.countdown = 60;
    pthread_mutex_unlock(&g_log_mutex);
}

Logger init_logger(const std::string& full_name, const std::string& file_dir, const std::string& base_file, SharedAppenderPtr fileAppender) {
    create_directory_recursive(file_dir);

    Logger logger = Logger::getInstance(full_name);
    if (!fileAppender) {
        std::string file_path = file_dir + "/" + base_file + ".log";
        fileAppender = SharedAppenderPtr(new RollingFileAppender(file_path, 1 * 1024 * 1024, 2));
        fileAppender->setLayout(std::auto_ptr<Layout>(
            new PatternLayout("%D{%Y-%m-%d %H:%M:%S} [%p] [%c] %m%n")));
    }

    SharedAppenderPtr sendAppender(new SendAppender());
    logger.addAppender(fileAppender);
    logger.addAppender(sendAppender);
    logger.setLogLevel(DEBUG_LOG_LEVEL);
    return logger;
}

// 重载版本：无 Appender 传入时调用上面的实现
log4cplus::Logger init_logger(const std::string& full_name,
                              const std::string& file_dir,
                              const std::string& base_file) {
    return init_logger(full_name, file_dir, base_file,
                       log4cplus::SharedAppenderPtr());  // 空指针
}

//进程的日志
void init_logger_process() {
    std::string base_dir = std::string("/FeProject/") + subdir + "/processNo" + intToString(g_front_seg_index) + "/log";
    logger_map["process"] = TypedLogger(init_logger(std::string("process"), base_dir, std::string("process")), LOGTYPE_DEFAULT);
    std::cout << "process log init ok" << std::endl;
}

//终端的日志
void init_loggers_bydevid(const char* dev_id) 
{
    if (!dev_id) return;

    std::string terminal_id(dev_id);  // 转为 std::string
    std::string base_dir = std::string("/FeProject/") + subdir + "/processNo" + intToString(g_front_seg_index) + "/log";

    ied_t* ied = NULL;
	int			iedno;
	ied_usr_t* ied_usr = NULL;

    for (iedno = 0; iedno < g_node->n_clients; iedno++) {
        ied = g_node->clients[iedno];

        if (!ied || !ied->usr_ext) {
            std::cout << "ied No."<< iedno << " is null" << std::endl;
            continue;
        }

        ied_usr = (ied_usr_t*)ied->usr_ext;

        //跳过不匹配的终端
        if (strcmp(ied_usr->terminal_id, dev_id) != 0) continue;

        const char* ip_cstr = (ied->channel[0].addr_str != NULL) ? ied->channel[0].addr_str : "unknown";

        std::string ip_str(ip_cstr);

        std::string device_dir = base_dir + "/" + ip_str;

        std::string device_key = std::string("terminal.") + dev_id;

        // 添加判断：终端日志 logger 是否已存在
        if (logger_map.find(device_key) == logger_map.end()) {

            // 所有终端日志（com 和 data）写到同一个 device 日志文件中
            std::string file_path_t = device_dir + "/" + dev_id + ".log";

            // 共用一个 appender 实例
            SharedAppenderPtr device_appender = SharedAppenderPtr(new RollingFileAppender(file_path_t, 1 * 1024 * 1024, 2));
            device_appender->setLayout(std::auto_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); //用终端id作为日志文件名
            logger_map[device_key]  = TypedLogger(device_logger, LOGTYPE_DEFAULT);

            DIY_INFOLOG_CODE(device_key.c_str(),1,LOG_CODE_OTHER,"【NORMAL】终端id:%s终端级日志初始化完毕", ied_usr->terminal_id);
        }

        // 初始化监测点
        // 监测点 logger 名称格式：monitor.<mp_id>
        for (int i = 0; i < 10; ++i) {
            if (strlen(ied_usr->LD_info[i].mp_id) > 0){
                std::ostringstream mon_key, mon_path, mon_name;
                mon_key << "monitor." << ied_usr->LD_info[i].mp_id;
                mon_path << device_dir << "/monitor" << i;//终端路径下用monitor+序号作为目录
                mon_name << ied_usr->LD_info[i].mp_id;

                // 添加判断：监测点 logger 是否已存在
                if (logger_map.find(mon_key.str()) == logger_map.end()) {

                    // 所有监测点日志（com 和 data）写到同一个 monitor 日志文件中
                    std::string file_path_m = mon_path.str() + "/" + mon_name.str() + ".log";

                    // 共用一个 appender 实例
                    SharedAppenderPtr monitor_appender = SharedAppenderPtr(new RollingFileAppender(file_path_m, 1 * 1024 * 1024, 2));
                    monitor_appender->setLayout(std::auto_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_DEFAULT);

                    DIY_INFOLOG_CODE(mon_key.str().c_str(),2,LOG_CODE_OTHER,"【NORMAL】监测点:%s - id:%s监测点级日志初始化完毕", ied_usr->LD_info[i].name,ied_usr->LD_info[i].mp_id);
                }
            }
            
        }

        break; // 只匹配一个 terminal_id
    }

    //lnk20260303添加日志上送控制 - 初始化时构建日志等级缓存
    refresh_log_level_cache_locked();
}

void init_loggers() {
    std::string base_dir = std::string("/FeProject/") + subdir + "/processNo" + intToString(g_front_seg_index) + "/log";

    ied_t* ied = NULL;
	int			iedno;
	ied_usr_t* ied_usr = NULL;

    for (iedno = 0; iedno < g_node->n_clients; iedno++) {
        ied = g_node->clients[iedno];

        if (!ied || !ied->usr_ext) {
            std::cout << "ied No."<< iedno << " is null" << std::endl;
            continue;
        }

        ied_usr = (ied_usr_t*)ied->usr_ext;

        const char* ip_cstr = (ied->channel[0].addr_str != NULL) ? ied->channel[0].addr_str : "unknown";

        std::string ip_str(ip_cstr);

        std::string device_dir = base_dir + "/" + ip_str;

        std::string device_key = std::string("terminal.") + ied_usr->terminal_id;

        // 所有终端日志（com 和 data）写到同一个 device 日志文件中
        std::string file_path_t = device_dir + "/" + ied_usr->terminal_id + ".log";

        // 共用一个 appender 实例
        SharedAppenderPtr device_appender = SharedAppenderPtr(new RollingFileAppender(file_path_t, 1 * 1024 * 1024, 2));
        device_appender->setLayout(std::auto_ptr<Layout>(new PatternLayout("%D{%Y-%m-%d %H:%M:%S} [%p] [%c] %m%n")));

        Logger device_logger = init_logger(device_key, device_dir, ied_usr->terminal_id, device_appender); //用终端id作为日志文件名

        logger_map[device_key]  = TypedLogger(device_logger, LOGTYPE_DEFAULT);

        DIY_INFOLOG_CODE(device_key.c_str(),1,LOG_CODE_OTHER,"【NORMAL】终端id:%s终端级日志初始化完毕", ied_usr->terminal_id);

        // 初始化监测点
        // 监测点 logger 名称格式：monitor.<mp_id>
        for (int i = 0; i < 10; ++i) {
            if (strlen(ied_usr->LD_info[i].mp_id) > 0){
                std::ostringstream mon_key, mon_path, mon_name;
                mon_key << "monitor." << ied_usr->LD_info[i].mp_id;

                mon_path << device_dir << "/monitor" << i;//终端路径下用monitor+序号作为目录
                mon_name << ied_usr->LD_info[i].mp_id;

                std::string file_path_m = mon_path.str() + "/" + mon_name.str() + ".log";

                // 共用一个 appender 实例
                SharedAppenderPtr monitor_appender = SharedAppenderPtr(new RollingFileAppender(file_path_m, 1 * 1024 * 1024, 2));
                monitor_appender->setLayout(std::auto_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_DEFAULT);

                DIY_INFOLOG_CODE(mon_key.str().c_str(),2,LOG_CODE_OTHER,"【NORMAL】监测点:%s - id:%s监测点级日志初始化完毕", ied_usr->LD_info[i].name,ied_usr->LD_info[i].mp_id);

            }
            
        }

    }
    //lnk20260303添加日志上送控制 - 初始化时构建日志等级缓存
    refresh_log_level_cache_locked();
}

void remove_loggers_by_terminal_id(const char* terminal_id_cstr) {
    if (!g_node || !terminal_id_cstr) return;

    std::string terminal_id(terminal_id_cstr);  // 转为 std::string

    for (int iedno = 0; iedno < g_node->n_clients; ++iedno) {
        ied_t* ied = g_node->clients[iedno];
        if (!ied || !ied->usr_ext) continue;

        ied_usr_t* ied_usr = (ied_usr_t*)ied->usr_ext;
        if (strcmp(ied_usr->terminal_id, terminal_id.c_str()) != 0) continue;

        // 删除终端日志 logger
        std::string terminal_key = "terminal." + terminal_id;;

        if (logger_map.count(terminal_key)) {
            logger_map[terminal_key].logger.removeAllAppenders();
            logger_map.erase(terminal_key);
        }

        // 删除监测点日志 logger
        for (int i = 0; i < 10; ++i) {
            const char* mp_id = ied_usr->LD_info[i].mp_id;
            if (strlen(mp_id) > 0) {
                std::string mon_key = std::string("monitor.") + mp_id;

                if (logger_map.count(mon_key)) {
                    logger_map[mon_key].logger.removeAllAppenders();
                    logger_map.erase(mon_key);
                }

            }
        }

        std::cout << "[LOG] Logger for terminal_id=" << terminal_id << " removed.\n";
        break; // 找到匹配终端后退出
    }
}



#ifdef __cplusplus
extern "C" {
#endif

    // 公共函数
    void log4_log_with_level(const char* key, const char* msg, int level) {
        std::map<std::string, TypedLogger>::iterator it = logger_map.find(key);
        if (it == logger_map.end()) return;
    
        Logger logger = it->second.logger;
        switch (level) {
            case 0: LOG4CPLUS_DEBUG(logger, msg); break;
            case 1: LOG4CPLUS_INFO(logger, msg);  break;
            case 2: LOG4CPLUS_WARN(logger, msg);  break;
            case 3: LOG4CPLUS_ERROR(logger, msg); break;
            default: break;
        }
    }
    
    // 四个包装函数
    void log_debug(const char* key, const char* msg) { log4_log_with_level(key, msg, 0); }
    void log_info (const char* key, const char* msg) { log4_log_with_level(key, msg, 1); }
    void log_warn (const char* key, const char* msg) { log4_log_with_level(key, msg, 2); }
    void log_error(const char* key, const char* msg) { log4_log_with_level(key, msg, 3); }

    void send_reply_to_kafka_c(const char* guid, const char* step, const char* result) {
        send_reply_to_kafka(std::string(guid), std::string(step), std::string(result));
    }

    void send_reply_to_kafka_recall_c(const char* guid, const char* step, const char* result,const char* lineIndex,const char* recallStartDate,const char* recallEndDate) {
        send_reply_to_kafka_recall(std::string(guid), std::string(step), std::string(result),std::string(lineIndex), std::string(recallStartDate), std::string(recallEndDate));
    }

    //标准化日志接口
    void format_log_msg(char* buf, size_t buf_size, const char* fmt, ...) {
        // 写入时间
        time_t now = time(NULL);
        struct tm tm_info;
        localtime_r(&now, &tm_info);
        strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S ", &tm_info);  // 时间+空格

        // 处理可变参数并写入剩余内容
        va_list args;
        va_start(args, fmt);
        vsnprintf(buf + strlen(buf), buf_size - strlen(buf), fmt, args);
        va_end(args);
    }
    
#ifdef __cplusplus
}
#endif


/*
int main() {
    initialize();
    init_loggers();

    LOG4CPLUS_INFO(logger_map["process.1.data"].logger, "程序启动，PID=" << getpid());

    LOG4CPLUS_WARN(logger_map["terminal.192.168.1.1.com"].logger, "串口异常，尝试重连");
    LOG4CPLUS_INFO(logger_map["terminal.192.168.1.1.data"].logger, "终端运行状态正常");
    LOG4CPLUS_DEBUG(logger_map["measurepoint.192.168.1.1.monitor1.data"].logger, "电压测量值=220.1V");

    process_log_command("192.168.1.1.monitor1", "measurepoint", "DEBUG", "data");
    LOG4CPLUS_DEBUG(logger_map["measurepoint.192.168.1.1.monitor1.data"].logger, "频率测量值=50.0Hz");

    sleep(65);
    LOG4CPLUS_ERROR(logger_map["terminal.192.168.1.2.data"].logger, "终端掉线");

    return 0;
}
*/
