日志系统设计
在工程实践中,完善的日志系统是排查问题的基石。C/C++ 编译器提供了两个特殊的预定义宏,用于精确定位日志来源:
__FILE__:自动替换为当前源文件的路径或文件名。例如在test.cpp中调用,日志将显示[test.cpp : ...]。__LINE__:自动替换为当前代码所在的行号。若在第 25 行调用,日志将显示[test.cpp : 25]。
基于这两个宏,我们可以封装一个统一的日志输出接口。以下是一个示例实现,定义了不同级别的日志宏并调用底层打印函数:
#pragma once
#include <iostream>
#include <string>
#include <ctime>
#define NORMAL 1
#define WARNING 2
#define DEBUG 3
#define FATAL 4
// 宏定义:将级别、消息、文件、行号传递给 log1 函数
#define LOG1(LEVEL, MESSAGE) log1(#LEVEL, MESSAGE, __FILE__, __LINE__)
void log1(std::string level, std::string message, std::string file, int line) {
std::cout << "[" << level << "]"
<< "[" << time(nullptr) << "]"
<< "[" << message << "]"
<< "[" << file << " : " << line << "]"
<< std::endl;
}
Server 端实现
Server 程序负责加载数据源、初始化搜索器并响应用户查询。数据源通常存储在 data/raw_html/raw.txt,前端资源位于 ./wwwroot/。
在主循环中,我们需要读取用户的搜索关键字。这里选择 fgets 而非 cin,因为 cin >> 遇到空格会截断输入,而 fgets 能整行读取,更适合处理包含空格的查询词。注意,fgets 会将换行符也读入缓冲区,需要在处理前移除。
以下是 server.cc 的核心逻辑:
#include "searcher.hpp"
#include <iostream>
#include <string>
#include <cstdio>
const std::string input = "data/raw_html/raw.txt";
const std::string root_path = "./wwwroot";
int main() {
ns_searcher::Searcher* search = new ns_searcher::Searcher();
search->InitSearcher(input);
std::string query;
std::string json_string;
char buffer[1024];
while (true) {
std::cout << "Enter Search Query: ";
// 使用 fgets 读取整行,避免 cin 忽略空格的问题
fgets(buffer, sizeof(buffer) - 1, stdin);
// 去除 fgets 读入的换行符
if (strlen(buffer) > 0 && buffer[strlen(buffer) - 1] == '\n') {
buffer[strlen(buffer) - 1] = 0;
}
query = buffer;
search->Search(query, &json_string);
std::cout << json_string << std::endl;
}
return 0;
}
注意:实际运行中需确保 searcher.hpp 已正确编译链接,且数据路径存在。


