hlog
hlog is the lightweight log ingestion worker that ships with hlquery. It tails one or more files, turns each line into a structured event, and can push those events into an hlquery collection such as logs.
Unlike the main daemon, hlog is not a search server. It is a small pipeline runner with a simple shape:
input_file -> event mapping -> filters -> outputs
The worker is configured with etc/hlog/run/conf/hlog.conf, while the main hlquery daemon still uses run/conf/hlquery.conf.
What hlog Is Good For
- Ingesting
hlquery.log,queries.log, or app logs into a searchable collection - Building a searchable operational log stream without adding a separate log stack
- Enriching raw file lines with fields such as host, tags, pipeline name, and timestamps
- Replaying failed inserts from a local failure buffer
Build and Run
Build from the etc/hlog directory:
cd etc/hlog
./configure
make
Common wrapper commands:
./run/hlog start
./run/hlog start --nofork
./run/hlog status
./run/hlog stop
./run/hlog restart
./run/hlog test
The normal entrypoint is etc/hlog/run/hlog. It handles pidfiles, backgrounding, status checks, and stop/restart logic. The compiled binary lives at etc/hlog/build/bin/hlog.
Typical Workflow
Example: ingest the main daemon log into a logs collection.
- Start hlquery.
- Create a collection for logs.
- Point
hlogat the daemon log file. - Start
hlog. - Query the ingested log lines with search or SQL.
Example collection:
curl -X POST http://localhost:9200/collections \
-H "Content-Type: application/json" \
-d '{
"name": "logs",
"fields": [
{"name": "message", "type": "string"},
{"name": "source_file", "type": "string"},
{"name": "source_path", "type": "string"},
{"name": "pipeline", "type": "string"},
{"name": "source_kind", "type": "string"},
{"name": "observed_at", "type": "string"},
{"name": "tags", "type": "string"}
]
}'
Start hlog against the daemon log:
cd etc/hlog
./run/hlog start --file ../../run/logs/hlquery.log --mode refresh --interval 1000
Check the data:
curl "http://localhost:9200/collections/logs/documents/search?q=error&limit=10"
Or with SQL:
curl "http://localhost:9200/sql?sql=SELECT%20COUNT(*)%20AS%20total_logs%20FROM%20logs%3B"
curl "http://localhost:9200/sql?sql=SELECT%20source_file%2C%20COUNT(*)%20AS%20total_docs%20FROM%20logs%20GROUP%20BY%20source_file%20ORDER%20BY%20total_docs%20DESC%3B"
Configuration File
The pipeline is described in etc/hlog/run/conf/hlog.conf.
Example:
<hlog>
<input_file path="tests/file.txt"
start_position="end"
method="inotify">
<event message_field="message"
path_field="source_path"
file_field="source_file"
date_field="observed_at"
date_format="%Y-%m-%dT%H:%M:%S"
tags_value="log_line"
include_date="true">
<filter_add_field field="pipeline" value="hlog">
<filter_add_field field="source_kind" value="file">
<output_stdout enabled="true">
<output_hlquery enabled="true"
endpoint="http://127.0.0.1:9200"
collection="logs"
auth_method="bearer"
auth_token=""
timeout="5">
If auth_token is empty, hlog sends requests without authentication headers. When your hlquery endpoint requires auth, set auth_token and choose auth_method="bearer" or auth_method="api-key".
Pipeline Stages
input_file: tail a fileevent: rename or enable generated event fieldsfilter_add_field: add constant fields to every eventfilter_drop_if_contains: drop lines when a field contains a substringoutput_stdout: print structured events to stdoutoutput_hlquery: send events into a collection
Watch Methods
inotify: use Linux kernel file notificationsrefresh: rescan the file everyrefresh_msauto: useinotifywhen available, otherwise fallback to refresh
Start Position
start_position="beginning": read the whole file from the startstart_position="end": only ingest newly appended lines
Use beginning when replaying old logs. Use end when attaching to a live file and you only want new lines.
Event Fields
Default emitted fields include:
idmessagepathfilehostingested_attags
The <event> block lets you rename those fields or disable some of them.
Example:
<event message_field="line"
date_field="created_at"
date_format="%Y.%m.%d"
include_host="false">
Minimal event payload:
<event message_field="raw"
include_date="false"
include_tags="false">
Configure-Time Overrides
etc/hlog/configure can rewrite values in the generated hlog.conf, which is useful for fast local setup.
Examples:
./configure --input=../../run/logs/hlquery.log
./configure --input=../../run/logs/queries.log --collection=query_logs
./configure --endpoint=http://127.0.0.1:9200 --collection=logs --method=refresh
./configure --auth-method=api-key --auth-token=secret-token
Useful flags:
--input=/path/to/file--method=inotify|refresh|auto--collection=logs--endpoint=http://127.0.0.1:9200--auth-method=bearer|api-key--auth-token=FOO--environment=dev--host=my-host--tags=my-tag--include-date=true|false--include-tags=true|false--timeout=5
Run ./configure --help inside etc/hlog for the full list.
Failure Buffer and Replay
If output_hlquery cannot insert an event, hlog appends the raw line and timestamp to etc/hlog/run/data/hlog_failed.log.
That gives you a simple replay path after the server is healthy again:
cd etc/hlog
./configure --input=../../run/data/hlog_failed.log
./run/hlog start --nofork
When replaying, use start_position="beginning" so every saved line is emitted again. After a successful replay, truncate or remove the failure log to avoid duplicate inserts.
Querying Ingested Logs
Once lines are in a collection, you can use normal search, filters, and SQL.
Examples:
curl "http://localhost:9200/collections/logs/documents/search?q=timeout&limit=20"
curl "http://localhost:9200/sql?sql=SELECT%20COUNT(*)%20AS%20total_logs%20FROM%20logs%3B"
curl "http://localhost:9200/sql?sql=SELECT%20source_kind%2C%20COUNT(*)%20AS%20total_docs%20FROM%20logs%20GROUP%20BY%20source_kind%3B"
Inside talk:
localhost:9200> use logs
localhost:9200|logs> search error 10 0 observed_at:desc
localhost:9200|logs> sql: SELECT COUNT(*) AS total_logs FROM logs;
localhost:9200|logs> sql: SELECT source_file, COUNT(*) AS total_docs FROM logs GROUP BY source_file ORDER BY total_docs DESC;
Operational Notes
hlogcan fall back to file log targets declared inhlquery.confwhen no explicitinput_filestages are configured.refreshmode is simpler and portable;inotifyis usually cheaper on Linux for active files.- If a log file is rotated externally, prefer validating behavior in your environment before relying on unattended ingestion.
- For analytics-style log queries, SQL grouped aggregates are usually easier to consume than raw hit output.
For implementation details and the standalone worker layout, see etc/hlog/README.md.