├── unified monitor ├── conf │ ├── grafana │ │ ├── dashboards │ │ │ └── container_overview.json │ │ └── datasources.yml │ ├── alertmanager.yml │ ├── rules.yml │ ├── promtail.yml │ ├── loki.yml │ └── prometheus.yml ├── app │ ├── requirements.txt │ └── main.py ├── entrypoint.sh ├── exporters │ └── generic_exporter.py └── Dockerfile ├── resource ├── logo.jpeg ├── cAdvisor.pdf ├── Prometheus.png └── thumbnail-cAdvisor.png ├── .github └── workflows │ ├── docker-image.yml │ └── docker-image-ci.yml └── README.md /unified monitor/conf/grafana/dashboards/container_overview.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resource/logo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashjani/Unified-Monitor/HEAD/resource/logo.jpeg -------------------------------------------------------------------------------- /resource/cAdvisor.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashjani/Unified-Monitor/HEAD/resource/cAdvisor.pdf -------------------------------------------------------------------------------- /resource/Prometheus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashjani/Unified-Monitor/HEAD/resource/Prometheus.png -------------------------------------------------------------------------------- /unified monitor/app/requirements.txt: -------------------------------------------------------------------------------- 1 | flask==3.0.2 2 | prometheus_client==0.20.0 3 | gunicorn==22.0.0 4 | -------------------------------------------------------------------------------- /resource/thumbnail-cAdvisor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yashjani/Unified-Monitor/HEAD/resource/thumbnail-cAdvisor.png -------------------------------------------------------------------------------- /unified monitor/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | # patch Alertmanager with runtime Slack webhook 5 | if [[ -n "$SLACK_WEBHOOK" ]]; then 6 | sed -i "s|\$SLACK_WEBHOOK|$SLACK_WEBHOOK|g" /etc/alertmanager/alertmanager.yml 7 | fi 8 | 9 | exec /init # hand over to s6-overlay 10 | -------------------------------------------------------------------------------- /unified monitor/conf/grafana/datasources.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | datasources: 3 | - name: Prometheus 4 | type: prometheus 5 | access: proxy 6 | url: http://localhost:9090 7 | isDefault: true 8 | - name: Loki 9 | type: loki 10 | access: proxy 11 | url: http://localhost:3100 12 | -------------------------------------------------------------------------------- /unified monitor/conf/alertmanager.yml: -------------------------------------------------------------------------------- 1 | route: 2 | receiver: default 3 | receivers: 4 | - name: default 5 | slack_configs: 6 | - api_url: $SLACK_WEBHOOK # injected at runtime 7 | channel: '#alerts' 8 | title: '{{ .CommonAnnotations.summary }}' 9 | text: '{{ .CommonLabels }}' 10 | -------------------------------------------------------------------------------- /unified monitor/conf/rules.yml: -------------------------------------------------------------------------------- 1 | groups: 2 | - name: latency 3 | rules: 4 | - alert: HighRequestLatency 5 | expr: histogram_quantile(0.95, sum by (le)(rate(request_latency_seconds_bucket[5m]))) > 0.75 6 | for: 2m 7 | labels: { severity: warning } 8 | annotations: 9 | summary: "P95 latency > 750 ms for 2 min" 10 | -------------------------------------------------------------------------------- /unified monitor/conf/promtail.yml: -------------------------------------------------------------------------------- 1 | server: 2 | http_listen_port: 9080 3 | grpc_listen_port: 0 4 | 5 | positions: 6 | filename: /tmp/positions.yaml 7 | 8 | clients: 9 | - url: http://localhost:3100/loki/api/v1/push 10 | 11 | scrape_configs: 12 | - job_name: varlogs 13 | static_configs: 14 | - targets: [localhost] 15 | labels: 16 | job: varlogs 17 | __path__: /var/log/*log 18 | -------------------------------------------------------------------------------- /unified monitor/conf/loki.yml: -------------------------------------------------------------------------------- 1 | auth_enabled: false 2 | server: 3 | http_listen_port: 3100 4 | grpc_listen_port: 0 5 | schema_config: 6 | configs: 7 | - from: 2020-10-24 8 | store: boltdb-shipper 9 | object_store: filesystem 10 | schema: v13 11 | index: 12 | prefix: index_ 13 | period: 24h 14 | storage_config: 15 | boltdb_shipper: 16 | active_index_directory: /loki/index 17 | shared_store: filesystem 18 | filesystem: 19 | directory: /loki/chunks 20 | -------------------------------------------------------------------------------- /.github/workflows/docker-image.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI # ← workflow name 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | 15 | - name: Build Docker image 16 | run: > 17 | docker build 18 | -f 'unified monitor/Dockerfile' 19 | -t yjani204/unified-monitoring:${{ github.sha }} 20 | 'unified monitor' 21 | -------------------------------------------------------------------------------- /unified monitor/conf/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | evaluation_interval: 15s 4 | 5 | scrape_configs: 6 | # auto-discover every running Docker container 7 | - job_name: docker 8 | docker_sd_configs: 9 | - host: unix:///var/run/docker.sock 10 | refresh_interval: 10s 11 | 12 | # scrape our demo service & exporter inside the same image 13 | - job_name: demo-stack 14 | static_configs: 15 | - targets: ['localhost:8000', 'localhost:9102'] 16 | 17 | alerting: 18 | alertmanagers: 19 | - static_configs: [{ targets: ['localhost:9093'] }] 20 | 21 | rule_files: [ '/etc/prometheus/rules.yml' ] 22 | -------------------------------------------------------------------------------- /unified monitor/exporters/generic_exporter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Simple exporter that fakes business metrics. 4 | 5 | Exposes: 6 | • items_open_total 7 | • items_avg_value_usd 8 | """ 9 | import time, random 10 | from prometheus_client import start_http_server, Gauge, Counter 11 | 12 | OPEN = Gauge("items_open_total", "Open items") 13 | AVGVAL = Gauge("items_avg_value_usd", "Average item value (USD)") 14 | ERRORS = Counter("exporter_errors_total", "Errors") 15 | 16 | def poll(): 17 | while True: 18 | try: 19 | OPEN.set(random.randint(40, 150)) 20 | AVGVAL.set(round(random.uniform(9_000, 25_000), 2)) 21 | except Exception: 22 | ERRORS.inc() 23 | time.sleep(30) 24 | 25 | if __name__ == "__main__": 26 | start_http_server(9102) 27 | poll() 28 | -------------------------------------------------------------------------------- /unified monitor/app/main.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify 2 | from prometheus_client import Counter, Histogram, generate_latest, CONTENT_TYPE_LATEST 3 | import random, time 4 | 5 | app = Flask(__name__) 6 | 7 | REQ = Counter("service_requests_total", "Requests handled", ["status"]) 8 | LAT = Histogram("request_latency_seconds", "Request latency", ["endpoint"]) 9 | 10 | @app.route("/api/v1/items", methods=["POST"]) 11 | @LAT.labels("/api/v1/items").time() 12 | def create_item(): 13 | if random.random() < 0.93: 14 | REQ.labels("success").inc() 15 | return jsonify(msg="stored"), 201 16 | REQ.labels("failed").inc() 17 | return jsonify(error="db busy"), 503 18 | 19 | @app.route("/metrics") 20 | def metrics(): 21 | return generate_latest(), 200, {"Content-Type": CONTENT_TYPE_LATEST} 22 | 23 | if __name__ == "__main__": 24 | app.run(host="0.0.0.0", port=8000) 25 | -------------------------------------------------------------------------------- /.github/workflows/docker-image-ci.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image Update 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | paths: 7 | - 'unified monitor/**' 8 | - '.github/workflows/docker-image-ci.yml' 9 | pull_request: 10 | branches: [main] 11 | paths: 12 | - 'unified monitor/**' 13 | - '.github/workflows/docker-image-ci.yml' 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | env: 19 | IMAGE_REPO: yjani204/unified-monitoring 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | 24 | # 1️⃣ Authenticate to Docker Hub 25 | - name: Log in to Docker Hub 26 | uses: docker/login-action@v3 27 | with: 28 | username: ${{ secrets.DOCKERHUB_USERNAME }} 29 | password: ${{ secrets.DOCKERHUB_TOKEN }} 30 | 31 | # 2️⃣ Build and push the image 32 | - name: Build and push image 33 | uses: docker/build-push-action@v5 34 | with: 35 | context: 'unified monitor' 36 | file: 'unified monitor/Dockerfile' 37 | push: true 38 | tags: | 39 | ${{ env.IMAGE_REPO }}:${{ github.sha }} 40 | ${{ env.IMAGE_REPO }}:latest 41 | -------------------------------------------------------------------------------- /unified monitor/Dockerfile: -------------------------------------------------------------------------------- 1 | ######################## 2 | # Builder – Python bits 3 | FROM python:3.12-slim AS builder 4 | WORKDIR /build 5 | COPY app/requirements.txt . 6 | RUN pip install --user -r requirements.txt 7 | COPY app/ /build/app 8 | COPY exporters/ /build/exporters 9 | 10 | ######################## 11 | # Final image 12 | FROM ubuntu:22.04 13 | ENV DEBIAN_FRONTEND=noninteractive 14 | # ---- system & s6-overlay ---- 15 | # RUN apt-get update && apt-get install -y curl ca-certificates && \ 16 | # curl -L https://github.com/just-containers/s6-overlay/releases/download/v3.1.5.0/s6-overlay-amd64.tar.gz \ 17 | # | tar xzf - -C / 18 | 19 | ARG S6_OVERLAY_VERSION=3.2.1.0 20 | 21 | # Install necessary packages 22 | RUN apt-get update && apt-get install -y curl xz-utils 23 | 24 | # Download and extract s6-overlay 25 | RUN curl -L -o /tmp/s6-overlay-noarch.tar.xz https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz && \ 26 | curl -L -o /tmp/s6-overlay-x86_64.tar.xz https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-x86_64.tar.xz && \ 27 | tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz && \ 28 | tar -C / -Jxpf /tmp/s6-overlay-x86_64.tar.xz 29 | 30 | 31 | # ---- install binaries ---- 32 | # Prometheus 2.53.4 (LTS) :contentReference[oaicite:0]{index=0} 33 | RUN curl -L https://github.com/prometheus/prometheus/releases/download/v2.53.4/prometheus-2.53.4.linux-amd64.tar.gz \ 34 | | tar xzf - -C /opt && mv /opt/prometheus-* /opt/prometheus 35 | # Alertmanager 0.27.0 36 | RUN curl -L https://github.com/prometheus/alertmanager/releases/download/v0.27.0/alertmanager-0.27.0.linux-amd64.tar.gz \ 37 | | tar xzf - -C /opt && mv /opt/alertmanager-* /opt/alertmanager 38 | # Grafana 12.0.0 :contentReference[oaicite:1]{index=1} 39 | RUN curl -L https://dl.grafana.com/oss/release/grafana_12.0.0_amd64.deb -o /tmp/g.deb && \ 40 | apt-get install -y /tmp/g.deb 41 | # Loki 3.3.4 :contentReference[oaicite:2]{index=2} 42 | RUN curl -L https://github.com/grafana/loki/releases/download/v3.3.4/loki-linux-amd64.zip -o /tmp/loki.zip && \ 43 | apt-get install -y unzip && unzip /tmp/loki.zip -d /opt && mv /opt/loki-linux-amd64 /opt/loki 44 | # Promtail 3.3.4 45 | RUN curl -L https://github.com/grafana/loki/releases/download/v3.3.4/promtail-linux-amd64.zip -o /tmp/promtail.zip && \ 46 | unzip /tmp/promtail.zip -d /opt && mv /opt/promtail-linux-amd64 /opt/promtail 47 | # cAdvisor v0.52.1 :contentReference[oaicite:3]{index=3} 48 | RUN curl -L https://github.com/google/cadvisor/releases/download/v0.52.1/cadvisor-v0.52.1-linux-amd64 -o /opt/cadvisor && \ 49 | chmod +x /opt/cadvisor 50 | 51 | # ---- copy python wheels & code ---- 52 | COPY --from=builder /root/.local /root/.local 53 | ENV PATH="/root/.local/bin:$PATH" 54 | COPY --from=builder /build /srv 55 | 56 | # ---- configs ---- 57 | COPY conf/prometheus.yml /etc/prometheus/ 58 | COPY conf/alertmanager.yml /etc/alertmanager/ 59 | COPY conf/loki.yml /etc/loki/ 60 | COPY conf/promtail.yml /etc/promtail/ 61 | COPY conf/grafana/ /etc/grafana/provisioning/ 62 | COPY entrypoint.sh /entrypoint.sh 63 | RUN chmod +x /entrypoint.sh 64 | 65 | # ---- s6 service definitions ---- 66 | COPY <<'EOF' /etc/services.d/api/run 67 | #!/command/execlineb -P 68 | with-contenv 69 | cd /srv/app 70 | gunicorn -b 0.0.0.0:8000 main:app 71 | EOF 72 | COPY <<'EOF' /etc/services.d/exporter/run 73 | #!/command/execlineb -P 74 | with-contenv 75 | python /srv/exporters/generic_exporter.py 76 | EOF 77 | COPY <<'EOF' /etc/services.d/prometheus/run 78 | #!/command/execlineb -P 79 | with-contenv 80 | /opt/prometheus/prometheus --config.file=/etc/prometheus/prometheus.yml 81 | EOF 82 | COPY <<'EOF' /etc/services.d/alertmanager/run 83 | #!/command/execlineb -P 84 | with-contenv 85 | /opt/alertmanager/alertmanager --config.file=/etc/alertmanager/alertmanager.yml 86 | EOF 87 | COPY <<'EOF' /etc/services.d/loki/run 88 | #!/command/execlineb -P 89 | with-contenv 90 | /opt/loki -config.file=/etc/loki/loki.yml 91 | EOF 92 | COPY <<'EOF' /etc/services.d/promtail/run 93 | #!/command/execlineb -P 94 | with-contenv 95 | /opt/promtail -config.file=/etc/promtail/promtail.yml 96 | EOF 97 | COPY <<'EOF' /etc/services.d/cadvisor/run 98 | #!/command/execlineb -P 99 | with-contenv 100 | /opt/cadvisor --docker_only --port=8080 101 | EOF 102 | COPY <<'EOF' /etc/services.d/grafana/run 103 | #!/command/execlineb -P 104 | with-contenv 105 | grafana-server -homepath /usr/share/grafana 106 | EOF 107 | 108 | RUN chmod +x /etc/services.d/*/run 109 | 110 | EXPOSE 3000 9090 9093 3100 9080 8080 8000 9102 111 | ENTRYPOINT ["/entrypoint.sh"] 112 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unified Monitor 🚀📊 2 | 3 | [](https://hub.docker.com/r/yjani204/unified-monitoring) 4 | 5 |
6 |
7 |
32 |
33 |