Skip to content

Latest commit

Β 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ” CI Root Cause Analyzer

Stop hunting through logs. Let AI tell you exactly what broke and who owns it.

Python FastAPI Celery PostgreSQL Redis Docker LiteLLM


Your pipeline fails. Instead of digging through hundreds of lines of logs, this agent automatically fetches them, classifies the failure, runs LLM-powered root cause analysis, and emails a structured incident report to the right team β€” in seconds, not hours.


Jenkins GitHub Actions GitLab CI CircleCI Azure DevOps Bitbucket


Built on a three-stage classification pipeline (regex β†’ semantic β†’ LLM fallback) with a self-learning knowledge store: the more failures it sees, the faster and more accurate it gets.

Supports two modes of operation:

  • 🌐 Webhook-driven HTTP API (FastAPI + Celery) β€” for production pipelines with Jenkins and GitHub Actions native integration
  • ⌨️ CLI (cli.py) β€” for local debugging and one-off analysis from any CI/CD service, no Redis or database setup required

πŸ“‘ Table of Contents


πŸ—οΈ Architecture

graph TB
    subgraph External["CI/CD Systems"]
        JK[Jenkins]
        GH[GitHub Actions]
    end

    subgraph API["FastAPI Ingest Service β€” port 8000"]
        ING["/failures/jenkins\n/failures/github"]
        HLT["/health"]
    end

    subgraph Broker["Message Broker"]
        RD[(Redis)]
    end

    subgraph Workers["Celery Workers"]
        NF["normalize_failure\n─ fetch stage-wise logs\n─ write .log files"]
        CF["classify_failure\n─ signal extraction\n─ deduplication\n─ classification"]
        AF["analyze_failure\n─ LLM RCA\n─ report generation\n─ email"]
    end

    subgraph Classification["Classification Pipeline"]
        LA["LogAnalyzer\nRegex signal extraction"]
        DD["SmartDeDuplicator\nHDBSCAN clustering"]
        KS["FailureKnowledgeDB\npgvector similarity search"]
        CO["ClassificationOrchestrator\nFusion scoring"]
        RC["RegexClassifier\nWeighted pattern matching"]
        SC["SemanticClassifier\nFAISS k-NN"]
        LLC["LLMClassifier\nLiteLLM fallback"]
    end

    subgraph RCALayer["RCA Layer"]
        RE["RCAEngine\nstructured LLM output"]
        PR["prompt.py\ncategory-aware prompt builder"]
    end

    subgraph Notifier["Notification"]
        GR["generate_report\nHTML report renderer"]
        MN["mail_notifier\nSMTP sender"]
    end

    subgraph Storage["Storage"]
        PG[(PostgreSQL + pgvector)]
        FS[Filesystem\nstorage/logs/]
        FM[(FAISS Index\nmodels/)]
    end

    subgraph Connectors["CI Connectors"]
        PF["PipelineFactory\nplatform router"]
        JC["JenkinsClient\nBlue Ocean API"]
        GC["GitHubClient\nGitHub Actions API"]
    end

    JK -->|webhook POST| ING
    GH -->|webhook POST| ING
    ING -->|persist record| PG
    ING -->|enqueue 3 tasks| RD

    RD -->|consume| NF
    RD -->|consume| CF
    RD -->|consume| AF

    NF --> PF
    PF --> JC
    PF --> GC
    JC -->|stage logs| FS
    GC -->|stage logs| FS
    NF -->|status update| PG

    CF --> LA
    LA -->|LogSignal list| DD
    DD -->|embeddings| FM
    DD -->|deduped signals| KS
    KS -->|cache hit β†’ SignalRCA| AF
    KS -->|cache miss| CO
    CO --> RC
    CO --> SC
    SC <-->|training / search| FM
    CO --> LLC
    LLC -->|OpenAI / LiteLLM| RCALayer
    CF -->|error.json| FS
    CF -->|status update| PG

    AF --> RE
    RE --> PR
    RE -->|LiteLLM call| RCALayer
    AF -->|store pattern| PG
    AF -->|root_cause.json| FS
    AF --> GR
    GR -->|rca_report.html| FS
    GR --> MN
    MN -->|email| External
Loading

πŸ”„ Data Flow

sequenceDiagram
    participant CI   as CI/CD System
    participant API  as FastAPI
    participant Redis as Redis
    participant NF   as normalize_failure
    participant CF   as classify_failure
    participant AF   as analyze_failure
    participant DB   as PostgreSQL
    participant FS   as Filesystem
    participant LLM  as LLM / Embedding API
    participant SMTP as SMTP Server

    CI->>API: POST /failures/{platform}
    API->>DB: Insert failure record (status=RECEIVED)
    API->>Redis: Enqueue normalize / classify / analyze
    API-->>CI: {failure_id, status: "Received successfully"}

    Redis->>NF: Execute normalize_failure
    NF->>CI: Fetch stage-wise logs (Jenkins Blue Ocean / GitHub API)
    NF->>FS: Write <stage>.log files
    NF->>DB: Update status = LOGS_COLLECTED

    Redis->>CF: Execute classify_failure
    CF->>FS: Read *.log files
    CF->>CF: Extract LogSignals (regex patterns)
    CF->>LLM: Generate text embeddings
    CF->>CF: Deduplicate via HDBSCAN clustering
    CF->>DB: pgvector cosine similarity search
    alt Cache hit (similarity β‰₯ 0.92)
        DB-->>CF: Return cached SignalRCA
        CF->>FS: Write root_cause.json
        CF->>DB: Update status = RESOLVED
    else Cache miss
        CF->>CF: Fused Regex + Semantic classification
        CF->>LLM: LLM fallback for UNKNOWN signals
        CF->>FS: Write error.json + embeddings.json
        CF->>DB: Update status = CLASSIFIED
    end

    Redis->>AF: Execute analyze_failure
    AF->>FS: Read error.json
    AF->>LLM: Run structured RCA (instructor + LiteLLM)
    AF->>DB: Upsert failure pattern (pgvector)
    AF->>FS: Write root_cause.json
    AF->>AF: generate_report β†’ rca_report.html
    AF->>SMTP: Send HTML email to owner team
    AF->>DB: Update status = RESOLVED
Loading

🧩 Components

Component Path Responsibility
🌐 FastAPI App api/app/main.py HTTP server, startup hooks
⌨️ CLI App cli.py CLI for root cause analysis
πŸ“₯ Ingest Routes api/routes/ingest.py Accept Jenkins/GitHub failure webhooks
❀️ Health Route api/routes/health.py Postgres / Redis / Celery health check
πŸ”€ PipelineFactory analyzer/connectors/pipeline_factory.py Detect CI platform, delegate log fetch
πŸ”§ JenkinsClient analyzer/connectors/jenkins_client.py Jenkins Blue Ocean REST API
πŸ™ GitHubClient analyzer/connectors/github_client.py GitHub Actions REST API
πŸ”Ž LogAnalyzer analyzer/extractors/log_analyzer.py Regex-based signal extraction from logs
🧹 SmartDeDuplicator analyzer/deduplicator/smart_deduplicator.py HDBSCAN semantic deduplication
πŸ“ RegexClassifier analyzer/classifiers/regex_classifier.py Weighted regex pattern scoring
🧠 SemanticClassifier analyzer/classifiers/semantic_classifier.py FAISS k-NN nearest-neighbour classifier
πŸ€– LLMClassifier analyzer/classifiers/llm_classifier.py LLM fallback for unresolved signals
πŸŽ›οΈ ClassificationOrchestrator analyzer/classifiers/classification_orchestrator.py Fuse regex+semantic, auto-learn feedback
πŸ”— EmbeddingService analyzer/embedding/embedding_service.py LiteLLM embedding wrapper (singleton)
πŸ”¬ RCAEngine analyzer/rca_engine/rca_engine.py LLM-based structured RCA
πŸ“„ generate_report analyzer/notifier/generate_report.py HTML incident report builder
πŸ“§ mail_notifier analyzer/notifier/mail_notifier.py SMTP email dispatch
πŸ—„οΈ DatabaseInit storage/database.py PostgreSQL schema bootstrap
πŸ’Ύ LogStorer storage/logs.py Read/write log and result files
πŸ“‹ PipelineFailureDB storage/pipeline_failure_record.py Failure metadata CRUD
🧬 FailureKnowledgeDB storage/failure_knowledge_record.py pgvector pattern store + similarity search
βš™οΈ Celery Tasks workers/tasks.py normalize / classify / analyze async tasks

πŸ“ Project Structure

ci-root-cause-analyzer/
β”œβ”€β”€ api/
β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”œβ”€β”€ config.py           # Pydantic settings (reads from .env)
β”‚   β”‚   └── main.py             # FastAPI application factory
β”‚   β”œβ”€β”€ routes/
β”‚   β”‚   β”œβ”€β”€ health.py           # GET /health
β”‚   β”‚   └── ingest.py           # POST /failures/jenkins, /failures/github
β”‚   └── schemas/                # Pydantic request / response models
β”œβ”€β”€ analyzer/
β”‚   β”œβ”€β”€ classifiers/
β”‚   β”‚   β”œβ”€β”€ classification_orchestrator.py   # Fusion + auto-learn
β”‚   β”‚   β”œβ”€β”€ failure_patterns.py              # Load YAML patterns
β”‚   β”‚   β”œβ”€β”€ failure_patterns.yaml            # Regex patterns per category
β”‚   β”‚   β”œβ”€β”€ llm_classifier.py                # LLM fallback classifier
β”‚   β”‚   β”œβ”€β”€ regex_classifier.py              # Weighted regex scorer
β”‚   β”‚   β”œβ”€β”€ semantic_classifier.py           # FAISS k-NN classifier
β”‚   β”‚   └── training/
β”‚   β”‚       └── synthetic_data_generator.py  # Bootstrap training data
β”‚   β”œβ”€β”€ connectors/
β”‚   β”‚   β”œβ”€β”€ github_client.py    # GitHub Actions API client
β”‚   β”‚   β”œβ”€β”€ jenkins_client.py   # Jenkins Blue Ocean API client
β”‚   β”‚   └── pipeline_factory.py # Platform detection + routing
β”‚   β”œβ”€β”€ deduplicator/
β”‚   β”‚   └── smart_deduplicator.py   # HDBSCAN-based dedup
β”‚   β”œβ”€β”€ embedding/
β”‚   β”‚   └── embedding_service.py    # LiteLLM embedding singleton
β”‚   β”œβ”€β”€ extractors/
β”‚   β”‚   └── log_analyzer.py         # Log β†’ LogSignal extraction
β”‚   β”œβ”€β”€ notifier/
β”‚   β”‚   β”œβ”€β”€ generate_report.py      # HTML report generator
β”‚   β”‚   └── mail_notifier.py        # SMTP email sender
β”‚   β”œβ”€β”€ ownership/
β”‚   β”‚   └── ownership_config.py     # Category β†’ team mapping
β”‚   └── rca_engine/
β”‚       β”œβ”€β”€ prompt.py               # Category-aware prompt builder
β”‚       └── rca_engine.py           # Structured LLM RCA runner
β”œβ”€β”€ models/
β”‚   β”œβ”€β”€ semantic.faiss          # FAISS flat L2 index
β”‚   └── semantic.pkl            # SemanticClassifier metadata
β”œβ”€β”€ storage/
β”‚   β”œβ”€β”€ database.py             # PostgreSQL init / table bootstrap
β”‚   β”œβ”€β”€ failure_knowledge_record.py  # pgvector knowledge store
β”‚   β”œβ”€β”€ init.sql                # SQL init script for Docker
β”‚   β”œβ”€β”€ logs.py                 # Log file read/write helpers
β”‚   └── pipeline_failure_record.py   # Failure metadata store
β”œβ”€β”€ utils/
β”‚   β”œβ”€β”€ execute_notifier.py     # Report + email orchestrator
β”‚   β”œβ”€β”€ hash_utils.py           # SHA-256 fingerprint generator
β”‚   └── text_normalizer.py      # Log text normalization
β”œβ”€β”€ workers/
β”‚   β”œβ”€β”€ celery_app.py           # Celery app + broker config
β”‚   └── tasks.py                # normalize / classify / analyze tasks
β”œβ”€β”€ cli.py                  # CLI entry point (no Celery/Redis required)
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ pyproject.toml
└── requirements.txt

βœ… Prerequisites

Requirement Details
🐳 Docker β‰₯ 24 + Docker Compose β‰₯ 2 Required for containerised deployment
πŸ€– LLM API key Any LiteLLM-compatible provider (OpenAI, Azure, Groq, etc.)
πŸ“§ SMTP account For email delivery of RCA reports
πŸ”§ Jenkins or GitHub Actions CI system to send webhooks (HTTP API mode)

βš™οΈ Installation

# Clone repository
git clone <repo-url>
cd ci-root-cause-analyzer

# Copy the environment template and fill in values
cp .env.example .env

πŸ”§ Configuration

Create a .env file in the project root:

# πŸ—„οΈ PostgreSQL
POSTGRES_USER=agentic
POSTGRES_PASSWORD=agentic
POSTGRES_DB=agentic_db
DB_HOST=postgresql
DB_PORT=5432

# ⚑ Redis
REDIS_HOST=redis
REDIS_PORT=6379

# πŸ”§ Jenkins
JENKINS_URL=https://<jenkins-host>/blue/rest/organizations/jenkins/
JENKINS_USER=<username>
JENKINS_TOKEN=<api-token>

# πŸ™ GitHub
GITHUB_TOKEN=<personal-access-token>
GITHUB_API_BASE_URL=https://api.github.com

# πŸ€– LLM (any LiteLLM-supported provider)
LLM_API_KEY=<api-key>
RCA_LLM_DEPLOYMENT=gpt-4o-mini
EMBEDDING_MODEL=text-embedding-3-small
RCA_TEMPERATURE=0
CLASSIFY_TEMPERATURE=0

# πŸ“§ SMTP
SMTP_SERVER=smtp.example.com
SMTP_PORT=587
SMTP_USER=sender@example.com
SMTP_PASSWORD=<password>
DEFAULT_MAIL=fallback@example.com

# πŸ’Ύ Storage
LOG_PATH=storage/logs
SEMANTIC_PATH=models/semantic.pkl
FAILURE_TABLE=failures
FAILURE_PATTERN_TABLE=failure_knowledge_table

πŸš€ Running the Services

🐳 Docker Compose (recommended)

# Build and start all services
docker compose up --build

# Start in detached mode
docker compose up --build -d

# View logs
docker compose logs -f ingest
docker compose logs -f dev_agent

# Stop all services
docker compose down

Services started:

Service Port Description
πŸ—„οΈ postgresql 5432 PostgreSQL 17 + pgvector
⚑ redis 6379 Redis 8 message broker
🌐 ingest 8000 FastAPI ingest service
βš™οΈ dev_agent β€” Celery worker

πŸ’» Local Development

# Install dependencies
pip install -r requirements.txt

# Start FastAPI
uvicorn api.app.main:app --host 0.0.0.0 --port 8000 --reload

# Start Celery worker (separate terminal)
celery -A workers.tasks worker --loglevel=INFO -P solo

# Pre-generate semantic classifier training data
python -c "from analyzer.classifiers.training.synthetic_data_generator import generate_and_save; generate_and_save()"

⌨️ CLI

cli.py runs the full analysis pipeline synchronously and without Celery or Redis β€” useful for local debugging, one-off analysis, and CI scripts. It calls the same underlying service functions as the Celery tasks.

The analyze logs subcommand accepts plain .log files from any source β€” Jenkins, GitHub Actions, GitLab CI, CircleCI, Bitbucket Pipelines, Azure DevOps, or any custom service.

pip install -r requirements.txt   # includes typer[all]

🏳️ --use-db flag

All three subcommands accept --use-db (off by default). Without it, no PostgreSQL connection is required.

With --use-db you get Without --use-db
βœ… Failure records persisted to PostgreSQL ❌ No DB writes
βœ… pgvector cache lookup (β‰₯ 0.92 similarity = instant recall) ❌ Always runs full RCA
βœ… Newly analysed patterns stored for future cache hits ❌ No pattern learning

πŸ“¦ Subcommands

analyze jenkins β€” fetch logs from Jenkins

# fully local β€” no database needed
python cli.py analyze jenkins \
  --job-name "my-project/my-pipeline" \
  --build-number 42 \
  --commit abc123 \
  --branch main

# with DB persistence and email
python cli.py analyze jenkins \
  --job-name "my-project/my-pipeline" \
  --build-number 42 \
  --commit abc123 \
  --branch main \
  --dev-email dev@example.com \
  --ci-email devops@example.com \
  --use-db

Prompts for any omitted required options.

analyze github β€” fetch logs from GitHub Actions

# fully local β€” no database needed
python cli.py analyze github \
  --owner my-org \
  --repo my-repo \
  --run-id 12345678 \
  --commit abc123 \
  --branch main

# with DB persistence
python cli.py analyze github \
  --owner my-org --repo my-repo --run-id 12345678 \
  --commit abc123 --branch main \
  --dev-email dev@example.com \
  --use-db

analyze logs β€” analyze local .log files from any CI/CD service

No Jenkins or GitHub connection needed. Point the command at any directory containing .log files β€” from any CI/CD platform:

# fully local β€” no database needed
python cli.py analyze logs ./my-logs/

# with email notification
python cli.py analyze logs ./my-logs/ \
  --dev-email dev@example.com \
  --branch feature/auth

# enable pgvector knowledge-store lookup and pattern storage
python cli.py analyze logs ./my-logs/ --use-db

The command copies your .log files into storage/logs/<failure_id>/, runs the full extract β†’ deduplicate β†’ classify β†’ RCA chain, and writes results alongside them.

πŸ“Š HTTP Pipeline vs CLI Comparison

Capability 🌐 HTTP + Celery ⌨️ CLI (default) ⌨️ CLI (--use-db)
Async / parallel tasks βœ… ❌ sequential ❌ sequential
Redis broker required not needed not needed
PostgreSQL required not needed required
Failure record + status tracking βœ… ❌ βœ…
pgvector cache lookup βœ… ❌ βœ…
Pattern auto-learning βœ… ❌ βœ…
HTML report + email βœ… βœ… βœ…

πŸ“‚ Output Files

Results are written to storage/logs/<failure_id>/:

File Contents
πŸ“„ <stage>.log Raw stage logs (jenkins/github) or copied input logs
πŸ” error.json Classified signals with category, confidence, owner
🧠 root_cause.json Structured RCA results per signal
πŸ“Š rca_report.html HTML incident report (same as emailed report)

πŸ“‘ API Reference

POST /failures/jenkins

Ingest a Jenkins pipeline failure.

Request body:

{
  "commit": "abc123def456",
  "branch": "main",
  "job_name": "my-project/my-pipeline",
  "build_number": 42,
  "mailRecipient": {
    "dev_email": "dev@example.com",
    "test_email": "qa@example.com",
    "ci_email": "devops@example.com"
  }
}

Response:

{
  "failure_id": "550e8400-e29b-41d4-a716-446655440000",
  "data": { "..." : "..." },
  "status": "Received successfully"
}

POST /failures/github

Ingest a GitHub Actions workflow failure.

Request body:

{
  "commit": "abc123def456",
  "branch": "main",
  "repo": "my-repo",
  "owner": "my-org",
  "run_id": 12345678,
  "mailRecipient": {
    "dev_email": "dev@example.com",
    "ci_email": "devops@example.com"
  }
}

Response: same shape as Jenkins response.


GET /health

Returns liveness and readiness of all dependencies.

Response:

{
  "status": "healthy",
  "postgres": { "status": "ok", "latency_ms": 1.23 },
  "redis":    { "status": "ok", "latency_ms": 0.45 },
  "celery":   { "status": "ok", "workers": 1, "worker_names": ["celery@hostname"] }
}

πŸ“– Interactive API Docs (after starting the service):


🧠 Classification Pipeline

Failures are classified across 3 categories using a three-stage pipeline:

Stage Method Fallback
1️⃣ Regex Weighted pattern matching against error line, context and stage β€”
2️⃣ Semantic FAISS k-NN on OpenAI embeddings Trained on synthetic data
3️⃣ LLM LiteLLM structured output Only for UNKNOWN signals

🏷️ Failure Categories

Category Covers Owner Team
πŸ”΄ DEV_FAILURE Compilation errors, linker failures, missing dependencies, code quality gate failures πŸ‘©β€πŸ’» Developers
🟑 TEST_FAILURE Test assertion failures, flaky tests, fixture/snapshot mismatches, test timeouts πŸ§ͺ QA Engineers
πŸ”΅ CI_INFRA_FAILURE Pipeline config, env/secrets, artifact publishing, Docker, Kubernetes, network, resource exhaustion, CI agents πŸ› οΈ DevOps Engineers

βš–οΈ Fusion Scoring

Regex and semantic scores are combined with fixed weights before applying per-category confidence thresholds:

fused_score = (0.65 Γ— regex_confidence) + (0.35 Γ— semantic_confidence)

Signals whose fused score falls below ABSOLUTE_MIN_CONFIDENCE = 0.20 are always marked UNKNOWN and routed to the LLM classifier.

πŸ” Auto-Learning

High-confidence classifications (confidence > 0.80) are fed back into the FAISS index as new training examples. After 20 feedback samples accumulate the index is retrained and persisted to models/semantic.faiss + models/semantic.pkl.


πŸ› οΈ Development

πŸ§ͺ Running Tests

pytest

πŸ”„ Regenerating Synthetic Training Data

python -m analyzer.classifiers.training.synthetic_data_generator

πŸ“– Interactive API Docs

After starting the service, open:

About

AI-powered tool for automated root cause analysis of CI/CD pipeline failures. Fetches logs from Jenkins or GitHub Actions, classifies errors using regex, semantic, and LLM-based methods, and emails structured incident reports to the right team. Supports both HTTP API and CLI modes. Self-learning for faster, smarter diagnostics.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages