ECVC Detector
The Event Count Vector Clustering Detector (ECVC) detects anomalies by calculating the distance between the count vectors from training and new ones. The method can be found in this publication.
In/out
Input and output schemas in the pipeline
| Schema | Description | |
|---|---|---|
| Input | ParserSchema | Structured log |
| Output | DetectorSchema | Alert / finding |
At a glance
| Learns from training data | Auto-configuration | Needs events |
Federation |
|---|---|---|---|
| ✅ | ❌ | ❌ | ✅ |
Description
A count vector is formed by counting the number of appearances of each event ID in a sequence of a specific window size.
Count vectors learned during training are stored via persistency, so a trained model can be saved and restored with a persist: block. A count vector is only comparable within the window it was counted over, so restoring state at a different window_size logs a warning, because the restored vectors cannot match and every window would alert.
Example
import yaml
from detectmatelibrary import schemas
from detectmatelibrary.detectors.ecvc_detector import ECVCDetector
with open("docs/examples/detectors/ecvc_detector.yaml") as f:
config = yaml.safe_load(f)
detector = ECVCDetector(name="ECVCDetector", config=config)
def event(event_id: int) -> schemas.ParserSchema:
"""A parsed log; only its EventID (the matched template) matters here."""
return schemas.ParserSchema({"eventID": event_id})
# normal session: 0 = login accepted, 1 = session opened, 2 = session closed.
# The detector works on sliding windows of 3 logs (window_size: 3).
for log in [event(i) for i in [0, 1, 2] * 8]:
detector.process(log)
# a burst of logins: windows whose EventID counts are far from anything learned
alerts = [detector.process(event(0)) for _ in range(4)]
print([alert["score"] if alert else None for alert in alerts]) # [None, 0.5, 0.8, 0.8]
Configuration file
The configuration used by the example above. It sets only what this use case needs; every other parameter keeps its default (see Configuration arguments).
detectors:
ECVCDetector:
method_type: ecvc_detector
params:
data_use_training: 20 # learn count vectors from the first 20 windows, then detect
window_size: 3 # count EventIDs over windows of 3 consecutive logs
The same file works unchanged in both places a detector runs:
- Library: load it with
yaml.safe_loadand pass the dict asconfig=, as in the example. The key underdetectors:must match the detector'sname. - DetectMateService: use it as the service's detector configuration.
Configuration arguments
All parameters this detector accepts, grouped by the YAML block they go in. Scope tells whether a parameter is specific to this detector or shared with other detectors (see the Detectors overview). Where this detector changes a shared default, the shared value is shown in brackets.
Top level
| Field | Type | Default | Scope | Description |
|---|---|---|---|---|
method_type |
string | ecvc_detector | shared | Indicates what type of method it is. |
auto_config |
boolean | True | shared | Runs the configuration step before the training process. Has no effect unless data_use_configure is set. |
events |
object | {} | shared | Events configuration dict keyed by event_id. |
global |
object | {} | shared | Instances monitoring event-independent header variables (e.g. hostname, level), keyed by instance name. Written as global in YAML. |
persist |
object, null | None | shared | Periodic state saving (path, interval_seconds, events_until_save, auto_load, storage_options). None disables it. See Saving state (persist) on the Detectors page. |
params
| Field | Type | Default | Scope | Description |
|---|---|---|---|---|
window_size |
integer | 10 | specific | Length of the event-ID window a count vector is built over. |
validation_per |
number | 0.2 | specific | Fraction of the learned count vectors held out as a validation split and used to derive the anomaly threshold. |
seed |
integer | 0 | specific | Random seed used to shuffle count vectors into train/validation splits. |
threshold_method |
string | mean | specific | Method used to derive the anomaly threshold from the validation split: 'mean' averages the distance scores, 'default' uses a fixed threshold of 0. |
start_id |
integer | 10 | shared | Number used to start the unique ID generator. |
data_use_training |
integer, null | None | shared | Number of logs used for training. None skips training. |
data_use_configure |
integer, null | None | shared | Number of logs used for the configuration step. None skips it. |
use_config_data_as_training |
boolean | True | shared | Combine the configured data in the training process if True. |
train_buffer_max_records |
integer | 100000 | shared | Configure records kept in memory for training (use_config_data_as_training) before the buffer spills to Parquet files on disk, in parts of this many records. |
train_buffer_dir |
string, null | None | shared | Local directory for the spilled training buffer. None uses the system temp directory (TMPDIR). Each spill goes to a private detectmate-train-* directory, removed after training reads it; a killed process leaves it behind. |
parser |
string | PARSER | shared | Name of the parser used. |
allow_fed |
boolean | False | shared | Builds the stores needed to take part in federation. |