OneUptime Syslog 接入指南:通过 HTTPS 将 RFC3164/RFC5424 日志转发到 OpenTelemetry 摄取服务
【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime
导读
Syslog 是路由器、防火墙、Linux 服务器等基础设施设备最广泛使用的日志协议,但传统 syslog 走 UDP 514 端口,既无认证也无加密。OneUptime 的 OpenTelemetry 摄取服务现已原生支持 syslog 载荷——你只需要用任意能发 HTTP POST 的工具(curl、rsyslog的omhttp模块、syslog-ng的 HTTP 目标插件),就能把 RFC3164(BSD)或 RFC5424 格式的日志直接推送进来。本文基于仓库中的 syslog.md 与 Syslog 摄取服务源码,完整讲解端点、请求格式、rsyslog 转发配置、解析后的属性体系与排障方法,并深入到解析器与写入链路的源码级细节,让你可以快速把基础设施日志统一汇入 OneUptime 的可搜索日志系统。
前置条件
在推送 syslog 数据之前,你需要准备以下三样东西:
- Telemetrie-Ingestion-Token(摄取令牌):进入Projekteinstellungen → Telemetrie & APM → Ingestion-Schlüssel(项目设置 → 遥测与 APM → 摄取密钥)创建一个密钥,并复制其中的
x-oneuptime-token值。该值将作为每次请求的认证凭据放在 HTTP Header 中。 - Syslog-Forwarder(转发器):任何能够发送 HTTP POST 请求的工具或服务都可以,例如命令行下的
curl、rsyslog的omhttp输出模块、syslog-ng的 HTTP 目标插件。 - Dienstname(可选,服务名):设置
x-oneuptime-service-nameHeader,即可将进入的日志归属到某个特定的遥测服务(Telemetry Service)。不设置时,OneUptime 会从日志内容本身推导服务名(详见下文「服务名解析」一节)。
从源码看,x-oneuptime-service-name的读取逻辑位于 OtelIngestBaseService.ts,它是服务名解析的最高优先级来源。
摄取端点
POST https://oneuptime.com/syslog/v1/logs两点使用说明:
- 如果你是自托管 OneUptime,请把
oneuptime.com替换为你自己的主机地址; - 每次请求都必须携带
x-oneuptime-tokenHeader,否则请求会被拒绝(返回 HTTP 401)。
在仓库源码中,该端点的注册位于 API/Syslog.ts,路由处理器依次经过三层中间件:
TelemetryIngestionDisabled.middleware—— 项目级摄取开关检查;setSyslogProductType—— 将本次请求标记为ProductType.Logs(即按日志产品计费与归类);TelemetryIngest.forSurface(TelemetryIngestSurface.Syslog)—— 摄取令牌校验与项目上下文注入;
最终落到SyslogIngestService.ingestSyslog(req, res, next)执行真正的接收与入队逻辑。
请求体格式
向该端点发送的数据可以是按行分隔的 syslog 字符串,也可以是带messages数组的 JSON 载荷。RFC3164(BSD)与 RFC5424 两种格式都受支持,甚至可以混在同一批请求中。
官方文档给出的 JSON 示例同时覆盖了两种格式:
{ "messages": [ "<34>1 2025-03-02T14:48:05.003Z web-01 nginx 7421 ID47 [env@32473 host=\"web-01\"] 502 on /api/login", "<13>Feb 5 17:32:18 db-01 postgres[2419]: connection received from 10.0.0.12" ] }- 第一条是RFC5424格式:
<34>是优先级(PRI),1是版本号,随后是时间戳、主机名、应用名、进程 ID、消息 ID,[env@32473 host="web-01"]是结构化数据(Structured Data),最后是消息正文; - 第二条是RFC3164(BSD)格式:
<13>是优先级,随后是传统时间戳Feb 5 17:32:18、主机名db-01,以及postgres[2419]:这样的"程序名[进程号]:"标签,最后是消息正文。
支持的 Content-Type
| Content-Type | 说明 |
|---|---|
application/json | 推荐使用,携带messages数组 |
text/plain | 按行分隔的多条消息 |
application/octet-stream | 原始二进制载荷,同样支持 Gzip 压缩(Content-Encoding: gzip) |
这些格式在服务端的normalizeMessages与extractMessagesFromRequest方法中有完整的解析逻辑(SyslogIngestService.ts):字符串按\r?\n分割并逐行去空白;Buffer会先按 UTF-8 解码;数组会递归展开;对象则依次识别messages、message、syslog(数组或字符串)等键。这也意味着一个请求体可以以多种形态承载 syslog 行,比如:
{ "message": "<13>Feb 5 17:32:18 db-01 postgres[2419]: connection received" }或
{ "syslog": "<34>1 2025-03-02T14:48:05.003Z web-01 nginx 7421 ID47 - 502 on /api/login" }都会被正常摄取。需要特别注意的是:如果请求体中不包含任何可识别的消息,服务端会抛出BadRequestException(HTTP 400),见 SyslogIngestService.ts。
用 curl 快速测试
最简单的接入方式就是一条 curl 命令:
curl \ -X POST https://oneuptime.com/syslog/v1/logs \ -H "Content-Type: application/json" \ -H "x-oneuptime-token: YOUR_TELEMETRY_KEY" \ -H "x-oneuptime-service-name: production-web" \ -d '{ "messages": [ "<34>1 2025-03-02T14:48:05.003Z web-01 nginx 7421 ID47 [env@32473 host=\"web-01\"] 502 on /api/login" ] }'服务端在收到请求后会立即返回成功响应(Response.sendEmptySuccessResponse),实际的解析与写入则由后台队列异步完成。这是摄取链路设计的核心:接收请求的 HTTP 层与解析、写入 ClickHouse 的 Worker 层解耦,保障了高吞吐场景下的稳定性。
从 rsyslog 转发
对于 Linux 服务器,最常用的方式是通过 rsyslog 的omhttp输出模块把本地 syslog 实时转发给 OneUptime。
1. 安装 HTTP 输出模块
sudo apt-get install rsyslog-omhttp2. 配置转发目标
在/etc/rsyslog.d/oneuptime.conf中追加以下配置:
module(load="omhttp") template(name="OneUptimeJson" type="list") { constant(value="{\"messages\":[\"") property(name="rawmsg") constant(value="\"]}") } action( type="omhttp" server="oneuptime.com" serverport="443" usehttps="on" endpoint="/syslog/v1/logs" header="Content-Type: application/json" header="x-oneuptime-token: YOUR_TELEMETRY_KEY" header="x-oneuptime-service-name: rsyslog-demo" template="OneUptimeJson" )配置要点:
template把每条原始 syslog 消息(rawmsg)包装成 JSON 的messages数组,与服务端约定的请求体结构完全一致;usehttps="on"配合serverport="443"启用 HTTPS 传输,保证日志在途加密;- 多个
header行可同时携带 Content-Type、认证令牌与服务名。
3. 重启 rsyslog
sudo systemctl restart rsyslog重启后,本地产生的所有匹配 syslog 消息会以 JSON 载荷的形式通过 HTTPS 推送到 OneUptime 摄取端点。
OneUptime 自动解析出的属性
每一条 syslog 日志在被解析后,OneUptime 都会自动附加一组syslog.*前缀的属性,这些属性可以直接在 Telemetrie-Log-Explorer(日志浏览器)中作为过滤条件搜索:
syslog.priority、syslog.facility.code、syslog.facility.namesyslog.severity.code、syslog.severity.namesyslog.hostname、syslog.appName、syslog.processId、syslog.messageIdsyslog.structured.*(RFC5424 结构化数据被扁平化后的键值对)syslog.raw(原始消息全文,用于追溯)
优先级、设施与严重级别的解码
Syslog 的 PRI 是一个打包了两段信息的数字:严重级别(severity)是低 3 位,设施(facility)是其余高位。在 SyslogParser.ts 中,解析器通过priority % 8得到 severity、Math.floor(priority / 8)得到 facility。
源码中维护了两张映射表(SyslogIngestService.ts):
- 设施名称表(24 项):
kernel、user、mail、system、security、syslogd、line_printer、network_news、uucp、clock、security2、ftp、ntp、log_audit、log_alert、clock2、以及local0~local7; - 严重级别名称表(8 项):
emergency、alert、critical、error、warning、notice、informational、debug。
例如<34>会被解析为 facility=4(security)、severity=2(critical)。测试用例对此有非常详细的验证,见 SyslogParser.test.ts:包括<0>解码为 facility 0/severity 0(内核紧急消息)、<191>解码为 facility 23/severity 7(local7debug)、<13>解码为 facility 1/severity 5(usernotice)等。
严重级别到 OTel 日志级别的映射
OneUptime 会把 syslog 严重级别映射为 OpenTelemetry 的日志级别(SyslogIngestService.ts):
| Syslog Severity | OTel SeverityNumber | OTel SeverityText |
|---|---|---|
| 0(emergency) | 23 | Fatal |
| 1(alert) | 23 | Fatal |
| 2(critical) | 19 | Error |
| 3(error) | 19 | Error |
| 4(warning) | 13 | Warning |
| 5(notice) | 9 | Information |
| 6(informational) | 9 | Information |
| 7(debug) | 5 | Debug |
这个映射直接决定了日志在浏览器中展示的严重级别,也是后续告警规则、保留策略(retention)按级别分桶(bucket)的依据——resolveTelemetryRetentionInDays会按日志级别对应的桶来决定每条日志的保留天数。
RFC5424 结构化数据扁平化
RFC5424 的 STRUCTURED-DATA 部分(形如[env@32473 host="web-01"])会被解析成syslog.structured.<SD-ID>.<参数名>形式的扁平键。从 SyslogIngestService.ts 可以看到,键名中的非法字符会被替换为下划线(sanitizeAttributeKey),从而保证属性名在 ClickHouse 与查询层中始终合法。原始的结构化数据片段也会以syslog.structured.raw保留。
原始消息追溯
每条日志都会附带syslog.raw属性保存解析前的原始字符串。这一点对排障尤为重要:测试文件 SyslogParser.test.ts 的注释强调了解析器的两条铁律——绝不丢失任何一行(无法理解的行也要完整保留文本在message中)与绝不虚构字段(发送方没有提供的 hostname/appName 必须留空,RFC 的-空值要转成undefined而不是字面量字符串)。
服务名解析:从 Header 到日志归属
如果你没有显式设置x-oneuptime-service-nameHeader,OneUptime 会按照如下优先级自动推导服务名(SyslogIngestService.ts):
x-oneuptime-service-nameHeader 中指定的名称(最高优先级);- RFC5424 格式中的
appName(应用名); - 主机名
hostname; - 兜底默认值
"Syslog"。
服务名解析完成后,日志会归属到对应的遥测服务(Telemetry Service),并携带该服务的serviceId与serviceName属性(通过TelemetryUtil.getAttributesForServiceIdAndServiceName写入)。这保证了在日志浏览器中你可以按服务维度过滤日志,与 OTLP 路径(OpenTelemetry 标准接入)进来的日志在同一套服务体系内管理。
摄入后的处理链路:与 OTLP 同级的日志加工
Syslog 日志并不会被"特殊对待"——它和标准 OTLP 日志一样,会经过同一套日志处理流水线。从 SyslogIngestService.ts 可以看到,每批消息处理前会加载三类配置:
- LogPipelineService—— 日志管道处理器(LogPipelines),可对日志做解析、转换、重命名等;
- LogDropFilterService—— 丢弃过滤器(Drop Filters),命中规则的行整条跳过;
- LogScrubRuleService—— 敏感数据脱敏规则(Scrub Rules),自动擦除日志中的敏感信息。
处理顺序(SyslogIngestService.ts)为:先判丢弃过滤器 → 再做敏感数据脱敏 → 最后跑管道处理器。这意味着你在 OneUptime 中为 OTLP 日志配置的所有治理规则(脱敏、丢弃、管道转换)都会自动作用于 syslog 日志,无需重复配置。
写入层面,日志行先按TELEMETRY_LOG_FLUSH_BATCH_SIZE批量缓冲,再交给共享的 fan-in 写入器(TelemetryFanInWriter)落盘到 ClickHouse。这里采用了ack-after-flush(落盘后再确认)的持久化策略:队列任务只有在所有写入批次真正落库后才算成功,任何一行的写入失败都会让任务重试(SyslogIngestService.ts),保证 syslog 日志在异常场景下不丢失。
此外,处理循环每 500 条消息会主动让出一次事件循环(EventLoop.yieldToEventLoop(),见 SyslogIngestService.ts),避免大批量推送时阻塞服务进程。
解析器细节:RFC5424 与 RFC3164 的判定逻辑
解析器 SyslogParser.ts 采用"先优先级、再按格式分派"的策略:
- 先用正则
^<(\d{1,3})>提取 PRI。超过 3 位数字(如<1234>)或非数字(如<abc>)都不会被当作优先级处理,而是整体作为消息正文保留——测试用例明确验证了这一行为(SyslogParser.test.ts); - 剩余部分优先尝试RFC5424:按空白切分出前 7 个 token(VERSION、TIMESTAMP、HOSTNAME、APP-NAME、PROCID、MSGID、STRUCTURED-DATA+MSG),并要求 VERSION 为纯数字,
-空值(NILVALUE)统一转换为undefined; - 失败则尝试RFC3164:匹配
Mmm dd hh:mm:ss hostname rest的传统时间戳格式,再从rest中解析程序名[进程号]:标签; - 两者都失败时,仍会返回一条"只有 raw 与 message"的最小解析结果——任何一行都不会被丢弃。
时间戳方面,RFC5424 使用OneUptimeDate.parseRfc5424Timestamp解析 ISO 8601 时间戳(可带毫秒与时区),RFC3164 使用parseRfc3164Timestamp解析传统的Feb 5 17:32:18格式(默认视为当年/当年份推断)。解析不到时间戳时,日志行会以服务端当前时间作为time字段(SyslogIngestService.ts),保证日志始终有时间轴位置。
RFC5424 结构化数据支持多个[...]块连续出现的情况(解析器用括号深度计数区分相邻块,见 SyslogParser.ts),每个块内的参数名="值"对会被逐一提取。测试文件共 470 行,覆盖了空输入、PRI 边界(0/34/191)、RFC5424 全字段、RFC3164 传统格式、畸形数据保留等完整场景(SyslogParser.test.ts)。
错误排查与常见问题
| 现象 | 原因与解决方案 |
|---|---|
| HTTP 401 或日志为空 | x-oneuptime-tokenHeader 不正确,或令牌不属于接收日志的那个项目。请到Projekteinstellungen → Telemetrie & APM → Ingestion-Schlüssel重新核对令牌并确认它与目标项目对应。 |
| 没有日志出现 | 请求体中没有真正的 syslog 行。空请求体会被以 HTTP 400 拒绝;请确认messages数组非空、每行都是合法的 syslog 字符串(或合法的 RFC3164/RFC5424 格式)。另外注意:接收请求是异步处理,日志从发出到在浏览器中可见会有短暂的延迟,可在日志浏览器中按时间刷新查看。 |
| 服务名不符合预期 | OneUptime 有自动推导服务名的逻辑(Header → appName → hostname → "Syslog")。如需强制归属,请始终设置x-oneuptime-service-nameHeader 来覆盖默认识别逻辑。 |
| 单行无法解析 | 由于"绝不丢失任何一行"的设计,无法解析的行会以原始文本形式进入message与syslog.raw,不会报错也不会丢弃;你可以在日志浏览器中按syslog.raw检索这些行,检查其格式是否满足 RFC 规范。 |
小结
OneUptime 的 Syslog 摄取能力本质上是一条**「HTTPS 上行 + 多格式解析 + 与 OTLP 同级的日志治理 + ClickHouse 落盘」**的完整链路:端点POST /syslog/v1/logs接收任意 RFC3164/RFC5424 来源,解析器保证不丢行、不虚构字段,服务名解析让日志自动归入正确的遥测服务,管道/脱敏/丢弃规则统一生效,最终以syslog.*属性体系呈现为可搜索、可过滤、可告警的结构化日志。无论你是用 curl 快速验证、用 rsyslog 转发整台服务器,还是用 syslog-ng 对接网络设备,都可以在几分钟内把基础设施日志统一汇入 OneUptime 的统一可观测性平台。
进一步阅读:摄取端点实现见 API/Syslog.ts,核心服务见 SyslogIngestService.ts,解析器见 SyslogParser.ts,测试用例见 SyslogParser.test.ts。如果你需要把日志从更多来源接入,仓库中还提供了 fluentd、fluentbit、OpenTelemetry 与 Kubernetes Agent 等接入指南。
【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考