A Logstash file input watches an existing log file or file pattern and turns each new line into a pipeline event. Operators use it when an application writes plain text logs locally and Logstash is responsible for sending those lines to Elasticsearch or another output.
The file input tracks byte offsets in a sincedb file so restarts can resume from the last consumed position. Tail mode follows files that keep growing, while read mode is for content-complete files, so a continuously written application log should normally use an absolute path, explicit tail mode, and a dedicated sincedb_path.
The pipeline needs a readable source file, a validated configuration, and a real event test after the service restarts. start_position ⇒ “beginning” affects only files that do not already have sincedb state, and remote network filesystems can produce misleading file identity or offset behavior.
$ sudo ls /var/log/app/*.log /var/log/app/app-error.log /var/log/app/app.log
Logstash file input paths must be absolute. Keep rotated compressed files out of the match with exclude unless the pipeline is intentionally reading archive files in read mode.
$ sudo -u logstash test -r /var/log/app/app.log
No output means the read check passed. If the command exits with an error, fix the file mode, file group, or parent-directory execute permission before editing the pipeline.
$ sudoedit /etc/logstash/conf.d/40-file-input.conf
Package installs normally load files under /etc/logstash/conf.d/ through /etc/logstash/pipelines.yml. Use the active path.config value on hosts with custom pipeline manifests.
Related: How to configure Logstash pipelines
input {
file {
id => "app_file_input"
path => ["/var/log/app/*.log"]
exclude => ["*.gz"]
mode => "tail"
start_position => "beginning"
sincedb_path => "/var/lib/logstash/file-input-app.sincedb"
}
}
output {
elasticsearch {
hosts => ["http://elasticsearch.example.net:9200"]
data_stream => false
ilm_enabled => false
index => "app-logs-%{+YYYY.MM.dd}"
}
}
Use a different sincedb_path for each file input. Reusing the same file lets inputs overwrite each other's offsets, and deleting it can replay old lines into the output.
The elasticsearch output block is a minimal index-mode destination for the smoke test. Use the dedicated output guide when the cluster requires HTTPS, authentication, custom certificates, ILM, or data streams.
Related: How to configure Logstash output to Elasticsearch
$ sudo -u logstash /usr/share/logstash/bin/logstash --path.settings /etc/logstash --path.data /tmp/logstash-file-input-test --config.test_and_exit -f /etc/logstash/conf.d/40-file-input.conf Using bundled JDK: /usr/share/logstash/jdk ##### snipped ##### Configuration OK [2026-06-18T15:17:02,718][INFO ][logstash.runner ] Using config.test_and_exit mode. Config Validation Result: OK. Exiting Logstash
The temporary --path.data directory keeps the one-off validation away from /var/lib/logstash. Current package installs should run this check as the logstash service account unless allow_superuser was intentionally enabled.
$ sudo rm --recursive --force /tmp/logstash-file-input-test
$ sudo systemctl restart logstash.service
Restarting Logstash pauses every active pipeline while inputs, filters, and outputs reopen.
$ sudo systemctl status logstash.service --no-pager --lines=0
● logstash.service - logstash
Loaded: loaded (/usr/lib/systemd/system/logstash.service; enabled; preset: enabled)
Active: active (running) since Thu 2026-06-18 15:24:41 UTC; 7s ago
Main PID: 24817 (java)
Tasks: 96 (limit: 28486)
Memory: 1.0G
$ printf '2026-06-18T15:25:00Z INFO request_id=9b2a5f2c status=200 path=/health logstash-file-input-test\n' | sudo tee -a /var/log/app/app.log 2026-06-18T15:25:00Z INFO request_id=9b2a5f2c status=200 path=/health logstash-file-input-test
Because the input runs in tail mode, append the smoke-test line after Logstash is running so it is treated as new data even when older sincedb state exists.
$ sudo ls -l /var/lib/logstash/file-input-app.sincedb -rw------- 1 logstash logstash 105 Jun 18 15:25 /var/lib/logstash/file-input-app.sincedb
The timestamp should change after new lines are consumed. A missing file usually means the watched path did not match, Logstash could not read the file, or the pipeline did not start.
$ curl --silent --show-error --fail "http://elasticsearch.example.net:9200/app-logs-*/_count?q=logstash-file-input-test&pretty"
{
"count" : 1,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
}
}
A count of 1 or more confirms that the file input read the appended line and the output wrote it to the expected index pattern. If the count stays at 0, check /var/log/logstash/logstash-plain.log for file permission, sincedb, and output connection errors.