Skip to content

Repository files navigation

🌩️ Baadal — Server Log Collector and Alerter

Build and ReleaseGo Report CardLicense

A lightweight, self-contained observability agent for monitoring Ubuntu servers with disk usage tracking, kernel monitoring, Docker container health, and webhook-based alerting.

✨ Features

  • 📊 Disk Usage Monitoring — Track largest directories with configurable thresholds
  • 🐳 Docker Log Monitoring — Filter container logs for errors, panics, OOM events
  • 🔍 Kernel Monitoring — Monitor dmesg for critical kernel events
  • 💓 Heartbeat — Periodic alive signals for health tracking
  • 🔄 Event Deduplication — Reduce noise with smart event hashing
  • 📈 Performance Stats — Track collector performance metrics
  • 🔔 Webhook Alerts — Discord, Slack, and custom API notifications
  • 🔒 Dead Man's Switch — Detect silent failures with receiver-side monitoring
  • 📝 Log Rotation — Automatic log rotation with lumberjack
  • 🔄 Hot Reload — Update config without restart (SIGHUP)
  • 🏗️ Dual Mode — Run as collector (agent) or receiver (central server)

� Table of Contents

🚀 Quick Start

Download Pre-built Binary

Download the latest release for your platform from GitHub Releases:

# Linux amd64
wget https://github.com/YOUR_USERNAME/baadhal/releases/latest/download/baadal-linux-amd64.tar.gz
tar -xzf baadal-linux-amd64.tar.gz
chmod +x baadal-linux-amd64
# Verify checksum
sha256sum -c baadal-linux-amd64.tar.gz.sha256

Build from Source

git clone https://github.com/YOUR_USERNAME/baadhal.git
cd baadhal
go mod download
go build -o baadal main.go

📋 Detailed Configuration

Baadal uses a YAML configuration file (config.yml) with comprehensive options for each monitoring component.

1. App Configuration

app:
name: "baadal"# Application name (used in logs)enabled: true # Master switch - set to false to disablelog_level: "info"# Logging level: debug | info | warn | errorheartbeat:
enabled: true # Enable periodic heartbeat eventsinterval: "*/5 * * * *"# Cron expression for heartbeat frequency# Examples:# "*/5 * * * *" - Every 5 minutes# "*/10 * * * *" - Every 10 minutes# "0 * * * *" - Every hourdeduplication:
enabled: true # Enable event deduplicationwindow_seconds: 60# Time window to check for duplicates# Events with identical type+host+data # within this window are discarded

Heartbeat Details:

  • Sends periodic "alive" signals to receiver
  • Includes uptime in seconds
  • Helps detect collector crashes or network issues
  • Recommended: 5-10 minutes for production

Deduplication Details:

  • Uses MD5 hash of (type + host + data) for comparison
  • Prevents alert spam from repeated errors
  • Memory-efficient with automatic cleanup every 5 minutes
  • Recommended: 60-300 seconds depending on alert frequency

2. Transport Configuration

transport:
mode: "remote"# "remote" or "local"remote: # Used when mode = "remote"endpoint: "http://receiver-ip:5170/ingest"# Receiver URL# Use Tailscale/VPN IP for securityauth:
enabled: false # Enable bearer token authenticationtoken: "your-secret-token"# Must match receiver tokenbatch_size: 10# Send after N events accumulateflush_interval: "5s"# Or send after this time (whichever first)retry_attempts: 3# Number of retries on failureretry_delay: "2s"# Delay between retry attemptslocal: # Used when mode = "local"log_output: "/var/log/baadal/events.log"# Local file path

Mode Selection:

  • remote: Recommended for production - sends to central receiver
  • local: For testing or standalone logging

Remote Transport Tips:

  • Use batch_size: 1 and flush_interval: "1s" for real-time alerting
  • Use batch_size: 50 and flush_interval: "30s" to reduce network traffic
  • Enable auth.enabled: true for production deployments

Endpoint Examples:

endpoint: "http://192.168.1.100:5170/ingest"# Local networkendpoint: "http://100.x.x.x:5170/ingest"# Tailscaleendpoint: "https://monitor.example.com/ingest"# Public (use HTTPS + auth!)

3. Disk Monitoring

disk:
enabled: true # Enable disk usage monitoringpaths: # Directories to scan
- / # Root filesystem
- /var # Common log location
- /var/lib/docker # Docker data
- /home # User directories
- /tmp # Temporary files
- /opt # Optional softwaretop_n: 5# Report top N largest directoriesmax_depth: 3# Maximum directory depth to scan# Higher = more detail but slowerschedule: "*/5 * * * *"# Cron schedule for scans# Examples:# "*/15 * * * *" - Every 15 minutes# "0 */2 * * *" - Every 2 hours# "0 3 * * *" - Daily at 3 AMalert:
enabled: true # Enable alerting for disk usagecondition: "size_gb > 20"# Alert when directory exceeds 20 GB# Can adjust threshold as neededwebhooks: # Webhook names to fire (from webhooks section)
- discord
- custom-api

Path Selection Tips:

  • Start with root paths (/, /var, /home)
  • Add Docker path if running containers: /var/lib/docker
  • Add application-specific paths: /opt/myapp, /data
  • Avoid network mounts (slow scans)

Performance Tuning:

# Fast scan (less detail, every 30 min)max_depth: 2schedule: "*/30 * * * *"# Detailed scan (more detail, hourly)max_depth: 4schedule: "0 * * * *"# Daily deep scanmax_depth: 5schedule: "0 2 * * *"# 2 AM daily

Alert Threshold Examples:

condition: "size_gb > 10"# Alert at 10 GBcondition: "size_gb > 50"# Alert at 50 GBcondition: "size_gb > 100"# Alert at 100 GB

4. Dmesg/Kernel Monitoring

dmesg:
enabled: true # Enable kernel message monitoringschedule: "*/1 * * * *"# Check every minute (recommended)filter_levels: # Kernel log levels to monitor
- err # Error conditions
- crit # Critical conditions
- alert # Action must be taken immediately
- emerg # System is unusable# Available but not recommended for production:# - warn # Warning conditions (very noisy)# - notice # Normal but significant# - info # Informational# - debug # Debug-level messagesalert:
enabled: true # Enable alertingcondition: "level == crit"# Alert on critical messages# Options: emerg, alert, crit, errwebhooks:
- discord

Filter Level Guide:

LevelSeverityTypical IssuesRecommended
emergEmergencyKernel panic, system crash✅ Yes
alertAlertHardware failure, critical bug✅ Yes
critCriticalHard disk errors, memory issues✅ Yes
errErrorDriver errors, non-critical failures✅ Yes
warnWarningDeprecation notices, soft errors⚠️ Noisy
noticeNoticeNormal but significant❌ Too noisy
infoInfoGeneral information❌ Too noisy
debugDebugDebug messages❌ Development only

Alert Condition Examples:

condition: "level == crit"# Only critical errorscondition: "level == alert"# Alert-level and abovecondition: "level == emerg"# Only emergency (kernel panic)

Best Practices:

  • Run every 1-2 minutes for timely kernel error detection
  • Filter to err, crit, alert, emerg only
  • Don't include warn - generates too many false positives

5. Docker Monitoring

docker:
enabled: true # Enable Docker log monitoringcontainers: # Which containers to monitor
- "all"# Monitor all running containers# OR specify by name:# - "nginx"# - "postgres"# - "redis"tail_lines: 100# Number of recent log lines to check# Higher = more coverage but slowerschedule: "*/2 * * * *"# Check every 2 minutesfilter_keywords: # Keywords to search for in logs
- "error"# Generic errors
- "fatal"# Fatal errors
- "panic"# Go panic, Python panic
- "OOM"# Out of memory
- "killed"# Process killed
- "segfault"# Segmentation fault
- "exception"# Exceptions (add if using Python/Java)alert:
enabled: truecondition: "keyword == fatal"# Alert on "fatal" keyword matcheswebhooks:
- discord
- custom-api

Container Selection:

# Monitor all containerscontainers: ["all"]# Monitor specific containerscontainers:
- "nginx"
- "postgres-primary"
- "redis"# Monitor by pattern (use "all" and filter in alerts)containers: ["all"]filter_keywords: ["error", "fatal"]

Keyword Selection by Stack:

Node.js/JavaScript:

filter_keywords:
- "error"
- "fatal"
- "uncaughtException"
- "unhandledRejection"
- "ECONNREFUSED"
- "ETIMEDOUT"

Python:

filter_keywords:
- "error"
- "fatal"
- "exception"
- "traceback"
- "critical"

Java/Spring:

filter_keywords:
- "error"
- "exception"
- "OutOfMemoryError"
- "StackOverflowError"
- "SQLException"

Go:

filter_keywords:
- "error"
- "fatal"
- "panic"
- "deadlock"

Database (Postgres/MySQL):

filter_keywords:
- "error"
- "fatal"
- "panic"
- "deadlock"
- "connection refused"

Alert Condition Examples:

condition: "keyword == fatal"# Only fatal errorscondition: "keyword == panic"# Only panicscondition: "keyword == OOM"# Only out of memory

Performance Tips:

# Frequent checks (every minute)tail_lines: 50schedule: "*/1 * * * *"# Balanced (every 2 minutes)tail_lines: 100schedule: "*/2 * * * *"# Less frequent but thorough (every 5 minutes)tail_lines: 500schedule: "*/5 * * * *"

6. Webhooks

Baadal supports multiple webhook destinations for alerts. Each webhook can have custom templates.

Discord Webhook

webhooks:
- name: "discord"enabled: trueurl: "https://discord.com/api/webhooks/YOUR_WEBHOOK_ID/YOUR_WEBHOOK_TOKEN"method: POSTheaders:
Content-Type: "application/json"payload_template: | { "content": "🚨 {{.Title}}", "embeds": [{ "description": "{{.Message}}", "fields": [ {"name": "Host", "value": "{{.Hostname}}", "inline": true}, {"name": "Type", "value": "{{.Type}}", "inline": true}, {"name": "Severity", "value": "{{.Severity}}", "inline": true}, {"name": "Time", "value": "{{.Timestamp}}", "inline": true} ], "color": 16711680 }] }

How to Get Discord Webhook URL:

  1. Open Discord server → Server Settings → Integrations
  2. Click "Webhooks" → "New Webhook"
  3. Choose channel, copy webhook URL
  4. Paste in config.yml

Discord Color Codes:

"color": 16711680# Red (critical)"color": 16776960# Yellow (warning)"color": 65280# Green (info)"color": 3447003# Blue (info)

Slack Webhook

 - name: "slack"enabled: trueurl: "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK"method: POSTheaders:
Content-Type: "application/json"payload_template: | { "text": "🚨 *{{.Title}}*", "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": "*{{.Title}}*\n{{.Message}}" } }, { "type": "section", "fields": [ {"type": "mrkdwn", "text": "*Host:*\n{{.Hostname}}"}, {"type": "mrkdwn", "text": "*Type:*\n{{.Type}}"}, {"type": "mrkdwn", "text": "*Severity:*\n{{.Severity}}"}, {"type": "mrkdwn", "text": "*Time:*\n{{.Timestamp}}"} ] } ] }

How to Get Slack Webhook URL:

  1. Visit https://api.slack.com/apps
  2. Create New App → "From scratch"
  3. Enable "Incoming Webhooks"
  4. Add New Webhook to Workspace
  5. Copy webhook URL

Custom API Webhook

 - name: "custom-api"enabled: trueurl: "https://your-api.com/alerts"method: POSTheaders:
Authorization: "Bearer YOUR_API_TOKEN"Content-Type: "application/json"X-Custom-Header: "baadal-alerts"payload_template: | { "alert": "{{.Title}}", "host": "{{.Hostname}}", "timestamp": "{{.Timestamp}}", "type": "{{.Type}}", "severity": "{{.Severity}}", "message": "{{.Message}}", "data": {{.Data}} }

PagerDuty Webhook

 - name: "pagerduty"enabled: trueurl: "https://events.pagerduty.com/v2/enqueue"method: POSTheaders:
Content-Type: "application/json"payload_template: | { "routing_key": "YOUR_INTEGRATION_KEY", "event_action": "trigger", "payload": { "summary": "{{.Title}}", "severity": "critical", "source": "{{.Hostname}}", "custom_details": { "message": "{{.Message}}", "type": "{{.Type}}", "timestamp": "{{.Timestamp}}" } } }

Email via SendGrid/Mailgun

 - name: "email"enabled: trueurl: "https://api.sendgrid.com/v3/mail/send"method: POSTheaders:
Authorization: "Bearer YOUR_SENDGRID_API_KEY"Content-Type: "application/json"payload_template: | { "personalizations": [{ "to": [{"email": "alerts@example.com"}] }], "from": {"email": "baadal@example.com"}, "subject": "{{.Title}}", "content": [{ "type": "text/plain", "value": "{{.Message}}\n\nHost: {{.Hostname}}\nTime: {{.Timestamp}}" }] }

Template Variables:

  • {{.Title}} - Alert title
  • {{.Message}} - Alert message
  • {{.Hostname}} - Source hostname
  • {{.Host}} - Same as Hostname
  • {{.Timestamp}} - ISO8601 timestamp (IST timezone)
  • {{.Type}} - Event type (disk_usage, dmesg, docker_log, etc.)
  • {{.Severity}} - Alert severity (critical, warning, info)
  • {{.Data}} - Raw JSON event data

7. Receiver Configuration

The receiver runs on your central monitoring server and accepts events from all collectors.

receiver:
enabled: true # Enable receiver modeport: 5170# Port to listen onauth:
enabled: false # Enable authenticationtoken: "your-secret-token"# Must match collector tokens# IMPORTANT: Enable in production!log_output: "/var/log/baadal/events.log"# Where to write eventslog_rotation: # Automatic log rotation (via lumberjack)max_size_mb: 50# Rotate after 50 MBmax_backups: 3# Keep 3 old log filesmax_age_days: 7# Delete logs older than 7 dayscompress: true # Gzip old log filesdead_mans_switch: # Detect missing collectorsenabled: truetimeout_minutes: 10# Alert if no events for 10 minutescheck_interval: "*/2 * * * *"# Check every 2 minuteswebhooks:
- discordpromtail: # Optional: Forward to Lokienabled: falseendpoint: "http://localhost:9080/loki/api/v1/push"

Log Rotation Examples:

High-frequency monitoring (lots of events):

log_rotation:
max_size_mb: 100# Larger filesmax_backups: 7# Keep more historymax_age_days: 14# 2 weeks retentioncompress: true

Low-frequency monitoring:

log_rotation:
max_size_mb: 20# Smaller filesmax_backups: 3# Less historymax_age_days: 7# 1 week retentioncompress: true

Dead Man's Switch:

  • Monitors when each collector last sent events
  • Fires webhook alert if collector goes silent
  • Helps detect crashed collectors or network issues

Dead Man's Switch Examples:

# Tight monitoring (5 min timeout)timeout_minutes: 5check_interval: "*/1 * * * *"# Relaxed monitoring (30 min timeout)timeout_minutes: 30check_interval: "*/10 * * * *"# Daily check (for non-critical servers)timeout_minutes: 1440# 24 hourscheck_interval: "0 * * * *"# Hourly check

Authentication:

# Development (no auth)auth:
enabled: false# Production (required!)auth:
enabled: truetoken: "use-a-long-random-string-here"# Generate token: openssl rand -base64 32

8. Node Identity

Configure how this server identifies itself in events:

node:
hostname: ""# Empty = auto-detect from OS# Or set manually: "web-server-01"environment: "production"# Environment label# Options: production, staging, dev, testtags: # Custom tags for filtering/grouping
- "ubuntu"
- "backend"
- "api-server"
- "us-east-1"

Hostname Examples:

hostname: ""# Auto-detect (recommended)hostname: "web-server-01"# Manual overridehostname: "db-primary"# For databaseshostname: "worker-03"# For worker nodes

Environment Best Practices:

environment: "production"# Live production serversenvironment: "staging"# Staging/QA environmentenvironment: "development"# Dev serversenvironment: "test"# CI/CD test runners

Tag Examples:

By Role:

tags: ["web-server", "nginx", "frontend"]tags: ["database", "postgres", "primary"]tags: ["worker", "celery", "background-jobs"]

By Location:

tags: ["aws", "us-east-1", "production"]tags: ["on-premise", "datacenter-1"]tags: ["cloud", "digitalocean", "sgp1"]

By Stack:

tags: ["nodejs", "express", "api"]tags: ["python", "django", "web"]tags: ["go", "microservice"]

🔧 Complete Configuration Example

Here's a production-ready config.yml with all features enabled:

# ─────────────────────────────────────────────# Baadal — Production Configuration# ─────────────────────────────────────────────app:
name: "baadal"enabled: truelog_level: "info"heartbeat:
enabled: trueinterval: "*/5 * * * *"deduplication:
enabled: truewindow_seconds: 60transport:
mode: "remote"remote:
endpoint: "http://100.64.1.100:5170/ingest"# Replace with your receiver IPauth:
enabled: truetoken: "your-generated-secret-token-here"# Generate: openssl rand -base64 32batch_size: 10flush_interval: "5s"retry_attempts: 3retry_delay: "2s"disk:
enabled: truepaths:
- /
- /var
- /var/lib/docker
- /home
- /opttop_n: 5max_depth: 3schedule: "*/10 * * * *"alert:
enabled: truecondition: "size_gb > 50"webhooks:
- discorddmesg:
enabled: trueschedule: "*/1 * * * *"filter_levels:
- err
- crit
- alert
- emergalert:
enabled: truecondition: "level == crit"webhooks:
- discorddocker:
enabled: truecontainers:
- "all"tail_lines: 100schedule: "*/2 * * * *"filter_keywords:
- "error"
- "fatal"
- "panic"
- "OOM"
- "killed"
- "segfault"alert:
enabled: truecondition: "keyword == fatal"webhooks:
- discordwebhooks:
- name: "discord"enabled: trueurl: "https://discord.com/api/webhooks/YOUR_WEBHOOK_ID/YOUR_TOKEN"method: POSTheaders:
Content-Type: "application/json"payload_template: | { "content": "🚨 {{.Title}}", "embeds": [{ "description": "{{.Message}}", "fields": [ {"name": "Host", "value": "{{.Hostname}}", "inline": true}, {"name": "Type", "value": "{{.Type}}", "inline": true}, {"name": "Severity", "value": "{{.Severity}}", "inline": true}, {"name": "Time", "value": "{{.Timestamp}}", "inline": true} ], "color": 16711680 }] }receiver:
enabled: false # Set to true only on receiver serverport: 5170auth:
enabled: truetoken: "your-generated-secret-token-here"# Must match collector tokenlog_output: "/var/log/baadal/events.log"log_rotation:
max_size_mb: 50max_backups: 3max_age_days: 7compress: truedead_mans_switch:
enabled: truetimeout_minutes: 10check_interval: "*/2 * * * *"webhooks:
- discordnode:
hostname: ""# Auto-detectenvironment: "production"tags:
- "ubuntu"
- "web-server"
- "backend"

🏃 Usage

Collector Mode (on monitored servers)

# Run directly
./baadal --mode=collector --config=config.yml
# Run in background
nohup ./baadal --mode=collector --config=config.yml > /dev/null 2>&1&# Check it's running
ps aux | grep baadal

Receiver Mode (on central monitoring server)

# Run directly
./baadal --mode=receiver --config=config.yml
# Run in background
nohup ./baadal --mode=receiver --config=config.yml > /dev/null 2>&1&

Systemd Installation (Recommended)

# On collector servers
sudo bash install.sh collector
# On receiver server
sudo bash install.sh receiver
# Service management
sudo systemctl start baadal
sudo systemctl enable baadal # Start on boot
sudo systemctl status baadal
sudo journalctl -u baadal -f # Follow logs# Reload configuration without restart
sudo systemctl kill -s HUP baadal
# Restart service
sudo systemctl restart baadal
# Stop service
sudo systemctl stop baadal

Configuration Hot Reload

Baadal supports reloading configuration without restart:

# If running via systemd
sudo systemctl kill -s HUP baadal
# If running manually (get PID first)
ps aux | grep baadal
kill -HUP <PID>

What gets reloaded:

  • ✅ Schedule intervals
  • ✅ Alert thresholds
  • ✅ Webhook configurations
  • ✅ Filter keywords
  • ✅ Paths to monitor
  • ❌ Mode (collector/receiver) - requires restart

🐳 Docker

Using Pre-built Image

# Pull from GitHub Container Registry
docker pull ghcr.io/YOUR_USERNAME/baadhal:latest
# Run collector
docker run -d \
--name baadal-collector \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v $(pwd)/config.yml:/app/config.yml:ro \
-e MODE=collector \
--restart unless-stopped \
ghcr.io/YOUR_USERNAME/baadhal:latest
# Run receiver
docker run -d \
--name baadal-receiver \
-p 5170:5170 \
-v $(pwd)/config.yml:/app/config.yml:ro \
-v baadal-logs:/var/log/baadal \
-e MODE=receiver \
--restart unless-stopped \
ghcr.io/YOUR_USERNAME/baadhal:latest
# View logs
docker logs -f baadal-collector
docker logs -f baadal-receiver
# Reload config
docker kill -s HUP baadal-collector

Docker Compose

version: '3.8'services:
# Receiver (central monitoring server)baadal-receiver:
image: ghcr.io/YOUR_USERNAME/baadhal:latestcontainer_name: baadal-receiverports:
- "5170:5170"volumes:
- ./config.yml:/app/config.yml:ro
- baadal-logs:/var/log/baadalenvironment:
- MODE=receiverrestart: unless-stoppedhealthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:5170/health"]interval: 30stimeout: 3sretries: 3# Collector (on same server or different server)baadal-collector:
image: ghcr.io/YOUR_USERNAME/baadhal:latestcontainer_name: baadal-collectorvolumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./config.yml:/app/config.yml:roenvironment:
- MODE=collectorrestart: unless-stoppedvolumes:
baadal-logs:

📊 Event Types

TypeDescriptionData FieldsTriggers
disk_usageDirectory size monitoringtop_dirs, scan_root, total_scanned_gbWhen scanned
dmesgKernel message monitoringlevel, message, kernel_tsOn new kernel messages
docker_logContainer log monitoringcontainer, line, matched_keywordOn keyword match
heartbeatPeriodic health signalstatus, uptime_secondsOn schedule
lifecycleStart/stop eventsevent, mode, version, uptime_secondsOn start/stop
collector_statsPerformance metricsdisk_scan_ms, events_sent, events_deduped, cycle_total_msEvery 5 min
dead_mans_switchMissing host alertN/A (webhook only)Receiver detects silence

Example Event JSON

Disk Usage Event:

{
"timestamp": "2026-03-06T18:45:00+05:30",
"type": "disk_usage",
"host": "web-server-01",
"environment": "production",
"tags": ["ubuntu", "backend"],
"data": {
"top_dirs": [
{
"path": "/var/lib/docker",
"size_gb": 45.3,
"size_mb": 46387,
"rank": 1
}
],
"scan_root": "/var",
"total_scanned_gb": 67.8
},
"alert_triggered": true,
"alert_condition": "size_gb > 20"
}

Docker Log Event:

{
"timestamp": "2026-03-06T18:50:12+05:30",
"type": "docker_log",
"host": "api-server-02",
"environment": "production",
"tags": ["nodejs", "api"],
"data": {
"container": "api-backend",
"line": "Fatal error: Cannot connect to database",
"matched_keyword": "fatal"
},
"alert_triggered": true,
"alert_condition": "keyword == fatal"
}

Heartbeat Event:

{
"timestamp": "2026-03-06T18:55:00+05:30",
"type": "heartbeat",
"host": "worker-01",
"environment": "production",
"tags": ["worker", "celery"],
"data": {
"status": "alive",
"uptime_seconds": 86400
},
"alert_triggered": false
}

🔧 Architecture

┌─────────────────────────────────────────────────────────────────┐
│ Monitored Servers │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Collector #1 │ │ Collector #2 │ │ Collector #N │ │
│ │ │ │ │ │ │ │
│ │ - Disk scan │ │ - Disk scan │ │ - Disk scan │ │
│ │ - Dmesg │ │ - Dmesg │ │ - Dmesg │ │
│ │ - Docker │ │ - Docker │ │ - Docker │ │
│ │ - Heartbeat │ │ - Heartbeat │ │ - Heartbeat │ │
│ │ - Dedup │ │ - Dedup │ │ - Dedup │ │
│ └───────┬──────┘ └───────┬──────┘ └───────┬──────┘ │
│ │ │ │ │
└──────────┼─────────────────┼──────────────────┼────────────────┘
│ │ │
│ Batched │ Batched │ Batched
│ Events │ Events │ Events
│ (HTTP/JSON) │ (HTTP/JSON) │ (HTTP/JSON)
│ │ │
└─────────────────┼──────────────────┘
│
▼
┌──────────────────────────────┐
│ Central Receiver Server │
│ │
│ - HTTP endpoint (port 5170) │
│ - Authentication │
│ - Log rotation (lumberjack) │
│ - Dead man's switch │
│ - Webhook dispatcher │
└───────────┬──────────────────┘
│
├─────────────┬──────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Discord │ │ Slack │ │ Custom │
│ Webhook │ │ Webhook │ │ API │
└──────────┘ └──────────┘ └──────────┘

Data Flow

  1. Collection: Collectors run scheduled jobs (cron)
  2. Deduplication: Events checked against recent history
  3. Batching: Events accumulated until batch_size or flush_interval
  4. Transport: HTTP POST to receiver with optional auth
  5. Logging: Receiver writes to rotated log file
  6. Alerting: Matching conditions trigger webhooks
  7. Dead Man's Switch: Receiver monitors for missing collectors

Performance Characteristics

Collector (per server):

  • CPU: < 1% average
  • Memory: ~15-20 MB
  • Disk I/O: Minimal (reads only during scans)
  • Network: < 1 KB/min average

Receiver:

  • CPU: < 1% average
  • Memory: ~20-30 MB + log buffer
  • Disk I/O: Sequential writes only
  • Network: Depends on number of collectors

🛠️ Development

Requirements

  • Go 1.24+
  • Docker (for container log monitoring)

Run Tests

go test ./...
go vet ./...
gofmt -s -l .

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing)
  3. Commit your changes (git commit -am 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing)
  5. Open a Pull Request

📝 License

MIT License - see LICENSE file for details.

🙏 Acknowledgments

Built with:

📞 Support


Made with ☁️ by the Baadal Team

About

A lightweight, self-contained observability agent for monitoring Ubuntu servers with disk usage tracking, kernel monitoring, Docker container health, and webhook-based alerting.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages