P4LF is the Perforce Log Feeder — a lightweight Go service that continuously
tails a Perforce server log (P4LOG) and writes compressed chunk files to a
configurable directory. External automation (outside the scope of this project)
is expected to pick up files matching log.*.gz, ship them elsewhere (e.g. for
ingestion into Splunk), and then delete them. P4LF's job is to populate the
directory; external software does the rest.
This near-real-time feeding of log data enables analytics and diagnostics in tools like Splunk while the Perforce server continues to run normally.
This works with servers deployed with the P4 Server Deployment Package (SDP).
Executables, binaries, and config files are deployed in the SDP structure in
the /p4/common/site/log_feeder folder.
The quickest way to install p4lf on a Linux SDP server is the included
install.sh script, run as root (it downloads the platform binary, example
config, and systemd unit from workshop.perforce.com):
curl -fsSL https://workshop.perforce.com/download/p4lf/main/install.sh -o install.sh
sudo bash install.sh
What it does:
p4lf binary, p4lf.cfg.example, and p4lf.service for
the selected stream (default: main) from workshop.perforce.com.<install_dir>/p4lf (default install dir:
/p4/common/site/log_feeder).p4lf.cfg.example, and — on first install only — copies it to
p4lf.cfg as a starting point. An existing p4lf.cfg is never
overwritten./etc/systemd/system/p4lf.service (only if it
differs from what's already on disk) and runs systemctl daemon-reload
when it does.Useful options:
-s <stream> — P4 stream to install from (default: main; e.g. dev,
r1.0).-d <dir> — Installation directory (default: /p4/common/site/log_feeder).-n — Dry run: show what would be done without making any changes.-h — Show help.After installing, edit the generated p4lf.cfg (set P4LogFile at minimum
if $P4LOG isn't available in the service environment — see
Config File Settings below), then:
sudo systemctl enable p4lf
sudo systemctl start p4lf
sudo systemctl status p4lf
journalctl -u p4lf -f
See the comments at the top of install.sh for the full option reference.
P4LF tails the P4LOG directly by reading bytes from the file, using an inode-based rotation detection scheme:
LogTailDelay interval, P4LF reads all new bytes from the P4LOG
since the last read and compresses them into a chunk file.LogChunksDir
with the naming format: log.<YYYY-MM-DD>.<startOffset>.<endOffset>.gzMaxRotationRecoverySize) and logs the event.StateFile after each flush,
so P4LF resumes correctly after a restart with no gaps or duplicates.When MaxLogChunks > 0 (default: 5000), P4LF enforces the limit by deleting
the oldest chunk files before writing a new one. This ensures p4lf keeps
running and capturing current P4LOG data even when the downstream consumer
(e.g. Splunk) is not processing files. A warning is logged whenever files are
deleted, noting that log data will be lost for those chunks.
MinLogSpace provides an independent disk-space guard: when free space in
LogChunksDir falls below the configured threshold, chunk writes are paused
until space is available.
The config file uses KEY = VALUE format. Lines beginning with # are
comments. The service reloads the config on SIGHUP or when it detects a
modification time change on the config file.
P4LogFile — Path to the Perforce server log to tail.
Default: $P4LOG (set by SDP p4_vars).
LogTailDelay — How often to flush a log chunk.
Format: <integer>[s|m|h] (e.g. 60s, 5m, 1h). Default: 60s.
LogChunksDir — Directory where compressed chunk files are written.
Default: $LOGS/logchunks.
MaxLogChunks — Maximum number of log.*.gz files in LogChunksDir.
When exceeded, the oldest files are deleted (oldest-first) to make room,
and a warning is logged that log data has been lost. Set to 0 for no
limit. Default: 5000.
MinLogSpace — Minimum free space in the LogChunksDir volume before
chunk writes are paused. Accepts a percentage (e.g. 3%) or a size
(e.g. 500M, 3G). None or 0 = no check. Default: None.
MaxLogSize — Maximum size of p4lf's own log ($LOGS/p4lf.log) before
it is rotated and gzipped. 0 = no rotation. Default: 100M.
MaxRotationRecoverySize — When a P4LOG rotation is detected, p4lf
reads from the beginning of the new log if its size is ≤ this value.
If the new log is already larger (e.g. the service was down for a long
time), p4lf starts from EOF and logs a warning to avoid ingesting a huge
backlog. 0 = always read from the beginning. Default: 500M.
StateFile — Path for the persistent state file (inode + byte offset).
Default: $LOGS/p4lf.state.
ReadFromStart — On first run (no state file), whether to read the
P4LOG from the beginning (true) or from the current end (false).
Default: true.
Debug — Verbosity: 0 = off, 1 = debug, 2 = pedantic. Default: 0.
LogTailDelay ticker fires periodically. On each tick, p4lf:
a. Checks for P4LOG rotation (inode change or truncation).
b. Reads all new bytes from the P4LOG.
c. If MaxLogChunks > 0 and the limit is reached, deletes the oldest files.
d. Compresses the bytes and atomically writes log.<date>.<start>.<end>.gz.
e. Saves updated state (inode + offset) to StateFile.p4lf, operating as User=perforce.MaxRotationRecoverySize controls this trade-off.p4 logtail command is used..tmp file
first, then renamed into place.$P4LOG and $LOGS environment variables
are used as defaults; the systemd unit sources /p4/common/bin/p4_vars.Working on p4lf itself (building, testing, versioning, or the Perforce
dev → main → release promotion workflow)? See
docs/DeveloperGuide.md.