Configuration
Every service in the system resolves configuration through the same precedence chain.
On this page
Precedence
Every service resolves configuration through HostingExtensions in this order —
later sources win:
Resources/Config/default.yaml, embedded in the assembly. On first run it is copied to the on-disk config path if no file is there, so a fresh install has a documented starting point.{ConfigFolder}/{Name}.yaml, reloaded on change.{ConfigFolder}/{Name}.{Environment}.yaml.- User secrets — Development environment only.
- Environment variables prefixed
PROVCOLLECTOR_, with__separating nested keys. - Command-line arguments.
So a nested key like Kafka:BootstrapServers becomes:
PROVCOLLECTOR_KAFKA__BOOTSTRAPSERVERS=broker:19092
CreateConfiguredApplicationBuilderstarts fromHost.CreateEmptyApplicationBuilderrather than the default builder, since the default logging and configuration providers are the ones this chain replaces. Inheriting them would produce two overlapping sets of rules.
Paths
Default paths come from PlatformConstants:
| Windows | Linux | |
|---|---|---|
| Config | %LOCALAPPDATA%\ProvCollector\{Name}\Config |
/etc/ProvCollector/{Name}/Config/ |
| Logs | %LOCALAPPDATA%\ProvCollector\{Name}\Logs |
/var/log/ProvCollector/{Name} |
{Name} is the entry assembly name with the ProvCollector prefix stripped, so
ProvCollector.EventProcessor uses .../EventProcessor/.
The installed agent is the exception
The installed Windows agent and updater use the machine-wide layout instead, set
explicitly in Program.cs and mirrored by UpdaterPaths:
C:\ProgramData\ProvCollector\Agent.Windows\Config
C:\ProgramData\ProvCollector\Agent.Windows\Logs
LocalApplicationDatafor aLocalSystemservice resolves to the systemprofile directory, which is not a location an operator would ordinarily inspect.
Credential protection
Agent SASL credentials are stored encrypted in the config file and decrypted at
startup by a PostConfigure<KafkaOptions> hook:
- Windows —
DPApiCredentialsProtector(DPAPI). - Linux —
PlatformCredentialsProtector.
IsProtected recognises the wrapped form, so a plaintext value in a development
config still works — you do not have to encrypt a value just to test locally.
Pushing configuration to a host
The dashboard reads and writes agent configuration through the fleet API, which
routes it to the updater’s GetConfig / PushConfig command handlers.
PushConfig writes the new YAML and restarts the affected service.
Because a pushed payload keys files by name and the dashboard does not always
know which platform it is talking to, IsAgentConfigFileName /
IsUpdaterConfigFileName accept several spellings and route each to the right
destination.
UpdaterPathsis the single source of truth for where those files land, and host startup,GetConfigandPushConfigall read it. A pushed config written to a path the services do not read produces the same observable result as a config that was never applied.
The fleet API reports config staleness, so the dashboard can distinguish “the host has this config” from “the host has been sent this config”.
A minimal agent config
Kafka:
BootstrapServers: broker:19092
SchemaRegistryUrl: https://broker:18081
SaslUsername: agent
SaslPassword: "..." # encrypted at rest once installed
EventBufferCapacity: 10000
EventSource:
EnabledSources: [Process, FileIO, IP, DNS, Registry, Account]
Serilog:
MinimumLevel: Information
A minimal event processor config
EventProcessor:
Processors: [IdentityResolver]
BufferLimit: 5000
FlushTimeout: "00:00:30"
WorkerThreads: 0 # 0 = Environment.ProcessorCount
IdentityStore: InMemory
EnableIdentityChangelog: true
IdentityRetention: "7.00:00:00" # must equal Writer:NodeCarryForwardWindow
MaxTrackedIdentities: 2000000
OffsetCommitInterval: "00:00:05"
See Settings reference for the full list and Invariants for the values that must agree across services.
Logging
Serilog throughout, configured by HostingExtensions.ConfigureAppLogging. A
bootstrap logger is installed before configuration is read, so early failures
such as a malformed YAML file or a missing certificate are recorded rather than
lost to an unconfigured logger.
The updater additionally forwards its own log events to FleetServer over
SignalR (SignalRSerilogSink), which is what populates the dashboard’s live log
view. LogStore on the server keeps bounded ring buffers behind the SSE streams:
CommandLogRetention (default 5 000) globally, UpdaterLogRetentionPerAgent
(default 2 000) per agent.