Rate
Stop any single log pattern from dominating its container's volume, on the forwarder, before that volume is billed downstream. Errors and warnings keep flowing, and patterns on a protection list are never touched.
The rate regulator watches each container's recent volume and trims back any one pattern that crosses a fixed share of it. That pattern is the same symbolMessage value a Reporter attributes cost to, so a top spender maps straight to what gets regulated. Nothing is sampled until a pattern actually dominates.
The cap
A pattern is left alone until it crosses maxSharePerFieldSet (default 20%) of its container's recent volume. At or below the cap every event is kept. Above it, the pattern is trimmed back toward the cap by dropping a fraction of its events.
Share is measured per container over a rolling window (resetIntervalMs, default 4 minutes): (pattern bytes + event) / (container bytes + event). The window is recent rather than all-time, so a pattern that spikes during a deploy and then goes quiet stops being trimmed on its own.
Severity floors
The cap never silences high-severity logs. severityFloors sets a minimum retention per level that beats the cap: even a pattern over its cap keeps at least Error 50%, Warn 30%, Info 10%. The floor reads the severity the level enrichment produced, so it applies whatever field the original log used.
Warmup
A container is left unregulated for warmupMs (default 5 minutes) after this regulator instance first sees its events. Lower for fast-starting apps that should be capped sooner after a restart, raise for slow-ramping JVMs or workloads with long init phases.
The warmup exists because the regulator's per-pattern sample counts start empty. Without a few minutes of accumulation, a low-volume pattern can look dominant purely because of ordering. Five minutes gives enough samples for typical Kubernetes traffic to tell a noisy pattern from a quiet one.
"First sees" is per regulator instance, not per container birth. A container that has been running for hours but whose events have only just started flowing through this regulator, after a regulator restart or a forwarder reconnect, restarts the warmup window. On a daemonset rolling restart the cap is therefore disabled for warmupMs per node as it cycles.
The first baselineCount events (default 5) of every pattern are also kept each window, so even a heavily-trimmed pattern leaves a sample to inspect.
Protection list
An optional mute file overrides the regulator for patterns an operator has declared. A listed, active pattern is decided by its entry, so the human declaration wins and the regulator is skipped for it; every other pattern is handled by the cap. The two run together rather than as separate modes.
File format, CSV with a header row, keyed by the joined fieldNames:
sampleRateretains that fraction:1.0is never sampled,0.0is a full mute.untilEpochSecexpires the entry, which then self-heals to a no-op.reasonis free text for audit.
The severity floor still applies, so a 0.0 mute never silences ERROR or FATAL. The file is typically committed to a repo and pulled via gitops, so each change carries a diff, a review, and a merge. The engine hot-reloads on in-place file writes (the gitops pattern); Kubernetes ConfigMap mounts don't reload because the CM swap is a symlink rename, not an in-place write.
Per-container caps
An optional cap file sets a byte cap for a specific container in priority over the fleet-wide absoluteCap. Listed containers get the file's cap; unlisted containers fall back to absoluteCap (or to no cap, when absoluteCap is 0).
File format, CSV with a header row, keyed by the containerField value (k8s container name by default):
bytesis the per-pattern per-window cap for the container.0exempts the container from the absolute cap.untilEpochSecexpires the entry, which then self-heals to a no-op.reasonis free text for audit. Must not contain commas (would break CSV parsing).
The cap value changes; the share guard and severity floor still apply. Intended use is via the log10x_configure_regulator MCP tool, which derives per-container caps from a monthly dollar budget and opens a PR against the file.
Same hot-reload contract as the mute file above: in-place writes only; Kubernetes ConfigMap mounts don't reload.
Containers
Share is scoped per container, named by containerField (default the k8s container name). That name is stable across replicas, so scaling from one pod to ten does not bypass the cap, and a sidecar never spends the application container's share. Use container, never pod.
Outside Kubernetes, or when no container field is present, the regulator falls back to a single node-wide bucket and caps each pattern across the node.
Savings
Drops are measured, not estimated. The receive-stage aggregators tally every event by pattern and container both before and after regulation, so the saving for a pattern is the volume seen minus the volume emitted. A dropped event still counts as seen, so the figure reflects exactly what the regulator removed.
Wiring
rateReceiver:
fieldNames:
- symbolMessage # the pattern identity
containerField: container # scopes the cap denominator
absoluteCap: 10485760 # 10 MB per pattern per container per window (optional; 0 = no fleet-wide cap)
minSharePercent: 0.05 # share guard (sanity)
severityFloors:
- INFO=0.1
- WARN=0.3
- ERROR=0.5
warmupMs: 300000 # 5m per-instance grace; raise for slow-ramping apps
baselineCount: 5
capLookup:
# file: $=path("data/caps") + "/caps.csv" # optional per-container overrides
retain: $=parseDuration("10m")
Tune these values in this config block, not via container environment variables. Any rateReceiver: key set here resolves to a launch argument at engine init and shadows a same-named env var, so env-only overrides are silently ignored. Edit the config (via a gitops PR) to change a value at runtime.
Config Files
To configure the rate receiver module, Edit these files.
Below is the default configuration from: rate/config.yaml.
ewogICJ0eXBlIiA6ICJvYmplY3QiLAogICJwcm9wZXJ0aWVzIiA6IHsKICAgICJpbmNsdWRlIiA6IHsKICAgICAgInR5cGUiIDogInN0cmluZyIKICAgIH0sCiAgICAidGVueCIgOiB7CiAgICAgICJ0eXBlIiA6ICJzdHJpbmciCiAgICB9LAogICAgInJhdGVSZWNlaXZlciIgOiB7CiAgICAgICJ0eXBlIiA6ICJvYmplY3QiLAogICAgICAiYWRkaXRpb25hbFByb3BlcnRpZXMiIDogZmFsc2UsCiAgICAgICJwcm9wZXJ0aWVzIiA6IHsKICAgICAgICAiZmllbGROYW1lcyIgOiB7CiAgICAgICAgICAidHlwZSIgOiBbCiAgICAgICAgICAgICJhcnJheSIsCiAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAibnVsbCIKICAgICAgICAgIF0sCiAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiTGlzdCBvZiBUZW5YT2JqZWN0IGZpZWxkcyB0byBpZGVudGlmeSByYXRlIGNvdW50ZXIgYnVja2V0c1xuXG5EZWZpbmVzIHRoZSBsaXN0IG9mIFRlblhPYmplY3QgZmllbGQgbmFtZXMgZXh0cmFjdGVkIHRvIGlkZW50aWZ5IHdoaWNoIHJhdGUgY291bnRlciBidWNrZXQgYW4gZXZlbnQgYmVsb25ncyB0by4gVGhlIGxpc3QgdXN1YWxseSBjb250YWlucyB0aGUgYHN5bWJvbE1lc3NhZ2VgIGZpZWxkIGZyb20gdGhlIFttZXNzYWdlIGVucmljaG1lbnRdKGh0dHBzOi8vZG9jLmxvZzEweC5jb20vcnVuL2luaXRpYWxpemUvbWVzc2FnZS8pIG1vZHVsZSBidXQgY2FuIGluY2x1ZGUgYWRkaXRpb25hbCBmaWVsZHMgbGlrZSBbR2VvSVBdKGh0dHBzOi8vZG9jLmxvZzEweC5jb20vcnVuL2luaXRpYWxpemUvZ2VvSVAvKSwgW0hUVFAgY29kZV0oaHR0cHM6Ly9kb2MubG9nMTB4LmNvbS9ydW4vaW5pdGlhbGl6ZS9odHRwQ29kZS8pLCBbazhzIGNvbnRhaW5lciBuYW1lXShodHRwczovL2RvYy5sb2cxMHguY29tL3J1bi9pbml0aWFsaXplL2s4cy8pLCBvciBjdXN0b20gZW5yaWNobWVudHMgZm9yIG11bHRpLWRpbWVuc2lvbmFsIHJhdGUgdHJhY2tpbmcuICAqKkNvbW1vbiBVc2UgQ2FzZXM6KiogICoqU2luZ2xlLWFwcCByZWNlaXZpbmcgKHBlciBldmVudCB0eXBlKToqKiBgYGB5YW1sIHJhdGVSZWNlaXZlckZpZWxkTmFtZXM6ICAgLSBzeW1ib2xNZXNzYWdlIGBgYCAgKipNdWx0aS1kaW1lbnNpb25hbCB0cmFja2luZyAoZXZlbnQgdHlwZSArIGdlb2dyYXBoeSArIEhUVFAgc3RhdHVzKToqKiBgYGB5YW1sIHJhdGVSZWNlaXZlckZpZWxkTmFtZXM6ICAgLSBzeW1ib2xNZXNzYWdlICAgLSBjb3VudHJ5ICAgLSBodHRwQ29kZSBgYGAgICoqTXVsdGktYXBwIHJlY2VpdmluZyBpbiBLdWJlcm5ldGVzOioqICAqT3B0aW9uIEE6IENhcCB0b3RhbCBzcGVuZCBwZXIgYXBwIChhbGwgZXZlbnQgdHlwZXMgY29tYmluZWQpOiogYGBgeWFtbCByYXRlUmVjZWl2ZXJGaWVsZE5hbWVzOiAgIC0gY29udGFpbmVyICAjIEFnZ3JlZ2F0ZXMgYWxsIGV2ZW50IHR5cGVzIGZvciBlYWNoIGFwcCBgYGAgRWFjaCBhcHAncyB0b3RhbCBzcGVuZCAoYWNyb3NzIGFsbCBldmVudCB0eXBlcyBhbmQgcG9kcykgZ2V0cyBvbmUgY2FwLiBTaW1wbGUgYnV0IGxvc2VzIGV2ZW50LXR5cGUgaW50ZWxsaWdlbmNlLiAgKk9wdGlvbiBCOiBDYXAgc3BlbmQgcGVyIGV2ZW50IHR5cGUgcGVyIGFwcDoqIGBgYHlhbWwgcmF0ZVJlY2VpdmVyRmllbGROYW1lczogICAtIHN5bWJvbE1lc3NhZ2UgICMgRXZlbnQgdHlwZSAgIC0gY29udGFpbmVyICAgICAgIyBBcHAgaWRlbnRpZmllciAoc2FtZSBhY3Jvc3MgYWxsIHBvZHMpIGBgYCBFYWNoIChldmVudCB0eXBlIMOXIGFwcCkgY29tYm8gZ2V0cyBpdHMgb3duIGNhcC4gUHJvdmlkZXMgZmFpcm5lc3Mgd2l0aGluIGFwcHMgYnV0IGFsbG93cyBhcHBzIHdpdGggbWFueSBldmVudCB0eXBlcyB0byBwb3RlbnRpYWxseSBleGNlZWQgb25lIHRvdGFsIGNhcC4gIFRoZSBjb250YWluZXIgaXMgY29uZmlndXJlZCBzZXBhcmF0ZWx5IHZpYSBgcmF0ZVJlY2VpdmVyQ29udGFpbmVyRmllbGRgIChpdCBzY29wZXMgdGhlIHNoYXJlIGRlbm9taW5hdG9yKSwgc28gYGZpZWxkTmFtZXNgIGlkZW50aWZpZXMgb25seSB0aGUgbG9nIHBhdHRlcm4gaXRzZWxmLiAoRGVmYXVsdDogW1wic3ltYm9sTWVzc2FnZVwiXSkiLAogICAgICAgICAgIml0ZW1zIiA6IHsKICAgICAgICAgICAgInR5cGUiIDogInN0cmluZyIKICAgICAgICAgIH0sCiAgICAgICAgICAiZGVmYXVsdCIgOiBbCiAgICAgICAgICAgICJzeW1ib2xNZXNzYWdlIgogICAgICAgICAgXQogICAgICAgIH0sCiAgICAgICAgImNvbnRhaW5lckZpZWxkIiA6IHsKICAgICAgICAgICJ0eXBlIiA6IFsKICAgICAgICAgICAgInN0cmluZyIsCiAgICAgICAgICAgICJudWxsIgogICAgICAgICAgXSwKICAgICAgICAgICJtYXJrZG93bkRlc2NyaXB0aW9uIiA6ICJGaWVsZCB3aG9zZSB2YWx1ZSBzY29wZXMgdGhlIHBlci1jb250YWluZXIgc2hhcmUgZGVub21pbmF0b3JcblxuTmFtZXMgdGhlIGZpZWxkIHdob3NlIHZhbHVlIHNjb3BlcyB0aGUgc2hhcmUgZGVub21pbmF0b3IgKHRoZSBwZXItY29udGFpbmVyIHRvdGFsKS4gQSBwYXR0ZXJuJ3Mgc2hhcmUgaXMgbWVhc3VyZWQgYWdhaW5zdCB0aGUgdG90YWwgdm9sdW1lIG9mIHRoZSBjb250YWluZXIgaXQgYmVsb25ncyB0bywgc28gdGhlIGNhcCBpcyBlbmZvcmNlZCBwZXIgYChwYXR0ZXJuLCBjb250YWluZXIpYC4gIERlZmF1bHRzIHRvIHRoZSBbazhzIGNvbnRhaW5lciBuYW1lXShodHRwczovL2RvYy5sb2cxMHguY29tL3J1bi9pbml0aWFsaXplL2s4cy8pLCB3aGljaCBpcyBzdGFibGUgYWNyb3NzIHBvZCByZXBsaWNhcyDigJQgc2NhbGluZyBmcm9tIDEgdG8gMTAgcG9kcyBkb2VzIG5vdCBieXBhc3MgdGhlIGNhcCwgYW5kIGEgc2lkZWNhciBuZXZlciBjb25zdW1lcyB0aGUgYXBwbGljYXRpb24gY29udGFpbmVyJ3MgYWxsb3dhbmNlLiBVc2UgYGNvbnRhaW5lcmAsIG5ldmVyIGBwb2RgLiAgV2hlbiB0aGUgZmllbGQgaXMgYWJzZW50IG9uIGFuIGV2ZW50IChub24tazhzIGlucHV0LCBvciBubyBrOHMgZXh0cmFjdG9yIGNvbmZpZ3VyZWQpLCB0aGUgcmVndWxhdG9yIGZhbGxzIGJhY2sgdG8gYSBzaW5nbGUgbm9kZS13aWRlIGJ1Y2tldCBhbmQgZW5mb3JjZXMgdGhlIGNhcCBwZXIgcGF0dGVybiBhY3Jvc3MgdGhlIG5vZGUuIChEZWZhdWx0OiApIiwKICAgICAgICAgICJkZWZhdWx0IiA6ICIiCiAgICAgICAgfSwKICAgICAgICAicmVzZXRJbnRlcnZhbE1zIiA6IHsKICAgICAgICAgICJ0eXBlIiA6IFsKICAgICAgICAgICAgIm51bWJlciIsCiAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAibnVsbCIKICAgICAgICAgIF0sCiAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiUmVzZXQgaW50ZXJ2YWwgZm9yIHJhdGUgY291bnRlcnMgaW4gbWlsbGlzZWNvbmRzXG5cbkRlZmluZXMgdGhlIHdpbmRvdyBpbiBtaWxsaXNlY29uZHMgb3ZlciB3aGljaCBhIHBhdHRlcm4ncyByZWNlbnQgc2hhcmUgaXMgbWVhc3VyZWQuIFRoZSBjb3VudGVycyByZXNldCBldmVyeSBpbnRlcnZhbCwgc28gc2hhcmUgcmVmbGVjdHMgcmVjZW50IHZvbHVtZSByYXRoZXIgdGhhbiBhbGwtdGltZSB0b3RhbHMuICBTaG9ydGVyIHdpbmRvd3MgKGUuZy4sIDEgbWludXRlKSBhcmUgbW9yZSByZWFjdGl2ZSBidXQgbm9pc2llcjsgbG9uZ2VyIHdpbmRvd3MgYXJlIHNtb290aGVyIGJ1dCBzbG93ZXIgdG8gYWRhcHQuIFRoZSBkZWZhdWx0IG9mIDQgbWludXRlcyBiYWxhbmNlcyB0aGUgdHdvLiAgKipWYWxpZGF0aW9uOioqIE11c3QgYmUgYXQgbGVhc3QgNjAwMDAgbWlsbGlzZWNvbmRzICgxIG1pbnV0ZSkuIFRoZSBlbmdpbmUgY2FwcyBjb3VudGVyIHJlc2V0IGludGVydmFscyBhdCAyNTUgc2Vjb25kcywgc28gdGhlIGVmZmVjdGl2ZSBtYXhpbXVtIHdpbmRvdyBpcyB+NC4yNSBtaW51dGVzIOKAlCB2YWx1ZXMgYWJvdmUgdGhhdCBhcmUgY2xhbXBlZC4gKEFjY2VwdHMgbnVtYmVyIG9yIHN0cmluZyB3aXRoICQ9IHByZWZpeCBmb3IgcnVudGltZSBldmFsdWF0aW9uKSAoRGVmYXVsdDogMjQwMDAwKSIsCiAgICAgICAgICAiZGVmYXVsdCIgOiAyNDAwMDAKICAgICAgICB9LAogICAgICAgICJtaW5SZXRlbnRpb25UaHJlc2hvbGQiIDogewogICAgICAgICAgInR5cGUiIDogWwogICAgICAgICAgICAibnVtYmVyIiwKICAgICAgICAgICAgInN0cmluZyIsCiAgICAgICAgICAgICJudWxsIgogICAgICAgICAgXSwKICAgICAgICAgICJtYXJrZG93bkRlc2NyaXB0aW9uIiA6ICJEZWZhdWx0IHJldGVudGlvbiBmbG9vciBmb3Igc2V2ZXJpdHkgbGV2ZWxzIG5vdCBsaXN0ZWQgaW4gc2V2ZXJpdHlGbG9vcnNcblxuRGVmaW5lcyB0aGUgcmV0ZW50aW9uIGZsb29yICgwLjAgdG8gMS4wKSB1c2VkIGZvciBhbnkgc2V2ZXJpdHkgbGV2ZWwgbm90IHByZXNlbnQgaW4gYHJhdGVSZWNlaXZlclNldmVyaXR5Rmxvb3JzYC4gRW5zdXJlcyBhIHBhdHRlcm4gb3ZlciBpdHMgY2FwIHN0aWxsIHJldGFpbnMgYXQgbGVhc3QgdGhpcyBmcmFjdGlvbiBvZiBldmVudHMgd2hvc2UgbGV2ZWwgaGFzIG5vIGV4cGxpY2l0IGZsb29yLCBwcmV2ZW50aW5nIGNvbXBsZXRlIGRhdGEgbG9zcy4gICoqVmFsaWRhdGlvbjoqKiBNdXN0IGJlIGdyZWF0ZXIgdGhhbiAwLjAxLiAoQWNjZXB0cyBudW1iZXIgb3Igc3RyaW5nIHdpdGggJD0gcHJlZml4IGZvciBydW50aW1lIGV2YWx1YXRpb24pIChEZWZhdWx0OiAwKSIsCiAgICAgICAgICAiZGVmYXVsdCIgOiAwCiAgICAgICAgfSwKICAgICAgICAic2V2ZXJpdHlGbG9vcnMiIDogewogICAgICAgICAgInR5cGUiIDogWwogICAgICAgICAgICAiYXJyYXkiLAogICAgICAgICAgICAic3RyaW5nIiwKICAgICAgICAgICAgIm51bGwiCiAgICAgICAgICBdLAogICAgICAgICAgIm1hcmtkb3duRGVzY3JpcHRpb24iIDogIk1pbmltdW0gcmV0ZW50aW9uIHBlciBzZXZlcml0eSBsZXZlbCwgYXBwbGllZCBhcyBhbiBhYnNvbHV0ZSBmbG9vclxuXG5EZWZpbmVzIGEgbWFwIG9mIFtzZXZlcml0eSBsZXZlbHNdKGh0dHBzOi8vZG9jLmxvZzEweC5jb20vcnVuL2luaXRpYWxpemUvbGV2ZWwvKSB0byBhIG1pbmltdW0gcmV0ZW50aW9uIGZyYWN0aW9uLiBUaGUgZmxvb3IgaXMgKiphYnNvbHV0ZSoqIChub3QgYSBtdWx0aXBsaWVyKSBhbmQgKipiZWF0cyB0aGUgc2hhcmUgY2FwKio6IGV2ZW4gYSBwYXR0ZXJuIG92ZXIgaXRzIGNhcCBrZWVwcyBhdCBsZWFzdCB0aGlzIGZyYWN0aW9uIG9mIGVhY2ggbGV2ZWwsIHNvIGhpZ2gtc2V2ZXJpdHkgZXZlbnRzIGFyZSBuZXZlciBmdWxseSBzdXBwcmVzc2VkLiAgVGhlIGZsb29yIGFsc28gYXBwbGllcyB1bmRlciBhIG11dGUtZmlsZSBlbnRyeSwgc28gYSBgMC4wYCBtdXRlIG5ldmVyIHNpbGVuY2VzIEVSUk9SL0ZBVEFMLiAgRmxvb3ItbWFwIGtleXMgbXVzdCBtYXRjaCB0aGUgbGV2ZWwgdm9jYWJ1bGFyeSBlbWl0dGVkIGJ5IHRoZSBsZXZlbCBlbnJpY2htZW50LiBBbnkgbGV2ZWwgbm90IGxpc3RlZCB1c2VzIGByYXRlUmVjZWl2ZXJNaW5SZXRlbnRpb25UaHJlc2hvbGRgLiAgRm9yIGV4YW1wbGU6ICBgYGAgeWFtbCBzZXZlcml0eUZsb29yczogICAtIFRSQUNFPTAuMSAgIC0gREVCVUc9MC4xICAgLSBJTkZPPTAuMSAgIC0gV0FSTj0wLjMgICAtIEVSUk9SPTAuNSAgIC0gRkFUQUw9MC41IGBgYCIsCiAgICAgICAgICAiaXRlbXMiIDogewogICAgICAgICAgICAidHlwZSIgOiAic3RyaW5nIgogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgImxvb2t1cCIgOiB7CiAgICAgICAgICAidHlwZSIgOiAib2JqZWN0IiwKICAgICAgICAgICJhZGRpdGlvbmFsUHJvcGVydGllcyIgOiBmYWxzZSwKICAgICAgICAgICJwcm9wZXJ0aWVzIiA6IHsKICAgICAgICAgICAgImZpbGUiIDogewogICAgICAgICAgICAgICJ0eXBlIiA6IFsKICAgICAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAgICAgIm51bGwiCiAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiRGVjbGFyYXRpdmUgbXV0ZSBmaWxlIGtleWVkIGJ5IGZpZWxkLXNldFxuXG5EZWZpbmVzIHRoZSBwYXRoIHRvIGEgZGVjbGFyYXRpdmUgKiptdXRlIGZpbGUqKiB0aGF0IGNhcHMgc3BlY2lmaWMgbG9nIHBhdHRlcm5zIGJ5IHRoZSBqb2luZWQgZmllbGQtc2V0IGRlZmluZWQgaW4gYHJhdGVSZWNlaXZlckZpZWxkTmFtZXNgIChlLmcuIGBzeW1ib2xNZXNzYWdlYCwgYGNvbnRhaW5lcmAsIGBodHRwQ29kZWApLiBUaGUga2V5IGZvcm1hdCBpcyB0aGUgc2FtZSBvbmUgdGhlIGxvY2FsIHJlY2VpdmVyIHVzZXMgZm9yIHBlci1ub2RlIGNvdW50ZXJzLiAgV2hlbiB0aGlzIG9wdGlvbiBpcyBzZXQsIHRoZSBtdXRlIGZpbGUgKipjb21wb3NlcyB3aXRoKiogdGhlIHJlZ3VsYXRvciByYXRoZXIgdGhhbiByZXBsYWNpbmcgaXQ6IGEgbGlzdGVkLCBhY3RpdmUgcGF0dGVybiBpcyBkZWNpZGVkIGJ5IGl0cyBmaWxlIGVudHJ5ICh0aGUgaHVtYW4gZGVjbGFyYXRpb24gd2lucywgYW5kIHRoZSByZWd1bGF0b3IgaXMgc2tpcHBlZCBmb3IgdGhhdCBldmVudCksIHdoaWxlIGV2ZXJ5IG90aGVyIHBhdHRlcm4gaXMgaGFuZGxlZCBieSB0aGUgc2hhcmUtYmFzZWQgcmVndWxhdG9yLiAgKipGaWxlIGZvcm1hdCoqIChDU1Y7IGhlYWRlciByb3cgKyBvbmUgY29tbWEtc2VwYXJhdGVkIGVudHJ5IHBlciByb3cpOiAgYGBgIGZpZWxkU2V0LHZhbHVlIDxmaWVsZFNldEtleT4sPHNhbXBsZVJhdGU+Ojx1bnRpbEVwb2NoU2VjPls6PHJlYXNvbj5dIGBgYCAgLSBgZmllbGRTZXRLZXlgIOKAlCB0aGUgam9pbmVkIHZhbHVlcyBvZiB0aGUgZmllbGRzIG5hbWVkIGluIGByYXRlUmVjZWl2ZXJGaWVsZE5hbWVzYCwgICBzZXBhcmF0ZWQgYnkgYF9gLiBXaXRoIGByYXRlUmVjZWl2ZXJGaWVsZE5hbWVzOiBbc3ltYm9sTWVzc2FnZV1gIHRoZSBrZXkgaXMganVzdCAgIHRoZSBzeW1ib2xNZXNzYWdlIChlLmcuIGBFcnJvcl9zeW5jaW5nX3BvZGApLiBXaXRoIGBbc3ltYm9sTWVzc2FnZSwgY29udGFpbmVyXWAgICB0aGUga2V5IGlzIGBzeW1ib2xNZXNzYWdlX2NvbnRhaW5lcmAgKGUuZy4gYGhlYXJ0YmVhdF9kZWJ1Z19mcm9udGVuZGApLiAtIGBzYW1wbGVSYXRlYCDigJQgcHJvYmFiaWxpdHkgaW4gYFswLCAxLjBdYCB0aGF0IGEgbWF0Y2hpbmcgZXZlbnQgaXMgcmV0YWluZWQuICAgYDBgID0gZnVsbCBtdXRlOyBgMC4xYCA9IGtlZXAgMTAlOyBgMS4wYCA9IG5vLW9wLiAtIGB1bnRpbEVwb2NoU2VjYCDigJQgbXV0ZSBleHBpcmVzIGF0IHRoaXMgVW5peCBlcG9jaCAoc2Vjb25kcykuIFBhc3QgdGhhdCwgdGhlICAgZW50cnkgYmVjb21lcyBhIG5vLW9wIHVudGlsIHNvbWVvbmUgZWRpdHMgb3IgcmVtb3ZlcyBpdC4gU2VsZi1oZWFsaW5nIGJ5IGRlc2lnbi4gLSBgcmVhc29uYCDigJQgb3B0aW9uYWwgZnJlZS10ZXh0IHN0cmluZyBmb3IgYXVkaXQuIE5vdCB1c2VkIGF0IHJ1bnRpbWUuIE11c3Qgbm90ICAgY29udGFpbiBjb21tYXMgKHdvdWxkIGJyZWFrIENTViBwYXJzaW5nKS4gICoqRXhhbXBsZSoqICh3aXRoIGByYXRlUmVjZWl2ZXJGaWVsZE5hbWVzOiBbc3ltYm9sTWVzc2FnZV1gKTogIGBgYCBmaWVsZFNldCx2YWx1ZSBFcnJvcl9zeW5jaW5nX3BvZCwwLjEwOjE3NDQ4NDgwMDA6cG9kIGVycm9yIHNwYW0gT1BTLTQ4MjEgaGVhcnRiZWF0X2RlYnVnLDA6MTc0NDQxNjAwMDprOHMgbGl2ZW5lc3MgMjAwcyBqd3RfdmFsaWRhdGVkLDAuMjU6MTc0NDUwMjQwMDphdXRoIGZsb29kIGFmdGVyIGRlcGxveSBgYGAgIFRoZSBmaWxlIGlzIGhvdC1yZWxvYWRlZCBvbiBpbi1wbGFjZSB3cml0ZXMgKHRoZSBnaXRvcHMgcGF0dGVybik7IGEgS3ViZXJuZXRlcyBgQ29uZmlnTWFwYCBtb3VudCB3b24ndCByZWxvYWQgYmVjYXVzZSB0aGUgQ00gc3dhcCBpcyBhIHN5bWxpbmsgcmVuYW1lLCBub3QgYW4gaW4tcGxhY2Ugd3JpdGUuICAqKldoeSB0aGlzIHNoYXBlOioqICAtICoqRmllbGQtc2V0IGtleWVkKiosIG5vdCByZWdleCBrZXllZCDihpIgbXV0ZSBrZXlzIGFyZSB0aGUgZXhhY3QgaWRlbnRpZmllcnMgdGhlICAgUmVwb3J0ZXIgYXR0cmlidXRlcyBjb3N0IHRvIChzYW1lIGByYXRlUmVjZWl2ZXJGaWVsZE5hbWVzYCBvbiBib3RoIHNpZGVzKSwgc28gYSAgIFwidG9wIHNwZW5kZXJcIiBpbiB0aGUgUmVwb3J0ZXIgbWFwcyAxOjEgdG8gYSBtdXRlIGVudHJ5LiAtICoqR2l0LWZyaWVuZGx5Kio6IHRoZSBmaWxlIGlzIGEgaHVtYW4tcmVhZGFibGUgZGVjbGFyYXRpb24gdGhhdCBjYW4gbGl2ZSBpbiBhICAgY29uZmlnIHJlcG8sIHJldmlld2VkIHZpYSBQUiwgYGdpdCBibGFtZWAtZCBmb3Igd2hvL3doeS4gLSAqKlNlbGYtaGVhbGluZyoqOiBldmVyeSBtdXRlIGhhcyBhbiBleHBsaWNpdCBleHBpcnksIHNvIGZvcmdvdHRlbiBlbnRyaWVzICAgZXZlbnR1YWxseSBzdG9wIGZpbHRlcmluZyBpbnN0ZWFkIG9mIHNpbGVudGx5IGRyb3BwaW5nIHByb2R1Y3Rpb24gZGF0YSBmb3JldmVyLiAtICoqQUktZWRpdGFibGUqKjogYW4gb3BlcmF0b3IgY2FuIGFzayBhbiBhc3Npc3RhbnQgKGUuZy4sIENsYXVkZSBDb2RlIHZpYSB0aGUgICBMb2cxMHggTUNQKSB0byBcIm11dGUgYEVycm9yX3N5bmNpbmdfcG9kYCBmb3IgMjQgaG91cnMgYXQgMTAlXCIg4oCUIHRoZSBhc3Npc3RhbnQgICByZWFkcyB0aGUgUmVwb3J0ZXIncyBjb3N0IGF0dHJpYnV0aW9uLCBhcHBlbmRzIHRoZSBlbnRyeSwgYW5kIG9wZW5zIGEgUFIuIFRoZSAgIG11dGUgZmlsZSBpcyB0aGUgaW50ZXJmYWNlLiAgKipTZXZlcml0eSBmbG9vciBzdGlsbCBhcHBsaWVzLioqIEV2ZW4gYSBgMC4wYCBtdXRlIHdpbGwgcmV0YWluIGhpZ2gtc2V2ZXJpdHkgZXZlbnRzIGF0IHRoZWlyIGByYXRlUmVjZWl2ZXJTZXZlcml0eUZsb29yc2AgZnJhY3Rpb24uIFRoaXMgcHJldmVudHMgYSBwb29ybHktc2NvcGVkIG11dGUgZnJvbSBzaWxlbmNpbmcgRVJST1IvRkFUQUwgdHJhZmZpYy4gIFdoZW4gYHJhdGVSZWNlaXZlckxvb2t1cEZpbGVgIGlzICoqdW5zZXQqKiwgdGhlIHJlZ3VsYXRvciBydW5zIGFsb25lIG9uIGV2ZXJ5IHBhdHRlcm4uIChEZWZhdWx0OiApIiwKICAgICAgICAgICAgICAiZGVmYXVsdCIgOiAiIgogICAgICAgICAgICB9LAogICAgICAgICAgICAicmV0YWluIiA6IHsKICAgICAgICAgICAgICAidHlwZSIgOiBbCiAgICAgICAgICAgICAgICAibnVtYmVyIiwKICAgICAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAgICAgIm51bGwiCiAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiUmV0ZW50aW9uIHBlcmlvZCBmb3IgdGhlIGxvb2t1cCBmaWxlIGNvbnRhaW5pbmcgZ2xvYmFsIGV2ZW50IHR5cGUgcmF0ZXNcblxuRGVmaW5lcyB0aGUgcmV0ZW50aW9uIHBlcmlvZCBmb3IgdGhlIGxvb2t1cCBmaWxlIGNvbnRhaW5pbmcgZ2xvYmFsIGV2ZW50IHR5cGUgZnJlcXVlbmN5IGRhdGEuIElmIHRoZSBmaWxlJ3MgbGFzdCBtb2RpZmllZCB0aW1lIGlzIG9sZGVyIHRoYW4gdGhpcyBwZXJpb2QsIHRoZSBsb29rdXAgaXMgY29uc2lkZXJlZCBzdGFsZSwgYW5kIGxvY2FsIGNvdW50ZXIgcmF0ZXMgYXJlIHVzZWQuIFVzZWQgdG8gbWFrZSBzYW1wbGluZyBkZWNpc2lvbnMgYmFzZWQgb24gY2x1c3Rlci13aWRlIGV2ZW50IHBhdHRlcm5zLiAgKipWYWxpZGF0aW9uOioqIE11c3QgYmUgZ3JlYXRlciB0aGFuIDYwMDAwIG1pbGxpc2Vjb25kcy4gKEFjY2VwdHMgbnVtYmVyIG9yIHN0cmluZyB3aXRoICQ9IHByZWZpeCBmb3IgcnVudGltZSBldmFsdWF0aW9uKSAoRGVmYXVsdDogMzAwMDAwKSIsCiAgICAgICAgICAgICAgImRlZmF1bHQiIDogMzAwMDAwCiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgICJhY3Rpb25Mb29rdXBGaWxlIiA6IHsKICAgICAgICAgICJ0eXBlIiA6IFsKICAgICAgICAgICAgInN0cmluZyIsCiAgICAgICAgICAgICJudWxsIgogICAgICAgICAgXSwKICAgICAgICAgICJtYXJrZG93bkRlc2NyaXB0aW9uIiA6ICJEZWNsYXJhdGl2ZSBwZXItc2VydmljZSBhY3Rpb24gZmlsZSwga2V5ZWQgYnkgdGhlIGByYXRlUmVjZWl2ZXJDb250YWluZXJGaWVsZGAgdmFsdWU7IGRlY2lkZXMgdGhlIGRpc3Bvc2l0aW9uIG9mIGVhY2ggc2VydmljZSdzIHJlZ3VsYXRvciBleGNlc3NcblxuRGVmaW5lcyB0aGUgcGF0aCB0byBhIGRlY2xhcmF0aXZlICoqcGVyLXNlcnZpY2UgYWN0aW9uIGZpbGUqKiAoc2libGluZyB0byB0aGUgY2FwIGZpbGUpLiBFYWNoIGVudHJ5IGFzc2lnbnMgdGhlIGRpc3Bvc2l0aW9uIG9mIGEgc2VydmljZSdzIHJlZ3VsYXRvci1pZGVudGlmaWVkIGV4Y2VzczogYGRyb3BgIChkZWZhdWx0KSwgYG9mZmxvYWRgICh0byBjdXN0b21lciBTMyksIGB0aWVyX2Rvd25gIChTSUVNIGNoZWFwIHRpZXIpLCBgY29tcGFjdGAgKGxvc3NsZXNzIGVuY29kZSksIGBzYW1wbGVgLCBvciBgcGFzc2AuIFRoZSBieXRlIGNhcCAoYHJhdGVSZWNlaXZlckNhcExvb2t1cEZpbGVgKSBzdGlsbCBib3VuZHMgdGhlIGV4Y2VzczsgdGhlIGFjdGlvbiBvbmx5IGRlY2lkZXMgd2hhdCBoYXBwZW5zIHRvIGl0LiBVbmxpc3RlZCBzZXJ2aWNlcyBkZWZhdWx0IHRvIGBkcm9wYCAodGhlIG9yaWdpbmFsIHJlZ3VsYXRvciBiZWhhdmlvcikuIFJlYWQgYnkgdGhlIGNhcC12YXJpYW50IHJlZ3VsYXRvciBjbGFzc2VzLCB3aGljaCBjYWxsIGByb3V0ZShhY3Rpb24pYCBhdCB0aGUgb3Zlci1idWRnZXQgZGVjaXNpb24gcG9pbnQgaW5zdGVhZCBvZiBhIGhhcmRjb2RlZCBkcm9wLiAgKipGaWxlIGZvcm1hdCoqIChDU1Y7IGhlYWRlciByb3cgKyBvbmUgY29tbWEtc2VwYXJhdGVkIGVudHJ5IHBlciByb3cpOiAgYGBgIGNvbnRhaW5lcixhY3Rpb24gPGNvbnRhaW5lcj4sPGFjdGlvbj5bOjx1bnRpbEVwb2NoU2VjPl1bOjxyZWFzb24+XSBgYGAgIC0gYGNvbnRhaW5lcmAg4oCUIHZhbHVlIG9mIGByYXRlUmVjZWl2ZXJDb250YWluZXJGaWVsZGAgKHRoZSBrOHMgY29udGFpbmVyID0gdGhlIHNlcnZpY2UpLiAtIGBhY3Rpb25gIOKAlCBvbmUgb2YgYGRyb3BgIC8gYG9mZmxvYWRgIC8gYHRpZXJfZG93bmAgLyBgY29tcGFjdGAgLyBgc2FtcGxlYCAvIGBwYXNzYC4gLSBgdW50aWxFcG9jaFNlY2Ag4oCUIG9wdGlvbmFsIFVuaXgtZXBvY2ggKHNlY29uZHMpIGV4cGlyeTsgcGFzdCBpdCB0aGUgZW50cnkgaXMgYSBuby1vcC4gLSBgcmVhc29uYCDigJQgb3B0aW9uYWwgZnJlZS10ZXh0IGZvciBhdWRpdC4gTXVzdCBub3QgY29udGFpbiBjb21tYXMgKHdvdWxkIGJyZWFrIENTViBwYXJzaW5nKS4gIEludGVuZGVkIHRvIGJlIG1hbmFnZWQgdmlhIEdpdE9wcyArIHRoZSBgbG9nMTB4X2NvbmZpZ3VyZV9lbmdpbmVgIE1DUCB0b29sLCB3aGljaCBkZXJpdmVzIHBlci1zZXJ2aWNlIGFjdGlvbnMgZnJvbSB0aGUgcGVyLXBhdHRlcm4gYWN0aW9uIHBsYW4gaXQgYWxyZWFkeSBjb21wdXRlcy4iCiAgICAgICAgfSwKICAgICAgICAiY2FwTG9va3VwIiA6IHsKICAgICAgICAgICJ0eXBlIiA6ICJvYmplY3QiLAogICAgICAgICAgImFkZGl0aW9uYWxQcm9wZXJ0aWVzIiA6IGZhbHNlLAogICAgICAgICAgInByb3BlcnRpZXMiIDogewogICAgICAgICAgICAiZmlsZSIgOiB7CiAgICAgICAgICAgICAgInR5cGUiIDogWwogICAgICAgICAgICAgICAgInN0cmluZyIsCiAgICAgICAgICAgICAgICAibnVsbCIKICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICJtYXJrZG93bkRlc2NyaXB0aW9uIiA6ICJEZWNsYXJhdGl2ZSBwZXItY29udGFpbmVyIGJ5dGUgY2FwIGZpbGUsIGtleWVkIGJ5IHRoZSBgcmF0ZVJlY2VpdmVyQ29udGFpbmVyRmllbGRgIHZhbHVlXG5cbkRlZmluZXMgdGhlIHBhdGggdG8gYSBkZWNsYXJhdGl2ZSAqKnBlci1jb250YWluZXIgY2FwIGZpbGUqKi4gRWFjaCBlbnRyeSBhc3NpZ25zIGEgYnl0ZSBjYXAgdG8gYSBzcGVjaWZpYyBjb250YWluZXIgKHRoZSB2YWx1ZSBvZiBgcmF0ZVJlY2VpdmVyQ29udGFpbmVyRmllbGRgLCB3aGljaCBkZWZhdWx0cyB0byB0aGUgazhzIGNvbnRhaW5lciBuYW1lKS4gVGhlIGZpbGUncyBjYXAgd2lucyBwZXItZXZlbnQgb3ZlciBgcmF0ZVJlY2VpdmVyQWJzb2x1dGVDYXBgOiBsaXN0ZWQgY29udGFpbmVycyBnZXQgdGhlIGZpbGUncyBjYXAsIHVubGlzdGVkIGNvbnRhaW5lcnMgZmFsbCBiYWNrIHRvIHRoZSBmbGVldC13aWRlIGNhcCAob3IgdG8gbm8gY2FwLCBpZiBgcmF0ZVJlY2VpdmVyQWJzb2x1dGVDYXBgIGlzIGAwYCkuICAqKkZpbGUgZm9ybWF0KiogKENTVjsgaGVhZGVyIHJvdyArIG9uZSBjb21tYS1zZXBhcmF0ZWQgZW50cnkgcGVyIHJvdyk6ICBgYGAgY29udGFpbmVyLGNhcCA8Y29udGFpbmVyPiw8Ynl0ZXM+Wzo8dW50aWxFcG9jaFNlYz5dWzo8cmVhc29uPl0gYGBgICAtIGBjb250YWluZXJgIOKAlCB2YWx1ZSBvZiBgcmF0ZVJlY2VpdmVyQ29udGFpbmVyRmllbGRgIGZvciB0aGUgZXZlbnRzIHRvIGNhcC4gSW4gazhzIHRoaXMgaXMgICB0aGUgazhzIGNvbnRhaW5lciBuYW1lLCBzdGFibGUgYWNyb3NzIHBvZCByZXBsaWNhcy4gLSBgYnl0ZXNgIOKAlCBpbnRlZ2VyIGJ5dGUgY2FwIHBlciBwYXR0ZXJuIHBlciBjb250YWluZXIgcGVyIHdpbmRvdy4gYDBgIGV4ZW1wdHMgdGhlICAgY29udGFpbmVyIGZyb20gdGhlIGFic29sdXRlIGNhcCBlbnRpcmVseSAodGhlIG92ZXItY2FwIGJyYW5jaCBpcyBza2lwcGVkIGZvciBpdCkuIC0gYHVudGlsRXBvY2hTZWNgIOKAlCBvcHRpb25hbCBVbml4LWVwb2NoIChzZWNvbmRzKSBleHBpcnkuIFBhc3QgdGhhdCwgdGhlIGVudHJ5IGJlY29tZXMgYSAgIG5vLW9wIGFuZCB0aGUgZmFsbGJhY2sgY2FwIGFwcGxpZXMuIC0gYHJlYXNvbmAg4oCUIG9wdGlvbmFsIGZyZWUtdGV4dCBzdHJpbmcgZm9yIGF1ZGl0LiBOb3QgdXNlZCBhdCBydW50aW1lLiBNdXN0IG5vdCBjb250YWluICAgY29tbWFzICh3b3VsZCBicmVhayBDU1YgcGFyc2luZykuICAqKkV4YW1wbGUqKjogIGBgYCBjb250YWluZXIsY2FwIHBheW1lbnQtc2VydmljZSw0MTk0MzA0OjE3MzU2ODk2MDA6YW5udWFsIGJ1ZGdldCBwcm90ZWN0aW9uIFBBWS0xMDEgYXV0aC1zZXJ2aWNlLDIwOTcxNTIgaXN0aW8tcHJveHksMDoxNzM1Njg5NjAwOmV4ZW1wdCBwbGF0Zm9ybSBzaWRlY2FyIFBMQVQtNDIgYGBgICAqKldoeSB0aGlzIHNoYXBlKio6ICAtICoqQ29udGFpbmVyLWtleWVkKiosIG1hdGNoaW5nIHRoZSByZWd1bGF0b3IncyBjb250YWluZXIgYXhpcy4gVGhlIGZpbGUncyBrZXkgaXMgdGhlIHNhbWUgICB2YWx1ZSB0aGUgcmVndWxhdG9yJ3MgY291bnRlcnMgYXJlIGJ1Y2tldGVkIGJ5LCBzbyBsaXN0ZWQgY2FwcyBtYXAgMToxIHRvIGNvdW50ZXJzIHdpdGhvdXQgICB0cmFuc2xhdGlvbi4gLSAqKkdpdC1mcmllbmRseSoqOiBhIGh1bWFuLXJlYWRhYmxlIGRlY2xhcmF0aW9uIHRoYXQgbGl2ZXMgaW4gYSBjb25maWcgcmVwbywgcmV2aWV3ZWQgdmlhICAgUFIsIGBnaXQgYmxhbWVgLWQgZm9yIHdoby93aHkuIC0gKipTZWxmLWhlYWxpbmcqKjogZXZlcnkgZW50cnkgY2FuIGNhcnJ5IGFuIGV4cGxpY2l0IGV4cGlyeSwgc28gZm9yZ290dGVuIGNhcHMgZXZlbnR1YWxseSAgIHN0b3AgZmlsdGVyaW5nIGluc3RlYWQgb2Ygc2lsZW50bHkgZHJvcHBpbmcgcHJvZHVjdGlvbiBkYXRhIGZvcmV2ZXIuIC0gKipBSS1lZGl0YWJsZSoqOiBhbiBvcGVyYXRvciBjYW4gYXNrIGFuIGFzc2lzdGFudCAoZS5nLiwgQ2xhdWRlIENvZGUgdmlhIHRoZSBMb2cxMHggTUNQICAgYGNvbmZpZ3VyZV9yZWd1bGF0b3JgIHRvb2wpIHRvIGRlcml2ZSBhIGNhcCBmcm9tIGEgbW9udGhseSBkb2xsYXIgYnVkZ2V0LCBhcHBlbmQgdGhlICAgZW50cnksIGFuZCBvcGVuIGEgUFIuIFRoZSBjYXAgZmlsZSBpcyB0aGUgaW50ZXJmYWNlLiAgKipTZXZlcml0eSBmbG9vciBzdGlsbCBhcHBsaWVzLioqIEV2ZW4gYXQgYSB0aWdodCBjYXAgdGhlIHJlZ3VsYXRvcidzIGByYXRlUmVjZWl2ZXJTZXZlcml0eUZsb29yc2AgcmV0YWluIEVSUk9SL0NSSVRJQ0FMIGV2ZW50cyBhdCB0aGVpciBmbG9vciBmcmFjdGlvbiwgc28gYSB0aWdodCBjYXAgbmV2ZXIgZnVsbHkgc2lsZW5jZXMgaGlnaC1zZXZlcml0eSB0cmFmZmljLiAgV2hlbiBgcmF0ZVJlY2VpdmVyQ2FwTG9va3VwRmlsZWAgaXMgKip1bnNldCoqLCBldmVyeSBjb250YWluZXIgZmFsbHMgYmFjayB0byBgcmF0ZVJlY2VpdmVyQWJzb2x1dGVDYXBgICh3aGljaCBpdHNlbGYgZGVmYXVsdHMgdG8gYDBgID0gZGlzYWJsZWQpLiAgVGhlIGZpbGUgaXMgaG90LXJlbG9hZGVkIG9uIGluLXBsYWNlIHdyaXRlcyAodGhlIGdpdG9wcyBwYXR0ZXJuKTsgYSBLdWJlcm5ldGVzIGBDb25maWdNYXBgIG1vdW50IHdvbid0IHJlbG9hZCBiZWNhdXNlIHRoZSBDTSBzd2FwIGlzIGEgc3ltbGluayByZW5hbWUsIG5vdCBhbiBpbi1wbGFjZSB3cml0ZS4gKERlZmF1bHQ6ICkiLAogICAgICAgICAgICAgICJkZWZhdWx0IiA6ICIiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJyZXRhaW4iIDogewogICAgICAgICAgICAgICJ0eXBlIiA6IFsKICAgICAgICAgICAgICAgICJudW1iZXIiLAogICAgICAgICAgICAgICAgInN0cmluZyIsCiAgICAgICAgICAgICAgICAibnVsbCIKICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICJtYXJrZG93bkRlc2NyaXB0aW9uIiA6ICJSZXRlbnRpb24gcGVyaW9kIGZvciB0aGUgcGVyLWNvbnRhaW5lciBjYXAgZmlsZSBiZWZvcmUgaXQgaXMgY29uc2lkZXJlZCBzdGFsZVxuXG5EZWZpbmVzIHRoZSByZXRlbnRpb24gcGVyaW9kIChpbiBtaWxsaXNlY29uZHMpIGZvciB0aGUgY2FwIGZpbGUgKGByYXRlUmVjZWl2ZXJDYXBMb29rdXBGaWxlYCkuIElmIHRoZSBmaWxlJ3MgbGFzdCBtb2RpZmllZCB0aW1lIGlzIG9sZGVyIHRoYW4gdGhpcyBwZXJpb2QsIGEgd2FybmluZyBpcyBsb2dnZWQuIFRoZSBjYXAgZW50cmllcyBjb250aW51ZSB0byBhcHBseTsgdGhlIHN0YWxlbmVzcyBjaGVjayBpcyBhZHZpc29yeSBzbyBvcGVyYXRvcnMgbm90aWNlIHdoZW4gYW4gYXV0b21hdGVkIHRvb2xpbmcgcGlwZWxpbmUgaGFzIHN0b3BwZWQgdXBkYXRpbmcgdGhlIGZpbGUuICAqKlZhbGlkYXRpb246KiogTXVzdCBiZSBncmVhdGVyIHRoYW4gNjAwMDAgbWlsbGlzZWNvbmRzLiAoQWNjZXB0cyBudW1iZXIgb3Igc3RyaW5nIHdpdGggJD0gcHJlZml4IGZvciBydW50aW1lIGV2YWx1YXRpb24pIChEZWZhdWx0OiAzMDAwMDApIiwKICAgICAgICAgICAgICAiZGVmYXVsdCIgOiAzMDAwMDAKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgIndhcm11cE1zIiA6IHsKICAgICAgICAgICJ0eXBlIiA6IFsKICAgICAgICAgICAgIm51bWJlciIsCiAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAibnVsbCIKICAgICAgICAgIF0sCiAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiUGVyLWNvbnRhaW5lciBncmFjZSBwZXJpb2QgYmVmb3JlIHRoaXMgcmVndWxhdG9yIGluc3RhbmNlIHN0YXJ0cyBjYXBwaW5nXG5cbkRlZmluZXMgYSBwZXItY29udGFpbmVyIGdyYWNlIHBlcmlvZCBpbiBtaWxsaXNlY29uZHMuIEEgY29udGFpbmVyIGlzIGxlZnQgdW5yZWd1bGF0ZWQgZm9yIHRoaXMgbG9uZyBhZnRlciB0aGlzIHJlZ3VsYXRvciBpbnN0YW5jZSBmaXJzdCBzZWVzIGl0cyBldmVudHMuIFRoZSBkZWZhdWx0IGlzIDUgbWludXRlcy4gIFdoeSBpdCBleGlzdHM6IHRoZSByZWd1bGF0b3IncyBwZXItcGF0dGVybiBzYW1wbGUgY291bnRzIHN0YXJ0IGVtcHR5LiBXaXRob3V0IGEgZmV3IG1pbnV0ZXMgb2YgYWNjdW11bGF0aW9uLCBhIGxvdy12b2x1bWUgcGF0dGVybiBjYW4gbG9vayBsaWtlIHRoZSBkb21pbmFudCBvbmUgcHVyZWx5IGJlY2F1c2Ugb2Ygb3JkZXJpbmcuIFRoZSB3YXJtdXAgZGVmZXJzIGNhcCBkZWNpc2lvbnMgdW50aWwgdGhlcmUgYXJlIGVub3VnaCBzYW1wbGVzIHRvIHRlbGwgYSBub2lzeSBwYXR0ZXJuIGZyb20gYSBxdWlldCBvbmUgd2l0aCBjb25maWRlbmNlLiBUaGlzIGlzIGEgKipkZWxheSBvbmx5Kio7IG5vIGxlYXJuZWQgYmFzZWxpbmUgaXMgYnVpbHQsIGFuZCB0aGUgb25seSBzdGF0ZSB0aGF0IHN1cnZpdmVzIGlzIHRoZSBjb250YWluZXIncyBmaXJzdC1zZWVuIHRpbWVzdGFtcC4gIFwiRmlyc3Qgc2Vlc1wiIGlzIHBlciByZWd1bGF0b3IgaW5zdGFuY2UsIG5vdCBwZXIgY29udGFpbmVyIGJpcnRoLiBBIGNvbnRhaW5lciB0aGF0IGhhcyBiZWVuIHJ1bm5pbmcgZm9yIGhvdXJzIGJ1dCB3aG9zZSBldmVudHMgaGF2ZSBvbmx5IGp1c3Qgc3RhcnRlZCBmbG93aW5nIHRocm91Z2ggdGhpcyByZWd1bGF0b3IgKGUuZy4gYWZ0ZXIgYSByZWd1bGF0b3IgcmVzdGFydCBvciBmb3J3YXJkZXIgcmVjb25uZWN0KSByZXN0YXJ0cyB0aGUgd2FybXVwIHdpbmRvdy4gT24gYSBkYWVtb25zZXQgcm9sbGluZyByZXN0YXJ0IHRoZSBjYXAgaXMgdGhlcmVmb3JlIGRpc2FibGVkIGZvciBgd2FybXVwTXNgIHBlciBub2RlIGFzIGl0IGN5Y2xlcy4gIExvd2VyIHRoZSB2YWx1ZSBmb3IgZmFzdC1zdGFydGluZyBhcHBzIHRoYXQgc2hvdWxkIGJlIGNhcHBlZCBzb29uZXIgYWZ0ZXIgYSByZXN0YXJ0LiBSYWlzZSBpdCBmb3Igc2xvdy1yYW1waW5nIEpWTXMgb3Igd29ya2xvYWRzIHdpdGggbG9uZyBpbml0IHBoYXNlcy4gUGF0dGVybnMgdGhhdCBhcmUgbGVnaXRpbWF0ZWx5IGRvbWluYW50IGluIHN0ZWFkeSBzdGF0ZSBiZWxvbmcgb24gdGhlIG11dGUgZmlsZSwgbm90IGluIGEgbG9uZ2VyIHdhcm11cC4gKEFjY2VwdHMgbnVtYmVyIG9yIHN0cmluZyB3aXRoICQ9IHByZWZpeCBmb3IgcnVudGltZSBldmFsdWF0aW9uKSAoRGVmYXVsdDogMzAwMDAwKSIsCiAgICAgICAgICAiZGVmYXVsdCIgOiAzMDAwMDAKICAgICAgICB9LAogICAgICAgICJiYXNlbGluZUNvdW50IiA6IHsKICAgICAgICAgICJ0eXBlIiA6IFsKICAgICAgICAgICAgIm51bWJlciIsCiAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAibnVsbCIKICAgICAgICAgIF0sCiAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiRXZlbnRzIHBlciBwYXR0ZXJuIGtlcHQgZWFjaCB3aW5kb3cgcmVnYXJkbGVzcyBvZiBzaGFyZVxuXG5EZWZpbmVzIGhvdyBtYW55IGV2ZW50cyBvZiBlYWNoIGAocGF0dGVybiwgY29udGFpbmVyKWAgYXJlIGFsd2F5cyBrZXB0IHBlciB3aW5kb3csIHJlZ2FyZGxlc3Mgb2Ygc2hhcmUsIHNvIGV2ZW4gYSBoZWF2aWx5LWNhcHBlZCBwYXR0ZXJuIGxlYXZlcyBhIHNtYWxsIGZvcmVuc2ljIHNhbXBsZSB0byBpbnNwZWN0IGR1cmluZyBhbiBpbmNpZGVudC4gKEFjY2VwdHMgbnVtYmVyIG9yIHN0cmluZyB3aXRoICQ9IHByZWZpeCBmb3IgcnVudGltZSBldmFsdWF0aW9uKSAoRGVmYXVsdDogNSkiLAogICAgICAgICAgImRlZmF1bHQiIDogNQogICAgICAgIH0sCiAgICAgICAgImFic29sdXRlQ2FwIiA6IHsKICAgICAgICAgICJ0eXBlIiA6IFsKICAgICAgICAgICAgIm51bWJlciIsCiAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAibnVsbCIKICAgICAgICAgIF0sCiAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiRmxlZXQtd2lkZSBieXRlIGNhcCBwZXIgcGF0dGVybiBwZXIgY29udGFpbmVyIHBlciB3aW5kb3c7IGAwYCAoZGVmYXVsdCkgZGlzYWJsZXMgdGhlIGNhcCB1bmxlc3Mgb3ZlcnJpZGRlbiBwZXItY29udGFpbmVyIHZpYSBgcmF0ZVJlY2VpdmVyQ2FwTG9va3VwRmlsZWBcblxuRGVmaW5lcyBhICoqZmxlZXQtd2lkZSoqIGJ5dGUgY2FwOiB0aGUgbWF4aW11bSBieXRlcyBvZiBhIHNpbmdsZSBwYXR0ZXJuIChhIHVuaXF1ZSBjb21iaW5hdGlvbiBvZiBgcmF0ZVJlY2VpdmVyRmllbGROYW1lc2AgdmFsdWVzKSB0aGF0IG1heSBiZSByZXRhaW5lZCBwZXIgY29udGFpbmVyIHdpdGhpbiB0aGUgY3VycmVudCB3aW5kb3cgKGByYXRlUmVjZWl2ZXJSZXNldEludGVydmFsTXNgKS4gQXBwbGllcyB0byBldmVyeSBjb250YWluZXIgdGhlIHJlZ3VsYXRvciBzZWVzLCB1bmxlc3MgdGhhdCBjb250YWluZXIgaGFzIGl0cyBvd24gZW50cnkgaW4gYHJhdGVSZWNlaXZlckNhcExvb2t1cEZpbGVgLCB3aGljaCB3aW5zIHBlci1ldmVudC4gIEF0IG9yIGJlbG93IHRoZSByZXNvbHZlZCBjYXAgdGhlIHBhdHRlcm4gaXMga2VwdCB1bnRvdWNoZWQuIEFib3ZlIGl0LCB0aGUgcmVndWxhdG9yIGVuZ2FnZXM6IGlmIHRoZSBwYXR0ZXJuIGlzIGFsc28gYWJvdmUgYHJhdGVSZWNlaXZlck1pblNoYXJlUGVyY2VudGAgKHRoZSBzYW5pdHkgZ3VhcmQpLCB0aGUgZXZlbnQgaXMgc2FtcGxlZCBhdCB0aGUgc2V2ZXJpdHkgZmxvb3IgcHJvYmFiaWxpdHkuICAqKmAwYCAodGhlIGRlZmF1bHQpIGRpc2FibGVzIHRoZSBmbGVldC13aWRlIGNhcC4qKiBXaXRoIG5vIGZsZWV0LXdpZGUgY2FwIGFuZCBubyBwZXItY29udGFpbmVyIGVudHJ5IGluIGByYXRlUmVjZWl2ZXJDYXBMb29rdXBGaWxlYCwgdGhlIHJlZ3VsYXRvcidzIG92ZXItY2FwIGJyYW5jaCBuZXZlciBlbmdhZ2VzIGZvciB0aGF0IGNvbnRhaW5lci4gUHJvdGVjdGlvbiBpcyBzdHJpY3RseSBvcHQtaW4uIFRocmVlIGNvbmZpZ3VyYXRpb25zIGFyZSBmaXJzdC1jbGFzczogIC0gKipQZXItY29udGFpbmVyIG9ubHkqKjogc2V0IGByYXRlUmVjZWl2ZXJDYXBMb29rdXBGaWxlYC4gTGlzdGVkIGNvbnRhaW5lcnMgZ2V0IHRoZWlyIGNhcDsgICB1bmxpc3RlZCBjb250YWluZXJzIGFyZSB1bnJlZ3VsYXRlZCBieSB0aGUgYWJzb2x1dGUgY2FwLiBNb3N0IHNlbGVjdGl2ZS4gLSAqKkZsZWV0LXdpZGUgb25seSoqOiBzZXQgYHJhdGVSZWNlaXZlckFic29sdXRlQ2FwYCB0byBhIHBvc2l0aXZlIGludGVnZXIuIEFwcGxpZXMgdG8gZXZlcnkgICBjb250YWluZXIuIC0gKipCb3RoKio6IHBlci1jb250YWluZXIgZW50cmllcyBvdmVycmlkZSB0aGUgZmxlZXQtd2lkZSBjYXA7IHVubGlzdGVkIGNvbnRhaW5lcnMgZmFsbCBiYWNrICAgdG8gdGhlIGZsZWV0LXdpZGUgY2FwIChzYWZldHkgZmxvb3IpLiAgKipFeGFtcGxlOioqIDEwNDg1NzYwICgxMCBNQikgbWVhbnMgbm8gc2luZ2xlIHBhdHRlcm4gY2FuIGV4Y2VlZCAxMCBNQiBwZXIgY29udGFpbmVyIHBlciA1LW1pbnV0ZSB3aW5kb3cuIFRoZSBtYXhpbXVtIG1vbnRobHkgc3BlbmQgcGVyIHBhdHRlcm4gcGVyIGNvbnRhaW5lciBjYW4gYmUgY29tcHV0ZWQgZnJvbSB0aGlzIGNhcCBhbmQgdGhlIHZlbmRvcidzIHBlci1HQiByYXRlLiAoQWNjZXB0cyBudW1iZXIgb3Igc3RyaW5nIHdpdGggJD0gcHJlZml4IGZvciBydW50aW1lIGV2YWx1YXRpb24pIChEZWZhdWx0OiAwKSIsCiAgICAgICAgICAiZGVmYXVsdCIgOiAwCiAgICAgICAgfSwKICAgICAgICAibWluU2hhcmVQZXJjZW50IiA6IHsKICAgICAgICAgICJ0eXBlIiA6IFsKICAgICAgICAgICAgIm51bWJlciIsCiAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAibnVsbCIKICAgICAgICAgIF0sCiAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiTWluaW11bSBzaGFyZSBvZiBjb250YWluZXIgdm9sdW1lIGJlbG93IHdoaWNoIGEgcGF0dGVybiBpcyBleGVtcHQgZnJvbSBzYW1wbGluZ1xuXG5EZWZpbmVzIHRoZSBzaGFyZS1vZi1jb250YWluZXIgc2FuaXR5IGd1YXJkICgwLjAgdG8gMS4wKTogaWYgYSBwYXR0ZXJuIGlzIGFib3ZlIHRoZSBhYnNvbHV0ZSBjYXAgQlVUIGJlbG93IHRoaXMgc2hhcmUgb2YgaXRzIGNvbnRhaW5lcidzIHRvdGFsIHZvbHVtZSwgdGhlIHJlZ3VsYXRvciBza2lwcyBpdC4gVGhlIHBhdHRlcm4gaXMgcGFydCBvZiBhIGxlZ2l0aW1hdGVseSBoaWdoLXZvbHVtZSBjb250YWluZXIgKGJ1c3kgQVBJIGdhdGV3YXksIGFjY2VzcyBsb2cgd29ya2xvYWQpLCBub3QgYSBub2lzeSBvdXRsaWVyLiAgU2hhcmUgaXMgYChwYXR0ZXJuIGJ5dGVzICsgZXZlbnQpIC8gKGNvbnRhaW5lciBieXRlcyArIGV2ZW50KWAgb3ZlciB0aGUgY3VycmVudCB3aW5kb3cuICAqKkV4YW1wbGU6KiogMC4wNSBtZWFucyBhIHBhdHRlcm4gYWJvdmUgdGhlIGFic29sdXRlIGNhcCBpcyBzdGlsbCByZXRhaW5lZCBpZiBpdCByZXByZXNlbnRzIGxlc3MgdGhhbiA1JSBvZiBpdHMgY29udGFpbmVyJ3MgdG90YWwgdm9sdW1lLiBQcmV2ZW50cyBmYWxzZSBwb3NpdGl2ZXMgb24gbmF0dXJhbGx5IGNoYXR0eSBjb250YWluZXJzLiAoQWNjZXB0cyBudW1iZXIgb3Igc3RyaW5nIHdpdGggJD0gcHJlZml4IGZvciBydW50aW1lIGV2YWx1YXRpb24pIChEZWZhdWx0OiAwKSIsCiAgICAgICAgICAiZGVmYXVsdCIgOiAwCiAgICAgICAgfSwKICAgICAgICAiaW5nZXN0aW9uQ29zdFBlckdCIiA6IHsKICAgICAgICAgICJ0eXBlIiA6IFsKICAgICAgICAgICAgIm51bWJlciIsCiAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAibnVsbCIKICAgICAgICAgIF0sCiAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiVmVuZG9yIGluZ2VzdGlvbiBjb3N0IHBlciBHQiBpbiBVU0QsIGZvciByZW5kZXJpbmcgc2F2aW5ncyBpbiBkb2xsYXJzXG5cbkRlZmluZXMgdGhlIGNvc3QgcGVyIEdCIGNoYXJnZWQgYnkgeW91ciBvYnNlcnZhYmlsaXR5IHZlbmRvciBmb3IgbG9nIGluZ2VzdGlvbi4gVXNlZCAqKm9ubHkqKiB0byByZW5kZXIgc2F2aW5ncyBtZXRyaWNzIGluIGRvbGxhcnMgKGRyb3BwZWQgYnl0ZXMgw5cgY29zdCBwZXIgR0IpOyBpdCBkb2VzICoqbm90KiogYWZmZWN0IHRoZSBrZWVwL2Ryb3AgZGVjaXNpb24sIHdoaWNoIGlzIHNoYXJlLWJhc2VkLiAgKipDb21tb24gdmVuZG9yIHByaWNpbmcgKDIwMjUpOioqIC0gKipTcGx1bmsgQ2xvdWQqKjogfiQxLjUwL0dCICh2YXJpZXMgYnkgY29udHJhY3QsIFNLVSkgLSAqKkRhdGFkb2cgTG9ncyoqOiB+JDAuMTAtJDAuMjUvR0IgKGRlcGVuZHMgb24gdGllcjogc3RhbmRhcmQsIGZsZXgsIG9ubGluZSBhcmNoaXZlcykgLSAqKkVsYXN0aWMgQ2xvdWQqKjogfiQwLjEwOS9HQiAoc3RhbmRhcmQgbG9nZ2luZyB0aWVyKSAtICoqTmV3IFJlbGljKio6IH4kMC4zMC9HQiAoRGF0YSBQbHVzKSAtICoqU3VtbyBMb2dpYyoqOiB+JDEuNTAvR0IgKGRlcGVuZHMgb24gcGxhbikgLSAqKkFXUyBDbG91ZFdhdGNoIExvZ3MqKjogfiQwLjUwL0dCIGluZ2VzdGlvbiArICQwLjAzL0dCIHN0b3JhZ2UgKEFjY2VwdHMgbnVtYmVyIG9yIHN0cmluZyB3aXRoICQ9IHByZWZpeCBmb3IgcnVudGltZSBldmFsdWF0aW9uKSAoRGVmYXVsdDogMSkiLAogICAgICAgICAgImRlZmF1bHQiIDogMQogICAgICAgIH0KICAgICAgfQogICAgfQogIH0sCiAgImFkZGl0aW9uYWxQcm9wZXJ0aWVzIiA6IHRydWUKfQ==
# 🔟❎ 'run' rate regulator configuration
# The rate regulator prevents any single log pattern from dominating a container's
# volume. For each event it computes the pattern's share of its container's recent
# bytes and trims the pattern back once it crosses a fixed cap. Severity floors keep
# errors/warnings flowing; an optional mute file overrides the regulator for
# explicitly declared patterns.
# To learn more see https://doc.log10x.com/run/receive/rate/
# Set the 10x pipeline to 'run'
tenx: run
# =============================== Dependencies ================================
include: run/modules/receive/rate
# ============================== Rate Options =================================
rateReceiver:
# 'fieldNames' identifies the log PATTERN (the numerator bucket). Usually the
# symbolMessage field from message enrichment. The container is configured
# separately via 'containerField' below -- it is the denominator and is keyed
# on its own, so a pattern's share is measured per container.
fieldNames:
- $=yield TenXEnv.get("symbolMessageField")
# 'containerField' names the field whose value scopes the share denominator
# (the per-container total). Defaults to the k8s container name, which is
# stable across pod replicas (never the pod). When the field is absent on an
# event (non-k8s input), the regulator falls back to a single node-wide bucket.
containerField: $=yield TenXEnv.get("k8sContainerNameField")
# 'resetIntervalMs' is the window over which recent share is measured. The
# engine caps counter reset intervals at 255 seconds, so the effective maximum
# window is ~4.25 minutes.
resetIntervalMs: $=parseDuration("4m")
# 'absoluteCap' is the fleet-wide trigger (HEADLINE GUARANTEE): the maximum bytes
# of a single pattern that may accumulate per container within the current
# window. No single pattern can exceed this many bytes per container per window;
# customers can compute their worst-case per-pattern-per-container spend from
# this number directly.
#
# Default 0 = disabled. Three customer configurations are first-class:
# - Per-container only: leave 'absoluteCap' unset, set 'capLookupFile' below.
# Listed containers get the file's cap; unlisted containers are
# unregulated by the absolute cap. Most selective.
# - Fleet-wide only: set 'absoluteCap' to a positive integer (e.g., 10485760
# for 10 MB). Applies to every container the regulator sees.
# - Both: per-container entries in 'capLookupFile' override the fleet-wide
# cap; unlisted containers fall back to the fleet-wide cap (safety floor).
# absoluteCap: 10485760 # 10 MB
# 'minSharePercent' is the sanity guard against false positives on legitimately
# high-volume containers. If a pattern is over `absoluteCap` BUT below this
# share of its container's volume, it is left alone -- the pattern is a small
# fraction of a chatty container, not an outlier.
minSharePercent: 0.05
# 'severityFloors' is the minimum retention per severity level, applied as an
# absolute floor that BEATS the share cap: even a pattern over its cap keeps at
# least this fraction of each level. Floor-map keys must match the level
# vocabulary emitted by the level enrichment.
severityFloors:
- TRACE=0.1
- DEBUG=0.1
- INFO=0.1
- WARN=0.3
- ERROR=0.5
- CRITICAL=0.5 # the level enrichment maps fatal/critical -> CRITICAL
- FATAL=0.5 # kept for forwarders whose level vocabulary emits FATAL
# 'minRetentionThreshold' is the floor used for any level not present in
# 'severityFloors'.
minRetentionThreshold: 0.1
# 'warmupMs' is the per-instance grace period before the regulator starts capping a
# newly-seen container, giving the per-pattern sample counts time to fill. Scope is
# per regulator instance, so a regulator restart restarts the window. See
# https://doc.log10x.com/run/receive/rate/#warmup for the operator guide.
warmupMs: $=parseDuration("5m")
# 'baselineCount' is the number of events of each pattern kept per window
# regardless of share, so even a heavily-capped pattern leaves a forensic sample.
baselineCount: 5
# 'ingestionCostPerGB' is used only to render savings metrics in dollars; it does
# not affect the keep/drop decision (the decision is share-based).
ingestionCostPerGB: 1.5
# ---------------------------- Mute File Options ----------------------------
# Optional declarative mute file keyed by the joined 'fieldNames'. Unlike before,
# the mute file COMPOSES with the regulator rather than replacing it: a listed,
# active pattern is decided by its file entry (the human declaration wins), and
# everything else is handled by the share-based regulator.
#
# File format (CSV; header row + one comma-separated entry per row):
# fieldSet,value
# <fieldSetKey>,<sampleRate>:<untilEpochSec>[:<reason>]
#
# sampleRate 1.0 = never sampled; <1.0 = retain at that rate. Entries self-heal
# past 'untilEpochSec'. The severity floor still applies so a 0.0 mute never
# silences ERROR/FATAL.
#
# Periodically pulling the mute file to keep it fresh is done via the gitops
# configuration -- see https://doc.log10x.com/config/github/#config
lookup:
# 'file' specifies the mute file path. Hot-reloaded on in-place writes (the
# gitops pattern); Kubernetes ConfigMap mounts won't reload. Comment out to
# run the regulator alone (the default).
# file: $=path("data/sample/mutes") + "/mutes.csv"
# 'retain' specifies the period before the file is marked as stale.
retain: $=parseDuration("10m")
# ---------------------------- Cap File Options -----------------------------
# Optional declarative per-container cap file keyed by the value of
# 'containerField' (the k8s container name by default). Each entry assigns a
# byte cap to a specific container; the file wins per-event over 'absoluteCap'
# above. Listed containers get the file's cap; unlisted containers fall back
# to 'absoluteCap' (or to no cap, when 'absoluteCap' is unset/0).
#
# File format (CSV; header row + one comma-separated entry per row):
# container,cap
# <container>,<bytes>[:<untilEpochSec>][:<reason>]
#
# Intended to be managed via GitOps + the log10x_configure_regulator MCP tool,
# which derives per-container caps from a monthly dollar budget and opens a PR
# against this file.
capLookup:
# 'file' specifies the per-container cap file path. Hot-reloaded on in-place
# writes (the gitops pattern); also hot-reloaded when the file is replaced
# via ATOMIC_MOVE (the kubernetes ConfigMap pull driver pattern).
#
# Default points at the stable destination written by the engine's
# kubernetes ConfigMap pull driver:
# ${java.io.tmpdir}/tenx/kubernetes/<namespace>/<configMap>/caps.csv
#
# CAP_LOOKUP_FILE env var overrides this for non-k8s deployments or for
# operators who prefer a fixed absolute path (gitops-managed file on disk).
file: $=TenXEnv.get("CAP_LOOKUP_FILE", TenXEnv.get("java.io.tmpdir", "/tmp") + "/tenx/kubernetes/" + TenXEnv.get("K8S_NAMESPACE", "demo") + "/" + TenXEnv.get("K8S_CONFIGMAP", "log10x-action-intent") + "/caps.csv")
# 'retain' specifies the period before the file is marked as stale.
retain: $=parseDuration("10m")
# --------------------------- Action File Options ---------------------------
# Optional declarative per-SERVICE action file, keyed by the value of
# 'containerField' (the k8s container name = the service). Each entry assigns
# the disposition of that service's regulator-identified excess: 'drop'
# (default), 'offload' (to customer S3), 'tier_down' (SIEM cheap tier),
# 'compact' (lossless encode), 'sample', or 'pass'. The byte cap above still
# bounds the excess; the action only decides what happens to it. Unlisted
# services default to 'drop' (the original regulator behavior).
#
# File format (CSV; header row + one comma-separated entry per row):
# container,action
# <container>,<action>[:<untilEpochSec>][:<reason>]
#
# Managed via GitOps + the log10x_configure_engine MCP tool, which derives the
# per-service action from the per-pattern action plan and opens a PR against
# this file (a sibling of the cap file in the same ConfigMap).
# 'actionLookupFile' is the per-service action file path. Declared as a FLAT
# key (like 'fieldNames' / 'minSharePercent') so it maps to the
# rateReceiverActionLookupFile option -- a new nested sub-group (e.g.
# actionLookup.file) is NOT recognized by the config-to-option mapper, even
# though capLookup.file is (capLookup is special-cased). Always set (default
# below, sibling to the cap file) so the cap-variant regulator can read it.
# ACTION_LOOKUP_FILE overrides for non-k8s / fixed-path deployments.
actionLookupFile: $=TenXEnv.get("ACTION_LOOKUP_FILE", TenXEnv.get("java.io.tmpdir", "/tmp") + "/tenx/kubernetes/" + TenXEnv.get("K8S_NAMESPACE", "demo") + "/" + TenXEnv.get("K8S_CONFIGMAP", "log10x-action-intent") + "/actions.csv")
Options
Specify the options below to configure the rate receiver:
| Name | Description |
|---|---|
| rateReceiverFieldNames | List of TenXObject fields to identify rate counter buckets |
| rateReceiverContainerField | Field whose value scopes the per-container share denominator |
| rateReceiverResetIntervalMs | Reset interval for rate counters in milliseconds |
| rateReceiverMinRetentionThreshold | Default retention floor for severity levels not listed in severityFloors |
| rateReceiverSeverityFloors | Minimum retention per severity level, applied as an absolute floor |
| rateReceiverLookupFile | Declarative mute file keyed by field-set |
| rateReceiverLookupRetain | Retention period for the lookup file containing global event type rates |
| rateReceiverActionLookupFile | Declarative per-service action file, keyed by the `rateReceiverContainerField` value; decides the disposition of each service's regulator excess |
| rateReceiverCapLookupFile | Declarative per-container byte cap file, keyed by the `rateReceiverContainerField` value |
| rateReceiverCapLookupRetain | Retention period for the per-container cap file before it is considered stale |
| rateReceiverWarmupMs | Per-container grace period before this regulator instance starts capping |
| rateReceiverBaselineCount | Events per pattern kept each window regardless of share |
| rateReceiverAbsoluteCap | Fleet-wide byte cap per pattern per container per window; `0` (default) disables the cap unless overridden per-container via `rateReceiverCapLookupFile` |
| rateReceiverMinSharePercent | Minimum share of container volume below which a pattern is exempt from sampling |
| rateReceiverIngestionCostPerGB | Vendor ingestion cost per GB in USD, for rendering savings in dollars |
rateReceiverFieldNames
List of TenXObject fields to identify rate counter buckets.
| Type | Default |
|---|---|
| List | [symbolMessage] |
Defines the list of TenXObject field names extracted to identify which rate counter bucket an event belongs to.
The list usually contains the symbolMessage field from the message enrichment module
but can include additional fields like GeoIP, HTTP code, k8s container name, or custom enrichments for multi-dimensional rate tracking.
Common Use Cases:
Single-app receiving (per event type):
Multi-dimensional tracking (event type + geography + HTTP status):
Multi-app receiving in Kubernetes:
Option A: Cap total spend per app (all event types combined):
Each app's total spend (across all event types and pods) gets one cap. Simple but loses event-type intelligence.
Option B: Cap spend per event type per app:
rateReceiverFieldNames:
- symbolMessage # Event type
- container # App identifier (same across all pods)
Each (event type × app) combo gets its own cap. Provides fairness within apps but allows apps with many event types to potentially exceed one total cap.
The container is configured separately via rateReceiverContainerField (it scopes the
share denominator), so fieldNames identifies only the log pattern itself.
rateReceiverContainerField
Field whose value scopes the per-container share denominator.
| Type | Default |
|---|---|
| String |
Names the field whose value scopes the share denominator (the per-container total).
A pattern's share is measured against the total volume of the container it belongs to,
so the cap is enforced per (pattern, container).
Defaults to the k8s container name, which is
stable across pod replicas, scaling from 1 to 10 pods does not bypass the cap, and a
sidecar never consumes the application container's allowance. Use container, never pod.
When the field is absent on an event (non-k8s input, or no k8s extractor configured), the regulator falls back to a single node-wide bucket and enforces the cap per pattern across the node.
rateReceiverResetIntervalMs
Reset interval for rate counters in milliseconds.
| Type | Default |
|---|---|
| Number | 240000 |
Defines the window in milliseconds over which a pattern's recent share is measured. The counters reset every interval, so share reflects recent volume rather than all-time totals.
Shorter windows (e.g., 1 minute) are more reactive but noisier; longer windows are smoother but slower to adapt. The default of 4 minutes balances the two.
Validation: Must be at least 60000 milliseconds (1 minute). The engine caps counter reset intervals at 255 seconds, so the effective maximum window is ~4.25 minutes, values above that are clamped.
rateReceiverMinRetentionThreshold
Default retention floor for severity levels not listed in severityFloors.
| Type | Default |
|---|---|
| Number | 0.1 |
Defines the retention floor (0.0 to 1.0) used for any severity level not present in
rateReceiverSeverityFloors. Ensures a pattern over its cap still retains at least this
fraction of events whose level has no explicit floor, preventing complete data loss.
Validation: Must be greater than 0.01.
rateReceiverSeverityFloors
Minimum retention per severity level, applied as an absolute floor.
| Type | Default |
|---|---|
| List | [] |
defines a map of severity levels to a minimum retention fraction. The floor is absolute (not a multiplier) and beats the share cap: even a pattern over its cap keeps at least this fraction of each level, so high-severity events are never fully suppressed.
The floor also applies under a mute-file entry, so a 0.0 mute never silences ERROR/FATAL.
Floor-map keys must match the level vocabulary emitted by the level enrichment. Any level not
listed uses rateReceiverMinRetentionThreshold.
For example:
rateReceiverLookupFile
Declarative mute file keyed by field-set.
| Type | Default |
|---|---|
| String |
Defines the path to a declarative mute file that caps specific log patterns by
the joined field-set defined in rateReceiverFieldNames (e.g. symbolMessage,
container, httpCode). The key format is the same one the local receiver uses
for per-node counters.
When this option is set, the mute file composes with the regulator rather than replacing it: a listed, active pattern is decided by its file entry (the human declaration wins, and the regulator is skipped for that event), while every other pattern is handled by the share-based regulator.
File format (CSV; header row + one comma-separated entry per row):
fieldSetKey, the joined values of the fields named inrateReceiverFieldNames, separated by_. WithrateReceiverFieldNames: [symbolMessage]the key is just the symbolMessage (e.g.Error_syncing_pod). With[symbolMessage, container]the key issymbolMessage_container(e.g.heartbeat_debug_frontend).sampleRate, probability in[0, 1.0]that a matching event is retained.0= full mute;0.1= keep 10%;1.0= no-op.untilEpochSec, mute expires at this Unix epoch (seconds). Past that, the entry becomes a no-op until someone edits or removes it. Self-healing by design.reason, optional free-text string for audit. Not used at runtime. Must not contain commas (would break CSV parsing).
Example (with rateReceiverFieldNames: [symbolMessage]):
fieldSet,value
Error_syncing_pod,0.10:1744848000:pod error spam OPS-4821
heartbeat_debug,0:1744416000:k8s liveness 200s
jwt_validated,0.25:1744502400:auth flood after deploy
The file is hot-reloaded on in-place writes (the gitops pattern); a Kubernetes
ConfigMap mount won't reload because the CM swap is a symlink rename, not an
in-place write.
Why this shape:
- Field-set keyed, not regex keyed → mute keys are the exact identifiers the
Reporter attributes cost to (same
rateReceiverFieldNameson both sides), so a "top spender" in the Reporter maps 1:1 to a mute entry. - Git-friendly: the file is a human-readable declaration that can live in a
config repo, reviewed via PR,
git blame-d for who/why. - Self-healing: every mute has an explicit expiry, so forgotten entries eventually stop filtering instead of silently dropping production data forever.
- AI-editable: an operator can ask an assistant (e.g., Claude Code via the
Log10x MCP) to "mute
Error_syncing_podfor 24 hours at 10%", the assistant reads the Reporter's cost attribution, appends the entry, and opens a PR. The mute file is the interface.
Severity floor still applies. Even a 0.0 mute will retain high-severity
events at their rateReceiverSeverityFloors fraction. This prevents a poorly-scoped
mute from silencing ERROR/FATAL traffic.
When rateReceiverLookupFile is unset, the regulator runs alone on every pattern.
rateReceiverLookupRetain
Retention period for the lookup file containing global event type rates.
| Type | Default |
|---|---|
| Number | 300000 |
Defines the retention period for the lookup file containing global event type frequency data.
If the file's last modified time is older than this period, the lookup is considered stale, and local counter rates are used. Used to make sampling decisions based on cluster-wide event patterns.
Validation: Must be greater than 60000 milliseconds.
rateReceiverActionLookupFile
Declarative per-service action file, keyed by the `rateReceiverContainerField` value; decides the disposition of each service's regulator excess.
| Type | Default |
|---|---|
| String | "" |
Defines the path to a declarative per-service action file (sibling to the cap file).
Each entry assigns the disposition of a service's regulator-identified excess: drop
(default), offload (to customer S3), tier_down (SIEM cheap tier), compact (lossless
encode), sample, or pass. The byte cap (rateReceiverCapLookupFile) still bounds the
excess; the action only decides what happens to it. Unlisted services default to drop
(the original regulator behavior). Read by the cap-variant regulator classes, which call
route(action) at the over-budget decision point instead of a hardcoded drop.
File format (CSV; header row + one comma-separated entry per row):
container, value ofrateReceiverContainerField(the k8s container = the service).action, one ofdrop/offload/tier_down/compact/sample/pass.untilEpochSec, optional Unix-epoch (seconds) expiry; past it the entry is a no-op.reason, optional free-text for audit. Must not contain commas (would break CSV parsing).
Intended to be managed via GitOps + the log10x_configure_engine MCP tool, which derives
per-service actions from the per-pattern action plan it already computes.
rateReceiverCapLookupFile
Declarative per-container byte cap file, keyed by the `rateReceiverContainerField` value.
| Type | Default |
|---|---|
| String |
Defines the path to a declarative per-container cap file. Each entry assigns a byte cap
to a specific container (the value of rateReceiverContainerField, which defaults to the k8s
container name). The file's cap wins per-event over rateReceiverAbsoluteCap: listed
containers get the file's cap, unlisted containers fall back to the fleet-wide cap (or to
no cap, if rateReceiverAbsoluteCap is 0).
File format (CSV; header row + one comma-separated entry per row):
container, value ofrateReceiverContainerFieldfor the events to cap. In k8s this is the k8s container name, stable across pod replicas.bytes, integer byte cap per pattern per container per window.0exempts the container from the absolute cap entirely (the over-cap branch is skipped for it).untilEpochSec, optional Unix-epoch (seconds) expiry. Past that, the entry becomes a no-op and the fallback cap applies.reason, optional free-text string for audit. Not used at runtime. Must not contain commas (would break CSV parsing).
Example:
container,cap
payment-service,4194304:1735689600:annual budget protection PAY-101
auth-service,2097152
istio-proxy,0:1735689600:exempt platform sidecar PLAT-42
Why this shape:
- Container-keyed, matching the regulator's container axis. The file's key is the same value the regulator's counters are bucketed by, so listed caps map 1:1 to counters without translation.
- Git-friendly: a human-readable declaration that lives in a config repo, reviewed via
PR,
git blame-d for who/why. - Self-healing: every entry can carry an explicit expiry, so forgotten caps eventually stop filtering instead of silently dropping production data forever.
- AI-editable: an operator can ask an assistant (e.g., Claude Code via the Log10x MCP
configure_regulatortool) to derive a cap from a monthly dollar budget, append the entry, and open a PR. The cap file is the interface.
Severity floor still applies. Even at a tight cap the regulator's rateReceiverSeverityFloors
retain ERROR/CRITICAL events at their floor fraction, so a tight cap never fully silences
high-severity traffic.
When rateReceiverCapLookupFile is unset, every container falls back to
rateReceiverAbsoluteCap (which itself defaults to 0 = disabled).
The file is hot-reloaded on in-place writes (the gitops pattern); a Kubernetes
ConfigMap mount won't reload because the CM swap is a symlink rename, not an
in-place write.
rateReceiverCapLookupRetain
Retention period for the per-container cap file before it is considered stale.
| Type | Default |
|---|---|
| Number | 300000 |
Defines the retention period (in milliseconds) for the cap file (rateReceiverCapLookupFile).
If the file's last modified time is older than this period, a warning is logged. The cap
entries continue to apply; the staleness check is advisory so operators notice when an
automated tooling pipeline has stopped updating the file.
Validation: Must be greater than 60000 milliseconds.
rateReceiverWarmupMs
Per-container grace period before this regulator instance starts capping.
| Type | Default |
|---|---|
| Number | 300000 |
Defines a per-container grace period in milliseconds. A container is left unregulated for this long after this regulator instance first sees its events. The default is 5 minutes.
Why it exists: the regulator's per-pattern sample counts start empty. Without a few minutes of accumulation, a low-volume pattern can look like the dominant one purely because of ordering. The warmup defers cap decisions until there are enough samples to tell a noisy pattern from a quiet one with confidence. This is a delay only; no learned baseline is built, and the only state that survives is the container's first-seen timestamp.
"First sees" is per regulator instance, not per container birth. A container that has been
running for hours but whose events have only just started flowing through this regulator
(e.g. after a regulator restart or forwarder reconnect) restarts the warmup window. On a
daemonset rolling restart the cap is therefore disabled for warmupMs per node as it cycles.
Lower the value for fast-starting apps that should be capped sooner after a restart. Raise it for slow-ramping JVMs or workloads with long init phases. Patterns that are legitimately dominant in steady state belong on the mute file, not in a longer warmup.
rateReceiverBaselineCount
Events per pattern kept each window regardless of share.
| Type | Default |
|---|---|
| Number | 5 |
Defines how many events of each (pattern, container) are always kept per window, regardless
of share, so even a heavily-capped pattern leaves a small forensic sample to inspect during an
incident.
rateReceiverAbsoluteCap
Fleet-wide byte cap per pattern per container per window; `0` (default) disables the cap unless overridden per-container via `rateReceiverCapLookupFile`.
| Type | Default |
|---|---|
| Number | 0 |
Defines a fleet-wide byte cap: the maximum bytes of a single pattern (a unique combination
of rateReceiverFieldNames values) that may be retained per container within the current
window (rateReceiverResetIntervalMs). Applies to every container the regulator sees, unless
that container has its own entry in rateReceiverCapLookupFile, which wins per-event.
At or below the resolved cap the pattern is kept untouched. Above it, the regulator engages:
if the pattern is also above rateReceiverMinSharePercent (the sanity guard), the event is
sampled at the severity floor probability.
0 (the default) disables the fleet-wide cap. With no fleet-wide cap and no per-container
entry in rateReceiverCapLookupFile, the regulator's over-cap branch never engages for that
container. Protection is strictly opt-in. Three configurations are first-class:
- Per-container only: set
rateReceiverCapLookupFile. Listed containers get their cap; unlisted containers are unregulated by the absolute cap. Most selective. - Fleet-wide only: set
rateReceiverAbsoluteCapto a positive integer. Applies to every container. - Both: per-container entries override the fleet-wide cap; unlisted containers fall back to the fleet-wide cap (safety floor).
Example: 10485760 (10 MB) means no single pattern can exceed 10 MB per container per 5-minute window. The maximum monthly spend per pattern per container can be computed from this cap and the vendor's per-GB rate.
rateReceiverMinSharePercent
Minimum share of container volume below which a pattern is exempt from sampling.
| Type | Default |
|---|---|
| Number | 0.05 |
Defines the share-of-container sanity guard (0.0 to 1.0): if a pattern is above the absolute cap BUT below this share of its container's total volume, the regulator skips it. The pattern is part of a legitimately high-volume container (busy API gateway, access log workload), not a noisy outlier.
Share is (pattern bytes + event) / (container bytes + event) over the current window.
Example: 0.05 means a pattern above the absolute cap is still retained if it represents less than 5% of its container's total volume. Prevents false positives on naturally chatty containers.
rateReceiverIngestionCostPerGB
Vendor ingestion cost per GB in USD, for rendering savings in dollars.
| Type | Default |
|---|---|
| Number | 1.5 |
Defines the cost per GB charged by your observability vendor for log ingestion. Used only to render savings metrics in dollars (dropped bytes × cost per GB); it does not affect the keep/drop decision, which is share-based.
Common vendor pricing (2025):
- Splunk Cloud: ~$1.50/GB (varies by contract, SKU)
- Datadog Logs: ~$0.10-$0.25/GB (depends on tier: standard, flex, online archives)
- Elastic Cloud: ~$0.109/GB (standard logging tier)
- New Relic: ~$0.30/GB (Data Plus)
- Sumo Logic: ~$1.50/GB (depends on plan)
- AWS CloudWatch Logs: ~$0.50/GB ingestion + $0.03/GB storage.
This module is defined in rate/module.yaml.