This project implements a pipeline that intercepts raw logs using Vector, enriches them with AI-predicted tags using XGBoost & TF-IDF, and forwards them to SigNoz for observability.
The system follows a sidecar architecture pattern:
- Log Source: Applications/VMs send logs via HTTP (JSON).
- Vector (Collector): Intercepts the logs.
- ML API (Sidecar): Vector pauses, sends the log text to the Python API.
- AI Engine:
- TF-IDF: Converts text to numbers.
- XGBoost: Predicts
source_type(e.g., Security) andcontent_type(e.g., Error).
- SigNoz: Displays the logs with the new AI tags.
| Directory/File | Description |
|---|---|
ml_api/ |
The Flask API that runs inside Docker. Serves predictions. |
training/ |
Source code to retrain the models from scratch. |
vector/ |
Configuration for the Vector log collector. |
models/ |
Binary model artifacts generated by training. |
docker-compose.yaml |
Orchestrates the entire pipeline. Starts the Vector and ML API containers. |
app.py |
(Optional) Script for local development/testing. |
The development process evolved through three distinct phases:
- Phase 1 (Deep Learning): Sentence Transformer + Neural Network.
- Phase 2 (The ML Hybrid): Sentence Transformer + XGBoost Classifier.
- Phase 3 (Current - Distillation): Qwen Labeling + TF-IDF + XGBoost.
The initial attempt focused purely on semantic understanding using pre-trained transformer models.
- Architecture:
- Embedding:
all-MiniLM-L6-v2to generate dense vectors. - Classifier: A fully connected Neural Network (PyTorch/TensorFlow).
- Embedding:
- Outcome:
- β Pros: Accurate classification.
- β Cons: Extremely slow inference and difficult to tune. The Neural Network required massive data to converge.
To improve training stability and interpretability, we replaced the Neural Network with XGBoost, but kept the heavy Sentence Transformer embeddings.
- Architecture:
- Embedding:
all-MiniLM-L6-v2 - Classifier: XGBoost (Gradient Boosting).
- Embedding:
- Why: XGBoost is generally faster and more robust than Neural Networks on tabular data (embeddings).
- The Bottleneck:
- β Latency: Slow embedding process.
- β Semantic Mismatch: Sentence Transformer is pre-trained on standard English (natural language). It focuses on the literal meaning of words, which causes poor performance on technical logs.
To solve the latency bottleneck, we moved to a Knowledge Distillation strategy. We realized we didn't need heavy Sentence Transformer embeddings at runtime if we had good labels.
- Model: Qwen (LLM).
- Role: We use Qwen to "read" raw logs and generate high-quality ground-truth labels. It acts as the intelligent teacher.
- Model: TF-IDF + XGBoost.
- Why: TF-IDF conversion takes lesser time.
- Result: The XGBoost model learns to mimic Qwen's high-quality labels using simple text features (TF-IDF).
The table below summarizes the trade-offs across all three phases.
| Phase | Embedding Strategy | Classifier | Verdict |
|---|---|---|---|
| Phase 1 | Sentence Transformer | Neural Network | Too Slow. |
| Phase 2 | Sentence Transformer | XGBoost | Bottlenecked. Embedding generation is too heavy. |
| Phase 3 | TF-IDF (Sparse) | XGBoost | Current Methodology. Speedup with higher accuracy due to LLM labeling. |
Follow these steps to set up the pipeline on a new server or development machine.
- Docker & Docker Compose (v2.0+)
- Python 3.9+ (For local training)
- Git
Clone the repository:
git clone http://<your-forgejo-url>/user/log-classification.git
cd log-classificationcd training
python -m venv .venv
source .venv/bin/activate
pip install -r training/requirements.txtThe training logic is split into 5 sequential steps located in training/src/. This pipeline transforms raw unstructured logs into a trained XGBoost classifier.
| Order | Script | Purpose |
|---|---|---|
| 1 | parse_logs.py |
Ingestion: Reads raw data (JSON/CSV) and converts unstructured text into a standard format. |
| 2 | label.py |
Applies heuristic labels (e.g., regex for "Security", "Network") to create initial training labels. |
| 3 | collapse.py |
Deduplication: Groups similar labeled logs into cluster to prevent the model from overfitting on repetitive error loops. |
| 4 | augmentation.py |
Balancing: Uses NLP techniques to generate synthetic data for rare log categories. |
| 5 | train.py |
Training: Vectorizes the dataset (TF-IDF) and trains the final XGBoost classifiers. |
We have provided a helper script to run the entire pipeline in the correct order. This is the preferred way to retrain the models.
Run the following command in your terminal:
./run_training.shNote: If you get a permission error, run chmod +x run_training.sh first.
What this script does:
- Sets
set -eto ensure the process stops immediately if any step fails. - Provides progress logs (e.g.,
[1/5] Parsing Logs...). - Saves all artifacts to the
models/directory.
If you need to debug a specific step, you can run the Python scripts individually from the root directory:
# 1. Parse raw input
python training/src/parse_logs.py
# 2. Label the data
python training/src/label.py
# 3. Collapse
python training/src/collapse.py
# 4. Augment (Generate synthetic samples)
python training/src/augmentation.py
# 5. Train Models
python training/src/train.pyOnce the training script finishes, navigate to the models/ directory. You must see the following four files for the application to work:
| File | Description |
|---|---|
tfidf_vectorizer.joblib |
The model that converts text to numbers. |
xgb_content_model.joblib |
Classifier for Content Type (Error, Info, Warning). |
xgb_source_model.json |
Classifier for Source Type (Security, Network, App). |
xgb_label_maps.json |
Mapping dictionary to convert numeric predictions back to text labels. |
If these files exist, you are ready to proceed to Deployment.
# Docker Deployment
Use **Docker Compose** to run the ML API and Vector side-by-side.
### 1. Architecture
The `docker-compose.yaml` defines two services:
* **`ml-api`:** Mounts the local `models/` folder so it can load the brains you just trained.
* **`vector`:** Mounts `vector/vector.toml` to configure the log pipeline.
### 2. Start the Pipeline
Run the following command in the root directory:
```bash
# Build and start in background
docker-compose up -d --build
Check if both containers are running:
docker psYou should see ml_api and vector-sidecar with status Up.
If containers are crashing, check the logs:
# Check ML API logs
docker logs ml_api
# Check Vector logs
docker logs vector-sidecarTest the system by sending logs manually via curl.
Test if the Python logic works (bypassing Vector):
curl -X POST http://localhost:8000/predict \
-H "Content-Type: application/json" \
-d '{"message": "[example-logs]"}'Expected Response:
{
"source_type": "[SOURCE]",
"content_type": "[CONTENT]",
"confidence": [CONFIDENCE]
}Test the full flow (Vector -> ML -> Vector -> Output):
NOW=$(date +%s%N)
curl -v -X POST http://localhost:5001/ -H "Content-Type: application/json" -d '{"resourceLogs":[{"resource":{},"scopeLogs":[{"scope":{},"logRecords":[{"body":{"stringValue":"Connection refused on port 80"},"attributes":[]}]}]}]}'
