ds@mcpanalytics.aiEmail your data and your question and get an answer about your own data, with the method shown.Email your data and question. Get an answer.

Server and Network Anomaly Detection

By MCP Analytics Team | Published , updated

Your monitoring tools alert on thresholds: CPU above 90%, response time above 500ms, disk above 80%. But some problems look normal on any single metric and only stand out when you look at everything together, such as an unusual combination of request rate, wait time and bytes sent. Isolation forest scores each record by how unlike the rest it is, so you can review the most unusual rows first. This page shows a simulated example with the code and the printed output, then explains how to read the results.

Worked Example (Simulated): Flagging Unusual Log Rows

Question: Which made-up server log rows differ from the usual pattern?

Inputs: Simulated data, seed 417. The run has 120 rows and three fields: requests per minute, wait time in milliseconds, and bytes sent. Rows 7, 38 and 91 are set to odd values by hand; the other 117 rows are random draws around usual values.

Method: Isolation Forest, a model that spots records unlike most, with 200 trees and a contamination setting of 0.05. That setting tells the model to flag 5 percent of the rows, whatever the data look like.

import numpy as np
from sklearn.ensemble import IsolationForest

seed = 417
rng = np.random.default_rng(seed)
rows = 120
ids = np.arange(rows)
req_per_min = rng.normal(40, 5, rows).clip(20, None)
latency_ms = rng.normal(120, 18, rows).clip(60, None)
bytes_sent = rng.normal(900, 140, rows).clip(400, None)
# Simulated log records with deliberately unusual combinations.
req_per_min[[7, 38, 91]] = [110, 18, 105]
latency_ms[[7, 38, 91]] = [310, 360, 115]
bytes_sent[[7, 38, 91]] = [2400, 420, 2800]
X = np.column_stack([req_per_min, latency_ms, bytes_sent])
model = IsolationForest(n_estimators=200, contamination=0.05, random_state=seed)
labels = model.fit_predict(X)
scores = model.decision_function(X)
flagged = np.flatnonzero(labels == -1)
print(f"Simulated data, seed {seed}")
print(f"Rows: {rows}; input fields: req_per_min, latency_ms, bytes_sent")
print("Method: IsolationForest(n_estimators=200, contamination=0.05, "
      "random_state=417)")
print(f"Flagged row IDs ({len(flagged)}): " + ", ".join(map(str, flagged)))
print("Lowest-score flagged records (lower means more unusual):")
for i in sorted(flagged, key=lambda i: scores[i])[:5]:
    print(f"row={i}, req_per_min={req_per_min[i]:.1f}, "
          f"latency_ms={latency_ms[i]:.1f}, bytes_sent={bytes_sent[i]:.1f}, "
          f"score={scores[i]:.4f}")

Printed output:

Simulated data, seed 417
Rows: 120; input fields: req_per_min, latency_ms, bytes_sent
Method: IsolationForest(n_estimators=200, contamination=0.05, random_state=417)
Flagged row IDs (6): 7, 12, 30, 38, 63, 91
Lowest-score flagged records (lower means more unusual):
row=7, req_per_min=110.0, latency_ms=310.0, bytes_sent=2400.0, score=-0.2886
row=91, req_per_min=105.0, latency_ms=115.0, bytes_sent=2800.0, score=-0.2763
row=38, req_per_min=18.0, latency_ms=360.0, bytes_sent=420.0, score=-0.2709
row=30, req_per_min=41.3, latency_ms=81.6, bytes_sent=1232.4, score=-0.0359
row=12, req_per_min=27.4, latency_ms=113.6, bytes_sent=1232.4, score=-0.0275

Result: The model marked six rows as unusual, and six is set by the contamination setting of 0.05, which asks for 5 percent of 120 rows. Three rows (7, 38, 91) were made odd on purpose and got the lowest scores. The other three flagged rows were not planted; they are ordinary rows flagged to fill that quota. Rows 30 and 12 have scores near zero (-0.036 and -0.028), which are borderline. The scores alone do not show why a row stands out, so check flagged rows in the source logs.

Limit: The script adds odd values to made-up records. This result does not show that a record is an attack or that this method will find issues in real logs.

Sources

Why Review Unusual Rows?

Threshold-based alerting tells you when a single metric has already crossed a line. A score built from several fields at once can point you to rows worth a look before then, such as a server that is within limits on every metric but behaving unlike its peers. Isolation forest can flag records that differ from the data it sees. A flag is a reason to review a record. It does not show that the record is an attack.

To find the rows in your own data that do not fit the usual pattern, try the free anomaly detection tool.

What This Analysis Does

This analysis uses isolation forest, an unsupervised machine learning method for finding unusual records in multi-dimensional data (Liu, Ting and Zhou published it in 2008; see Sources). Unlike a single-metric threshold, it scores every record using all the fields you give it (packet size, protocol, source IP, response time, bytes transferred) at once. You still choose how many rows get flagged, through the contamination setting.

Here, the model gave the lowest scores to rows 7, 91, and 38. Check flagged rows in the source logs. A score alone does not show why a row stands out. In the example above, IsolationForest used 200 trees and marked six rows as unusual.

Scoring several fields together can point to cases that single-metric alerts do not express:

When to Use This Analysis

What Data Do You Need?

A CSV export from any system that produces timestamped event data with numeric and categorical fields.

Common sources

What makes a good dataset

A single column of response times is little more than a threshold with extra steps. Several columns (response time, request size, status code, source, and endpoint) give the method context to score combinations.

How to Read the Report

Anomaly score distribution: a histogram showing scores for every record. Normal records cluster at low scores; anomalies sit in the right tail. A clear gap between the lowest scores and the rest suggests distinct rows, as in the example above. A gradual tail with no clear gap means the boundary is fuzzy: review the top-scored items but don't treat the flag as absolute. Scores near zero are borderline.

Feature importance: ranks which dimensions contributed most to the anomaly scores. If "packet_length" dominates, your anomalies are primarily about unusual sizes. If multiple features contribute roughly equally, the anomalies are multi-dimensional. They look unusual across several metrics simultaneously, which often indicates more interesting patterns.

Top anomalies table: the action list. Each row shows the anomaly score and the actual feature values for the flagged record. Start with the highest-scored items and work down. The raw values help you see how a record differs, such as a very large packet, an error status from a source that normally gets successes, or a request to a destination no other client contacts. The score alone does not show why a row stands out.

Feature space scatter plot: shows anomalies highlighted against normal data in two dimensions. If the anomalies form a cluster, you may have a systematic pattern (a batch of bad requests, a compromised host, a misconfigured service). If they scatter, each anomaly may have a different cause.

Normal vs. anomaly comparison: side-by-side statistics for flagged vs. normal records on every dimension. This is where you can see which fields differ most between flagged and normal rows.

What to Do With the Results

Immediate

Strategic

When to Use Something Else

Your turn

Bring your own data and the question you actually need answered.

MCP AnalyticsData science by email Send us your data and your question, and we will reply. ds@mcpanalytics.ai