增加了日志功能,修复了bug

This commit is contained in:
zjk
2025-05-19 02:14:11 +08:00
parent 9e1819cd75
commit 50a496e3e2
4 changed files with 222 additions and 20 deletions
+163
View File
@@ -54,6 +54,11 @@ void HttpServer::handleWebSocketEvent(struct mg_connection* c, int ev, void* ev_
}
}
}
} else if (ev == MG_EV_WS_MSG) {
// WebSocket消息处理
struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
std::string msg(wm->data.buf, wm->data.len);
handleLogRequest(c, msg);
} else if (ev == MG_EV_HTTP_MSG) {
// HTTP请求处理
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
@@ -216,11 +221,18 @@ bool HttpServer::serverThreadFunc() {
// 定期推送系统数据
static uint64_t last_push_time = 0;
static uint64_t last_log_check_time = 0;
uint64_t now = mg_millis();
if (now - last_push_time > 1000) { // 每秒推送一次
last_push_time = now;
pushSystemData();
}
if (now - last_log_check_time > 500) { // 每500ms检查一次日志
last_log_check_time = now;
monitorLogFile();
}
}
return true;
}
@@ -550,3 +562,154 @@ void HttpServer::stop() {
bool HttpServer::isRunning() const {
return running_;
}
void HttpServer::handleLogRequest(struct mg_connection* c, const std::string& msg) {
try {
Json::Value json;
Json::CharReaderBuilder builder;
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
const char* msg_cstr = msg.c_str();
std::string errors;
if (!reader->parse(msg_cstr, msg_cstr + msg.size(), &json, &errors)) {
LOG_F(ERROR, "Failed to parse log request JSON: %s", errors.c_str());
return;
}
std::string type = json["type"].asString();
if (type == "get_logs") {
int page = json["page"].asInt();
int pageSize = json["pageSize"].asInt();
std::string level = json["filter"]["level"].asString();
std::string search = json["filter"]["search"].asString();
bool reverse = json["reverse"].asBool(); // 新增参数,控制是否倒序显示
auto logs = readLogFile(page, pageSize, level, search);
Json::Value response;
response["type"] = "log";
response["page"] = page;
response["pageSize"] = pageSize;
response["total"] = logs.size(); // 返回总条数
response["content"] = Json::arrayValue;
if (reverse) {
// 如果需要倒序,反转日志顺序
for (auto it = logs.rbegin(); it != logs.rend(); ++it) {
response["content"].append(*it);
}
} else {
// 否则按原顺序返回
for (const auto& log : logs) {
response["content"].append(log);
}
}
Json::StreamWriterBuilder builder;
std::string responseStr = Json::writeString(builder, response);
mg_ws_send(c, responseStr.c_str(), responseStr.size(), WEBSOCKET_OP_TEXT);
}
} catch (const std::exception& e) {
LOG_F(ERROR, "Error handling log request: %s", e.what());
}
}
std::vector<std::string> HttpServer::readLogFile(int page, int pageSize, const std::string& level, const std::string& search) {
std::vector<std::string> logs;
std::ifstream file(m_logFilePath);
if (!file.is_open()) {
LOG_F(ERROR, "Failed to open log file: %s", m_logFilePath.c_str());
return logs;
}
// 获取文件大小
file.seekg(0, std::ios::end);
std::streampos fileSize = file.tellg();
file.seekg(0, std::ios::beg);
std::string line;
std::vector<std::string> filteredLogs;
// 读取并过滤所有行
while (std::getline(file, line)) {
// 过滤日志级别和搜索内容
if ((level.empty() || level == "ALL" || line.find(level) != std::string::npos) &&
(search.empty() || line.find(search) != std::string::npos)) {
filteredLogs.push_back(line);
}
}
// 计算总页数
int totalLines = filteredLogs.size();
// 如果没有内容,直接返回空
if (totalLines == 0) {
return logs;
}
// 计算当前页的起始和结束索引
int start = std::max(0, totalLines - (page * pageSize));
int end = std::max(0, totalLines - ((page - 1) * pageSize));
// 返回当前页的日志(已经是倒序的)
return std::vector<std::string>(filteredLogs.begin() + start, filteredLogs.begin() + end);
}
void HttpServer::monitorLogFile() {
static std::streampos lastPos = 0;
std::ifstream file(m_logFilePath);
if (!file.is_open()) {
LOG_F(ERROR, "Failed to open log file for monitoring: %s", m_logFilePath.c_str());
return;
}
// 获取文件大小
file.seekg(0, std::ios::end);
std::streampos currentPos = file.tellg();
// 如果文件大小没有变化,直接返回
if (currentPos == lastPos) {
return;
}
// 如果是第一次读取或文件被截断,从头开始读
if (currentPos < lastPos) {
lastPos = 0;
}
// 移动到上次读取的位置
file.seekg(lastPos);
std::string line;
std::vector<std::string> newLogs;
// 读取新的日志行
while (std::getline(file, line)) {
newLogs.push_back(line);
}
// 更新最后读取位置
lastPos = currentPos;
// 如果有新日志,推送给所有客户端
if (!newLogs.empty()) {
Json::Value json;
json["type"] = "new_log";
json["content"] = Json::arrayValue;
// 只保留最新的100行
size_t start = newLogs.size() > 100 ? newLogs.size() - 100 : 0;
for (size_t i = start; i < newLogs.size(); ++i) {
json["content"].append(newLogs[i]);
}
Json::StreamWriterBuilder builder;
std::string msg = Json::writeString(builder, json);
std::lock_guard<std::mutex> lock(ws_connections_mutex_);
for (auto c : ws_connections_) {
mg_ws_send(c, msg.c_str(), msg.size(), WEBSOCKET_OP_TEXT);
}
}
}
+7 -7
View File
@@ -51,6 +51,12 @@ public:
// 监控日志文件变化并推送新内容
void monitorLogFile();
// 处理日志请求
void handleLogRequest(struct mg_connection* c, const std::string& msg);
// 读取日志文件
std::vector<std::string> readLogFile(int page, int pageSize, const std::string& level, const std::string& search);
private:
// WebSocket事件处理函数
void handleWebSocketEvent(struct mg_connection* c, int ev, void* ev_data, void* fn_data);
@@ -72,12 +78,6 @@ private:
std::vector<mg_connection*> ws_connections_; // WebSocket连接列表
std::unordered_map<mg_connection*, uint64_t> ws_last_io_time_; // 连接最后活动时间
// 读取日志文件
std::vector<std::string> readLogFile(int page, int pageSize, const std::string& level, const std::string& search);
// 处理WebSocket消息
void handleWebSocketMessage(struct mg_connection* c, const std::string& msg);
// 日志文件相关
std::string m_logFilePath = "pPowerManger.log";
std::ifstream m_logFile;
@@ -87,4 +87,4 @@ private:
};
#endif // HTTP_SERVER_H
#endif // HTTP_SERVER_H
+14 -1
View File
@@ -213,7 +213,11 @@ body {
<h1>Power Manager System</h1>
<div class="status-bar">
<div class="status-info">
<span>🟢 系统状态: 运行中</span>
<span>🟢 系统状态: <span id="systemStatus">运行中</span></span>
<span>⚡ 应用频率: <span id="appFreq">0</span> Hz</span>
<span>📡 通信频率: <span id="commFreq">0</span> Hz</span>
<span>💻 CPU负载: <span id="cpuLoad">0</span>%</span>
<span>⏱️ 迭代间隔: <span id="timeSinceIterate">0</span>ms</span>
<span>🕒 更新时间: <time id="updateTime">2025-05-18 15:52</time></span>
</div>
</div>
@@ -243,6 +247,15 @@ function initWebSocket() {
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('收到系统数据:', data);
// 更新MOOSDB信息
if (data.moosdb) {
document.getElementById('appFreq').textContent = data.moosdb.appFreq.toFixed(2);
document.getElementById('commFreq').textContent = data.moosdb.commFreq.toFixed(2);
document.getElementById('cpuLoad').textContent = data.moosdb.cpuLoad.toFixed(1);
document.getElementById('timeSinceIterate').textContent = data.moosdb.timeSinceIterate.toFixed(0);
}
updateTime();
};
+38 -12
View File
@@ -373,17 +373,37 @@ function initWebSocket() {
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'log') {
// 初始加载的日志数据
allLogs = data.content;
filterAndDisplayLogs();
} else if (data.type === 'new_log') {
// 新的日志条目
if (Array.isArray(data.content)) {
// 初始加载的日志数据
allLogs = data.content;
filterAndDisplayLogs();
} else {
// 新的日志条目
allLogs.push(data.content);
if (shouldShowLog(data.content)) {
appendLogEntry(data.content);
let shouldUpdate = false;
data.content.forEach(log => {
allLogs.push(log);
if (shouldShowLog(log)) {
filteredLogs.push(log);
shouldUpdate = true;
// 如果在最后一页或自动滚动模式下,直接添加到显示
if (currentPage === totalPages || autoScroll) {
appendLogEntry(log);
}
}
});
if (shouldUpdate) {
totalPages = Math.ceil(filteredLogs.length / pageSize);
updatePagination();
// 如果开启了自动滚动,确保滚动到底部
if (autoScroll) {
logContent.scrollTop = logContent.scrollHeight;
}
}
}
} else if (data.type === 'system_status') {
updateStatus(data.status, true);
}
updateTime();
};
@@ -391,7 +411,12 @@ function initWebSocket() {
ws.onclose = () => {
console.log('WebSocket连接已关闭');
updateStatus('已断开', false);
setTimeout(initWebSocket, 5000);
// 增加重连延迟,避免快速重连
setTimeout(() => {
if (!ws || ws.readyState === WebSocket.CLOSED) {
initWebSocket();
}
}, 2000);
};
ws.onerror = (error) => {
@@ -505,9 +530,9 @@ function appendLogEntry(content) {
entry.className = 'log-entry';
// 根据日志内容设置不同的样式
if (content.includes('ERROR')) {
if (content.includes('ERROR') || content.includes('ERR')) {
entry.classList.add('error');
} else if (content.includes('WARNING')) {
} else if (content.includes('WARNING') || content.includes('WARN')) {
entry.classList.add('warning');
} else if (content.includes('INFO')) {
entry.classList.add('info');
@@ -515,7 +540,8 @@ function appendLogEntry(content) {
entry.textContent = content;
logContent.appendChild(entry);
// 只在自动滚动模式下滚动到底部
if (autoScroll) {
logContent.scrollTop = logContent.scrollHeight;
}