跳到主要内容
版本:1.2

Splunk

概述​

GreptimeDB 实现了 Splunk HTTP Event Collector (HEC) 协议的一个子集。已经在用 HEC 的采集器——比如 Vector 和 OpenTelemetry Collector——只需要改一下地址和 token 就能写入 GreptimeDB。

提供两个写入端点:

  • /services/collector/event 接收结构化的 JSON 事件。
  • /services/collector/raw 接收纯文本,原样存储。

Splunk 的 index 对应 GreptimeDB 的表。host、source、sourcetype 以及 fields 下的各个 key 会成为 Tag 列,GreptimeDB 会把它们加进表的主键。

不支持 indexer acknowledgment(/services/collector/ack)。channel 参数会被接收但忽略。

注意

Fluent Bit 自带的 splunk output 用不了这个端点。它把请求路径写死成 /services/collector/event,也没有提供配置路径的选项,所以在没有反向代理的情况下访问不到 GreptimeDB 的 /v1/splunk。要从 Fluent Bit 写入,请改用它的 HTTP output。

HTTP API​

基础路径是 /v1/splunk,采集路径由客户端自己拼接。把采集器指向 http://${db_host}:${db_http_port}/v1/splunk 即可,例如 http://localhost:4000/v1/splunk。

端点方法用途
/v1/splunk/services/collector/eventPOST写入 JSON 事件。别名:/services/collector、/services/collector/event/1.0
/v1/splunk/services/collector/rawPOST写入纯文本。别名:/services/collector/raw/1.0
/v1/splunk/services/collector/healthGET健康检查。别名:/services/collector/health/1.0

请求体支持 gzip 压缩(Content-Encoding: gzip)。

鉴权​

只有在服务端配置了 user provider 时才会校验鉴权。没有配置时请求直接放行。

HEC 客户端发送的是 Authorization: Splunk <token>,GreptimeDB 把这个 token 按 username:password 解析:

Authorization: Splunk greptime_user:greptime_pwd

Authorization: Basic <base64> 同样接受。

注意

大多数 Splunk 客户端默认用一个不含冒号的 opaque token,这种 token 会被 GreptimeDB 拒绝并返回 HEC code 4。请把客户端的 token 配置成 <username>:<password> 的形式。

健康检查端点是公开的,任何情况下都不需要 token。

写入 JSON 事件​

POST /v1/splunk/services/collector/event

请求体是一个或多个 HEC 事件对象。它们可以直接拼接、用换行或空格这类 JSON 空白字符分隔,也可以放在一个顶层 JSON 数组里。其他分隔符(比如逗号、分号)会导致解析失败,请求返回 HEC code 6。

字段映射​

HEC 字段对应到
timegreptime_timestamp 时间索引
index表名
host、source、sourcetypeTag 列
fields 下的各个 keyTag 列,每个 key 一列
event 及其余 key数据列

time 是 epoch 秒,可以带小数。大于等于 1e12 的值按毫秒解析。time 缺失或为 null 时使用服务端的写入时间。

注意

time 存在但解析不了不会回退,而是直接报错,请求返回 HEC code 6。raw 端点的 ?time= 同理。

表名路由​

表名按以下顺序确定:

  1. 事件里的 index,会被规整成合法表名。[A-Za-z0-9_:\-.@#] 之外的字符替换成 _,首字符不合法时在前面补一个下划线。例如 my index/2026 会变成 my_index_2026。
  2. table query 参数。
  3. 默认表 splunk_logs。

Query 参数​

参数说明
db目标数据库,默认 public。
table事件里没有 index 时使用的兜底表名。
pipeline_name使用的 Pipeline,默认是内置的 greptime_identity。
versionPipeline 版本,默认使用最新版本。
注意

这个端点只认上面这几个参数。其他日志写入参数如 msg_field、custom_time_index、ignore_errors 在这里不生效。

示例​

curl -X POST "http://localhost:4000/v1/splunk/services/collector/event" \
-H "Authorization: Splunk greptime_user:greptime_pwd" \
-H "Content-Type: application/json" \
-d '{"time":1785312000,"host":"web-01","source":"/var/log/nginx/access.log","sourcetype":"nginx:access","index":"splunk_events","fields":{"env":"prod","region":"us-west"},"event":{"status":200,"path":"/api/v1/health","latency_ms":12}}
{"time":1785312001,"host":"web-02","source":"/var/log/nginx/access.log","sourcetype":"nginx:access","index":"splunk_events","fields":{"env":"prod","region":"eu-central"},"event":{"status":503,"path":"/api/v1/orders","latency_ms":841}}'

写入成功返回:

{"code":0,"text":"Success"}

第一次写入时会自动建表 splunk_events:

DESC TABLE splunk_events;
+--------------------+---------------------+------+------+---------+---------------+
| Column | Type | Key | Null | Default | Semantic Type |
+--------------------+---------------------+------+------+---------+---------------+
| greptime_timestamp | TimestampNanosecond | PRI | NO | | TIMESTAMP |
| env | String | PRI | YES | | TAG |
| event.latency_ms | Int64 | | YES | | FIELD |
| event.path | String | | YES | | FIELD |
| event.status | Int64 | | YES | | FIELD |
| host | String | PRI | YES | | TAG |
| region | String | PRI | YES | | TAG |
| source | String | PRI | YES | | TAG |
| sourcetype | String | PRI | YES | | TAG |
+--------------------+---------------------+------+------+---------+---------------+

默认 Pipeline 会把嵌套的 event 对象打平,所以数据列的名字是 event.status、event.path、event.latency_ms。

SELECT * FROM splunk_events ORDER BY greptime_timestamp;
+---------------------+------+------------------+----------------+--------------+--------+------------+---------------------------+--------------+
| greptime_timestamp | env | event.latency_ms | event.path | event.status | host | region | source | sourcetype |
+---------------------+------+------------------+----------------+--------------+--------+------------+---------------------------+--------------+
| 2026-07-29 08:00:00 | prod | 12 | /api/v1/health | 200 | web-01 | us-west | /var/log/nginx/access.log | nginx:access |
| 2026-07-29 08:00:01 | prod | 841 | /api/v1/orders | 503 | web-02 | eu-central | /var/log/nginx/access.log | nginx:access |
+---------------------+------+------------------+----------------+--------------+--------+------------+---------------------------+--------------+

后续写入里 fields 新出现的 key 会自动加成 Tag 列并加入主键。

写入纯文本​

POST /v1/splunk/services/collector/raw

请求体原样存进 message 列,GreptimeDB 不解析内容。如果需要结构化,用自定义 Pipeline 读 message 字段。

注意

默认情况下整个请求体是一个事件,这样堆栈这类多行内容能保持完整。要把请求体切成多个事件,用 linebreaker 传入分隔符(需要百分号编码),例如 ?linebreaker=%0A 按换行切分。只含空白的片段会被丢弃。

这个端点的元数据是请求级的:来自 query 参数,对请求里的所有事件生效。

Query 参数​

参数说明
host、source、sourcetypeTag 列,对请求内所有事件生效。
index表名,规整规则和 /event 的 index 字段一致。
time对所有事件生效的 epoch 时间戳,默认使用写入时间。
table没有 index 时的兜底表名。
linebreaker用于切分请求体的分隔符字面量,需要百分号编码。不传时整个请求体是一个事件。
pipeline_name使用的 Pipeline,默认 greptime_identity。
versionPipeline 版本。
db目标数据库,默认 public。
channel接收但忽略。也可以用 x-splunk-request-channel 请求头传。

示例​

printf 'line one\nline two\nline three\n' | curl -X POST \
"http://localhost:4000/v1/splunk/services/collector/raw?index=splunk_raw&host=web-01&source=app.log&sourcetype=applog&linebreaker=%0A" \
-H "Authorization: Splunk greptime_user:greptime_pwd" \
--data-binary @-

这会写入三行。同样的请求去掉 linebreaker 则只写入一行,内容是完整的三行文本。

SHOW CREATE TABLE splunk_raw;
CREATE TABLE IF NOT EXISTS `splunk_raw` (
`greptime_timestamp` TIMESTAMP(9) NOT NULL,
`host` STRING NULL,
`message` STRING NULL,
`source` STRING NULL,
`sourcetype` STRING NULL,
TIME INDEX (`greptime_timestamp`),
PRIMARY KEY (`host`, `source`, `sourcetype`)
)

ENGINE=mito
WITH(
'comment' = 'Created on insertion',
append_mode = 'true'
)

使用 Pipeline​

两个端点都会让每个事件走一遍 Pipeline。默认是内置的 greptime_identity,它把输入的每个 key 映射成同名的列。

可以用 pipeline_name query 参数或 x-greptime-pipeline-name 请求头覆盖,两者同时存在时 query 参数优先。用 version 可以指定 Pipeline 版本。

注意

把 host、source、sourcetype 和 fields 的 key 提升为 Tag 列只发生在默认的 greptime_identity 路径上。自定义 Pipeline 自己决定输出 schema,需要索引哪些列要在 Pipeline 里自己声明。

响应码​

响应体是 {"text": ..., "code": ...},和 HEC 一致,客户端根据 code 分支处理。

Code含义
0成功
2缺少 token
4token 非法
5没有数据
6数据格式错误,包括 time 或 version 解析失败
7index 错误,即最终解析出的表名不合法
8服务端内部错误
12缺少 event 字段
13event 字段为空
17健康检查端点返回,表示 collector 正常
注意

校验失败会让整个请求失败。一批事件里只要有一条缺 event、event 为空,或者 time 存在但解析不了,这一批就一条都不会写入——端点不会跳过坏事件继续写其余的。host、source 这类可选元数据缺失不影响写入。

Vector​

Vector 的 splunk_hec_logs sink 不需要额外改造就能写入 GreptimeDB:

[sinks.greptime]
type = "splunk_hec_logs"
inputs = ["my_source"]
endpoint = "http://localhost:4000/v1/splunk"
default_token = "greptime_user:greptime_pwd"
index = "vector_logs"
compression = "gzip"
encoding.codec = "json"
  • endpoint:填 /v1/splunk 基础路径,不要带采集路径,Vector 会自己拼。
  • default_token:必须是 <username>:<password>,不能是 opaque token。
  • index:目标表名。
  • encoding.codec:这个 sink 的必填项。
  • endpoint_target:默认 event,走 /services/collector/event。设成 raw 则走 raw 端点。

改用 raw 端点:

[sinks.greptime]
type = "splunk_hec_logs"
inputs = ["my_source"]
endpoint = "http://localhost:4000/v1/splunk"
default_token = "greptime_user:greptime_pwd"
index = "vector_raw_logs"
endpoint_target = "raw"
encoding.codec = "text"
batch.max_events = 1

Vector 批量发送时事件之间没有分隔符,所以在 raw 端点上一整批会被当成一个事件。像上面这样设 batch.max_events = 1,或者用默认的 event 模式即可。

注意

服务端的 linebreaker 本来可以把这样一批切开,但这个 sink 送不出去:它没有配置任意 query 参数的选项,把参数拼到 endpoint 上也不行——Vector 是把 endpoint 和采集路径按字符串直接拼接的,http://localhost:4000/v1/splunk?linebreaker=%0A 会拼成 /v1/splunk?linebreaker=%0A/services/collector/raw?index=...,路由匹配不上。能自由设置 query 参数的 HEC 客户端可以正常使用 linebreaker。

OpenTelemetry Collector​

splunk_hec exporter 的配置方式类似:

exporters:
splunk_hec:
endpoint: "http://localhost:4000/v1/splunk/services/collector"
token: "greptime_user:greptime_pwd"
index: "otel_logs"
tls:
insecure: true

service:
pipelines:
logs:
receivers: [otlp]
exporters: [splunk_hec]

和 Vector 不同,这个 exporter 的 endpoint 需要填完整的采集路径。