Class FileAuditSink
- All Implemented Interfaces:
McpAuditSink
This is the record every tier gets. A licence buys a longer window and the right to send the records somewhere else; it does not buy the existence of a record, because a product sold on knowing what an agent did cannot have a free tier that knows nothing.
The same file mechanics as the spool, the opposite lifecycle
SpoolingAuditSink also writes rolling JSONL segments, and the resemblance is deliberate.
But a spool is a delivery queue: a segment exists until a delegate confirms it, and is then
deleted as soon as possible. This is a retention store: a segment exists until it is old
enough to delete, and there is no delegate to confirm anything. They disagree about the one thing
that decides when a file may be removed, which is why this is a sibling rather than a subclass.
Do not wrap this in a spool. Spooling a sink whose delivery mechanism is "write it to
disk" produces two copies of the same bytes, one of which is deleted the moment the other is
written. McpAuditSinks composes it directly for that reason.
What "retention" costs, and what it does not promise
Records that age out are gone. That is the feature, not a limitation: a store that quietly kept everything would be a worse position to be in than one that deletes on a schedule, because the retention window is what makes it defensible under a storage-limitation rule.
The window is enforced at segment granularity, so a record may outlive it by up to one segment. Segments roll on size, so a quiet server holds its oldest records longer than a busy one. Nothing here should be relied on to delete a specific record at a specific minute.
MCP_AUDIT_RETENTION_DAYS=0 means no trail at all — this sink is not built.
See fromEnvironment(String).
Two ways records are lost, and only one of them counts
Ageing out is the policy working and is not counted as a drop. Being evicted early
because MCP_AUDIT_FILE_MAX_BYTES was reached is a drop: those records were inside
the window an operator was promised and are gone anyway, which is exactly what
getDroppedCount() exists to say.
Copyright 2003-2026 ATB Consultancy Services Ltd
(formerly Orinda Software Ltd, Dublin, Ireland)
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final Stringstatic final longGenerous enough for a real trail, small enough that it cannot quietly fill a volume.static final intTwenty-four hours: the free tier's window, and the safe default for everyone else.static final longMatches the spool, so the two directories behave alike to anyone looking at them.static final Stringstatic final Stringstatic final Stringstatic final Stringstatic final Stringstatic final String -
Constructor Summary
ConstructorsConstructorDescriptionFileAuditSink(Path theDirectoryValue, int theRetentionDaysValue, long theMaxBytesValue, long theSegmentBytesValue) -
Method Summary
Modifier and TypeMethodDescriptionvoidclose()Close the active segment so the trail on disk is complete, and say what was lost.describe()A short human description of what this sink is, for an operator reading a status page.static FileAuditSinkfromEnvironment(String theSubdirectoryValue) Build from the environment, or null when no local trail is wanted.static FileAuditSinkfromEnvironment(String theSubdirectoryValue, int theCeilingDays) AsfromEnvironment(String), with a hard ceiling on the window.longRecords written.Where the trail is, so a status page can name it.longRecords evicted before their window expired, or lost to a write failure.longAlways zero: there is no delivery step to be behind on.intThe configured window, in days.longHow far back the trail actually goes, in millis since the epoch, or -1 when it is empty.static longWhen this segment was closed, from its name, falling back to the file's own timestamp.voidrecord(McpAuditEvent theEvent) Record one call.Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface com.mcpdbwizard.pub.McpAuditSink
flush
-
Field Details
-
DIRECTORY_VARIABLE
- See Also:
-
RETENTION_DAYS_VARIABLE
- See Also:
-
MAX_BYTES_VARIABLE
- See Also:
-
SEGMENT_BYTES_VARIABLE
- See Also:
-
DEFAULT_RETENTION_DAYS
public static final int DEFAULT_RETENTION_DAYSTwenty-four hours: the free tier's window, and the safe default for everyone else.- See Also:
-
DEFAULT_MAX_BYTES
public static final long DEFAULT_MAX_BYTESGenerous enough for a real trail, small enough that it cannot quietly fill a volume.- See Also:
-
DEFAULT_SEGMENT_BYTES
public static final long DEFAULT_SEGMENT_BYTESMatches the spool, so the two directories behave alike to anyone looking at them.- See Also:
-
ACTIVE_NAME
- See Also:
-
SEGMENT_PREFIX
- See Also:
-
SEGMENT_SUFFIX
- See Also:
-
-
Constructor Details
-
FileAuditSink
public FileAuditSink(Path theDirectoryValue, int theRetentionDaysValue, long theMaxBytesValue, long theSegmentBytesValue)
-
-
Method Details
-
fromEnvironment
Build from the environment, or null when no local trail is wanted.Returns null in two cases, and the difference matters to nobody but is worth stating: no
DIRECTORY_VARIABLEmeans the deployment never asked for a trail, andMCP_AUDIT_RETENTION_DAYS=0means it asked for one and then asked to keep nothing. Zero is a supported, deliberate setting — the deployment that streams every record to a SIEM and wants no production data resting on this box.Zero is never inferred. An unset window is one day, and a window that cannot be parsed stops start-up. Nothing here silently decides to keep no records.
- Parameters:
theSubdirectoryValue- a per-process directory name, or null; a trail directory tolerates exactly one writer, for the same reason a spool does
-
fromEnvironment
AsfromEnvironment(String), with a hard ceiling on the window.The ceiling exists because a process cannot always be trusted with its own environment. A generated server is launched by something that sets its variables deliberately; the web application reads the variables an operator gave it, so a window it is not entitled to has to be cut down here rather than believed.
Deliberately an int, not a licence. This module is the Apache-2.0 half and must carry no licensing logic; the caller works out what the ceiling is and passes a number.
- Parameters:
theCeilingDays- the largest window to honour, whatever the environment asks for
-
record
Record one call. Must not throw.Appends to the trail. Never throws.
- Specified by:
recordin interfaceMcpAuditSink- Parameters:
theEvent- the call to record; never null
-
openedAt
When this segment was closed, from its name, falling back to the file's own timestamp.The fallback matters: a file someone copied, renamed or restored from a backup would otherwise be treated as having been opened at the epoch and deleted on the next prune.
-
oldestRecordMillis
public long oldestRecordMillis()How far back the trail actually goes, in millis since the epoch, or -1 when it is empty. -
getRetentionDays
public int getRetentionDays()The configured window, in days. -
getDirectory
Where the trail is, so a status page can name it. -
getDroppedCount
public long getDroppedCount()Records evicted before their window expired, or lost to a write failure.Deliberately NOT counting records that simply aged out. Those left on schedule, and reporting them as losses would make a healthy trail permanently look broken.
- Specified by:
getDroppedCountin interfaceMcpAuditSink
-
getDeliveredCount
public long getDeliveredCount()Records written. For this sink, written is delivered.- Specified by:
getDeliveredCountin interfaceMcpAuditSink
-
getPendingCount
public long getPendingCount()Always zero: there is no delivery step to be behind on.- Specified by:
getPendingCountin interfaceMcpAuditSink
-
describe
Description copied from interface:McpAuditSinkA short human description of what this sink is, for an operator reading a status page.Defaults to the class name. A wrapper overrides it to name what it wraps — otherwise a spooled Kafka sink reports only "SpoolingAuditSink", and where the records finally go is the part being asked about.
- Specified by:
describein interfaceMcpAuditSink
-
close
public void close()Close the active segment so the trail on disk is complete, and say what was lost.- Specified by:
closein interfaceMcpAuditSink
-