240717班级,工业化控制系统,煤矿相关行业,昆仑系统
fufu
2024-10-31 57a43626b15297d191382d40e63f7ba07b024f01
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
#include <time.h>
#include <chrono>
#include <stdarg.h>
#include "log.h"
#include <fstream>
#include <iostream>
 
using namespace std;
 
// 构造函数
Log::Log() : m_count(0), m_is_async(false) {}
 
// 析构函数
Log::~Log() {
    if (m_fp.is_open()) {
        m_fp.close(); // 关闭日志文件
    }
}
 
//异步写入
void Log::async_write_log() {
    while (m_is_async) {
        char* log;
        if (m_log_queue->pop(log)) {
            ParsedLog parsed_log = parseLog(log); 
            write_log(INFO, "%s", log); // 先写入日志文件
            writeLogToDatabase(parsed_log); // 再写入数据库
            delete[] log; // 释放内存
        }
    }
}
 
bool Log::check_log_size() {
    if (m_fp.tellp() >= max_size) {
        rotate_logs(); // 如果日志文件大小超过最大值,轮换日志
        return true;
    }
    return false;
}
 
 
// 接收原始日志并解析
void Log::receiveLog(const char* raw_log) {
    ParsedLog parsed_log = parseLog(raw_log);
    write_log(levelToInt(parsed_log.level), "%s [%s] %s", 
               parsed_log.timestamp, 
               parsed_log.device_id, 
               parsed_log.content);
}
 
//写入数据库
void Log::writeLogToDatabase(const ParsedLog& log) {
    const char* sql = "INSERT INTO parsed_logs (timestamp, device_id, level, content, source, user_id) VALUES (?, ?, ?, ?, ?, ?)";
    sqlite3_stmt* stmt;
 
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
        cerr << "Error: Failed to prepare statement: " << sqlite3_errmsg(db) << endl;
        return;
    }
 
    sqlite3_bind_text(stmt, 1, log.timestamp, -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 2, log.device_id, -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 3, log.level, -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 4, log.content, -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 5, log.source, -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 6, log.user_id, -1, SQLITE_STATIC);
 
    if (sqlite3_step(stmt) != SQLITE_DONE) {
        cerr << "Error: Failed to execute statement: " << sqlite3_errmsg(db) << endl;
    }
 
    sqlite3_finalize(stmt); // 清理准备语句
}
 
 
// 解析日志字符串
ParsedLog Log::parseLog(const char* log) {
    ParsedLog parsed_log;
    char level[16];
 
    // 读取时间戳、设备ID和日志级别
    sscanf(log, "%s %s %s %[^\n]", parsed_log.timestamp, parsed_log.device_id, level, parsed_log.content);
    // 设置解析后的级别
    for (int i = 0; i < 16; ++i) {
        parsed_log.level[i] = level[i];
    }
 
    return parsed_log;
}
 
// 初始化日志系统
bool Log::init(const char* file_name, int close_log, int log_buf_size, int split_lines, int max_queue_size) {
    if (max_queue_size >= 1) {
        m_is_async = true; // 启用异步写入
        m_log_queue = new block_queue<char*>(max_queue_size); // 创建阻塞队列
        std::thread(&Log::flush_log_thread, this).detach(); // 创建刷新日志线程
    }
 
    m_close_log = close_log; // 设置关闭日志标志
    m_log_buf_size = log_buf_size; // 设置缓冲区大小
    m_buf = new char[m_log_buf_size]; // 分配缓冲区
    memset(m_buf, '\0', m_log_buf_size); // 清空缓冲区
    m_split_lines = split_lines; // 设置最大行数
 
    time_t t = time(NULL);
    struct tm *sys_tm = localtime(&t);
    char log_full_name[256];
 
    // 根据文件路径和当前日期生成完整日志文件名
    if (strchr(file_name, '/') == nullptr) {
        sprintf(log_full_name, "%d_%d_%d_%s",
                sys_tm->tm_year + 1900, sys_tm->tm_mon + 1, sys_tm->tm_mday, file_name);
    } else {
        char log_name[128];
        char dir_name[128];
        char* last_slash = strrchr(file_name, '/');
        int dir_len = last_slash - file_name + 1;
        strncpy(dir_name, file_name, dir_len);
        dir_name[dir_len] = '\0';
        strcpy(log_name, last_slash + 1);
        
        sprintf(log_full_name, "%s%d_%d_%d_%s",
                dir_name, sys_tm->tm_year + 1900, sys_tm->tm_mon + 1, sys_tm->tm_mday, log_name);
    }
 
    m_today = sys_tm->tm_mday; // 记录今天的日期
    m_fp.open(log_full_name, std::ios::out | std::ios::app); // 打开日志文件
    if (!m_fp.is_open()) {
        cerr << "Error: Could not open log file: " << log_full_name << endl;
        return false; // 打开失败
    }
 
    return true; // 初始化成功
}
 
//查询日志草最
void Log::queryLogs(const char *device_id) {
    const char* sql = "SELECT * FROM parsed_logs WHERE device_id = ?";
    sqlite3_stmt* stmt;
 
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
        cerr << "Error: Failed to prepare statement: " << sqlite3_errmsg(db) << endl;
        return;
    }
 
    sqlite3_bind_text(stmt, 1, device_id, -1, SQLITE_STATIC);
    
    while (sqlite3_step(stmt) == SQLITE_ROW) {
        cout << "Timestamp: " << sqlite3_column_text(stmt, 1) << ", "
             << "Device ID: " << sqlite3_column_text(stmt, 2) << ", "
             << "Level: " << sqlite3_column_text(stmt, 3) << ", "
             << "Content: " << sqlite3_column_text(stmt, 4) << ", "
             << "Source: " << sqlite3_column_text(stmt, 5) << ", "
             << "User ID: " << sqlite3_column_text(stmt, 6) << endl;
    }
 
    sqlite3_finalize(stmt); // 清理准备语句
}
 
 
 
// 写入日志
void Log::write_log(int level, const char *format, ...) {
    auto now = std::chrono::system_clock::now();
    auto now_time_t = std::chrono::system_clock::to_time_t(now);
    struct tm *sys_tm = localtime(&now_time_t);
    
    char s[32];
 
    // 根据日志级别设置前缀
    switch (level) {
        case DEBUG: strcpy(s, "[debug]: "); break;
        case INFO: strcpy(s, "[info]: "); break;
        case WARN: strcpy(s, "[warn]: "); break;
        case ERROR: strcpy(s, "[error]: "); break;
        default: strcpy(s, "[info]: "); break;
    }
 
    m_mutex.lock(); // 锁定互斥体
    m_count++; // 增加日志计数
 
    // 检查是否需要轮换日志
    if (m_today != sys_tm->tm_mday || m_count % m_split_lines == 0) {
        rotate_logs(); // 调用日志轮换函数
    }
 
    // 写入日志内容
    va_list valist;
    va_start(valist, format);
    vsnprintf(m_buf, m_log_buf_size, format, valist); // 写入日志内容
 
    m_fp << s << m_buf << std::endl; // 使用ofstream写入文件
    va_end(valist);
 
    m_mutex.unlock(); // 解锁互斥体
 
    // 异步写入日志
    if (m_is_async && !m_log_queue->full()) {
        m_log_queue->push(m_buf); // 将日志推入队列
    }
}
 
// 刷新日志文件
void Log::flush(void) {
    m_mutex.lock(); // 锁定互斥体
    m_fp.flush(); // 刷新文件
    m_mutex.unlock(); // 解锁互斥体
}
 
// 刷新日志线程
void Log::flush_log_thread() {
    while (m_is_async) {
        // 从队列中获取日志并写入
        char* log;
        if (m_log_queue->pop(log)) {
            write_log(INFO, "%s", log);
        }
    }
}
 
//转换字符串
const char* Log::log_level_to_string(int level) {
    switch (level) {
        case DEBUG: return "[debug]: ";
        case INFO: return "[info]: ";
        case WARN: return "[warn]: ";
        case ERROR: return "[error]: ";
        default: return "[info]: "; // 默认返回INFO
    }
}
 
// 日志级别转换为整数
int Log::levelToInt(const char* level) {
    if (strcmp(level, "[debug]:") == 0) return DEBUG;
    if (strcmp(level, "[info]:") == 0) return INFO;
    if (strcmp(level, "[warn]:") == 0) return WARN;
    if (strcmp(level, "[error]:") == 0) return ERROR;
    return INFO; // 默认返回INFO
}
 
//打开关闭数据库
void Log::openDatabase(const char *db_name) {
    if (sqlite3_open(db_name, &db) != SQLITE_OK) {
        cerr << "打不开数据库!!错误: " << sqlite3_errmsg(db) << endl;
    }
}
 
void Log::closeDatabase() {
    if (db) {
        sqlite3_close(db);
    }
}
 
// 日志轮换函数
void Log::rotate_logs() {
    // 关闭当前文件
    m_fp.close();
 
    // 生成新文件名
    time_t t = time(NULL);
    struct tm *sys_tm = localtime(&t);
    char new_log_name[256];
    sprintf(new_log_name, "%d_%d_%d_log.txt",
            sys_tm->tm_year + 1900, sys_tm->tm_mon + 1, sys_tm->tm_mday);
 
    // 打开新的日志文件
    m_fp.open(new_log_name, std::ios::out | std::ios::app);
    if (!m_fp.is_open()) {
        cerr << "Error: Could not open new log file: " << new_log_name << endl;
        return;
    }
 
    m_today = sys_tm->tm_mday; // 更新今天的日期
    m_count = 0; // 重置日志计数
}