LogGrep Server 是一个基于 LogGrep 核心技术构建的高性能日志处理平台。它将原始的命令行工具扩展为一个功能强大的服务器,提供日志的摄取、存储、实时查询和深度分析能力。本服务器旨在利用静态和运行时模式,实现快速、经济高效的云日志存储。
- 高性能日志摄取:
- 通过 HTTP
POST /_bulk端点接收日志数据,支持流式传输。 - 内置 ZSTD 压缩支持,显著减少网络传输和存储空间。
- 采用
RollingWriter机制,实现日志文件的滚动管理,优化存储效率。 - 集成 WAL (Write-Ahead Log) 机制,确保数据持久性和可靠性,并支持可选的启动时恢复。
- 通过 HTTP
- 强大的日志查询:
- 提供 HTTP
POST /query端点,支持 SPL (Search Processing Language) 语法,实现灵活的日志搜索和过滤。- 提供针对参数变量的数值型和文本型变量统计功能,包括平均值、总和、最大值、最小值、计数、中位数、标准差、百分位数。
- 支持文本型数据的唯一值计数 (基于 HyperLogLog 算法)、频率分布和 Top-K 值分析。
- 强大的分组聚合 (
GROUP BY) 功能,允许用户按指定字段进行分组后执行统计计算。 - 提供
timechart功能,支持按时间跨度或时间段对日志事件进行计数和分组统计,便于趋势分析。
- 利用位图索引、布隆过滤器和模式哈希等先进技术,实现毫秒级的查询响应。
- 支持通配符搜索、KMP 模式匹配以及复杂的布尔逻辑 (
AND,OR,NOT)。 - 提供
/indices端点用于管理日志索引,包括创建、删除和查看现有索引。
- 提供 HTTP
- HTTP API 接口:
- 提供 RESTful 风格的 API 接口,便于与其他系统和工具集成。
- 所有查询和统计结果均以 JSON 格式返回,支持
pretty参数格式化输出。 - 包含
/health端点用于健康检查。
- 高并发与可配置性:
- 服务器设计支持多线程处理客户端请求,提高吞吐量。
- 部分行为可通过环境变量进行配置,例如 WAL 恢复策略 (
LOGGREP_RECOVER_AT_START) 和工作线程数 (LOGGREP_WORKERS)。
LogGrep Server 采用模块化设计,主要组件包括:
- Ingestor (摄取器): 负责接收、压缩和写入日志数据。通过
RollingWriter管理日志文件和 WAL。 - LogStoreApi (日志存储 API): 底层数据访问接口,处理日志的读取、解压缩、索引管理和位图操作。
- LogDispatcher (日志分发器): 协调查询请求,将 SPL 查询解析并分发到底层
LogStoreApi执行,并处理聚合和时间序列分析。 - StatisticsAPI (统计 API): 提供基于
LogStoreApi的高级统计分析功能。 - ServerMain (服务器主程序): 负责网络通信、HTTP 请求解析和路由,将请求分发给相应的处理模块。
graph TD
A[客户端] -->|HTTP 请求| B(ServerMain)
B -->|POST /_bulk| C(Ingestor)
B -->|POST /query| D(LogDispatcher)
B -->|GET /indices| D
B -->|POST /indices| D
B -->|GET /health| B
C -->|写入日志 & WAL| E(日志存储)
D -->|查询 & 统计请求| F(LogStoreApi)
D -->|统计分析| G(StatisticsAPI)
F -->|读取日志 & 索引| E
G -->|获取数据| F
E -->|日志文件 & 索引文件| H[磁盘]
- 操作系统: 兼容 Linux 环境 (例如 Red Hat 4.8.5 with Linux kernel 3.10.0, Ubuntu 11.3.0 with Linux kernel 5.15.0)。
- 编译器:
gcc版本 4.8.5 20150623 或更高。 - 其他依赖:
- Python 3.6.8+ (用于辅助脚本,如
quickTest.py,largeTest.py,var_alias_tool.py)。 pip3 install --upgrade requestsyum groupinstall 'Development Tools'(或等效的包管理命令安装开发工具)。
- Python 3.6.8+ (用于辅助脚本,如
请参考 ./http_server_quicktest.txt 中的主要步骤进行编译和测试运行。
LOGGREP_RECOVER_AT_START: 设置为1(或其他非零值) 以在服务器启动时执行 WAL 恢复。LOGGREP_MAX_PENDING: 设置最大待处理请求数 (默认为4096)。LOGGREP_WORKERS: 设置处理请求的工作线程数 (默认为 CPU 核心数)。LOGGREP_ROLLING_SIZE_MB: 单个日志段文件达到该大小时触发滚动,默认 64 (MB)。LOGGREP_ROLLING_LINES: 单个日志段文件达到该条数时触发滚动,默认 5000000 (条)。LOGGREP_MAX_DISK_BYTES: 索引目录总磁盘空间达到该大小时触发滚动,默认 0 (字节,表示无限制)。LOGGREP_MAX_SEGMENTS: 同一索引下最多保留的日志段数量,默认 100。LOGGREP_FLUSH_BYTES: 日志写入后按字节大小自动刷盘,默认 64m (字节)。LOGGREP_FLUSH_RECORDS: 日志写入后按记录条数自动刷盘,默认 50000 (条)。LOGGREP_FLUSH_INTERVAL_MS: 日志写入后自动刷盘间隔,默认 3000 (毫秒)。LOGGREP_WAL_FSYNC: 是否启用 WAL 同步刷盘,默认 0 (关闭)。LOGGREP_MAX_BODY_BYTES: 单次上传数据最大上限,默认 256 (MB)。
- 端点:
GET /health - 描述: 检查服务器是否正常运行。
- 响应:
{ "status": "ok" }
-
端点:
POST /_bulk -
描述: 批量摄取日志数据。支持 ZSTD 压缩和分块传输。
-
请求参数 (URL Query 或 Request Body):
index(string, 必需): 日志所属的索引名称。sync(string, 可选): 如果存在且非空,表示在摄取后同步 WAL。flush(string, 可选): 如果存在且非空,表示在摄取后强制刷新 segment。
-
请求头:
Content-Encoding: zstd(可选): 如果日志数据经过 ZSTD 压缩。Transfer-Encoding: chunked(可选): 如果使用分块传输。
-
请求体: 原始日志数据,每行一条日志。
-
响应:
{ "ingested": 100, // 成功摄取的日志行数 "flushed": true, // 是否已刷新到磁盘 "segment": "seg_name",// 如果刷新,对应的日志段名称 "synced": true // 是否已同步 WAL } -
示例 (使用
curl):未压缩日志摄取:
curl -X POST "http://localhost:8080/_bulk?index=my_logs" \ -H "Content-Type: text/plain" \ --data-binary $'log line 1\nlog line 2\nlog line 3'
ZSTD 压缩日志摄取:
echo -e "compressed log line 1\ncompressed log line 2" | zstd | \ curl -X POST "http://localhost:8080/_bulk?index=my_logs" \ -H "Content-Type: application/octet-stream" \ -H "Content-Encoding: zstd" \ --data-binary @-
-
端点:
POST /query -
描述: 执行日志查询和统计分析。
-
请求参数 (URL Query 或 Request Body):
index(string, 必需): 要查询的索引名称。q(string, 必需): SPL (Search Processing Language) 查询语句。limit(int, 可选): 返回的日志条数限制,默认为100。pretty(string, 可选): 如果存在且非空,响应 JSON 将进行美化格式化。
-
请求体: 可以是
application/x-www-form-urlencoded格式的键值对,或者直接在 URL Query 中提供参数。 -
SPL 语法示例:
- 基本搜索:
q=error AND "connection refused" - 时间图表:
q=timechart span=1h count() by host - 去重计数:
q=stats distinct(user) by host - Top-K:
q=top 10 user - 字段别名查询:
q=Host:LabSZ(详见下文“字段别名系统”) - 数值过滤:
q=Port:>=1024(详见下文“数值过滤”)
- 基本搜索:
-
响应: JSON 格式的查询结果。具体结构取决于 SPL 查询语句。
-
示例 (使用
curl):基本查询:
curl -X POST "http://localhost:8080/query" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "index=my_logs" \ --data-urlencode "q=error AND \"failed to connect\"" \ --data-urlencode "pretty=true"
时间图表查询:
curl -X POST "http://localhost:8080/query" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "index=my_logs" \ --data-urlencode "q=timechart span=1h count() by host" \ --data-urlencode "pretty=true"
-
端点:
GET /indices -
描述: 获取当前服务器管理的所有索引及其对应的存储路径。
-
响应:
{ "indices": { "main": "../lib_output_zip/Ssh", "ssh": "../lib_output_zip/Ssh", "my_logs": "/path/to/my_logs_data" }, "pending": 0 // 待处理的摄取任务数量 } -
端点:
POST /indices -
描述: 添加或删除日志索引。
-
请求参数 (URL Query 或 Request Body):
index(string, 必需): 索引名称。path(string, 可选): 索引对应的存储路径。如果提供,则添加或更新索引。delete(string, 可选): 如果存在且非空,则删除指定索引。- 索引级设置 (可选): 当提供以下任一参数时,服务器会在该索引目录生成
ingest.conf并持久化,用于覆盖默认刷新策略:flush_bytes(string): 如64m、1gflush_records(int): 触发刷新所需记录数,如50000flush_interval_ms(int): 定时刷新间隔,毫秒max_segments(int): 每索引保留段的最大数量max_disk_bytes(string): 段占用磁盘的最大总量,如5gwal_fsync(int): 是否对 WAL 执行fsync,1开启
-
响应:
{ "ok": true } -
示例 (使用
curl):添加/更新索引:
curl -X POST "http://localhost:8080/indices" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "index=new_logs" \ --data-urlencode "path=/var/loggrep/new_logs_data"
添加索引并设置刷新策略:
curl -X POST "http://localhost:8080/indices" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "index=access" \ --data-urlencode "path=./ingest_example/access" \ --data-urlencode "flush_records=1" \ --data-urlencode "flush_interval_ms=0" \ --data-urlencode "wal_fsync=1"
删除索引:
curl -X POST "http://localhost:8080/indices" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "index=old_logs" \ --data-urlencode "delete=true"
LogGrep Server 支持通过字段别名简化查询,并提供更灵活的匹配选项。
- 优先读取压缩文件同目录下的
<文件名>.var_alias。 - 若不存在,则回退到目录级
var_alias.conf。
支持两种配置格式:
-
变量ID → 别名:
E<模板ID>_V<变量ID>.<类型>=<别名>示例:
E1_V1.VAR=src.ip(表示模板1的变量1,类型为VAR,别名为src.ip) -
别名 → 多变量:
<别名>: E<模板ID>_V<变量ID>, E<模板ID>_V<变量ID>, ...示例:
Host: E7_V4, E6_V4, E30_V3(表示Host别名映射到多个模板的变量)
在 /query 端点的 q 参数中,可以使用 别名:值 语法。
<别名>:<值>[|<选项>]
- 选项:
strict: 仅在别名映射的变量位执行过滤;不回落到主模板常量匹配与异常匹配。ci: 回落到主模板常量匹配时大小写不敏感 (case-insensitive)。
- 支持操作符:
==,!=,>,>=,<,<= - 支持范围写法:
a..b(闭区间),例如1024..65535
示例:
Port:22(等价于Port:==22)Port:>=1024(数值大于等于)Port:1024..65535(范围过滤)Port:22|strict(仅变量位过滤,不回落常量)
- 当别名映射的变量位没有命中且未指定
strict时,系统会回落到主模板常量匹配并物化输出。 - 指定
ci时,常量匹配大小写不敏感。
q=Host:LabSZq=Host:LabSZ|ciq=Port:22q=Port:>=1024q=Port:1024..65535|strict
- 某些数据集 (例如示例 Ssh) 中,
Host更像模板常量而非变量位;在此情况下|strict可能无命中,建议使用默认或|ci以获得常量匹配效果。
LogGrep Server 的核心技术源自以下学术论文:
Junyu Wei, Guangyan Zhang, Junchao Chen, Yang Wang, Weimin Zheng, Tingtao Sun, Jiesheng Wu, Jiangwei Jiang. LogGrep: Fast and Cheap Cloud Log Storage by Exploiting both Static and Runtime Patterns. in Proceedings of the 18th European Conference on Computer Systems (EuroSys’23), Roma, Italy, May 2023.