From 6f70c5f66b82f29c4aec0a4cc05da8a325ef1c01 Mon Sep 17 00:00:00 2001 From: cato447 Date: Sat, 21 Feb 2026 19:04:31 +0100 Subject: [PATCH] refined grafana and prometheus --- app/blueprints/slides/routes.py | 9 +- app/models.py | 119 +++-- app/utils.py | 2 + .../provisioning/dashboards/tutor-tool.json | 439 ++++++------------ prometheus/blackbox.yml | 10 - prometheus/prometheus.yml | 30 +- 6 files changed, 239 insertions(+), 370 deletions(-) diff --git a/app/blueprints/slides/routes.py b/app/blueprints/slides/routes.py index 144852e..88eaa47 100644 --- a/app/blueprints/slides/routes.py +++ b/app/blueprints/slides/routes.py @@ -1,7 +1,7 @@ from . import slides_bp from flask import current_app, abort, redirect, url_for, request, send_from_directory from app.utils import get_cached_deck_info, token_required -from app.models import Deck, db, Course +from app.models import Deck, db, Course, PageView import os import flask_login import re @@ -115,6 +115,13 @@ def serve_deck(course_folder, deck, token, path="index.html"): current_app.logger.info( f"User {token.name} accessed deck {deck_info['deck_name']}" ) + try: + pv = PageView(deck_id=deck_info["deck_id"], token_id=token.id) + db.session.add(pv) + db.session.commit() + except Exception as e: + db.session.rollback() + current_app.logger.error(f"Failed to log page view: {e}") return send_from_directory(deck_path, path) log_404("File missing within deck", deck, course_folder, path, token) diff --git a/app/models.py b/app/models.py index 0c5182a..4f2fc78 100644 --- a/app/models.py +++ b/app/models.py @@ -6,20 +6,29 @@ from typing import List, Optional import pytz from flask_sqlalchemy import SQLAlchemy from flask import current_app -from sqlalchemy import Boolean, Column, DateTime, String, TypeDecorator, ForeignKey, UniqueConstraint +from sqlalchemy import ( + Boolean, + Column, + DateTime, + String, + TypeDecorator, + ForeignKey, + UniqueConstraint, +) from sqlalchemy.orm import Mapped, mapped_column, relationship -db : SQLAlchemy = SQLAlchemy() + +db: SQLAlchemy = SQLAlchemy() deck_password = db.Table( "deck_password", Column("deck_id", db.Integer, db.ForeignKey("deck.id"), primary_key=True), - Column("password_id", db.Integer, db.ForeignKey("password.id"), primary_key=True) + Column("password_id", db.Integer, db.ForeignKey("password.id"), primary_key=True), ) deck_token = db.Table( "deck_token", Column("deck_id", db.Integer, db.ForeignKey("deck.id"), primary_key=True), - Column("token_id", db.Integer, db.ForeignKey("token.id"), primary_key=True) + Column("token_id", db.Integer, db.ForeignKey("token.id"), primary_key=True), ) @@ -38,22 +47,29 @@ class UTCDateTime(TypeDecorator): value = value.replace(tzinfo=pytz.utc) return value + class Password(db.Model): __tablename__ = "password" - id : Mapped[int] = mapped_column(primary_key=True) - value : Mapped[str] = mapped_column(String(60)) - expires_at: Mapped[Optional[datetime]] = mapped_column(UTCDateTime()) # Optional expiration + id: Mapped[int] = mapped_column(primary_key=True) + value: Mapped[str] = mapped_column(String(60)) + expires_at: Mapped[Optional[datetime]] = mapped_column( + UTCDateTime() + ) # Optional expiration - decks : Mapped[List[Deck]] = relationship("Deck", secondary=deck_password, back_populates='passwords') + decks: Mapped[List[Deck]] = relationship( + "Deck", secondary=deck_password, back_populates="passwords" + ) - def __init__(self, value: str, expires_at: datetime|None) -> None: + def __init__(self, value: str, expires_at: datetime | None) -> None: self.value = value self.expires_at = expires_at def is_expired(self) -> bool: """Check if the password is expired""" - return self.expires_at is not None and datetime.now(timezone.utc) > self.expires_at + return ( + self.expires_at is not None and datetime.now(timezone.utc) > self.expires_at + ) def __repr__(self) -> str: return f"" @@ -62,59 +78,78 @@ class Password(db.Model): class Deck(db.Model): __tablename__ = "deck" - __table_args__ = ( - UniqueConstraint('course_id', 'deck', name='_course_deck_uc'), - ) + __table_args__ = (UniqueConstraint("course_id", "deck", name="_course_deck_uc"),) - id : Mapped[int] = mapped_column(primary_key=True) - name : Mapped[str] = mapped_column(String(60), unique=True, nullable=False) - deck : Mapped[str] = mapped_column(String(60), nullable=False) - description : Mapped[str] = mapped_column(String(60)) + id: Mapped[int] = mapped_column(primary_key=True) + name: Mapped[str] = mapped_column(String(60), unique=True, nullable=False) + deck: Mapped[str] = mapped_column(String(60), nullable=False) + description: Mapped[str] = mapped_column(String(60)) index_file: Mapped[str] = mapped_column(String(40), nullable=False) export_file: Mapped[Optional[str]] = mapped_column(String(40), nullable=True) - passwords : Mapped[List[Password]] = relationship("Password", secondary=deck_password, back_populates='decks') - tokens : Mapped[List[Token]] = relationship("Token", secondary=deck_token, back_populates='decks') + passwords: Mapped[List[Password]] = relationship( + "Password", secondary=deck_password, back_populates="decks" + ) + tokens: Mapped[List[Token]] = relationship( + "Token", secondary=deck_token, back_populates="decks" + ) course_id: Mapped[int] = mapped_column(ForeignKey("course.id")) - course: Mapped['Course'] = relationship("Course", back_populates='decks') + course: Mapped["Course"] = relationship("Course", back_populates="decks") - - def __init__(self, name: str, deck: str, course: Course, description: str = "", index_file: str = "index.html", export_file: str | None = None) -> None: + def __init__( + self, + name: str, + deck: str, + course: Course, + description: str = "", + index_file: str = "index.html", + export_file: str | None = None, + ) -> None: self.name = name self.deck = deck self.description = description self.course = course self.index_file = index_file if export_file: - self.export_file = export_file + self.export_file = export_file def __repr__(self) -> str: return f"" + class Token(db.Model): __tablename__ = "token" - id : Mapped[int] = mapped_column(primary_key=True) + id: Mapped[int] = mapped_column(primary_key=True) name: Mapped[str] = mapped_column(String(60), unique=True, nullable=False) - active_course_id: Mapped[int] = mapped_column(ForeignKey("course.id"), nullable=True) - active_course: Mapped[Course] = relationship("Course", foreign_keys=[active_course_id]) - decks : Mapped[List[Deck]]= relationship("Deck", secondary=deck_token, back_populates='tokens') + created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False) + active_course_id: Mapped[int] = mapped_column( + ForeignKey("course.id"), nullable=True + ) + active_course: Mapped[Course] = relationship( + "Course", foreign_keys=[active_course_id] + ) + decks: Mapped[List[Deck]] = relationship( + "Deck", secondary=deck_token, back_populates="tokens" + ) def __init__(self, name: str) -> None: self.name = name + self.created_at = datetime.now(timezone.utc) self.active_course_id = current_app.config["DEFAULT_COURSE"] def __repr__(self) -> str: return f"" - def is_unlocked(self, deck: str) -> bool : + def is_unlocked(self, deck: str) -> bool: return deck in [deck.deck for deck in self.decks] + class Course(db.Model): __tablename__ = "course" - id : Mapped[int] = mapped_column(primary_key=True) + id: Mapped[int] = mapped_column(primary_key=True) folder: Mapped[str] = mapped_column(String(20), unique=True, nullable=False) name: Mapped[str] = mapped_column(String(60), unique=True, nullable=False) - decks: Mapped[List['Deck']] = relationship(back_populates='course') + decks: Mapped[List["Deck"]] = relationship(back_populates="course") def __init__(self, name: str, folder: str) -> None: self.name = name @@ -126,11 +161,27 @@ class Course(db.Model): class InfoBanner(db.Model): __tablename__ = "info_banner" - id : Mapped[int] = mapped_column(primary_key=True) - content : Mapped[str] = mapped_column(String(280)) - is_active : Mapped[bool] = mapped_column(Boolean) + id: Mapped[int] = mapped_column(primary_key=True) + content: Mapped[str] = mapped_column(String(280)) + is_active: Mapped[bool] = mapped_column(Boolean) - def __init__(self, content : str) -> None: + def __init__(self, content: str) -> None: self.content = content self.is_active = False + +class PageView(db.Model): + __tablename__ = "page_view" + + id: Mapped[int] = mapped_column(primary_key=True) + deck_id: Mapped[int] = mapped_column(ForeignKey("deck.id"), nullable=False) + token_id: Mapped[int] = mapped_column(ForeignKey("token.id"), nullable=False) + viewed_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False) + + deck: Mapped["Deck"] = relationship("Deck") + token: Mapped["Token"] = relationship("Token") + + def __init__(self, deck_id: int, token_id: int) -> None: + self.deck_id = deck_id + self.token_id = token_id + self.viewed_at = datetime.now(timezone.utc) diff --git a/app/utils.py b/app/utils.py index 19a41bb..d4ecbe4 100644 --- a/app/utils.py +++ b/app/utils.py @@ -15,6 +15,7 @@ from .models import Deck, InfoBanner, Token, db, Course logger = logging.getLogger(__name__) + def init_password_generator(): wordfile = xkcd_password.locate_wordfile() global words @@ -225,6 +226,7 @@ def get_cached_deck_info(token_id, course_folder, deck_slug): "auth": is_unlocked, "course_exists": True, "deck_exists": True, + "deck_id": deck_obj.id, "deck_name": deck_obj.name, "index_file": deck_obj.index_file } diff --git a/grafana/provisioning/dashboards/tutor-tool.json b/grafana/provisioning/dashboards/tutor-tool.json index 4cb9403..cd12ea6 100644 --- a/grafana/provisioning/dashboards/tutor-tool.json +++ b/grafana/provisioning/dashboards/tutor-tool.json @@ -20,6 +20,22 @@ "graphTooltip": 0, "id": 1, "links": [], + "templating": { + "list": [ + { + "name": "course_id", + "type": "query", + "datasource": "PostgreSQL", + "query": "SELECT id AS __value, name AS __text FROM course ORDER BY name", + "refresh": 2, + "multi": false, + "includeAll": true, + "allValue": null, + "hide": 0, + "label": "Course" + } + ] + }, "panels": [ { "datasource": "Prometheus", @@ -68,7 +84,6 @@ "graphMode": "area", "justifyMode": "auto", "orientation": "auto", - "percentChangeColorMode": "standard", "reduceOptions": { "calcs": [ "lastNotNull" @@ -76,183 +91,21 @@ "fields": "", "values": false }, - "showPercentChange": false, "textMode": "auto", "wideLayout": true }, "pluginVersion": "12.3.3", "targets": [ - { - "datasource": "Prometheus", - "expr": "probe_success{job=\"blackbox_http\"}", - "legendFormat": "{{ instance }}", - "refId": "A" - }, { "datasource": "Prometheus", "expr": "probe_success{job=\"blackbox_tcp\"}", "legendFormat": "{{ instance }}", - "refId": "B" + "refId": "A" } ], "title": "Service Health", "type": "stat" }, - { - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "ms" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 4 - }, - "id": 2, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.3.3", - "targets": [ - { - "datasource": "Prometheus", - "expr": "probe_duration_seconds{job=\"blackbox_http\"} * 1000", - "legendFormat": "{{ instance }}", - "refId": "A" - } - ], - "title": "HTTP Response Time (ms)", - "type": "timeseries" - }, - { - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "mappings": [], - "max": 100, - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": 0 - }, - { - "color": "yellow", - "value": 95 - }, - { - "color": "green", - "value": 99 - } - ] - }, - "unit": "percent" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 4 - }, - "id": 3, - "options": { - "colorMode": "background", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "percentChangeColorMode": "standard", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showPercentChange": false, - "textMode": "auto", - "wideLayout": true - }, - "pluginVersion": "12.3.3", - "targets": [ - { - "datasource": "Prometheus", - "expr": "avg_over_time(probe_success{job=\"blackbox_http\", instance=\"http://tutortool:5000/grafana/health\"}[24h]) * 100", - "legendFormat": "Flask App", - "refId": "A" - } - ], - "title": "Uptime % (24h)", - "type": "stat" - }, { "datasource": "PostgreSQL", "fieldConfig": { @@ -264,10 +117,6 @@ { "color": "green", "value": 0 - }, - { - "color": "red", - "value": 80 } ] } @@ -286,7 +135,6 @@ "graphMode": "area", "justifyMode": "auto", "orientation": "auto", - "percentChangeColorMode": "standard", "reduceOptions": { "calcs": [ "lastNotNull" @@ -294,7 +142,6 @@ "fields": "", "values": false }, - "showPercentChange": false, "textMode": "auto", "wideLayout": true }, @@ -321,10 +168,6 @@ { "color": "green", "value": 0 - }, - { - "color": "red", - "value": 80 } ] } @@ -343,7 +186,6 @@ "graphMode": "area", "justifyMode": "auto", "orientation": "auto", - "percentChangeColorMode": "standard", "reduceOptions": { "calcs": [ "lastNotNull" @@ -351,7 +193,6 @@ "fields": "", "values": false }, - "showPercentChange": false, "textMode": "auto", "wideLayout": true }, @@ -378,10 +219,6 @@ { "color": "green", "value": 0 - }, - { - "color": "red", - "value": 80 } ] } @@ -400,7 +237,6 @@ "graphMode": "area", "justifyMode": "auto", "orientation": "auto", - "percentChangeColorMode": "standard", "reduceOptions": { "calcs": [ "lastNotNull" @@ -408,7 +244,6 @@ "fields": "", "values": false }, - "showPercentChange": false, "textMode": "auto", "wideLayout": true }, @@ -456,7 +291,6 @@ "graphMode": "area", "justifyMode": "auto", "orientation": "auto", - "percentChangeColorMode": "standard", "reduceOptions": { "calcs": [ "lastNotNull" @@ -464,7 +298,6 @@ "fields": "", "values": true }, - "showPercentChange": false, "textMode": "auto", "wideLayout": true }, @@ -480,93 +313,6 @@ "title": "Users per Active Course", "type": "stat" }, - { - "datasource": "PostgreSQL", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "fillOpacity": 80, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineWidth": 1, - "scaleDistribution": { - "type": "linear" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [] - }, - "gridPos": { - "h": 10, - "w": 24, - "x": 0, - "y": 16 - }, - "id": 8, - "options": { - "barRadius": 0, - "barWidth": 0.7, - "fullHighlight": false, - "groupWidth": 0.7, - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "right", - "showLegend": true - }, - "orientation": "horizontal", - "showValue": "never", - "stacking": "none", - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - }, - "xTickLabelRotation": 0, - "xTickLabelSpacing": 0 - }, - "pluginVersion": "12.3.3", - "targets": [ - { - "datasource": "PostgreSQL", - "format": "table", - "rawSql": "SELECT d.name AS \"Deck\", COUNT(dt.token_id) AS \"Users\" FROM deck d JOIN course c ON d.course_id = c.id LEFT JOIN deck_token dt ON d.id = dt.deck_id WHERE c.name = 'GRNVS Tutorium SS 25' GROUP BY d.name ORDER BY regexp_replace(d.name, '\\D', '', 'g')::integer ASC NULLS LAST", - "refId": "A" - } - ], - "title": "Users with Access per Deck — GRNVS Tutorium SS 25", - "type": "barchart" - }, { "datasource": "PostgreSQL", "fieldConfig": { @@ -602,10 +348,6 @@ { "color": "green", "value": 0 - }, - { - "color": "red", - "value": 80 } ] } @@ -616,9 +358,12 @@ "h": 10, "w": 24, "x": 0, - "y": 26 + "y": 16 }, - "id": 9, + "id": 8, + "repeat": "course_id", + "repeatDirection": "v", + "maxPerRow": 1, "options": { "barRadius": 0, "barWidth": 0.7, @@ -640,46 +385,148 @@ }, "xTickLabelRotation": 0, "xTickLabelSpacing": 0 - }, - "orientation": "horizontal", - "showValue": "auto", - "stacking": "none", - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - }, - "xField": "Deck", - "xTickLabelRotation": 0, - "xTickLabelSpacing": 0 }, "pluginVersion": "12.3.3", "targets": [ { "datasource": "PostgreSQL", "format": "table", - "rawSql": "SELECT d.name AS \"Deck\", COUNT(dt.token_id) AS \"Users\" FROM deck d JOIN course c ON d.course_id = c.id LEFT JOIN deck_token dt ON d.id = dt.deck_id WHERE c.name = 'IT-Sec Tutorium WS 25/26' GROUP BY d.name ORDER BY regexp_replace(d.name, '\\D', '', 'g')::integer ASC NULLS LAST", + "rawSql": "SELECT d.name AS \"Deck\", COUNT(dt.token_id) AS \"Users\" FROM deck d JOIN course c ON d.course_id = c.id LEFT JOIN deck_token dt ON d.id = dt.deck_id WHERE c.id = ${course_id} GROUP BY d.name ORDER BY regexp_replace(d.name, '\\D', '', 'g')::integer ASC NULLS LAST", "refId": "A" } ], - "title": "Users with Access per Deck — IT-Sec Tutorium WS 25/26", + "title": "Users with Access per Deck \u2014 $course_id", "type": "barchart" + }, + { + "datasource": "PostgreSQL", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Views", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 100 + }, + "id": 10, + "repeat": "course_id", + "repeatDirection": "v", + "maxPerRow": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.3.3", + "targets": [ + { + "datasource": "PostgreSQL", + "format": "time_series", + "rawSql": "SELECT date_trunc('hour', pv.viewed_at) AS time, d.name AS metric, COUNT(*) AS value FROM page_view pv JOIN deck d ON pv.deck_id = d.id JOIN course c ON d.course_id = c.id WHERE c.id = ${course_id} AND $__timeFilter(pv.viewed_at) GROUP BY 1, 2 ORDER BY 1", + "refId": "A" + } + ], + "title": "Deck Views Over Time \u2014 $course_id", + "type": "timeseries" + }, + { + "id": 11, + "title": "User Registrations Over Time", + "type": "timeseries", + "gridPos": { "h": 10, "w": 24, "x": 0, "y": 300 }, + "datasource": "PostgreSQL", + "options": { + "legend": { "displayMode": "list", "placement": "bottom", "showLegend": false }, + "tooltip": { "mode": "single", "sort": "none" } + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "bars", + "fillOpacity": 80, + "lineWidth": 1, + "showPoints": "never" + } + }, + "overrides": [] + }, + "targets": [ + { + "datasource": "PostgreSQL", + "format": "time_series", + "rawSql": "SELECT date_trunc('day', created_at) AS time, COUNT(*) AS value FROM token WHERE $__timeFilter(created_at) GROUP BY 1 ORDER BY 1", + "refId": "A" + } + ] } ], "preload": false, "refresh": "1m", "schemaVersion": 42, "tags": [], - "templating": { - "list": [] - }, "time": { - "from": "now-6h", + "from": "now-7d", "to": "now" }, "timepicker": {}, "timezone": "", "title": "Tutor Tool", "uid": "tutor-tool", - "version": 3 + "version": 5 } diff --git a/prometheus/blackbox.yml b/prometheus/blackbox.yml index 7f2c875..69ca1f5 100644 --- a/prometheus/blackbox.yml +++ b/prometheus/blackbox.yml @@ -1,14 +1,4 @@ modules: - http_2xx: - prober: http - timeout: 5s - http: - valid_http_versions: ["HTTP/1.1", "HTTP/2.0"] - valid_status_codes: [200] - method: GET - fail_if_ssl: false - fail_if_not_ssl: false - tcp_connect: prober: tcp timeout: 5s diff --git a/prometheus/prometheus.yml b/prometheus/prometheus.yml index 7219553..91e83a0 100644 --- a/prometheus/prometheus.yml +++ b/prometheus/prometheus.yml @@ -3,25 +3,6 @@ global: evaluation_interval: 30s scrape_configs: - - # --- Health checks via Blackbox Exporter --- - - job_name: 'blackbox_http' - metrics_path: /probe - params: - module: [http_2xx] - static_configs: - - targets: - - http://tutortool:5000/grafana/health - - http://tutortool:5000/ - relabel_configs: - - source_labels: [__address__] - target_label: __param_target - - source_labels: [__param_target] - target_label: instance - - target_label: __address__ - replacement: blackbox-exporter:9115 - - # --- TCP check for Postgres --- - job_name: 'blackbox_tcp' metrics_path: /probe params: @@ -30,6 +11,7 @@ scrape_configs: - targets: - db:5432 - redis:6379 + - tutortool:5000 relabel_configs: - source_labels: [__address__] target_label: __param_target @@ -37,13 +19,3 @@ scrape_configs: target_label: instance - target_label: __address__ replacement: blackbox-exporter:9115 - - # --- Blackbox exporter itself --- - - job_name: 'blackbox_exporter' - static_configs: - - targets: ['blackbox-exporter:9115'] - - # --- Prometheus itself --- - - job_name: 'prometheus' - static_configs: - - targets: ['localhost:9090']