├── dev ├── .env.example ├── README.md └── docker-compose.yml ├── dev-postgres ├── .env.example ├── README.md └── docker-compose.yml ├── .gitignore ├── config ├── dev.env ├── dev-sqlite.env ├── nginx.conf ├── Caddyfile.example ├── anubis-rules.yml └── prod.env ├── grafana ├── provisioning │ ├── datasources │ │ ├── loki.yaml │ │ ├── prometheus.yaml │ │ └── postgres.yaml │ └── dashboards │ │ └── dashboards.yml ├── web.yml ├── README.md ├── gen-pass.py ├── prometheus.yml ├── loki-config.yaml ├── docker-compose.yml ├── alloy-config.river ├── wger.rules └── dashboards │ ├── docker_daemon_metrics.json │ ├── django.json │ └── caddy.json ├── .github ├── pull_request_template.md └── contributing.md ├── AUTHORS.md ├── README.md ├── docker-compose.override.example.yml ├── docker-compose.yml └── LICENSE /dev/.env.example: -------------------------------------------------------------------------------- 1 | # Copy to .env 2 | 3 | WGER_CODEPATH=/path/to/wger/server -------------------------------------------------------------------------------- /dev-postgres/.env.example: -------------------------------------------------------------------------------- 1 | # Copy to .env 2 | 3 | WGER_CODEPATH=/path/to/wger/server -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /config/Caddyfile 2 | /docker-compose.override.yml 3 | /dev-postgres/.env 4 | /dev/.env -------------------------------------------------------------------------------- /dev/README.md: -------------------------------------------------------------------------------- 1 | # Dev environment for wger 2 | 3 | Please consult for details -------------------------------------------------------------------------------- /dev-postgres/README.md: -------------------------------------------------------------------------------- 1 | # Dev environment for wger 2 | 3 | Please consult for details -------------------------------------------------------------------------------- /config/dev.env: -------------------------------------------------------------------------------- 1 | DJANGO_DEBUG=True 2 | WGER_USE_GUNICORN=False 3 | EXERCISE_CACHE_TTL=30 4 | SYNC_EXERCISES_ON_STARTUP=False 5 | AXES_ENABLED=False 6 | -------------------------------------------------------------------------------- /grafana/provisioning/datasources/loki.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | datasources: 4 | - name: Loki 5 | type: loki 6 | access: proxy 7 | url: http://loki:3100 8 | isDefault: false -------------------------------------------------------------------------------- /grafana/web.yml: -------------------------------------------------------------------------------- 1 | # Check gen-pass.py to generate a different password 2 | # user: admin 3 | # password: adminadmin 4 | basic_auth_users: 5 | admin: $2b$12$SBshyt4Rw6HD1t4lDfE8geSlbWyTcAPKaGzGk4pM6VszCkNJy7e8G 6 | -------------------------------------------------------------------------------- /config/dev-sqlite.env: -------------------------------------------------------------------------------- 1 | # Note: this is the path *within* the docker container 2 | DJANGO_DB_ENGINE=django.db.backends.sqlite3 3 | DJANGO_DB_DATABASE=/home/wger/src/database.sqlite 4 | 5 | CELERY_WORKER_CONCURRENCY=1 6 | -------------------------------------------------------------------------------- /grafana/provisioning/dashboards/dashboards.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | providers: 4 | - name: "default" 5 | folder: "" 6 | type: file 7 | options: 8 | path: "/var/lib/grafana/dashboards" 9 | updateIntervalSeconds: 10 -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Proposed Changes 2 | 3 | - 4 | - 5 | 6 | ## Related Issue(s) 7 | 8 | If applicable, please link to any related issues (`Closes #123`, 9 | `Closes wger-project/other-repo#123`, `See also #123`, etc.) 10 | -------------------------------------------------------------------------------- /grafana/README.md: -------------------------------------------------------------------------------- 1 | # Monitoring with grafana 2 | 3 | This folder contains a pre-configured grafana instance. Basically just 4 | start the docker compose file. 5 | 6 | Please consult the documentation at https://wger.readthedocs.io/en/latest/production/docker.html#monitoring-with-grafana 7 | -------------------------------------------------------------------------------- /grafana/provisioning/datasources/prometheus.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | datasources: 4 | - name: Prometheus 5 | type: prometheus 6 | access: proxy 7 | url: http://prometheus:9090 8 | isDefault: true 9 | basicAuth: true 10 | basicAuthUser: "admin" 11 | secureJsonData: 12 | basicAuthPassword: "adminadmin" 13 | jsonData: 14 | timeInterval: "5s" 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /grafana/provisioning/datasources/postgres.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | datasources: 4 | - name: PostgreSQL 5 | type: postgres 6 | access: proxy 7 | url: postgres:5432 8 | isDefault: false 9 | jsonData: 10 | database: wger 11 | user: wger 12 | sslmode: disable 13 | postgresVersion: 1500 # 1500 = 15.x 14 | timescaledb: false 15 | secureJsonData: 16 | password: wger -------------------------------------------------------------------------------- /grafana/gen-pass.py: -------------------------------------------------------------------------------- 1 | # /// script 2 | # requires-python = ">=3.12" 3 | # dependencies = [ 4 | # "bcrypt", 5 | # ] 6 | # /// 7 | 8 | # 9 | # Run "uv run gen-pass.py" to generate a bcrypt password hash 10 | # 11 | 12 | import getpass 13 | import bcrypt 14 | 15 | password = getpass.getpass("password: ") 16 | hashed_password = bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt()) 17 | print(hashed_password.decode()) 18 | 19 | -------------------------------------------------------------------------------- /config/nginx.conf: -------------------------------------------------------------------------------- 1 | upstream wger { 2 | server web:8000; 3 | } 4 | 5 | server { 6 | 7 | listen 80; 8 | 9 | location / { 10 | proxy_pass http://wger; 11 | proxy_set_header Host $http_host; 12 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 13 | proxy_set_header X-Forwarded-Proto $scheme; 14 | proxy_set_header X-Forwarded-Host $http_host; 15 | proxy_redirect off; 16 | } 17 | 18 | location /static/ { 19 | alias /wger/static/; 20 | } 21 | 22 | location /media/ { 23 | alias /wger/media/; 24 | } 25 | 26 | # Increase max body size to allow for video uploads 27 | client_max_body_size 100M; 28 | } -------------------------------------------------------------------------------- /grafana/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 10s 3 | evaluation_interval: 10s 4 | 5 | external_labels: 6 | monitor: django-monitor 7 | 8 | rule_files: 9 | - 'wger.rules' 10 | 11 | scrape_configs: 12 | - job_name: caddy 13 | metrics_path: /metrics 14 | static_configs: 15 | - targets: [ 'caddy:2019' ] 16 | 17 | - job_name: django 18 | metrics_path: /prometheus/metrics 19 | static_configs: 20 | - targets: ['web:8000'] 21 | 22 | - job_name: 'node-exporter' 23 | 24 | # Override the global default and scrape targets from this job every 5 seconds. 25 | scrape_interval: 15s 26 | 27 | static_configs: 28 | - targets: ['node_exporter:9100'] 29 | 30 | - job_name: docker 31 | static_configs: 32 | - targets: ["host.docker.internal:9323"] 33 | -------------------------------------------------------------------------------- /.github/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to wger 2 | 3 | 🎉 Thanks for showing interest in contributing! 🎉 4 | 5 | We have centralized the documentation for contributing to wger in the online 6 | docs, especially for non-code contributions such as documentation, translations, 7 | etc.: 8 | 9 | 10 | 11 | ## Questions 12 | 13 | Are you just using the software and have a question or improvement? Let us know! 14 | 15 | * Discord: 16 | * Mastodon: 17 | 18 | ## Issues 19 | 20 | If you run into a bug describe the problem as well as you can. 21 | 22 | - Steps and any useful information to reproduce the issue 23 | - Environment details (app type: web / mobile, installation method, OS, etc.) 24 | - Any changes you may have done, either to the compose file or the configuration 25 | - Any logs if applicable 26 | - Git SHAs of this checkout, docker images, etc. -------------------------------------------------------------------------------- /dev/docker-compose.yml: -------------------------------------------------------------------------------- 1 | name: wger-dev 2 | 3 | services: 4 | web: 5 | build: 6 | pull: true 7 | context: ${WGER_CODEPATH:?set the absolute path to the wger backend code in the .env file or env variable} 8 | dockerfile: ./extras/docker/development/Dockerfile 9 | develop: 10 | watch: 11 | - action: sync 12 | path: ${WGER_CODEPATH} 13 | target: /home/wger/src 14 | - action: rebuild 15 | path: ${WGER_CODEPATH}/pyproject.toml 16 | - action: rebuild 17 | path: ${WGER_CODEPATH}/package.json 18 | env_file: 19 | - ../config/prod.env 20 | - ../config/dev.env 21 | - ../config/dev-sqlite.env 22 | ports: 23 | - "8000:8000" 24 | 25 | command: tail -f /dev/null 26 | 27 | cache: 28 | image: redis 29 | expose: 30 | - 6379 31 | healthcheck: 32 | test: redis-cli ping 33 | interval: 10s 34 | timeout: 5s 35 | retries: 5 36 | start_period: 30s 37 | restart: unless-stopped 38 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | # Contributors and translators to this repository 2 | 3 | Thank you all for contributing to the project, you are true heroes! 🫶 4 | 5 | ## Contributors 6 | 7 | - Roland Geider - [https://github.com/rolandgeider](https://github.com/rolandgeider) 8 | - Peter Dave Hello - [https://github.com/PeterDaveHello](https://github.com/PeterDaveHello) 9 | - James - [https://github.com/jagg2](https://github.com/jagg2) 10 | - Taylor Fuller - [https://github.com/taylor-fuller](https://github.com/taylor-fuller) 11 | - Dieter Plaetinck - [https://github.com/Dieterbe](https://github.com/Dieterbe) 12 | - goodnewz - [https://github.com/goodnewz](https://github.com/goodnewz) 13 | - Mohammad Rafigh - [https://github.com/mohammadrafigh](https://github.com/mohammadrafigh) 14 | - AlexAsh - [https://github.com/AlexAshs](https://github.com/AlexAshs) 15 | - kuseler - [https://github.com/kuseler](https://github.com/kuseler) 16 | - Allan Nordhøy - [https://github.com/comradekingu](https://github.com/comradekingu) 17 | 18 | ## Translators 19 | 20 | No translators found. 21 | -------------------------------------------------------------------------------- /grafana/loki-config.yaml: -------------------------------------------------------------------------------- 1 | auth_enabled: false 2 | 3 | server: 4 | http_listen_port: 3100 5 | grpc_listen_port: 9096 6 | log_level: info 7 | grpc_server_max_concurrent_streams: 1000 8 | 9 | common: 10 | instance_addr: 127.0.0.1 11 | path_prefix: /tmp/loki 12 | storage: 13 | filesystem: 14 | chunks_directory: /tmp/loki/chunks 15 | rules_directory: /tmp/loki/rules 16 | replication_factor: 1 17 | ring: 18 | kvstore: 19 | store: inmemory 20 | 21 | query_range: 22 | results_cache: 23 | cache: 24 | embedded_cache: 25 | enabled: true 26 | max_size_mb: 100 27 | 28 | limits_config: 29 | metric_aggregation_enabled: true 30 | retention_period: 720h # prune logs after 30 days 31 | 32 | schema_config: 33 | configs: 34 | - from: 2020-10-24 35 | store: tsdb 36 | object_store: filesystem 37 | schema: v13 38 | index: 39 | prefix: index_ 40 | period: 24h 41 | 42 | pattern_ingester: 43 | enabled: true 44 | metric_aggregation: 45 | loki_address: loki:3100 46 | 47 | 48 | frontend: 49 | encoding: protobuf 50 | 51 | analytics: 52 | reporting_enabled: false -------------------------------------------------------------------------------- /config/Caddyfile.example: -------------------------------------------------------------------------------- 1 | # The Caddyfile is an easy way to configure your Caddy web server. 2 | # 3 | # Unless the file starts with a global options block, the first 4 | # uncommented line is always the address of your site. 5 | # 6 | # To use your own domain name (with automatic HTTPS), first make 7 | # sure your domain's A/AAAA DNS records are properly pointed to 8 | # this machine's public IP, then replace ":80" below with your 9 | # domain name. 10 | 11 | { 12 | servers { 13 | metrics 14 | } 15 | 16 | admin :2019 17 | 18 | log access-json { 19 | include http.log.access.wger 20 | output file /var/log/www/access.log 21 | } 22 | 23 | log access-console { 24 | include http.log.access.wger 25 | format console 26 | } 27 | } 28 | 29 | #your.domain.example.com { 30 | localhost { 31 | tls your@email.address 32 | log wger 33 | 34 | encode 35 | 36 | # or "reverse_proxy anubis:3000 {" if you are using Anubis 37 | reverse_proxy web:8000 { 38 | header_up Host {host} 39 | header_up X-Real-IP {remote_host} 40 | header_up X-Forwarded-For {http.X-Forwarded-For} {remote_host} 41 | header_up X-Forwarded-Proto {scheme} 42 | } 43 | 44 | handle /static/* { 45 | root * /wger 46 | file_server 47 | } 48 | 49 | handle /media/* { 50 | root * /wger 51 | file_server 52 | } 53 | } 54 | 55 | # Refer to the Caddy docs for more information: 56 | # https://caddyserver.com/docs/caddyfile -------------------------------------------------------------------------------- /dev-postgres/docker-compose.yml: -------------------------------------------------------------------------------- 1 | name: wger-dev-postgres 2 | 3 | services: 4 | web: 5 | build: 6 | pull: true 7 | context: ${WGER_CODEPATH:?set the absolute path to the wger backend code in the .env file or env variable} 8 | dockerfile: ./extras/docker/development/Dockerfile 9 | develop: 10 | watch: 11 | - action: sync 12 | path: ${WGER_CODEPATH} 13 | target: /home/wger/src 14 | - action: rebuild 15 | path: ${WGER_CODEPATH}/pyproject.toml 16 | - action: rebuild 17 | path: ${WGER_CODEPATH}/package.json 18 | env_file: 19 | - ../config/prod.env 20 | - ../config/dev.env 21 | ports: 22 | - "8000:8000" 23 | 24 | command: tail -f /dev/null 25 | 26 | cache: 27 | image: redis 28 | expose: 29 | - 6379 30 | healthcheck: 31 | test: redis-cli ping 32 | interval: 10s 33 | timeout: 5s 34 | retries: 5 35 | start_period: 30s 36 | restart: unless-stopped 37 | 38 | db: 39 | image: postgres:15-alpine 40 | environment: 41 | - POSTGRES_USER=wger 42 | - POSTGRES_PASSWORD=wger 43 | - POSTGRES_DB=wger 44 | volumes: 45 | - postgres-data-dev:/var/lib/postgresql/data/ 46 | ports: 47 | - "5432:5432" 48 | expose: 49 | - 5432 50 | healthcheck: 51 | test: pg_isready -U wger 52 | interval: 10s 53 | timeout: 5s 54 | retries: 5 55 | start_period: 30s 56 | restart: unless-stopped 57 | 58 | volumes: 59 | postgres-data-dev: 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | wger logo 2 | 3 | 4 | # docker compose stacks for wger 5 | Contains 3 docker compose environments: 6 | 7 | * prod (in root of this repository) 8 | * dev (uses sqlite) 9 | * dev-postgres (uses postgresql) 10 | 11 | The production Docker Compose file initializes a production environment with the 12 | application server, a reverse proxy, a database, a caching server, and a Celery 13 | queue, all configured. Data is persisted in volumes, if you want to use folders, 14 | read the warning in the env file. 15 | 16 | **TLDR:** just do `docker compose up -d` 17 | 18 | For more details, consult the documentation (and the config files): 19 | 20 | * production: 21 | * development: 22 | 23 | It is recommended to regularly pull the latest version of the compose file, 24 | since sometimes new configurations or environmental variables are added. 25 | 26 | ## Contact 27 | 28 | Feel free to contact us if you found this useful or if there was something that 29 | didn't behave as you expected. We can't fix what we don't know about, so please 30 | report liberally. If you're not sure if something is a bug or not, feel free to 31 | file a bug anyway. 32 | 33 | * Mastodon: 34 | * Discord: 35 | * Issue tracker: 36 | 37 | 38 | ## Sources 39 | 40 | All the code and the content is freely available: 41 | 42 | * 43 | 44 | ## Licence 45 | 46 | The application is licenced under the Affero GNU General Public License 3 or 47 | later (AGPL 3+). 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /grafana/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | prometheus: 3 | image: prom/prometheus:latest 4 | restart: 'no' 5 | volumes: 6 | - prometheus_data:/prometheus 7 | - ./prometheus.yml:/etc/prometheus/prometheus.yml 8 | - ./web.yml:/etc/prometheus/web.yml 9 | - ./wger.rules:/etc/prometheus/wger.rules 10 | command: 11 | - --config.file=/etc/prometheus/prometheus.yml 12 | - --web.config.file=/etc/prometheus/web.yml 13 | ports: 14 | - "9090:9090" 15 | extra_hosts: 16 | - 'host.docker.internal:host-gateway' 17 | 18 | grafana: 19 | image: grafana/grafana:latest 20 | environment: 21 | - GF_SECURITY_ADMIN_PASSWORD=adminadmin 22 | - GF_PROVISIONING_DASHBOARDS_ENABLE=1 23 | - GF_PROVISIONING_DASHBOARDS_PATH=/etc/grafana/provisioning/dashboards 24 | - GF_PROVISIONING_DATASOURCES_ENABLE=1 25 | - GF_PROVISIONING_DATASOURCES_PATH=/etc/grafana/provisioning/datasources 26 | restart: 'no' 27 | volumes: 28 | - ./provisioning/dashboards:/etc/grafana/provisioning/dashboards 29 | - ./provisioning/datasources:/etc/grafana/provisioning/datasources 30 | - ./dashboards:/var/lib/grafana/dashboards 31 | ports: 32 | - "3000:3000" 33 | # expose: 34 | # - 3000 35 | 36 | loki: 37 | image: grafana/loki:latest 38 | ports: 39 | - "3100:3100" 40 | volumes: 41 | - ./loki-config.yaml:/etc/loki/local-config.yaml 42 | command: -config.file=/etc/loki/local-config.yaml 43 | 44 | alloy: 45 | image: grafana/alloy:latest 46 | volumes: 47 | - ./alloy-config.river:/etc/alloy/config.alloy 48 | - /var/run/docker.sock:/var/run/docker.sock:ro 49 | ports: 50 | - "9080:9080" 51 | #- "12345:12345" 52 | command: 53 | - run 54 | - /etc/alloy/config.alloy 55 | restart: 56 | unless-stopped 57 | depends_on: 58 | - loki 59 | 60 | volumes: 61 | prometheus_data: 62 | 63 | networks: 64 | default: 65 | name: wger_network 66 | external: true 67 | -------------------------------------------------------------------------------- /docker-compose.override.example.yml: -------------------------------------------------------------------------------- 1 | # Example override file. Copy as docker-compose.override.yml and edit as needed 2 | 3 | services: 4 | 5 | web: 6 | env_file: 7 | - ./config/prod.env 8 | - ./config/wger-local.env # Only add the variables that you have changed 9 | 10 | celery_worker: 11 | env_file: 12 | - ./config/prod.env 13 | - ./config/wger-local.env 14 | 15 | celery_beat: 16 | env_file: 17 | - ./config/prod.env 18 | - ./config/wger-local.env 19 | 20 | # 21 | # Example configuration to add Anubis as a debugging proxy in front of the web 22 | # service. If you set up wger on a public server, and get flooded with ai crawler 23 | # requests, you sadly will have to deal with them. 24 | anubis: 25 | image: ghcr.io/techarohq/anubis:latest 26 | pull_policy: always 27 | environment: 28 | BIND: ":3000" 29 | METRICS_BIND: ":9090" 30 | TARGET: http://web:8000 31 | POLICY_FNAME: "/data/cfg/anubis-rules.yml" 32 | WEBMASTER_EMAIL: "hello@wger.de" 33 | 34 | # generate with: openssl rand -hex 32 35 | ED25519_PRIVATE_KEY_HEX: "dba7c07331693b7beaeae102765568dd3c35cc1b6b3b23adaeeb5ecee406cc71" 36 | healthcheck: 37 | test: [ "CMD", "anubis", "--healthcheck" ] 38 | interval: 5s 39 | timeout: 30s 40 | retries: 5 41 | start_period: 500ms 42 | volumes: 43 | - "./config/anubis-rules.yml:/data/cfg/anubis-rules.yml:ro" 44 | 45 | # 46 | # Example configuration using caddy instead of nginx. Since we don't want to 47 | # change the main compose file as it would break existing deployments, the nginx 48 | # service needs to stay there. Here we simply remove any exposed ports 49 | 50 | # caddy: 51 | # image: caddy:latest 52 | # depends_on: 53 | # - web 54 | # ports: 55 | # - "2019:2019" 56 | # - "80:80" 57 | # - "443:443" 58 | # - "443:443/udp" 59 | # volumes: 60 | # - ./config/Caddyfile:/etc/caddy/Caddyfile 61 | # - caddy-data:/data 62 | # - caddy-logs:/var/www/logs 63 | # - caddy-config:/config 64 | # - static:/wger/static:ro 65 | # - media:/wger/media:ro 66 | # 67 | # nginx: 68 | # ports: !reset [] 69 | 70 | celery_flower: 71 | image: docker.io/wger/server:latest 72 | command: /start-flower 73 | env_file: 74 | - ./config/prod.env 75 | ports: 76 | - "5555:5555" 77 | healthcheck: 78 | test: wget --no-verbose --tries=1 http://localhost:5555/healthcheck 79 | interval: 10s 80 | timeout: 5s 81 | retries: 5 82 | depends_on: 83 | celery_worker: 84 | condition: service_healthy 85 | 86 | #volumes: 87 | # caddy_data: 88 | # caddy-data: 89 | # caddy-config: 90 | # caddy-logs: -------------------------------------------------------------------------------- /grafana/alloy-config.river: -------------------------------------------------------------------------------- 1 | logging { 2 | level = "info" 3 | format = "logfmt" 4 | } 5 | 6 | discovery.docker "docker_containers" { 7 | host = "unix:///var/run/docker.sock" 8 | } 9 | 10 | discovery.relabel "docker_containers" { 11 | targets = discovery.docker.docker_containers.targets 12 | 13 | // clean up container name 14 | rule { 15 | source_labels = ["__meta_docker_container_name"] 16 | regex = "/(.*)" 17 | replacement = "$1" 18 | target_label = "container" 19 | } 20 | 21 | } 22 | 23 | loki.source.docker "container_logs" { 24 | host = "unix:///var/run/docker.sock" 25 | targets = discovery.relabel.docker_containers.output // Use relabeled targets 26 | forward_to = [loki.process.process_logs.receiver] // Forward ALL logs to the main processing block 27 | labels = { "job" = "docker" } // Base job label 28 | relabel_rules = discovery.relabel.docker_containers.rules // Apply relabel rules defined above 29 | } 30 | 31 | loki.process "process_logs" { 32 | stage.docker {} 33 | 34 | // Python containers 35 | stage.match { 36 | selector = "{container=~\".*(web|celery_worker|celery_beat).*\"}" 37 | 38 | // Python multiline tracebacks 39 | stage.multiline { 40 | firstline = "^level=(INFO|DEBUG|WARNING|ERROR|CRITICAL) ts=\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}" 41 | max_wait_time = "1s" 42 | } 43 | 44 | stage.template { 45 | source = "level" 46 | template = "{{ ToLower .Value }}" 47 | } 48 | 49 | stage.labels { 50 | values = { 51 | log_type = "python", 52 | level = "", 53 | } 54 | } 55 | } 56 | 57 | // Process Caddy JSON Logs 58 | stage.match { 59 | selector = "{container=~\".*caddy.*\"}" 60 | 61 | stage.json { 62 | expressions = { 63 | level = "", 64 | ts = "", 65 | logger = "", 66 | msg = "", 67 | duration = "", 68 | size = "", 69 | status = "", 70 | request_method = "request.method", 71 | request_uri = "request.uri", 72 | request_proto = "request.proto", 73 | request_host = "request.host", 74 | } 75 | } 76 | 77 | stage.labels { 78 | values = { 79 | level = "", 80 | } 81 | } 82 | } 83 | 84 | // Parse logs from loki and alloy 85 | stage.match { 86 | selector = "{ container =~ \".*(loki|alloy).*\" }" 87 | stage.logfmt { 88 | mapping = { 89 | "level" = "", 90 | "timestape" = "ts", 91 | "message" = "msg", 92 | } 93 | } 94 | 95 | stage.labels { 96 | values = { 97 | level = "", 98 | } 99 | } 100 | } 101 | 102 | 103 | forward_to = [loki.write.loki_endpoint.receiver] 104 | } // End loki.process process_logs 105 | 106 | 107 | loki.write "loki_endpoint" { 108 | endpoint { 109 | url = "http://loki:3100/loki/api/v1/push" 110 | } 111 | } -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Please consult the `Deployment` section in the docs if you want to deploy 3 | # this. You *need* to keep this nginx service, even if you have your own, 4 | # otherwise the static files will not be served correctly! If you do remove 5 | # it, configure yours similarly to what's in config/nginx.conf 6 | # Also take a look at the "Static files" section in the .env file 7 | 8 | services: 9 | web: 10 | image: docker.io/wger/server:latest 11 | depends_on: 12 | db: 13 | condition: service_healthy 14 | cache: 15 | condition: service_healthy 16 | env_file: 17 | - ./config/prod.env 18 | volumes: 19 | - static:/home/wger/static 20 | - media:/home/wger/media 21 | expose: 22 | - 8000 23 | logging: 24 | driver: json-file 25 | options: 26 | max-size: 5m 27 | max-file: 5 28 | healthcheck: 29 | test: wget --no-verbose --tries=1 --spider http://localhost:8000 30 | interval: 10s 31 | timeout: 5s 32 | start_period: 300s 33 | retries: 5 34 | restart: unless-stopped 35 | 36 | nginx: 37 | image: docker.io/nginx:stable 38 | depends_on: 39 | - web 40 | volumes: 41 | - ./config/nginx.conf:/etc/nginx/conf.d/default.conf 42 | - static:/wger/static:ro 43 | - media:/wger/media:ro 44 | ports: 45 | - "80:80" 46 | healthcheck: 47 | test: service nginx status 48 | interval: 10s 49 | timeout: 5s 50 | retries: 5 51 | start_period: 30s 52 | restart: unless-stopped 53 | 54 | db: 55 | image: docker.io/postgres:15-alpine 56 | environment: 57 | - POSTGRES_USER=wger 58 | - POSTGRES_PASSWORD=wger 59 | - POSTGRES_DB=wger 60 | - TZ=Europe/Berlin 61 | volumes: 62 | - postgres-data:/var/lib/postgresql/data/ 63 | expose: 64 | - 5432 65 | logging: 66 | driver: json-file 67 | options: 68 | max-size: 5m 69 | max-file: 5 70 | healthcheck: 71 | test: pg_isready -U wger 72 | interval: 10s 73 | timeout: 5s 74 | retries: 5 75 | start_period: 30s 76 | restart: unless-stopped 77 | 78 | cache: 79 | image: docker.io/redis 80 | expose: 81 | - 6379 82 | logging: 83 | driver: json-file 84 | options: 85 | max-size: 5m 86 | max-file: 5 87 | volumes: 88 | - ./config/redis.conf:/usr/local/etc/redis/redis.conf 89 | - redis-data:/data 90 | command: [ "redis-server", "/usr/local/etc/redis/redis.conf"] 91 | healthcheck: 92 | test: redis-cli ping 93 | interval: 10s 94 | timeout: 5s 95 | retries: 5 96 | start_period: 30s 97 | restart: unless-stopped 98 | 99 | # You probably want to limit the memory usage of the cache, otherwise it might 100 | # hog all the available memory. Remove or change according to your needs. 101 | #mem_limit: 5gb 102 | 103 | celery_worker: 104 | image: docker.io/wger/server:latest 105 | command: /start-worker 106 | env_file: 107 | - ./config/prod.env 108 | volumes: 109 | - media:/home/wger/media 110 | logging: 111 | driver: json-file 112 | options: 113 | max-size: 5m 114 | max-file: 5 115 | depends_on: 116 | web: 117 | condition: service_healthy 118 | healthcheck: 119 | test: celery -A wger inspect ping 120 | interval: 10s 121 | timeout: 5s 122 | retries: 5 123 | start_period: 30s 124 | 125 | celery_beat: 126 | image: docker.io/wger/server:latest 127 | command: /start-beat 128 | logging: 129 | driver: json-file 130 | options: 131 | max-size: 5m 132 | max-file: 5 133 | volumes: 134 | - celery-beat:/home/wger/beat/ 135 | env_file: 136 | - ./config/prod.env 137 | depends_on: 138 | celery_worker: 139 | condition: service_healthy 140 | 141 | volumes: 142 | postgres-data: 143 | celery-beat: 144 | redis-data: 145 | 146 | # Heads up, if you remove these volumes and use folders directly you need to chown them 147 | # to the UID and GID 1000 even if it doesn't exist on your system. Also, they should 148 | # be readable by everyone. 149 | # 150 | # https://wger.readthedocs.io/en/latest/production/docker.html#missing-static-files 151 | media: 152 | static: 153 | 154 | networks: 155 | default: 156 | name: wger_network 157 | -------------------------------------------------------------------------------- /config/anubis-rules.yml: -------------------------------------------------------------------------------- 1 | # Anubis rules configuration file 2 | # 3 | # This was copied from https://github.com/TecharoHQ/anubis/blob/main/data/meta/default-config.yaml 4 | # but can be imported like this once the next version of Anubis is released: 5 | # - import: (data)/meta/default-config.yaml 6 | 7 | 8 | bots: 9 | - # Pathological bots to deny 10 | # This correlates to data/bots/_deny-pathological.yaml in the source tree 11 | # https://github.com/TecharoHQ/anubis/blob/main/data/bots/_deny-pathological.yaml 12 | import: (data)/bots/_deny-pathological.yaml 13 | - import: (data)/bots/aggressive-brazilian-scrapers.yaml 14 | 15 | # Aggressively block AI/LLM related bots/agents by default 16 | #- import: (data)/meta/ai-block-aggressive.yaml 17 | 18 | # Consider replacing the aggressive AI policy with more selective policies: 19 | - import: (data)/meta/ai-block-moderate.yaml 20 | # - import: (data)/meta/ai-block-permissive.yaml 21 | 22 | # Search engine crawlers to allow, defaults to: 23 | # - Google (so they don't try to bypass Anubis) 24 | # - Apple 25 | # - Bing 26 | # - DuckDuckGo 27 | # - Qwant 28 | # - The Internet Archive 29 | # - Kagi 30 | # - Marginalia 31 | # - Mojeek 32 | - import: (data)/crawlers/_allow-good.yaml 33 | # Challenge Firefox AI previews 34 | - import: (data)/clients/x-firefox-ai.yaml 35 | 36 | # Allow common "keeping the internet working" routes (well-known, favicon, robots.txt) 37 | - import: (data)/common/keep-internet-working.yaml 38 | 39 | # # Punish any bot with "bot" in the user-agent string 40 | # # This is known to have a high false-positive rate, use at your own risk 41 | # - name: generic-bot-catchall 42 | # user_agent_regex: (?i:bot|crawler) 43 | # action: CHALLENGE 44 | # challenge: 45 | # difficulty: 16 # impossible 46 | # report_as: 4 # lie to the operator 47 | # algorithm: slow # intentionally waste CPU cycles and time 48 | 49 | # Requires a subscription to Thoth to use, see 50 | # https://anubis.techaro.lol/docs/admin/thoth#geoip-based-filtering 51 | #- name: countries-with-aggressive-scrapers 52 | # action: WEIGH 53 | # geoip: 54 | # countries: 55 | # - BR 56 | # - CN 57 | # weight: 58 | # adjust: 10 59 | 60 | # Requires a subscription to Thoth to use, see 61 | # https://anubis.techaro.lol/docs/admin/thoth#asn-based-filtering 62 | #- name: aggressive-asns-without-functional-abuse-contact 63 | # action: WEIGH 64 | # asns: 65 | # match: 66 | # - 13335 # Cloudflare 67 | # - 136907 # Huawei Cloud 68 | # - 45102 # Alibaba Cloud 69 | # weight: 70 | # adjust: 10 71 | 72 | # ## System load based checks. 73 | # # If the system is under high load, add weight. 74 | # - name: high-load-average 75 | # action: WEIGH 76 | # expression: load_1m >= 10.0 # make sure to end the load comparison in a .0 77 | # weight: 78 | # adjust: 20 79 | 80 | ## If your backend service is running on the same operating system as Anubis, 81 | ## you can uncomment this rule to make the challenge easier when the system is 82 | ## under low load. 83 | ## 84 | ## If it is not, remove weight. 85 | # - name: low-load-average 86 | # action: WEIGH 87 | # expression: load_15m <= 4.0 # make sure to end the load comparison in a .0 88 | # weight: 89 | # adjust: -10 90 | 91 | # Assert behaviour that only genuine browsers display. This ensures that Chrome 92 | # or Firefox versions 93 | - name: realistic-browser-catchall 94 | expression: 95 | all: 96 | - '"User-Agent" in headers' 97 | - '( userAgent.contains("Firefox") ) || ( userAgent.contains("Chrome") ) || ( userAgent.contains("Safari") )' 98 | - '"Accept" in headers' 99 | - '"Sec-Fetch-Dest" in headers' 100 | - '"Sec-Fetch-Mode" in headers' 101 | - '"Sec-Fetch-Site" in headers' 102 | - '"Accept-Encoding" in headers' 103 | - '( headers["Accept-Encoding"].contains("zstd") || headers["Accept-Encoding"].contains("br") )' 104 | - '"Accept-Language" in headers' 105 | action: WEIGH 106 | weight: 107 | adjust: -10 108 | 109 | # The Upgrade-Insecure-Requests header is typically sent by browsers, but not always 110 | - name: upgrade-insecure-requests 111 | expression: '"Upgrade-Insecure-Requests" in headers' 112 | action: WEIGH 113 | weight: 114 | adjust: -2 115 | 116 | # Chrome should behave like Chrome 117 | - name: chrome-is-proper 118 | expression: 119 | all: 120 | - userAgent.contains("Chrome") 121 | - '"Sec-Ch-Ua" in headers' 122 | - 'headers["Sec-Ch-Ua"].contains("Chromium")' 123 | - '"Sec-Ch-Ua-Mobile" in headers' 124 | - '"Sec-Ch-Ua-Platform" in headers' 125 | action: WEIGH 126 | weight: 127 | adjust: -5 128 | 129 | - name: should-have-accept 130 | expression: '!("Accept" in headers)' 131 | action: WEIGH 132 | weight: 133 | adjust: 5 134 | 135 | # Generic catchall rule 136 | - name: generic-browser 137 | user_agent_regex: >- 138 | Mozilla|Opera 139 | action: WEIGH 140 | weight: 141 | adjust: 10 142 | 143 | store: 144 | # backend: bbolt 145 | # parameters: 146 | # path: /data/anubis.bdb 147 | 148 | backend: valkey 149 | parameters: 150 | url: "redis://cache:6379/3" -------------------------------------------------------------------------------- /grafana/wger.rules: -------------------------------------------------------------------------------- 1 | groups: 2 | - name: django.rules 3 | rules: 4 | - record: job:django_http_requests_before_middlewares_total:sum_rate30s 5 | expr: sum(rate(django_http_requests_before_middlewares_total[30s])) BY (job) 6 | - record: job:django_http_requests_unknown_latency_total:sum_rate30s 7 | expr: sum(rate(django_http_requests_unknown_latency_total[30s])) BY (job) 8 | - record: job:django_http_ajax_requests_total:sum_rate30s 9 | expr: sum(rate(django_http_ajax_requests_total[30s])) BY (job) 10 | - record: job:django_http_responses_before_middlewares_total:sum_rate30s 11 | expr: sum(rate(django_http_responses_before_middlewares_total[30s])) BY (job) 12 | - record: job:django_http_requests_unknown_latency_including_middlewares_total:sum_rate30s 13 | expr: sum(rate(django_http_requests_unknown_latency_including_middlewares_total[30s])) 14 | BY (job) 15 | - record: job:django_http_requests_body_total_bytes:sum_rate30s 16 | expr: sum(rate(django_http_requests_body_total_bytes[30s])) BY (job) 17 | - record: job:django_http_responses_streaming_total:sum_rate30s 18 | expr: sum(rate(django_http_responses_streaming_total[30s])) BY (job) 19 | - record: job:django_http_responses_body_total_bytes:sum_rate30s 20 | expr: sum(rate(django_http_responses_body_total_bytes[30s])) BY (job) 21 | - record: job:django_http_requests_total:sum_rate30s 22 | expr: sum(rate(django_http_requests_total_by_method[30s])) BY (job) 23 | - record: job:django_http_requests_total_by_method:sum_rate30s 24 | expr: sum(rate(django_http_requests_total_by_method[30s])) BY (job, method) 25 | - record: job:django_http_requests_total_by_transport:sum_rate30s 26 | expr: sum(rate(django_http_requests_total_by_transport[30s])) BY (job, transport) 27 | - record: job:django_http_requests_total_by_view:sum_rate30s 28 | expr: sum(rate(django_http_requests_total_by_view_transport_method[30s])) BY (job, 29 | view) 30 | - record: job:django_http_requests_total_by_view_transport_method:sum_rate30s 31 | expr: sum(rate(django_http_requests_total_by_view_transport_method[30s])) BY (job, 32 | view, transport, method) 33 | - record: job:django_http_responses_total_by_templatename:sum_rate30s 34 | expr: sum(rate(django_http_responses_total_by_templatename[30s])) BY (job, templatename) 35 | - record: job:django_http_responses_total_by_status:sum_rate30s 36 | expr: sum(rate(django_http_responses_total_by_status[30s])) BY (job, status) 37 | - record: job:django_http_responses_total_by_status_name_method:sum_rate30s 38 | expr: sum(rate(django_http_responses_total_by_status_name_method[30s])) BY (job, 39 | status, name, method) 40 | - record: job:django_http_responses_total_by_charset:sum_rate30s 41 | expr: sum(rate(django_http_responses_total_by_charset[30s])) BY (job, charset) 42 | - record: job:django_http_exceptions_total_by_type:sum_rate30s 43 | expr: sum(rate(django_http_exceptions_total_by_type[30s])) BY (job, type) 44 | - record: job:django_http_exceptions_total_by_view:sum_rate30s 45 | expr: sum(rate(django_http_exceptions_total_by_view[30s])) BY (job, view) 46 | - record: job:django_http_requests_latency_including_middlewares_seconds:quantile_rate30s 47 | expr: histogram_quantile(0.5, sum(rate(django_http_requests_latency_including_middlewares_seconds_bucket[30s])) 48 | BY (job, le)) 49 | labels: 50 | quantile: "50" 51 | - record: job:django_http_requests_latency_including_middlewares_seconds:quantile_rate30s 52 | expr: histogram_quantile(0.95, sum(rate(django_http_requests_latency_including_middlewares_seconds_bucket[30s])) 53 | BY (job, le)) 54 | labels: 55 | quantile: "95" 56 | - record: job:django_http_requests_latency_including_middlewares_seconds:quantile_rate30s 57 | expr: histogram_quantile(0.99, sum(rate(django_http_requests_latency_including_middlewares_seconds_bucket[30s])) 58 | BY (job, le)) 59 | labels: 60 | quantile: "99" 61 | - record: job:django_http_requests_latency_including_middlewares_seconds:quantile_rate30s 62 | expr: histogram_quantile(0.999, sum(rate(django_http_requests_latency_including_middlewares_seconds_bucket[30s])) 63 | BY (job, le)) 64 | labels: 65 | quantile: "99.9" 66 | - record: job:django_http_requests_latency_seconds:quantile_rate30s 67 | expr: histogram_quantile(0.5, sum(rate(django_http_requests_latency_seconds_bucket[30s])) 68 | BY (job, le)) 69 | labels: 70 | quantile: "50" 71 | - record: job:django_http_requests_latency_seconds:quantile_rate30s 72 | expr: histogram_quantile(0.95, sum(rate(django_http_requests_latency_seconds_bucket[30s])) 73 | BY (job, le)) 74 | labels: 75 | quantile: "95" 76 | - record: job:django_http_requests_latency_seconds:quantile_rate30s 77 | expr: histogram_quantile(0.99, sum(rate(django_http_requests_latency_seconds_bucket[30s])) 78 | BY (job, le)) 79 | labels: 80 | quantile: "99" 81 | - record: job:django_http_requests_latency_seconds:quantile_rate30s 82 | expr: histogram_quantile(0.999, sum(rate(django_http_requests_latency_seconds_bucket[30s])) 83 | BY (job, le)) 84 | labels: 85 | quantile: "99.9" 86 | - record: job:django_model_inserts_total:sum_rate1m 87 | expr: sum(rate(django_model_inserts_total[1m])) BY (job, model) 88 | - record: job:django_model_updates_total:sum_rate1m 89 | expr: sum(rate(django_model_updates_total[1m])) BY (job, model) 90 | - record: job:django_model_deletes_total:sum_rate1m 91 | expr: sum(rate(django_model_deletes_total[1m])) BY (job, model) 92 | - record: job:django_db_new_connections_total:sum_rate30s 93 | expr: sum(rate(django_db_new_connections_total[30s])) BY (alias, vendor) 94 | - record: job:django_db_new_connection_errors_total:sum_rate30s 95 | expr: sum(rate(django_db_new_connection_errors_total[30s])) BY (alias, vendor) 96 | - record: job:django_db_execute_total:sum_rate30s 97 | expr: sum(rate(django_db_execute_total[30s])) BY (alias, vendor) 98 | - record: job:django_db_execute_many_total:sum_rate30s 99 | expr: sum(rate(django_db_execute_many_total[30s])) BY (alias, vendor) 100 | - record: job:django_db_errors_total:sum_rate30s 101 | expr: sum(rate(django_db_errors_total[30s])) BY (alias, vendor, type) 102 | - record: job:django_migrations_applied_total:max 103 | expr: max(django_migrations_applied_total) BY (job, connection) 104 | - record: job:django_migrations_unapplied_total:max 105 | expr: max(django_migrations_unapplied_total) BY (job, connection) -------------------------------------------------------------------------------- /config/prod.env: -------------------------------------------------------------------------------- 1 | # Django's secret key, change to a 50 character random string if you are running 2 | # this instance publicly. For an online generator, see e.g. https://djecrety.ir/ 3 | SECRET_KEY=wger-docker-supersecret-key-1234567890!@#$%^&*(-_) 4 | 5 | # Signing key used for JWT, use something different than the secret key 6 | SIGNING_KEY=wger-docker-secret-jwtkey-1234567890!@#$%^&*(-_=+) 7 | 8 | # The server's timezone, for a list of possible names: 9 | # https://en.wikipedia.org/wiki/List_of_tz_database_time_zones 10 | TIME_ZONE=Europe/Berlin 11 | TZ=Europe/Berlin 12 | 13 | # 14 | # If you get CSRF errors set your domain here 15 | # Consult the docs for more details: 16 | # https://wger.readthedocs.io/en/latest/production/docker.html#csrf-errors 17 | 18 | # CSRF_TRUSTED_ORIGINS=https://my.domain.example.com,https://118.999.881.119 19 | # X_FORWARDED_PROTO_HEADER_SET=True 20 | 21 | # 22 | # Static files 23 | # If you are running the application behind a reverse proxy or changed the port, the 24 | # links for some images *might* break (specially in the mobile app). Also note that 25 | # the API response is cached and contains the host, if you change this setting, just run 26 | # docker compose exec web python3 manage.py warmup-exercise-api-cache --force 27 | # MEDIA_URL=https://your-domain.example.com/media/ 28 | # STATIC_URL=https://your-domain.example.com/static/ 29 | 30 | # 31 | # These settings usually don't need changing 32 | # 33 | 34 | # 35 | # Application 36 | WGER_INSTANCE=https://wger.de # Wger instance from which to sync exercises, images, etc. 37 | ALLOW_REGISTRATION=True 38 | ALLOW_GUEST_USERS=True 39 | ALLOW_UPLOAD_VIDEOS=True 40 | # Users won't be able to contribute to exercises if their account age is 41 | # lower than this amount in days. 42 | MIN_ACCOUNT_AGE_TO_TRUST=21 43 | # Synchronzing exercises 44 | # It is recommended to keep the local database synchronized with the wger 45 | # instance specified in WGER_INSTANCE since there are new added or translations 46 | # improved. For this you have different possibilities: 47 | # - Sync exercises on startup: 48 | # SYNC_EXERCISES_ON_STARTUP=True 49 | # DOWNLOAD_EXERCISE_IMAGES_ON_STARTUP=True 50 | # - Sync them in the background with celery. This will setup a job that will run 51 | # once a week at a random time (this time is selected once when starting the server) 52 | SYNC_EXERCISES_CELERY=True 53 | SYNC_EXERCISE_IMAGES_CELERY=True 54 | SYNC_EXERCISE_VIDEOS_CELERY=True 55 | # - Manually trigger the process as needed: 56 | # docker compose exec web python3 manage.py sync-exercises 57 | # docker compose exec web python3 manage.py download-exercise-images 58 | # docker compose exec web python3 manage.py download-exercise-videos 59 | 60 | # Synchronzing ingredients 61 | # You can also syncronize the ingredients from a remote wger instance, and have 62 | # basically the same options as for the ingredients: 63 | # - Sync them in the background with celery. This will setup a job that will run 64 | # once a week at a random time (this time is selected once when starting the server) 65 | SYNC_INGREDIENTS_CELERY=True 66 | # - Manually trigger the process as needed: 67 | # docker compose exec web python3 manage.py sync-ingredients 68 | 69 | # This option controls whether to download ingredients and their images from the 70 | # configured wger instance. When scanning products with the barcode scanner, it is 71 | # possible to dynamically fetch the ingredient if it is not known in the local database. 72 | # Possible values: WGER or None (to deactivate). Requires USE_CELERY to be set to true. 73 | DOWNLOAD_INGREDIENTS_FROM=WGER 74 | 75 | # Keep exercise api cache warmed up. This will setup a job that will run once 76 | # a day at a random time (this time is selected once when starting the server). 77 | # Requires USE_CELERY to be set to true. 78 | CACHE_API_EXERCISES_CELERY=True 79 | 80 | # Whether to force updating the exercise api cache every time the job runs 81 | CACHE_API_EXERCISES_CELERY_FORCE_UPDATE=False 82 | 83 | 84 | # Whether celery is configured and should be used. Can be left to true with 85 | # this setup but can be deactivated if you are using the app in some other way 86 | USE_CELERY=True 87 | 88 | # 89 | # Celery 90 | CELERY_BROKER=redis://cache:6379/2 91 | CELERY_BACKEND=redis://cache:6379/2 92 | CELERY_FLOWER_PASSWORD=adminadmin 93 | CELERY_WORKER_CONCURRENCY=4 # Set to one if using sqlite 94 | 95 | # 96 | # Database 97 | DJANGO_DB_ENGINE=django.db.backends.postgresql 98 | DJANGO_DB_DATABASE=wger 99 | DJANGO_DB_USER=wger 100 | DJANGO_DB_PASSWORD=wger 101 | DJANGO_DB_HOST=db 102 | DJANGO_DB_PORT=5432 103 | DJANGO_PERFORM_MIGRATIONS=True # Perform any new database migrations on startup 104 | 105 | # 106 | # Cache 107 | DJANGO_CACHE_BACKEND=django_redis.cache.RedisCache 108 | DJANGO_CACHE_LOCATION=redis://cache:6379/1 109 | DJANGO_CACHE_TIMEOUT=1296000 # in seconds - 60*60*24*15, 15 Days 110 | DJANGO_CACHE_CLIENT_CLASS=django_redis.client.DefaultClient 111 | # DJANGO_CACHE_CLIENT_PASSWORD=abcde... # Only if you changed the redis config 112 | # DJANGO_CACHE_CLIENT_SSL_KEYFILE=/path/to/ssl_keyfile # Path to an ssl private key. 113 | # DJANGO_CACHE_CLIENT_SSL_CERTFILE=/path/to/ssl_certfile # Path to an ssl certificate. 114 | # DJANGO_CACHE_CLIENT_SSL_CERT_REQS= # The string value for the verify_mode. 115 | # DJANGO_CACHE_CLIENT_SSL_CHECK_HOSTNAME=False # If set, match the hostname during the SSL handshake. 116 | 117 | # 118 | # Brute force login attacks 119 | # https://django-axes.readthedocs.io/en/latest/index.html 120 | AXES_ENABLED=True 121 | AXES_FAILURE_LIMIT=10 122 | AXES_COOLOFF_TIME=30 # in minutes 123 | AXES_HANDLER=axes.handlers.cache.AxesCacheHandler 124 | AXES_LOCKOUT_PARAMETERS=ip_address 125 | AXES_IPWARE_PROXY_COUNT=1 126 | AXES_IPWARE_META_PRECEDENCE_ORDER=HTTP_X_FORWARDED_FOR,REMOTE_ADDR 127 | # 128 | # Others 129 | DJANGO_DEBUG=False 130 | WGER_USE_GUNICORN=True 131 | EXERCISE_CACHE_TTL=18000 # in seconds - 5*60*60, 5 hours 132 | SITE_URL=http://localhost 133 | 134 | # 135 | # JWT auth 136 | ACCESS_TOKEN_LIFETIME=10 # The lifetime duration of the access token, in minutes 137 | REFRESH_TOKEN_LIFETIME=24 # The lifetime duration of the refresh token, in hours 138 | 139 | # 140 | # Auth Proxy Authentication 141 | # 142 | # Please read the documentation before enabling this feature: 143 | # https://wger.readthedocs.io/en/latest/administration/auth_proxy.html 144 | AUTH_PROXY_HEADER='' 145 | AUTH_PROXY_TRUSTED_IPS='' 146 | AUTH_PROXY_CREATE_UNKNOWN_USER=False 147 | AUTH_PROXY_USER_EMAIL_HEADER='' 148 | AUTH_PROXY_USER_NAME_HEADER='' 149 | 150 | # 151 | # Other possible settings 152 | 153 | # Log level for the web app, possible values: DEBUG, INFO, WARNING, ERROR, CRITICAL 154 | LOG_LEVEL_PYTHON=INFO 155 | 156 | # Recaptcha keys. You will need to create an account and register your domain 157 | # https://www.google.com/recaptcha/ 158 | # RECAPTCHA_PUBLIC_KEY=abcde... 159 | # RECAPTCHA_PRIVATE_KEY=abcde... 160 | USE_RECAPTCHA=False 161 | 162 | # Clears the static files before copying the new ones (i.e. just calls collectstatic 163 | # with the appropriate flag: "manage.py collectstatic --no-input --clear"). Usually 164 | # This can be left like this but if you have problems and new static files are not 165 | # being copied correctly, clearing everything might help 166 | DJANGO_CLEAR_STATIC_FIRST=False 167 | 168 | # 169 | # Email 170 | # https://docs.djangoproject.com/en/4.1/topics/email/#smtp-backend 171 | # ENABLE_EMAIL=False 172 | # EMAIL_HOST=email.example.com 173 | # EMAIL_PORT=587 174 | # EMAIL_HOST_USER=username 175 | # EMAIL_HOST_PASSWORD=password 176 | # EMAIL_USE_TLS=True 177 | # EMAIL_USE_SSL=False 178 | FROM_EMAIL='wger Workout Manager ' 179 | 180 | # Set your name and email to be notified if an internal server error occurs. 181 | # Needs a working email configuration 182 | # DJANGO_ADMINS=your name,email@example.com 183 | 184 | # Whether to compress css and js files into one (of each) 185 | # COMPRESS_ENABLED=True 186 | 187 | # 188 | # Django Rest Framework 189 | # The number of proxies in front of the application. In the default configuration 190 | # only nginx is. Change as approtriate if your setup differs. Also note that this 191 | # is only used when throttling API requests. 192 | NUMBER_OF_PROXIES=1 193 | 194 | # 195 | # Gunicorn 196 | # 197 | # Additional gunicorn options, change as needed. 198 | # For the number of workers to spawn, a usually recommended value is (2 x $num_cores) + 1 199 | # see: 200 | # - https://docs.gunicorn.org/en/stable/settings.html 201 | # - https://github.com/wger-project/wger/blob/master/extras/docker/production/entrypoint.sh#L95 202 | GUNICORN_CMD_ARGS="--workers 3 --threads 2 --worker-class gthread --proxy-protocol True --timeout 240" 203 | 204 | # 205 | # Prometheus metrics 206 | EXPOSE_PROMETHEUS_METRICS=False -------------------------------------------------------------------------------- /grafana/dashboards/docker_daemon_metrics.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": { 7 | "type": "grafana", 8 | "uid": "-- Grafana --" 9 | }, 10 | "enable": true, 11 | "hide": true, 12 | "iconColor": "rgba(0, 211, 255, 1)", 13 | "name": "Annotations & Alerts", 14 | "type": "dashboard" 15 | } 16 | ] 17 | }, 18 | "description": "Docker daemon (engine) metrics", 19 | "editable": true, 20 | "fiscalYearStartMonth": 0, 21 | "graphTooltip": 0, 22 | "id": 11, 23 | "links": [], 24 | "panels": [ 25 | { 26 | "datasource": { 27 | "type": "prometheus", 28 | "uid": "f6b72a59-10e5-4c3e-bb1e-40557c426097" 29 | }, 30 | "fieldConfig": { 31 | "defaults": { 32 | "color": { 33 | "mode": "thresholds" 34 | }, 35 | "mappings": [], 36 | "thresholds": { 37 | "mode": "absolute", 38 | "steps": [ 39 | { 40 | "color": "green", 41 | "value": null 42 | }, 43 | { 44 | "color": "red", 45 | "value": 80 46 | } 47 | ] 48 | } 49 | }, 50 | "overrides": [] 51 | }, 52 | "gridPos": { 53 | "h": 6, 54 | "w": 6, 55 | "x": 0, 56 | "y": 0 57 | }, 58 | "id": 1, 59 | "options": { 60 | "colorMode": "value", 61 | "graphMode": "none", 62 | "justifyMode": "auto", 63 | "orientation": "auto", 64 | "percentChangeColorMode": "standard", 65 | "reduceOptions": { 66 | "calcs": [ 67 | "lastNotNull" 68 | ], 69 | "fields": "", 70 | "values": false 71 | }, 72 | "showPercentChange": false, 73 | "textMode": "auto", 74 | "wideLayout": true 75 | }, 76 | "pluginVersion": "11.5.2", 77 | "targets": [ 78 | { 79 | "datasource": { 80 | "type": "prometheus", 81 | "uid": "$datasource" 82 | }, 83 | "editorMode": "code", 84 | "expr": "engine_daemon_engine_cpus_cpus{instance=~'$instance'}", 85 | "instant": false, 86 | "legendFormat": "__auto", 87 | "range": true, 88 | "refId": "A" 89 | } 90 | ], 91 | "title": "Engine cpus", 92 | "type": "stat" 93 | }, 94 | { 95 | "datasource": { 96 | "type": "prometheus", 97 | "uid": "$datasource" 98 | }, 99 | "fieldConfig": { 100 | "defaults": { 101 | "color": { 102 | "mode": "thresholds" 103 | }, 104 | "mappings": [], 105 | "thresholds": { 106 | "mode": "absolute", 107 | "steps": [ 108 | { 109 | "color": "green", 110 | "value": null 111 | }, 112 | { 113 | "color": "red", 114 | "value": 80 115 | } 116 | ] 117 | } 118 | }, 119 | "overrides": [] 120 | }, 121 | "gridPos": { 122 | "h": 6, 123 | "w": 6, 124 | "x": 6, 125 | "y": 0 126 | }, 127 | "id": 2, 128 | "options": { 129 | "colorMode": "value", 130 | "graphMode": "none", 131 | "justifyMode": "auto", 132 | "orientation": "auto", 133 | "percentChangeColorMode": "standard", 134 | "reduceOptions": { 135 | "calcs": [ 136 | "lastNotNull" 137 | ], 138 | "fields": "", 139 | "values": false 140 | }, 141 | "showPercentChange": false, 142 | "textMode": "auto", 143 | "wideLayout": true 144 | }, 145 | "pluginVersion": "11.5.2", 146 | "targets": [ 147 | { 148 | "datasource": { 149 | "type": "prometheus", 150 | "uid": "$datasource" 151 | }, 152 | "editorMode": "code", 153 | "expr": "engine_daemon_container_states_containers{instance=~'$instance', state=\"running\"}", 154 | "instant": false, 155 | "legendFormat": "__auto", 156 | "range": true, 157 | "refId": "A" 158 | } 159 | ], 160 | "title": "Running container", 161 | "type": "stat" 162 | }, 163 | { 164 | "datasource": { 165 | "type": "prometheus", 166 | "uid": "$datasource" 167 | }, 168 | "fieldConfig": { 169 | "defaults": { 170 | "color": { 171 | "mode": "palette-classic" 172 | }, 173 | "custom": { 174 | "axisBorderShow": false, 175 | "axisCenteredZero": false, 176 | "axisColorMode": "text", 177 | "axisLabel": "", 178 | "axisPlacement": "auto", 179 | "barAlignment": 0, 180 | "barWidthFactor": 0.6, 181 | "drawStyle": "line", 182 | "fillOpacity": 0, 183 | "gradientMode": "none", 184 | "hideFrom": { 185 | "legend": false, 186 | "tooltip": false, 187 | "viz": false 188 | }, 189 | "insertNulls": false, 190 | "lineInterpolation": "linear", 191 | "lineWidth": 1, 192 | "pointSize": 5, 193 | "scaleDistribution": { 194 | "type": "linear" 195 | }, 196 | "showPoints": "auto", 197 | "spanNulls": false, 198 | "stacking": { 199 | "group": "A", 200 | "mode": "none" 201 | }, 202 | "thresholdsStyle": { 203 | "mode": "off" 204 | } 205 | }, 206 | "mappings": [], 207 | "thresholds": { 208 | "mode": "absolute", 209 | "steps": [ 210 | { 211 | "color": "green", 212 | "value": null 213 | }, 214 | { 215 | "color": "red", 216 | "value": 80 217 | } 218 | ] 219 | } 220 | }, 221 | "overrides": [] 222 | }, 223 | "gridPos": { 224 | "h": 6, 225 | "w": 12, 226 | "x": 12, 227 | "y": 0 228 | }, 229 | "id": 7, 230 | "options": { 231 | "legend": { 232 | "calcs": [], 233 | "displayMode": "list", 234 | "placement": "bottom", 235 | "showLegend": true 236 | }, 237 | "tooltip": { 238 | "hideZeros": false, 239 | "maxHeight": 600, 240 | "mode": "single", 241 | "sort": "none" 242 | } 243 | }, 244 | "pluginVersion": "11.5.2", 245 | "targets": [ 246 | { 247 | "datasource": { 248 | "type": "prometheus", 249 | "uid": "$datasource" 250 | }, 251 | "editorMode": "code", 252 | "expr": "rate(engine_daemon_container_actions_seconds_count{instance=~'$instance'}[10m])", 253 | "instant": false, 254 | "legendFormat": "{{action}}", 255 | "range": true, 256 | "refId": "A" 257 | } 258 | ], 259 | "title": "Container actions", 260 | "type": "timeseries" 261 | }, 262 | { 263 | "datasource": { 264 | "type": "prometheus", 265 | "uid": "$datasource" 266 | }, 267 | "fieldConfig": { 268 | "defaults": { 269 | "color": { 270 | "mode": "thresholds" 271 | }, 272 | "mappings": [], 273 | "thresholds": { 274 | "mode": "absolute", 275 | "steps": [ 276 | { 277 | "color": "green", 278 | "value": null 279 | } 280 | ] 281 | }, 282 | "unit": "decbytes" 283 | }, 284 | "overrides": [] 285 | }, 286 | "gridPos": { 287 | "h": 6, 288 | "w": 6, 289 | "x": 0, 290 | "y": 6 291 | }, 292 | "id": 6, 293 | "options": { 294 | "colorMode": "value", 295 | "graphMode": "none", 296 | "justifyMode": "auto", 297 | "orientation": "auto", 298 | "percentChangeColorMode": "standard", 299 | "reduceOptions": { 300 | "calcs": [ 301 | "lastNotNull" 302 | ], 303 | "fields": "", 304 | "values": false 305 | }, 306 | "showPercentChange": false, 307 | "textMode": "auto", 308 | "wideLayout": true 309 | }, 310 | "pluginVersion": "11.5.2", 311 | "targets": [ 312 | { 313 | "datasource": { 314 | "type": "prometheus", 315 | "uid": "$datasource" 316 | }, 317 | "editorMode": "code", 318 | "expr": "engine_daemon_engine_memory_bytes{instance=~'$instance'}", 319 | "instant": false, 320 | "legendFormat": "__auto", 321 | "range": true, 322 | "refId": "A" 323 | } 324 | ], 325 | "title": "Engine memory", 326 | "type": "stat" 327 | }, 328 | { 329 | "datasource": { 330 | "type": "prometheus", 331 | "uid": "$datasource" 332 | }, 333 | "fieldConfig": { 334 | "defaults": { 335 | "color": { 336 | "mode": "thresholds" 337 | }, 338 | "mappings": [], 339 | "thresholds": { 340 | "mode": "absolute", 341 | "steps": [ 342 | { 343 | "color": "green", 344 | "value": null 345 | }, 346 | { 347 | "color": "red", 348 | "value": 80 349 | } 350 | ] 351 | } 352 | }, 353 | "overrides": [] 354 | }, 355 | "gridPos": { 356 | "h": 6, 357 | "w": 6, 358 | "x": 6, 359 | "y": 6 360 | }, 361 | "id": 3, 362 | "options": { 363 | "colorMode": "value", 364 | "graphMode": "none", 365 | "justifyMode": "auto", 366 | "orientation": "auto", 367 | "percentChangeColorMode": "standard", 368 | "reduceOptions": { 369 | "calcs": [ 370 | "lastNotNull" 371 | ], 372 | "fields": "", 373 | "values": false 374 | }, 375 | "showPercentChange": false, 376 | "textMode": "auto", 377 | "wideLayout": true 378 | }, 379 | "pluginVersion": "11.5.2", 380 | "targets": [ 381 | { 382 | "datasource": { 383 | "type": "prometheus", 384 | "uid": "$datasource" 385 | }, 386 | "editorMode": "code", 387 | "expr": "engine_daemon_container_states_containers{instance=~'$instance',state=\"stopped\"}", 388 | "instant": false, 389 | "legendFormat": "__auto", 390 | "range": true, 391 | "refId": "A" 392 | } 393 | ], 394 | "title": "Stopped container", 395 | "type": "stat" 396 | }, 397 | { 398 | "datasource": { 399 | "type": "prometheus", 400 | "uid": "$datasource" 401 | }, 402 | "fieldConfig": { 403 | "defaults": { 404 | "color": { 405 | "mode": "thresholds" 406 | }, 407 | "mappings": [], 408 | "thresholds": { 409 | "mode": "absolute", 410 | "steps": [ 411 | { 412 | "color": "green", 413 | "value": null 414 | }, 415 | { 416 | "color": "red", 417 | "value": 80 418 | } 419 | ] 420 | } 421 | }, 422 | "overrides": [] 423 | }, 424 | "gridPos": { 425 | "h": 6, 426 | "w": 4, 427 | "x": 12, 428 | "y": 6 429 | }, 430 | "id": 4, 431 | "options": { 432 | "colorMode": "value", 433 | "graphMode": "none", 434 | "justifyMode": "auto", 435 | "orientation": "auto", 436 | "percentChangeColorMode": "standard", 437 | "reduceOptions": { 438 | "calcs": [ 439 | "lastNotNull" 440 | ], 441 | "fields": "", 442 | "values": false 443 | }, 444 | "showPercentChange": false, 445 | "textMode": "auto", 446 | "wideLayout": true 447 | }, 448 | "pluginVersion": "11.5.2", 449 | "targets": [ 450 | { 451 | "datasource": { 452 | "type": "prometheus", 453 | "uid": "$datasource" 454 | }, 455 | "editorMode": "code", 456 | "expr": "engine_daemon_container_states_containers{instance=~'$instance', state=\"paused\"}", 457 | "instant": false, 458 | "legendFormat": "__auto", 459 | "range": true, 460 | "refId": "A" 461 | } 462 | ], 463 | "title": "Paused container", 464 | "type": "stat" 465 | }, 466 | { 467 | "datasource": { 468 | "type": "prometheus", 469 | "uid": "$datasource" 470 | }, 471 | "fieldConfig": { 472 | "defaults": { 473 | "color": { 474 | "mode": "palette-classic" 475 | }, 476 | "custom": { 477 | "axisBorderShow": false, 478 | "axisCenteredZero": false, 479 | "axisColorMode": "text", 480 | "axisLabel": "", 481 | "axisPlacement": "auto", 482 | "barAlignment": 0, 483 | "barWidthFactor": 0.6, 484 | "drawStyle": "line", 485 | "fillOpacity": 25, 486 | "gradientMode": "none", 487 | "hideFrom": { 488 | "legend": false, 489 | "tooltip": false, 490 | "viz": false 491 | }, 492 | "insertNulls": false, 493 | "lineInterpolation": "linear", 494 | "lineWidth": 1, 495 | "pointSize": 5, 496 | "scaleDistribution": { 497 | "type": "linear" 498 | }, 499 | "showPoints": "auto", 500 | "spanNulls": false, 501 | "stacking": { 502 | "group": "A", 503 | "mode": "none" 504 | }, 505 | "thresholdsStyle": { 506 | "mode": "off" 507 | } 508 | }, 509 | "mappings": [], 510 | "thresholds": { 511 | "mode": "absolute", 512 | "steps": [ 513 | { 514 | "color": "green", 515 | "value": null 516 | }, 517 | { 518 | "color": "red", 519 | "value": 80 520 | } 521 | ] 522 | } 523 | }, 524 | "overrides": [] 525 | }, 526 | "gridPos": { 527 | "h": 6, 528 | "w": 4, 529 | "x": 16, 530 | "y": 6 531 | }, 532 | "id": 9, 533 | "options": { 534 | "legend": { 535 | "calcs": [], 536 | "displayMode": "list", 537 | "placement": "bottom", 538 | "showLegend": true 539 | }, 540 | "tooltip": { 541 | "hideZeros": false, 542 | "maxHeight": 600, 543 | "mode": "single", 544 | "sort": "none" 545 | } 546 | }, 547 | "pluginVersion": "11.5.2", 548 | "targets": [ 549 | { 550 | "datasource": { 551 | "type": "prometheus", 552 | "uid": "$datasource" 553 | }, 554 | "editorMode": "code", 555 | "expr": "rate(engine_daemon_network_actions_seconds_count{instance=~'$instance'}[10m])", 556 | "instant": false, 557 | "legendFormat": "{{action}}", 558 | "range": true, 559 | "refId": "A" 560 | } 561 | ], 562 | "title": "Daemon network actions", 563 | "type": "timeseries" 564 | }, 565 | { 566 | "datasource": { 567 | "type": "prometheus", 568 | "uid": "$datasource" 569 | }, 570 | "fieldConfig": { 571 | "defaults": { 572 | "color": { 573 | "mode": "palette-classic" 574 | }, 575 | "custom": { 576 | "axisBorderShow": false, 577 | "axisCenteredZero": false, 578 | "axisColorMode": "text", 579 | "axisLabel": "", 580 | "axisPlacement": "auto", 581 | "barAlignment": 0, 582 | "barWidthFactor": 0.6, 583 | "drawStyle": "line", 584 | "fillOpacity": 25, 585 | "gradientMode": "none", 586 | "hideFrom": { 587 | "legend": false, 588 | "tooltip": false, 589 | "viz": false 590 | }, 591 | "insertNulls": false, 592 | "lineInterpolation": "linear", 593 | "lineWidth": 1, 594 | "pointSize": 5, 595 | "scaleDistribution": { 596 | "type": "linear" 597 | }, 598 | "showPoints": "auto", 599 | "spanNulls": false, 600 | "stacking": { 601 | "group": "A", 602 | "mode": "none" 603 | }, 604 | "thresholdsStyle": { 605 | "mode": "off" 606 | } 607 | }, 608 | "mappings": [], 609 | "thresholds": { 610 | "mode": "absolute", 611 | "steps": [ 612 | { 613 | "color": "green", 614 | "value": null 615 | }, 616 | { 617 | "color": "red", 618 | "value": 80 619 | } 620 | ] 621 | } 622 | }, 623 | "overrides": [] 624 | }, 625 | "gridPos": { 626 | "h": 6, 627 | "w": 4, 628 | "x": 20, 629 | "y": 6 630 | }, 631 | "id": 8, 632 | "options": { 633 | "legend": { 634 | "calcs": [], 635 | "displayMode": "hidden", 636 | "placement": "right", 637 | "showLegend": false 638 | }, 639 | "tooltip": { 640 | "hideZeros": false, 641 | "maxHeight": 600, 642 | "mode": "single", 643 | "sort": "none" 644 | } 645 | }, 646 | "pluginVersion": "11.5.2", 647 | "targets": [ 648 | { 649 | "datasource": { 650 | "type": "prometheus", 651 | "uid": "$datasource" 652 | }, 653 | "editorMode": "code", 654 | "expr": "rate(builder_builds_triggered_total{instance=~'$instance'}[30m])", 655 | "instant": false, 656 | "legendFormat": "__auto", 657 | "range": true, 658 | "refId": "A" 659 | } 660 | ], 661 | "title": "Builds triggered", 662 | "type": "timeseries" 663 | }, 664 | { 665 | "datasource": { 666 | "type": "prometheus", 667 | "uid": "$datasource" 668 | }, 669 | "fieldConfig": { 670 | "defaults": { 671 | "color": { 672 | "mode": "thresholds" 673 | }, 674 | "custom": { 675 | "align": "auto", 676 | "cellOptions": { 677 | "type": "auto" 678 | }, 679 | "inspect": false 680 | }, 681 | "mappings": [], 682 | "thresholds": { 683 | "mode": "absolute", 684 | "steps": [ 685 | { 686 | "color": "green", 687 | "value": null 688 | }, 689 | { 690 | "color": "red", 691 | "value": 80 692 | } 693 | ] 694 | } 695 | }, 696 | "overrides": [] 697 | }, 698 | "gridPos": { 699 | "h": 4, 700 | "w": 24, 701 | "x": 0, 702 | "y": 12 703 | }, 704 | "id": 5, 705 | "options": { 706 | "cellHeight": "sm", 707 | "footer": { 708 | "countRows": false, 709 | "fields": "", 710 | "reducer": [ 711 | "sum" 712 | ], 713 | "show": false 714 | }, 715 | "showHeader": true 716 | }, 717 | "pluginVersion": "11.5.2", 718 | "targets": [ 719 | { 720 | "datasource": { 721 | "type": "prometheus", 722 | "uid": "$datasource" 723 | }, 724 | "editorMode": "code", 725 | "exemplar": false, 726 | "expr": "max(engine_daemon_engine_info{instance=~'$instance'}) by (os, os_type, version)", 727 | "format": "table", 728 | "instant": true, 729 | "legendFormat": "", 730 | "range": false, 731 | "refId": "A" 732 | } 733 | ], 734 | "title": "Info", 735 | "transformations": [ 736 | { 737 | "id": "organize", 738 | "options": { 739 | "excludeByName": { 740 | "Time": true, 741 | "Ubuntu 22.04.3 LTS": false, 742 | "Value": true 743 | }, 744 | "includeByName": {}, 745 | "indexByName": { 746 | "Time": 0, 747 | "Value": 4, 748 | "os": 3, 749 | "os_type": 2, 750 | "version": 1 751 | }, 752 | "renameByName": { 753 | "Ubuntu 22.04.3 LTS": "", 754 | "os": "OS", 755 | "os_type": "OS Type", 756 | "version": "Docker version" 757 | } 758 | } 759 | } 760 | ], 761 | "type": "table" 762 | } 763 | ], 764 | "preload": false, 765 | "refresh": "1m", 766 | "schemaVersion": 40, 767 | "tags": [], 768 | "templating": { 769 | "list": [ 770 | { 771 | "current": { 772 | "text": "host.docker.internal:9323", 773 | "value": "host.docker.internal:9323" 774 | }, 775 | "datasource": { 776 | "type": "prometheus", 777 | "uid": "$datasource" 778 | }, 779 | "definition": "engine_daemon_engine_info", 780 | "includeAll": false, 781 | "label": "instance", 782 | "name": "instance", 783 | "options": [], 784 | "query": { 785 | "qryType": 4, 786 | "query": "engine_daemon_engine_info", 787 | "refId": "PrometheusVariableQueryEditor-VariableQuery" 788 | }, 789 | "refresh": 1, 790 | "regex": "/instance=\"([^\"]+)\"/", 791 | "type": "query" 792 | }, 793 | { 794 | "current": { 795 | "text": "prometheus", 796 | "value": "f6b72a59-10e5-4c3e-bb1e-40557c426097" 797 | }, 798 | "includeAll": false, 799 | "label": "Data Source", 800 | "name": "datasource", 801 | "options": [], 802 | "query": "prometheus", 803 | "refresh": 1, 804 | "regex": "", 805 | "type": "datasource" 806 | } 807 | ] 808 | }, 809 | "time": { 810 | "from": "now-3h", 811 | "to": "now" 812 | }, 813 | "timepicker": {}, 814 | "timezone": "", 815 | "title": "Docker daemon metrics", 816 | "uid": "dockerDaemons", 817 | "version": 2, 818 | "weekStart": "" 819 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published by 637 | the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | -------------------------------------------------------------------------------- /grafana/dashboards/django.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": { 7 | "type": "datasource", 8 | "uid": "grafana" 9 | }, 10 | "enable": true, 11 | "hide": true, 12 | "iconColor": "rgba(0, 211, 255, 1)", 13 | "name": "Annotations & Alerts", 14 | "target": { 15 | "limit": 100, 16 | "matchAny": false, 17 | "tags": [], 18 | "type": "dashboard" 19 | }, 20 | "type": "dashboard" 21 | } 22 | ] 23 | }, 24 | "description": "Django metrics dashboard using django-prometheus metrics exporter", 25 | "editable": true, 26 | "fiscalYearStartMonth": 0, 27 | "graphTooltip": 0, 28 | "id": 5, 29 | "links": [], 30 | "liveNow": true, 31 | "panels": [ 32 | { 33 | "datasource": { 34 | "type": "prometheus", 35 | "uid": "$datasource" 36 | }, 37 | "description": "", 38 | "fieldConfig": { 39 | "defaults": { 40 | "color": { 41 | "mode": "thresholds" 42 | }, 43 | "mappings": [ 44 | { 45 | "options": { 46 | "match": "null", 47 | "result": { 48 | "text": "N/A" 49 | } 50 | }, 51 | "type": "special" 52 | } 53 | ], 54 | "thresholds": { 55 | "mode": "absolute", 56 | "steps": [ 57 | { 58 | "color": "green", 59 | "value": null 60 | }, 61 | { 62 | "color": "red", 63 | "value": 80 64 | } 65 | ] 66 | }, 67 | "unit": "reqps" 68 | }, 69 | "overrides": [] 70 | }, 71 | "gridPos": { 72 | "h": 4, 73 | "w": 6, 74 | "x": 0, 75 | "y": 0 76 | }, 77 | "id": 13, 78 | "maxDataPoints": 100, 79 | "options": { 80 | "colorMode": "none", 81 | "graphMode": "none", 82 | "justifyMode": "auto", 83 | "orientation": "horizontal", 84 | "percentChangeColorMode": "standard", 85 | "reduceOptions": { 86 | "calcs": [ 87 | "mean" 88 | ], 89 | "fields": "", 90 | "values": false 91 | }, 92 | "showPercentChange": false, 93 | "text": { 94 | "valueSize": 40 95 | }, 96 | "textMode": "auto", 97 | "wideLayout": true 98 | }, 99 | "pluginVersion": "11.5.2", 100 | "targets": [ 101 | { 102 | "datasource": { 103 | "uid": "$datasource" 104 | }, 105 | "editorMode": "code", 106 | "expr": "sum(irate(django_http_requests_total_by_transport_total{app=~\"^$application$\"}[$__rate_interval]))", 107 | "format": "time_series", 108 | "intervalFactor": 1, 109 | "range": true, 110 | "refId": "A" 111 | } 112 | ], 113 | "title": "Requests", 114 | "type": "stat" 115 | }, 116 | { 117 | "datasource": { 118 | "type": "prometheus", 119 | "uid": "$datasource" 120 | }, 121 | "fieldConfig": { 122 | "defaults": { 123 | "color": { 124 | "mode": "thresholds" 125 | }, 126 | "decimals": 2, 127 | "mappings": [ 128 | { 129 | "options": { 130 | "match": "null", 131 | "result": { 132 | "text": "N/A" 133 | } 134 | }, 135 | "type": "special" 136 | } 137 | ], 138 | "noValue": "0", 139 | "thresholds": { 140 | "mode": "absolute", 141 | "steps": [ 142 | { 143 | "color": "green", 144 | "value": null 145 | }, 146 | { 147 | "color": "red", 148 | "value": 80 149 | } 150 | ] 151 | }, 152 | "unit": "reqps" 153 | }, 154 | "overrides": [] 155 | }, 156 | "gridPos": { 157 | "h": 2, 158 | "w": 3, 159 | "x": 6, 160 | "y": 0 161 | }, 162 | "id": 15, 163 | "maxDataPoints": 100, 164 | "options": { 165 | "colorMode": "none", 166 | "graphMode": "none", 167 | "justifyMode": "auto", 168 | "orientation": "horizontal", 169 | "percentChangeColorMode": "standard", 170 | "reduceOptions": { 171 | "calcs": [ 172 | "mean" 173 | ], 174 | "fields": "", 175 | "values": false 176 | }, 177 | "showPercentChange": false, 178 | "text": { 179 | "valueSize": 20 180 | }, 181 | "textMode": "auto", 182 | "wideLayout": true 183 | }, 184 | "pluginVersion": "11.5.2", 185 | "targets": [ 186 | { 187 | "datasource": { 188 | "uid": "$datasource" 189 | }, 190 | "editorMode": "code", 191 | "expr": "sum(irate(django_http_responses_total_by_status_total{status=~\"2.+\",app=~\"^$application$\"}[$__rate_interval]))", 192 | "format": "time_series", 193 | "intervalFactor": 1, 194 | "legendFormat": "", 195 | "range": true, 196 | "refId": "A" 197 | } 198 | ], 199 | "title": "2XX Responses", 200 | "type": "stat" 201 | }, 202 | { 203 | "datasource": { 204 | "type": "prometheus", 205 | "uid": "$datasource" 206 | }, 207 | "fieldConfig": { 208 | "defaults": { 209 | "color": { 210 | "mode": "thresholds" 211 | }, 212 | "decimals": 2, 213 | "mappings": [ 214 | { 215 | "options": { 216 | "match": "null", 217 | "result": { 218 | "text": "N/A" 219 | } 220 | }, 221 | "type": "special" 222 | } 223 | ], 224 | "noValue": "0", 225 | "thresholds": { 226 | "mode": "absolute", 227 | "steps": [ 228 | { 229 | "color": "green", 230 | "value": null 231 | }, 232 | { 233 | "color": "red", 234 | "value": 80 235 | } 236 | ] 237 | }, 238 | "unit": "reqps" 239 | }, 240 | "overrides": [] 241 | }, 242 | "gridPos": { 243 | "h": 2, 244 | "w": 3, 245 | "x": 9, 246 | "y": 0 247 | }, 248 | "id": 16, 249 | "maxDataPoints": 100, 250 | "options": { 251 | "colorMode": "none", 252 | "graphMode": "none", 253 | "justifyMode": "auto", 254 | "orientation": "horizontal", 255 | "percentChangeColorMode": "standard", 256 | "reduceOptions": { 257 | "calcs": [ 258 | "mean" 259 | ], 260 | "fields": "", 261 | "values": false 262 | }, 263 | "showPercentChange": false, 264 | "text": { 265 | "valueSize": 20 266 | }, 267 | "textMode": "auto", 268 | "wideLayout": true 269 | }, 270 | "pluginVersion": "11.5.2", 271 | "targets": [ 272 | { 273 | "datasource": { 274 | "uid": "$datasource" 275 | }, 276 | "editorMode": "code", 277 | "expr": "sum(irate(django_http_responses_total_by_status_total{status=~\"4.+\",app=~\"^$application$\"}[$__rate_interval]))", 278 | "format": "time_series", 279 | "intervalFactor": 1, 280 | "legendFormat": "", 281 | "range": true, 282 | "refId": "A" 283 | } 284 | ], 285 | "title": "4XX Responses", 286 | "type": "stat" 287 | }, 288 | { 289 | "datasource": { 290 | "type": "prometheus", 291 | "uid": "PBFA97CFB590B2093" 292 | }, 293 | "fieldConfig": { 294 | "defaults": { 295 | "color": { 296 | "mode": "thresholds" 297 | }, 298 | "mappings": [], 299 | "min": 0, 300 | "noValue": "0", 301 | "thresholds": { 302 | "mode": "absolute", 303 | "steps": [ 304 | { 305 | "color": "green", 306 | "value": null 307 | }, 308 | { 309 | "color": "#EAB839", 310 | "value": 1 311 | }, 312 | { 313 | "color": "red", 314 | "value": 10 315 | } 316 | ] 317 | } 318 | }, 319 | "overrides": [] 320 | }, 321 | "gridPos": { 322 | "h": 4, 323 | "w": 3, 324 | "x": 12, 325 | "y": 0 326 | }, 327 | "id": 37, 328 | "options": { 329 | "minVizHeight": 75, 330 | "minVizWidth": 75, 331 | "orientation": "auto", 332 | "reduceOptions": { 333 | "calcs": [ 334 | "lastNotNull" 335 | ], 336 | "fields": "", 337 | "values": false 338 | }, 339 | "showThresholdLabels": false, 340 | "showThresholdMarkers": true, 341 | "sizing": "auto" 342 | }, 343 | "pluginVersion": "11.5.2", 344 | "targets": [ 345 | { 346 | "datasource": { 347 | "type": "prometheus", 348 | "uid": "PBFA97CFB590B2093" 349 | }, 350 | "editorMode": "code", 351 | "exemplar": false, 352 | "expr": "sum(max_over_time(django_db_errors_total{app=~\"^$application$\"}[$__range]))", 353 | "format": "time_series", 354 | "instant": false, 355 | "legendFormat": "__auto", 356 | "range": true, 357 | "refId": "A" 358 | } 359 | ], 360 | "title": "DB Query Errors", 361 | "type": "gauge" 362 | }, 363 | { 364 | "datasource": { 365 | "type": "prometheus", 366 | "uid": "PBFA97CFB590B2093" 367 | }, 368 | "fieldConfig": { 369 | "defaults": { 370 | "color": { 371 | "mode": "thresholds" 372 | }, 373 | "mappings": [], 374 | "min": 0, 375 | "noValue": "0", 376 | "thresholds": { 377 | "mode": "absolute", 378 | "steps": [ 379 | { 380 | "color": "green", 381 | "value": null 382 | }, 383 | { 384 | "color": "#EAB839", 385 | "value": 1 386 | }, 387 | { 388 | "color": "red", 389 | "value": 5 390 | } 391 | ] 392 | } 393 | }, 394 | "overrides": [] 395 | }, 396 | "gridPos": { 397 | "h": 4, 398 | "w": 3, 399 | "x": 15, 400 | "y": 0 401 | }, 402 | "id": 38, 403 | "options": { 404 | "minVizHeight": 75, 405 | "minVizWidth": 75, 406 | "orientation": "auto", 407 | "reduceOptions": { 408 | "calcs": [ 409 | "lastNotNull" 410 | ], 411 | "fields": "", 412 | "values": false 413 | }, 414 | "showThresholdLabels": false, 415 | "showThresholdMarkers": true, 416 | "sizing": "auto" 417 | }, 418 | "pluginVersion": "11.5.2", 419 | "targets": [ 420 | { 421 | "datasource": { 422 | "type": "prometheus", 423 | "uid": "PBFA97CFB590B2093" 424 | }, 425 | "editorMode": "code", 426 | "expr": "sum(max_over_time(django_db_new_connection_errors_total{app=~\"^$application$\"}[$__range]))", 427 | "legendFormat": "__auto", 428 | "range": true, 429 | "refId": "A" 430 | } 431 | ], 432 | "title": "DB Connection Errors", 433 | "type": "gauge" 434 | }, 435 | { 436 | "datasource": { 437 | "type": "prometheus", 438 | "uid": "PBFA97CFB590B2093" 439 | }, 440 | "fieldConfig": { 441 | "defaults": { 442 | "color": { 443 | "mode": "thresholds" 444 | }, 445 | "decimals": 0, 446 | "mappings": [], 447 | "max": 1, 448 | "min": 0, 449 | "thresholds": { 450 | "mode": "absolute", 451 | "steps": [ 452 | { 453 | "color": "red", 454 | "value": null 455 | }, 456 | { 457 | "color": "yellow", 458 | "value": 0.4 459 | }, 460 | { 461 | "color": "green", 462 | "value": 0.7 463 | } 464 | ] 465 | }, 466 | "unit": "percentunit" 467 | }, 468 | "overrides": [] 469 | }, 470 | "gridPos": { 471 | "h": 4, 472 | "w": 6, 473 | "x": 18, 474 | "y": 0 475 | }, 476 | "id": 31, 477 | "options": { 478 | "minVizHeight": 75, 479 | "minVizWidth": 75, 480 | "orientation": "auto", 481 | "reduceOptions": { 482 | "calcs": [ 483 | "lastNotNull" 484 | ], 485 | "fields": "", 486 | "values": false 487 | }, 488 | "showThresholdLabels": false, 489 | "showThresholdMarkers": true, 490 | "sizing": "auto" 491 | }, 492 | "pluginVersion": "11.5.2", 493 | "targets": [ 494 | { 495 | "datasource": { 496 | "type": "prometheus", 497 | "uid": "PBFA97CFB590B2093" 498 | }, 499 | "editorMode": "code", 500 | "expr": "sum(django_cache_get_hits_total{app=~\"^$application$\"}) by (backend) / sum(django_cache_get_total{app=~\"^$application$\"}) by (backend)", 501 | "legendFormat": "__auto", 502 | "range": true, 503 | "refId": "A" 504 | } 505 | ], 506 | "title": "Cache Hit Ratio", 507 | "type": "gauge" 508 | }, 509 | { 510 | "datasource": { 511 | "type": "prometheus", 512 | "uid": "$datasource" 513 | }, 514 | "fieldConfig": { 515 | "defaults": { 516 | "color": { 517 | "mode": "thresholds" 518 | }, 519 | "decimals": 2, 520 | "mappings": [ 521 | { 522 | "options": { 523 | "match": "null", 524 | "result": { 525 | "text": "N/A" 526 | } 527 | }, 528 | "type": "special" 529 | } 530 | ], 531 | "noValue": "0", 532 | "thresholds": { 533 | "mode": "absolute", 534 | "steps": [ 535 | { 536 | "color": "green", 537 | "value": null 538 | }, 539 | { 540 | "color": "red", 541 | "value": 80 542 | } 543 | ] 544 | }, 545 | "unit": "reqps" 546 | }, 547 | "overrides": [] 548 | }, 549 | "gridPos": { 550 | "h": 2, 551 | "w": 3, 552 | "x": 6, 553 | "y": 2 554 | }, 555 | "id": 23, 556 | "maxDataPoints": 100, 557 | "options": { 558 | "colorMode": "none", 559 | "graphMode": "none", 560 | "justifyMode": "auto", 561 | "orientation": "horizontal", 562 | "percentChangeColorMode": "standard", 563 | "reduceOptions": { 564 | "calcs": [ 565 | "mean" 566 | ], 567 | "fields": "", 568 | "values": false 569 | }, 570 | "showPercentChange": false, 571 | "text": { 572 | "valueSize": 20 573 | }, 574 | "textMode": "auto", 575 | "wideLayout": true 576 | }, 577 | "pluginVersion": "11.5.2", 578 | "targets": [ 579 | { 580 | "datasource": { 581 | "uid": "$datasource" 582 | }, 583 | "editorMode": "code", 584 | "expr": "sum(irate(django_http_responses_total_by_status_total{status=~\"3.+\",app=~\"^$application$\"}[$__rate_interval]))", 585 | "format": "time_series", 586 | "intervalFactor": 1, 587 | "legendFormat": "", 588 | "range": true, 589 | "refId": "A" 590 | } 591 | ], 592 | "title": "3XX Responses", 593 | "type": "stat" 594 | }, 595 | { 596 | "datasource": { 597 | "type": "prometheus", 598 | "uid": "$datasource" 599 | }, 600 | "fieldConfig": { 601 | "defaults": { 602 | "color": { 603 | "mode": "thresholds" 604 | }, 605 | "decimals": 2, 606 | "mappings": [ 607 | { 608 | "options": { 609 | "match": "null", 610 | "result": { 611 | "text": "N/A" 612 | } 613 | }, 614 | "type": "special" 615 | } 616 | ], 617 | "noValue": "0", 618 | "thresholds": { 619 | "mode": "absolute", 620 | "steps": [ 621 | { 622 | "color": "green", 623 | "value": null 624 | }, 625 | { 626 | "color": "red", 627 | "value": 80 628 | } 629 | ] 630 | }, 631 | "unit": "reqps" 632 | }, 633 | "overrides": [] 634 | }, 635 | "gridPos": { 636 | "h": 2, 637 | "w": 3, 638 | "x": 9, 639 | "y": 2 640 | }, 641 | "id": 17, 642 | "maxDataPoints": 100, 643 | "options": { 644 | "colorMode": "none", 645 | "graphMode": "none", 646 | "justifyMode": "auto", 647 | "orientation": "horizontal", 648 | "percentChangeColorMode": "standard", 649 | "reduceOptions": { 650 | "calcs": [ 651 | "mean" 652 | ], 653 | "fields": "", 654 | "values": false 655 | }, 656 | "showPercentChange": false, 657 | "text": { 658 | "valueSize": 20 659 | }, 660 | "textMode": "auto", 661 | "wideLayout": true 662 | }, 663 | "pluginVersion": "11.5.2", 664 | "targets": [ 665 | { 666 | "datasource": { 667 | "uid": "$datasource" 668 | }, 669 | "editorMode": "code", 670 | "expr": "sum(irate(django_http_responses_total_by_status_total{status=~\"5.+\",app=~\"^$application$\"}[$__rate_interval]))", 671 | "format": "time_series", 672 | "intervalFactor": 1, 673 | "legendFormat": "", 674 | "range": true, 675 | "refId": "A" 676 | } 677 | ], 678 | "title": "5XX Responses", 679 | "type": "stat" 680 | }, 681 | { 682 | "datasource": { 683 | "type": "prometheus", 684 | "uid": "PBFA97CFB590B2093" 685 | }, 686 | "description": "", 687 | "fieldConfig": { 688 | "defaults": { 689 | "custom": { 690 | "hideFrom": { 691 | "legend": false, 692 | "tooltip": false, 693 | "viz": false 694 | }, 695 | "scaleDistribution": { 696 | "type": "linear" 697 | } 698 | } 699 | }, 700 | "overrides": [] 701 | }, 702 | "gridPos": { 703 | "h": 8, 704 | "w": 12, 705 | "x": 0, 706 | "y": 4 707 | }, 708 | "id": 20, 709 | "options": { 710 | "calculate": false, 711 | "cellGap": 1, 712 | "cellValues": { 713 | "unit": "reqps" 714 | }, 715 | "color": { 716 | "exponent": 0.5, 717 | "fill": "dark-orange", 718 | "mode": "scheme", 719 | "reverse": false, 720 | "scale": "exponential", 721 | "scheme": "Spectral", 722 | "steps": 64 723 | }, 724 | "exemplars": { 725 | "color": "rgba(255,0,255,0.7)" 726 | }, 727 | "filterValues": { 728 | "le": 1e-9 729 | }, 730 | "legend": { 731 | "show": true 732 | }, 733 | "rowsFrame": { 734 | "layout": "auto", 735 | "value": "Responses" 736 | }, 737 | "tooltip": { 738 | "mode": "single", 739 | "showColorScale": false, 740 | "yHistogram": true 741 | }, 742 | "yAxis": { 743 | "axisPlacement": "left", 744 | "decimals": 0, 745 | "reverse": false, 746 | "unit": "s" 747 | } 748 | }, 749 | "pluginVersion": "11.5.2", 750 | "targets": [ 751 | { 752 | "datasource": { 753 | "type": "prometheus", 754 | "uid": "PBFA97CFB590B2093" 755 | }, 756 | "editorMode": "code", 757 | "expr": "sum(rate(django_http_requests_latency_including_middlewares_seconds_bucket{app=~\"^$application$\"}[$__rate_interval])) by (le)", 758 | "format": "heatmap", 759 | "interval": "", 760 | "legendFormat": "{{le}}", 761 | "range": true, 762 | "refId": "A" 763 | } 764 | ], 765 | "title": "Number of Requests by Processing Time", 766 | "type": "heatmap" 767 | }, 768 | { 769 | "datasource": { 770 | "type": "prometheus", 771 | "uid": "PBFA97CFB590B2093" 772 | }, 773 | "description": "", 774 | "fieldConfig": { 775 | "defaults": { 776 | "custom": { 777 | "hideFrom": { 778 | "legend": false, 779 | "tooltip": false, 780 | "viz": false 781 | }, 782 | "scaleDistribution": { 783 | "type": "linear" 784 | } 785 | } 786 | }, 787 | "overrides": [] 788 | }, 789 | "gridPos": { 790 | "h": 8, 791 | "w": 12, 792 | "x": 12, 793 | "y": 4 794 | }, 795 | "id": 22, 796 | "options": { 797 | "calculate": false, 798 | "cellGap": 1, 799 | "cellValues": { 800 | "unit": "reqps" 801 | }, 802 | "color": { 803 | "exponent": 0.5, 804 | "fill": "dark-orange", 805 | "mode": "scheme", 806 | "reverse": false, 807 | "scale": "exponential", 808 | "scheme": "Spectral", 809 | "steps": 64 810 | }, 811 | "exemplars": { 812 | "color": "rgba(255,0,255,0.7)" 813 | }, 814 | "filterValues": { 815 | "le": 1e-9 816 | }, 817 | "legend": { 818 | "show": true 819 | }, 820 | "rowsFrame": { 821 | "layout": "auto", 822 | "value": "Responses" 823 | }, 824 | "tooltip": { 825 | "mode": "single", 826 | "showColorScale": false, 827 | "yHistogram": true 828 | }, 829 | "yAxis": { 830 | "axisPlacement": "left", 831 | "decimals": 0, 832 | "reverse": false, 833 | "unit": "bytes" 834 | } 835 | }, 836 | "pluginVersion": "11.5.2", 837 | "targets": [ 838 | { 839 | "datasource": { 840 | "type": "prometheus", 841 | "uid": "PBFA97CFB590B2093" 842 | }, 843 | "editorMode": "code", 844 | "exemplar": false, 845 | "expr": "sum(rate(django_http_responses_body_total_bytes_bucket{app=~\"^$application$\"}[$__rate_interval])) by (le)", 846 | "format": "heatmap", 847 | "instant": false, 848 | "interval": "", 849 | "legendFormat": "{{le}}", 850 | "range": true, 851 | "refId": "A" 852 | } 853 | ], 854 | "title": "Number of Responses by Size", 855 | "type": "heatmap" 856 | }, 857 | { 858 | "datasource": { 859 | "type": "prometheus", 860 | "uid": "$datasource" 861 | }, 862 | "fieldConfig": { 863 | "defaults": { 864 | "color": { 865 | "mode": "palette-classic" 866 | }, 867 | "custom": { 868 | "axisBorderShow": false, 869 | "axisCenteredZero": false, 870 | "axisColorMode": "text", 871 | "axisLabel": "", 872 | "axisPlacement": "auto", 873 | "barAlignment": 0, 874 | "barWidthFactor": 0.6, 875 | "drawStyle": "line", 876 | "fillOpacity": 10, 877 | "gradientMode": "none", 878 | "hideFrom": { 879 | "legend": false, 880 | "tooltip": false, 881 | "viz": false 882 | }, 883 | "insertNulls": false, 884 | "lineInterpolation": "linear", 885 | "lineWidth": 1, 886 | "pointSize": 5, 887 | "scaleDistribution": { 888 | "linearThreshold": 1, 889 | "log": 2, 890 | "type": "log" 891 | }, 892 | "showPoints": "never", 893 | "spanNulls": false, 894 | "stacking": { 895 | "group": "A", 896 | "mode": "none" 897 | }, 898 | "thresholdsStyle": { 899 | "mode": "dashed" 900 | } 901 | }, 902 | "mappings": [], 903 | "thresholds": { 904 | "mode": "absolute", 905 | "steps": [ 906 | { 907 | "color": "green", 908 | "value": null 909 | }, 910 | { 911 | "color": "red", 912 | "value": 1 913 | } 914 | ] 915 | }, 916 | "unit": "s" 917 | }, 918 | "overrides": [] 919 | }, 920 | "gridPos": { 921 | "h": 8, 922 | "w": 12, 923 | "x": 0, 924 | "y": 12 925 | }, 926 | "id": 4, 927 | "interval": "30s", 928 | "options": { 929 | "legend": { 930 | "calcs": [], 931 | "displayMode": "list", 932 | "placement": "bottom", 933 | "showLegend": true 934 | }, 935 | "tooltip": { 936 | "hideZeros": false, 937 | "mode": "multi", 938 | "sort": "none" 939 | } 940 | }, 941 | "pluginVersion": "11.5.2", 942 | "targets": [ 943 | { 944 | "datasource": { 945 | "uid": "$datasource" 946 | }, 947 | "editorMode": "code", 948 | "expr": "histogram_quantile(0.50, sum(irate(django_http_requests_latency_seconds_by_view_method_bucket{app=~\"^$application$\"}[$__rate_interval])) by (le))", 949 | "format": "time_series", 950 | "interval": "", 951 | "intervalFactor": 1, 952 | "legendFormat": "50 quantile", 953 | "range": true, 954 | "refId": "A" 955 | }, 956 | { 957 | "datasource": { 958 | "uid": "$datasource" 959 | }, 960 | "editorMode": "code", 961 | "expr": "histogram_quantile(0.95, sum(irate(django_http_requests_latency_seconds_by_view_method_bucket{app=~\"^$application$\"}[$__rate_interval])) by (le))", 962 | "format": "time_series", 963 | "hide": false, 964 | "interval": "", 965 | "intervalFactor": 1, 966 | "legendFormat": "95 quantile", 967 | "range": true, 968 | "refId": "B" 969 | }, 970 | { 971 | "datasource": { 972 | "uid": "$datasource" 973 | }, 974 | "editorMode": "code", 975 | "expr": "histogram_quantile(0.99, sum(irate(django_http_requests_latency_seconds_by_view_method_bucket{app=~\"^$application$\"}[$__rate_interval])) by (le))", 976 | "format": "time_series", 977 | "hide": false, 978 | "interval": "", 979 | "intervalFactor": 1, 980 | "legendFormat": "99 quantile", 981 | "range": true, 982 | "refId": "C" 983 | } 984 | ], 985 | "title": "Request Latency", 986 | "type": "timeseries" 987 | }, 988 | { 989 | "datasource": { 990 | "type": "prometheus", 991 | "uid": "$datasource" 992 | }, 993 | "fieldConfig": { 994 | "defaults": { 995 | "color": { 996 | "mode": "palette-classic" 997 | }, 998 | "custom": { 999 | "axisBorderShow": false, 1000 | "axisCenteredZero": false, 1001 | "axisColorMode": "text", 1002 | "axisLabel": "", 1003 | "axisPlacement": "auto", 1004 | "barAlignment": 0, 1005 | "barWidthFactor": 0.6, 1006 | "drawStyle": "line", 1007 | "fillOpacity": 10, 1008 | "gradientMode": "none", 1009 | "hideFrom": { 1010 | "legend": false, 1011 | "tooltip": false, 1012 | "viz": false 1013 | }, 1014 | "insertNulls": false, 1015 | "lineInterpolation": "linear", 1016 | "lineWidth": 1, 1017 | "pointSize": 5, 1018 | "scaleDistribution": { 1019 | "type": "linear" 1020 | }, 1021 | "showPoints": "never", 1022 | "spanNulls": false, 1023 | "stacking": { 1024 | "group": "A", 1025 | "mode": "none" 1026 | }, 1027 | "thresholdsStyle": { 1028 | "mode": "off" 1029 | } 1030 | }, 1031 | "decimals": 2, 1032 | "mappings": [], 1033 | "thresholds": { 1034 | "mode": "absolute", 1035 | "steps": [ 1036 | { 1037 | "color": "green", 1038 | "value": null 1039 | }, 1040 | { 1041 | "color": "red", 1042 | "value": 80 1043 | } 1044 | ] 1045 | }, 1046 | "unit": "reqps" 1047 | }, 1048 | "overrides": [] 1049 | }, 1050 | "gridPos": { 1051 | "h": 8, 1052 | "w": 12, 1053 | "x": 12, 1054 | "y": 12 1055 | }, 1056 | "id": 11, 1057 | "interval": "30s", 1058 | "options": { 1059 | "legend": { 1060 | "calcs": [ 1061 | "mean", 1062 | "max" 1063 | ], 1064 | "displayMode": "table", 1065 | "placement": "right", 1066 | "showLegend": true 1067 | }, 1068 | "tooltip": { 1069 | "hideZeros": false, 1070 | "mode": "multi", 1071 | "sort": "none" 1072 | } 1073 | }, 1074 | "pluginVersion": "11.5.2", 1075 | "targets": [ 1076 | { 1077 | "datasource": { 1078 | "uid": "$datasource" 1079 | }, 1080 | "editorMode": "code", 1081 | "expr": "sum(irate(django_http_responses_total_by_status_total{app=~\"^$application$\"}[$__rate_interval])) by(status)", 1082 | "format": "time_series", 1083 | "interval": "", 1084 | "intervalFactor": 1, 1085 | "legendFormat": "{{status}}", 1086 | "range": true, 1087 | "refId": "A" 1088 | } 1089 | ], 1090 | "title": "Response Status", 1091 | "type": "timeseries" 1092 | }, 1093 | { 1094 | "datasource": { 1095 | "type": "prometheus", 1096 | "uid": "PBFA97CFB590B2093" 1097 | }, 1098 | "description": "", 1099 | "fieldConfig": { 1100 | "defaults": { 1101 | "color": { 1102 | "mode": "thresholds" 1103 | }, 1104 | "decimals": 0, 1105 | "mappings": [], 1106 | "max": 1, 1107 | "min": 0, 1108 | "thresholds": { 1109 | "mode": "absolute", 1110 | "steps": [ 1111 | { 1112 | "color": "green", 1113 | "value": null 1114 | }, 1115 | { 1116 | "color": "#EAB839", 1117 | "value": 0.3 1118 | }, 1119 | { 1120 | "color": "red", 1121 | "value": 0.6 1122 | } 1123 | ] 1124 | }, 1125 | "unit": "percentunit" 1126 | }, 1127 | "overrides": [] 1128 | }, 1129 | "gridPos": { 1130 | "h": 8, 1131 | "w": 12, 1132 | "x": 0, 1133 | "y": 20 1134 | }, 1135 | "id": 25, 1136 | "options": { 1137 | "displayMode": "gradient", 1138 | "legend": { 1139 | "calcs": [], 1140 | "displayMode": "list", 1141 | "placement": "bottom", 1142 | "showLegend": false 1143 | }, 1144 | "maxVizHeight": 300, 1145 | "minVizHeight": 10, 1146 | "minVizWidth": 0, 1147 | "namePlacement": "auto", 1148 | "orientation": "horizontal", 1149 | "reduceOptions": { 1150 | "calcs": [ 1151 | "sum" 1152 | ], 1153 | "fields": "", 1154 | "limit": 20, 1155 | "values": true 1156 | }, 1157 | "showUnfilled": true, 1158 | "sizing": "auto", 1159 | "text": {}, 1160 | "valueMode": "color" 1161 | }, 1162 | "pluginVersion": "11.5.2", 1163 | "targets": [ 1164 | { 1165 | "datasource": { 1166 | "type": "prometheus", 1167 | "uid": "PBFA97CFB590B2093" 1168 | }, 1169 | "editorMode": "code", 1170 | "exemplar": false, 1171 | "expr": "topk(20, (1 - (sum(max_over_time(django_http_requests_latency_seconds_by_view_method_bucket{app=~\"^$application$\",le=\"$threshold\"}[$__range]) / ignoring(le) max_over_time(django_http_requests_latency_seconds_by_view_method_count{app=~\"^$application$\"}[$__range])) by (method, view) / count(present_over_time(django_http_requests_latency_seconds_by_view_method_count{app=~\"^$application$\"}[$__range])) by (method, view))) > 0.0099)", 1172 | "format": "table", 1173 | "instant": true, 1174 | "interval": "", 1175 | "legendFormat": "{{method}} {{view}}", 1176 | "range": false, 1177 | "refId": "A" 1178 | } 1179 | ], 1180 | "title": "Top 20 Views by Response Time (> $threshold)", 1181 | "type": "bargauge" 1182 | }, 1183 | { 1184 | "datasource": { 1185 | "type": "prometheus", 1186 | "uid": "$datasource" 1187 | }, 1188 | "description": "", 1189 | "fieldConfig": { 1190 | "defaults": { 1191 | "color": { 1192 | "mode": "palette-classic" 1193 | }, 1194 | "custom": { 1195 | "axisBorderShow": false, 1196 | "axisCenteredZero": false, 1197 | "axisColorMode": "text", 1198 | "axisLabel": "", 1199 | "axisPlacement": "auto", 1200 | "barAlignment": 0, 1201 | "barWidthFactor": 0.6, 1202 | "drawStyle": "line", 1203 | "fillOpacity": 10, 1204 | "gradientMode": "none", 1205 | "hideFrom": { 1206 | "legend": false, 1207 | "tooltip": false, 1208 | "viz": false 1209 | }, 1210 | "insertNulls": false, 1211 | "lineInterpolation": "linear", 1212 | "lineWidth": 1, 1213 | "pointSize": 5, 1214 | "scaleDistribution": { 1215 | "type": "linear" 1216 | }, 1217 | "showPoints": "never", 1218 | "spanNulls": false, 1219 | "stacking": { 1220 | "group": "A", 1221 | "mode": "none" 1222 | }, 1223 | "thresholdsStyle": { 1224 | "mode": "off" 1225 | } 1226 | }, 1227 | "decimals": 2, 1228 | "mappings": [], 1229 | "thresholds": { 1230 | "mode": "absolute", 1231 | "steps": [ 1232 | { 1233 | "color": "green", 1234 | "value": null 1235 | }, 1236 | { 1237 | "color": "red", 1238 | "value": 80 1239 | } 1240 | ] 1241 | }, 1242 | "unit": "reqps" 1243 | }, 1244 | "overrides": [] 1245 | }, 1246 | "gridPos": { 1247 | "h": 8, 1248 | "w": 12, 1249 | "x": 12, 1250 | "y": 20 1251 | }, 1252 | "id": 2, 1253 | "interval": "30s", 1254 | "options": { 1255 | "legend": { 1256 | "calcs": [ 1257 | "mean", 1258 | "max" 1259 | ], 1260 | "displayMode": "table", 1261 | "placement": "right", 1262 | "showLegend": true, 1263 | "sortBy": "Mean", 1264 | "sortDesc": true 1265 | }, 1266 | "tooltip": { 1267 | "hideZeros": false, 1268 | "mode": "multi", 1269 | "sort": "none" 1270 | } 1271 | }, 1272 | "pluginVersion": "11.5.2", 1273 | "targets": [ 1274 | { 1275 | "datasource": { 1276 | "uid": "$datasource" 1277 | }, 1278 | "editorMode": "code", 1279 | "exemplar": false, 1280 | "expr": "topk(10, sum(irate(django_http_requests_total_by_view_transport_method_total{app=~\"^$application$\",view!~\"prometheus-django-metrics|healthcheck|.*shop_product_import_1c_status\"}[$__rate_interval])) by(method, view) > 0)", 1281 | "format": "time_series", 1282 | "hide": false, 1283 | "instant": false, 1284 | "interval": "", 1285 | "intervalFactor": 1, 1286 | "legendFormat": "{{method}} /{{view}}", 1287 | "range": true, 1288 | "refId": "A" 1289 | } 1290 | ], 1291 | "title": "Top Requests", 1292 | "type": "timeseries" 1293 | }, 1294 | { 1295 | "datasource": { 1296 | "type": "prometheus", 1297 | "uid": "PBFA97CFB590B2093" 1298 | }, 1299 | "fieldConfig": { 1300 | "defaults": { 1301 | "color": { 1302 | "mode": "palette-classic" 1303 | }, 1304 | "custom": { 1305 | "axisBorderShow": false, 1306 | "axisCenteredZero": false, 1307 | "axisColorMode": "text", 1308 | "axisLabel": "", 1309 | "axisPlacement": "auto", 1310 | "barAlignment": 0, 1311 | "barWidthFactor": 0.6, 1312 | "drawStyle": "line", 1313 | "fillOpacity": 0, 1314 | "gradientMode": "none", 1315 | "hideFrom": { 1316 | "legend": false, 1317 | "tooltip": false, 1318 | "viz": false 1319 | }, 1320 | "insertNulls": false, 1321 | "lineInterpolation": "linear", 1322 | "lineWidth": 1, 1323 | "pointSize": 5, 1324 | "scaleDistribution": { 1325 | "type": "linear" 1326 | }, 1327 | "showPoints": "auto", 1328 | "spanNulls": false, 1329 | "stacking": { 1330 | "group": "A", 1331 | "mode": "none" 1332 | }, 1333 | "thresholdsStyle": { 1334 | "mode": "off" 1335 | } 1336 | }, 1337 | "mappings": [], 1338 | "thresholds": { 1339 | "mode": "absolute", 1340 | "steps": [ 1341 | { 1342 | "color": "green", 1343 | "value": null 1344 | }, 1345 | { 1346 | "color": "red", 1347 | "value": 80 1348 | } 1349 | ] 1350 | }, 1351 | "unit": "ops" 1352 | }, 1353 | "overrides": [] 1354 | }, 1355 | "gridPos": { 1356 | "h": 8, 1357 | "w": 12, 1358 | "x": 0, 1359 | "y": 28 1360 | }, 1361 | "id": 35, 1362 | "options": { 1363 | "legend": { 1364 | "calcs": [], 1365 | "displayMode": "list", 1366 | "placement": "bottom", 1367 | "showLegend": false 1368 | }, 1369 | "tooltip": { 1370 | "hideZeros": false, 1371 | "mode": "single", 1372 | "sort": "none" 1373 | } 1374 | }, 1375 | "pluginVersion": "11.5.2", 1376 | "targets": [ 1377 | { 1378 | "datasource": { 1379 | "type": "prometheus", 1380 | "uid": "PBFA97CFB590B2093" 1381 | }, 1382 | "editorMode": "code", 1383 | "expr": "sum(irate(django_db_execute_total{app=~\"^$application$\"}[$__rate_interval])) by (vendor)", 1384 | "legendFormat": "__auto", 1385 | "range": true, 1386 | "refId": "A" 1387 | } 1388 | ], 1389 | "title": "Database Total Queries", 1390 | "type": "timeseries" 1391 | }, 1392 | { 1393 | "datasource": { 1394 | "type": "prometheus", 1395 | "uid": "PBFA97CFB590B2093" 1396 | }, 1397 | "fieldConfig": { 1398 | "defaults": { 1399 | "custom": { 1400 | "hideFrom": { 1401 | "legend": false, 1402 | "tooltip": false, 1403 | "viz": false 1404 | }, 1405 | "scaleDistribution": { 1406 | "type": "linear" 1407 | } 1408 | } 1409 | }, 1410 | "overrides": [] 1411 | }, 1412 | "gridPos": { 1413 | "h": 8, 1414 | "w": 12, 1415 | "x": 12, 1416 | "y": 28 1417 | }, 1418 | "id": 33, 1419 | "options": { 1420 | "calculate": false, 1421 | "cellGap": 1, 1422 | "cellValues": { 1423 | "unit": "ops" 1424 | }, 1425 | "color": { 1426 | "exponent": 0.5, 1427 | "fill": "dark-orange", 1428 | "mode": "scheme", 1429 | "reverse": false, 1430 | "scale": "exponential", 1431 | "scheme": "Spectral", 1432 | "steps": 64 1433 | }, 1434 | "exemplars": { 1435 | "color": "rgba(255,0,255,0.7)" 1436 | }, 1437 | "filterValues": { 1438 | "le": 1e-9 1439 | }, 1440 | "legend": { 1441 | "show": true 1442 | }, 1443 | "rowsFrame": { 1444 | "layout": "auto" 1445 | }, 1446 | "tooltip": { 1447 | "mode": "single", 1448 | "showColorScale": false, 1449 | "yHistogram": true 1450 | }, 1451 | "yAxis": { 1452 | "axisPlacement": "left", 1453 | "decimals": 0, 1454 | "reverse": false, 1455 | "unit": "s" 1456 | } 1457 | }, 1458 | "pluginVersion": "11.5.2", 1459 | "targets": [ 1460 | { 1461 | "datasource": { 1462 | "type": "prometheus", 1463 | "uid": "PBFA97CFB590B2093" 1464 | }, 1465 | "editorMode": "code", 1466 | "expr": "sum(rate(django_db_query_duration_seconds_bucket{app=~\"^$application$\"}[$__rate_interval])) by (le)", 1467 | "format": "heatmap", 1468 | "legendFormat": "{{le}}", 1469 | "range": true, 1470 | "refId": "A" 1471 | } 1472 | ], 1473 | "title": "Database Query Duration", 1474 | "type": "heatmap" 1475 | } 1476 | ], 1477 | "preload": false, 1478 | "refresh": "30s", 1479 | "schemaVersion": 40, 1480 | "tags": [ 1481 | "Web", 1482 | "Django", 1483 | "Database", 1484 | "Cache" 1485 | ], 1486 | "templating": { 1487 | "list": [ 1488 | { 1489 | "current": { 1490 | "text": "Prometheus", 1491 | "value": "PBFA97CFB590B2093" 1492 | }, 1493 | "includeAll": false, 1494 | "name": "datasource", 1495 | "options": [], 1496 | "query": "prometheus", 1497 | "refresh": 1, 1498 | "regex": "", 1499 | "type": "datasource" 1500 | }, 1501 | { 1502 | "current": { 1503 | "text": "All", 1504 | "value": "$__all" 1505 | }, 1506 | "datasource": { 1507 | "type": "prometheus", 1508 | "uid": "$datasource" 1509 | }, 1510 | "definition": "label_values(python_info,app)", 1511 | "includeAll": true, 1512 | "label": "application", 1513 | "name": "application", 1514 | "options": [], 1515 | "query": { 1516 | "query": "label_values(python_info,app)", 1517 | "refId": "StandardVariableQuery" 1518 | }, 1519 | "refresh": 1, 1520 | "regex": "", 1521 | "type": "query" 1522 | }, 1523 | { 1524 | "current": { 1525 | "text": "1.0", 1526 | "value": "1.0" 1527 | }, 1528 | "description": "Request duration threshold", 1529 | "includeAll": false, 1530 | "label": "threshold", 1531 | "name": "threshold", 1532 | "options": [ 1533 | { 1534 | "selected": false, 1535 | "text": "100ms", 1536 | "value": "0.1" 1537 | }, 1538 | { 1539 | "selected": false, 1540 | "text": "250ms", 1541 | "value": "0.25" 1542 | }, 1543 | { 1544 | "selected": false, 1545 | "text": "500ms", 1546 | "value": "0.5" 1547 | }, 1548 | { 1549 | "selected": false, 1550 | "text": "750ms", 1551 | "value": "0.75" 1552 | }, 1553 | { 1554 | "selected": true, 1555 | "text": "1s", 1556 | "value": "1.0" 1557 | }, 1558 | { 1559 | "selected": false, 1560 | "text": "2.5s", 1561 | "value": "2.5" 1562 | }, 1563 | { 1564 | "selected": false, 1565 | "text": "5s", 1566 | "value": "5.0" 1567 | }, 1568 | { 1569 | "selected": false, 1570 | "text": "7.5s", 1571 | "value": "7.5" 1572 | }, 1573 | { 1574 | "selected": false, 1575 | "text": "10s", 1576 | "value": "10.0" 1577 | }, 1578 | { 1579 | "selected": false, 1580 | "text": "25s", 1581 | "value": "25.0" 1582 | } 1583 | ], 1584 | "query": "100ms : 0.1, 250ms : 0.25, 500ms : 0.5, 750ms : 0.75, 1s : 1.0, 2.5s : 2.5, 5s : 5.0, 7.5s : 7.5, 10s : 10.0, 25s : 25.0", 1585 | "type": "custom" 1586 | } 1587 | ] 1588 | }, 1589 | "time": { 1590 | "from": "now-1h", 1591 | "to": "now" 1592 | }, 1593 | "timepicker": {}, 1594 | "timezone": "", 1595 | "title": "Django", 1596 | "uid": "O6v4rMpizda", 1597 | "version": 1, 1598 | "weekStart": "" 1599 | } -------------------------------------------------------------------------------- /grafana/dashboards/caddy.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": { 7 | "type": "grafana", 8 | "uid": "-- Grafana --" 9 | }, 10 | "enable": true, 11 | "hide": true, 12 | "iconColor": "rgba(0, 211, 255, 1)", 13 | "name": "Annotations & Alerts", 14 | "type": "dashboard" 15 | } 16 | ] 17 | }, 18 | "description": "Caddy HTTP server monitoring.", 19 | "editable": true, 20 | "fiscalYearStartMonth": 0, 21 | "graphTooltip": 0, 22 | "id": 5, 23 | "links": [], 24 | "panels": [ 25 | { 26 | "collapsed": false, 27 | "gridPos": { 28 | "h": 1, 29 | "w": 24, 30 | "x": 0, 31 | "y": 0 32 | }, 33 | "id": 8, 34 | "panels": [], 35 | "title": "Summary", 36 | "type": "row" 37 | }, 38 | { 39 | "datasource": { 40 | "type": "prometheus", 41 | "uid": "${datasource}" 42 | }, 43 | "description": "The number of requests currently being handled by the server.", 44 | "fieldConfig": { 45 | "defaults": { 46 | "color": { 47 | "mode": "fixed" 48 | }, 49 | "mappings": [], 50 | "thresholds": { 51 | "mode": "absolute", 52 | "steps": [ 53 | { 54 | "color": "green", 55 | "value": null 56 | } 57 | ] 58 | } 59 | }, 60 | "overrides": [] 61 | }, 62 | "gridPos": { 63 | "h": 5, 64 | "w": 4, 65 | "x": 0, 66 | "y": 1 67 | }, 68 | "id": 7, 69 | "options": { 70 | "colorMode": "value", 71 | "graphMode": "none", 72 | "justifyMode": "auto", 73 | "orientation": "auto", 74 | "percentChangeColorMode": "standard", 75 | "reduceOptions": { 76 | "calcs": [ 77 | "lastNotNull" 78 | ], 79 | "fields": "", 80 | "values": false 81 | }, 82 | "showPercentChange": false, 83 | "textMode": "auto", 84 | "wideLayout": true 85 | }, 86 | "pluginVersion": "11.5.2", 87 | "targets": [ 88 | { 89 | "datasource": { 90 | "type": "prometheus", 91 | "uid": "PBFA97CFB590B2093" 92 | }, 93 | "editorMode": "code", 94 | "expr": "sum(caddy_http_requests_in_flight{job=\"$job\",instance=\"$instance\"})", 95 | "instant": false, 96 | "legendFormat": "__auto", 97 | "range": true, 98 | "refId": "A" 99 | } 100 | ], 101 | "title": "Requests in flight", 102 | "type": "stat" 103 | }, 104 | { 105 | "datasource": { 106 | "type": "prometheus", 107 | "uid": "${datasource}" 108 | }, 109 | "description": "Total requests handled in the selected time range.", 110 | "fieldConfig": { 111 | "defaults": { 112 | "color": { 113 | "mode": "fixed" 114 | }, 115 | "mappings": [], 116 | "thresholds": { 117 | "mode": "absolute", 118 | "steps": [ 119 | { 120 | "color": "green", 121 | "value": null 122 | } 123 | ] 124 | } 125 | }, 126 | "overrides": [] 127 | }, 128 | "gridPos": { 129 | "h": 5, 130 | "w": 4, 131 | "x": 4, 132 | "y": 1 133 | }, 134 | "id": 1, 135 | "options": { 136 | "colorMode": "value", 137 | "graphMode": "none", 138 | "justifyMode": "auto", 139 | "orientation": "auto", 140 | "percentChangeColorMode": "standard", 141 | "reduceOptions": { 142 | "calcs": [ 143 | "lastNotNull" 144 | ], 145 | "fields": "", 146 | "values": false 147 | }, 148 | "showPercentChange": false, 149 | "textMode": "auto", 150 | "wideLayout": true 151 | }, 152 | "pluginVersion": "11.5.2", 153 | "targets": [ 154 | { 155 | "datasource": { 156 | "type": "prometheus", 157 | "uid": "PBFA97CFB590B2093" 158 | }, 159 | "disableTextWrap": false, 160 | "editorMode": "code", 161 | "expr": "sum(increase(caddy_http_requests_total{job=\"$job\",instance=\"$instance\"}[$__range]))", 162 | "fullMetaSearch": false, 163 | "includeNullMetadata": true, 164 | "instant": false, 165 | "legendFormat": "__auto", 166 | "range": true, 167 | "refId": "A", 168 | "useBackend": false 169 | } 170 | ], 171 | "title": "Total requests", 172 | "type": "stat" 173 | }, 174 | { 175 | "datasource": { 176 | "type": "prometheus", 177 | "uid": "${datasource}" 178 | }, 179 | "description": "Rate of requests handled per second in the selected time range.", 180 | "fieldConfig": { 181 | "defaults": { 182 | "color": { 183 | "mode": "fixed" 184 | }, 185 | "mappings": [], 186 | "thresholds": { 187 | "mode": "absolute", 188 | "steps": [ 189 | { 190 | "color": "green", 191 | "value": null 192 | } 193 | ] 194 | } 195 | }, 196 | "overrides": [] 197 | }, 198 | "gridPos": { 199 | "h": 5, 200 | "w": 4, 201 | "x": 8, 202 | "y": 1 203 | }, 204 | "id": 2, 205 | "options": { 206 | "colorMode": "value", 207 | "graphMode": "none", 208 | "justifyMode": "auto", 209 | "orientation": "auto", 210 | "percentChangeColorMode": "standard", 211 | "reduceOptions": { 212 | "calcs": [ 213 | "lastNotNull" 214 | ], 215 | "fields": "", 216 | "values": false 217 | }, 218 | "showPercentChange": false, 219 | "textMode": "auto", 220 | "wideLayout": true 221 | }, 222 | "pluginVersion": "11.5.2", 223 | "targets": [ 224 | { 225 | "datasource": { 226 | "type": "prometheus", 227 | "uid": "PBFA97CFB590B2093" 228 | }, 229 | "editorMode": "code", 230 | "expr": "sum(rate(caddy_http_requests_total{job=\"$job\",instance=\"$instance\"}[$__range]))", 231 | "instant": false, 232 | "legendFormat": "__auto", 233 | "range": true, 234 | "refId": "A" 235 | } 236 | ], 237 | "title": "Requests per second", 238 | "type": "stat" 239 | }, 240 | { 241 | "datasource": { 242 | "type": "prometheus", 243 | "uid": "PBFA97CFB590B2093" 244 | }, 245 | "description": "Median round-trip request duration for the selected time range.", 246 | "fieldConfig": { 247 | "defaults": { 248 | "color": { 249 | "mode": "fixed" 250 | }, 251 | "mappings": [], 252 | "thresholds": { 253 | "mode": "absolute", 254 | "steps": [ 255 | { 256 | "color": "green", 257 | "value": null 258 | } 259 | ] 260 | }, 261 | "unit": "s" 262 | }, 263 | "overrides": [] 264 | }, 265 | "gridPos": { 266 | "h": 5, 267 | "w": 4, 268 | "x": 12, 269 | "y": 1 270 | }, 271 | "id": 3, 272 | "options": { 273 | "colorMode": "value", 274 | "graphMode": "none", 275 | "justifyMode": "auto", 276 | "orientation": "auto", 277 | "percentChangeColorMode": "standard", 278 | "reduceOptions": { 279 | "calcs": [ 280 | "lastNotNull" 281 | ], 282 | "fields": "", 283 | "values": false 284 | }, 285 | "showPercentChange": false, 286 | "textMode": "auto", 287 | "wideLayout": true 288 | }, 289 | "pluginVersion": "11.5.2", 290 | "targets": [ 291 | { 292 | "datasource": { 293 | "type": "prometheus", 294 | "uid": "PBFA97CFB590B2093" 295 | }, 296 | "editorMode": "code", 297 | "expr": "histogram_quantile(0.5, sum(rate(caddy_http_request_duration_seconds_bucket{job=\"$job\",instance=\"$instance\"}[$__range])) by (le))", 298 | "instant": false, 299 | "legendFormat": "__auto", 300 | "range": true, 301 | "refId": "A" 302 | } 303 | ], 304 | "title": "Median request duration", 305 | "type": "stat" 306 | }, 307 | { 308 | "datasource": { 309 | "type": "prometheus", 310 | "uid": "PBFA97CFB590B2093" 311 | }, 312 | "description": "Median time-to-first-byte response duration for the selected time range.", 313 | "fieldConfig": { 314 | "defaults": { 315 | "color": { 316 | "mode": "fixed" 317 | }, 318 | "mappings": [], 319 | "thresholds": { 320 | "mode": "absolute", 321 | "steps": [ 322 | { 323 | "color": "green", 324 | "value": null 325 | } 326 | ] 327 | }, 328 | "unit": "s" 329 | }, 330 | "overrides": [] 331 | }, 332 | "gridPos": { 333 | "h": 5, 334 | "w": 4, 335 | "x": 16, 336 | "y": 1 337 | }, 338 | "id": 20, 339 | "options": { 340 | "colorMode": "value", 341 | "graphMode": "none", 342 | "justifyMode": "auto", 343 | "orientation": "auto", 344 | "percentChangeColorMode": "standard", 345 | "reduceOptions": { 346 | "calcs": [ 347 | "lastNotNull" 348 | ], 349 | "fields": "", 350 | "values": false 351 | }, 352 | "showPercentChange": false, 353 | "textMode": "auto", 354 | "wideLayout": true 355 | }, 356 | "pluginVersion": "11.5.2", 357 | "targets": [ 358 | { 359 | "datasource": { 360 | "type": "prometheus", 361 | "uid": "PBFA97CFB590B2093" 362 | }, 363 | "editorMode": "code", 364 | "expr": "histogram_quantile(0.5, sum(rate(caddy_http_response_duration_seconds_bucket{job=\"$job\",instance=\"$instance\"}[$__range])) by (le))", 365 | "instant": false, 366 | "legendFormat": "__auto", 367 | "range": true, 368 | "refId": "A" 369 | } 370 | ], 371 | "title": "Median response duration", 372 | "type": "stat" 373 | }, 374 | { 375 | "datasource": { 376 | "type": "prometheus", 377 | "uid": "${datasource}" 378 | }, 379 | "description": "A number of middleware errors encountered while handling requests in the selected time range.", 380 | "fieldConfig": { 381 | "defaults": { 382 | "color": { 383 | "mode": "fixed" 384 | }, 385 | "decimals": 0, 386 | "mappings": [], 387 | "noValue": "0", 388 | "thresholds": { 389 | "mode": "absolute", 390 | "steps": [ 391 | { 392 | "color": "green", 393 | "value": null 394 | } 395 | ] 396 | } 397 | }, 398 | "overrides": [] 399 | }, 400 | "gridPos": { 401 | "h": 5, 402 | "w": 4, 403 | "x": 20, 404 | "y": 1 405 | }, 406 | "id": 5, 407 | "options": { 408 | "colorMode": "value", 409 | "graphMode": "none", 410 | "justifyMode": "auto", 411 | "orientation": "auto", 412 | "percentChangeColorMode": "standard", 413 | "reduceOptions": { 414 | "calcs": [ 415 | "lastNotNull" 416 | ], 417 | "fields": "", 418 | "values": false 419 | }, 420 | "showPercentChange": false, 421 | "textMode": "auto", 422 | "wideLayout": true 423 | }, 424 | "pluginVersion": "11.5.2", 425 | "targets": [ 426 | { 427 | "datasource": { 428 | "type": "prometheus", 429 | "uid": "PBFA97CFB590B2093" 430 | }, 431 | "editorMode": "code", 432 | "expr": "sum(increase(caddy_http_request_errors_total{job=\"$job\",instance=\"$instance\"}[$__range]))", 433 | "instant": false, 434 | "legendFormat": "__auto", 435 | "range": true, 436 | "refId": "A" 437 | } 438 | ], 439 | "title": "Total middleware errors", 440 | "type": "stat" 441 | }, 442 | { 443 | "datasource": { 444 | "type": "prometheus", 445 | "uid": "${datasource}" 446 | }, 447 | "description": "Median request (estimated) size in bytes in the selected time range. Includes body.", 448 | "fieldConfig": { 449 | "defaults": { 450 | "color": { 451 | "mode": "fixed" 452 | }, 453 | "mappings": [], 454 | "thresholds": { 455 | "mode": "absolute", 456 | "steps": [ 457 | { 458 | "color": "green", 459 | "value": null 460 | } 461 | ] 462 | }, 463 | "unit": "bytes" 464 | }, 465 | "overrides": [] 466 | }, 467 | "gridPos": { 468 | "h": 5, 469 | "w": 4, 470 | "x": 0, 471 | "y": 6 472 | }, 473 | "id": 4, 474 | "options": { 475 | "colorMode": "value", 476 | "graphMode": "none", 477 | "justifyMode": "auto", 478 | "orientation": "auto", 479 | "percentChangeColorMode": "standard", 480 | "reduceOptions": { 481 | "calcs": [ 482 | "lastNotNull" 483 | ], 484 | "fields": "", 485 | "values": false 486 | }, 487 | "showPercentChange": false, 488 | "textMode": "auto", 489 | "wideLayout": true 490 | }, 491 | "pluginVersion": "11.5.2", 492 | "targets": [ 493 | { 494 | "datasource": { 495 | "type": "prometheus", 496 | "uid": "PBFA97CFB590B2093" 497 | }, 498 | "editorMode": "code", 499 | "expr": "histogram_quantile(0.5, sum(rate(caddy_http_request_size_bytes_bucket{job=\"$job\",instance=\"$instance\"}[$__range])) by (le))", 500 | "instant": false, 501 | "legendFormat": "__auto", 502 | "range": true, 503 | "refId": "A" 504 | } 505 | ], 506 | "title": "Median request size", 507 | "type": "stat" 508 | }, 509 | { 510 | "datasource": { 511 | "type": "prometheus", 512 | "uid": "${datasource}" 513 | }, 514 | "description": "Median returned response body size in bytes in the selected time range.", 515 | "fieldConfig": { 516 | "defaults": { 517 | "color": { 518 | "mode": "fixed" 519 | }, 520 | "mappings": [], 521 | "thresholds": { 522 | "mode": "absolute", 523 | "steps": [ 524 | { 525 | "color": "green", 526 | "value": null 527 | } 528 | ] 529 | }, 530 | "unit": "bytes" 531 | }, 532 | "overrides": [] 533 | }, 534 | "gridPos": { 535 | "h": 5, 536 | "w": 4, 537 | "x": 4, 538 | "y": 6 539 | }, 540 | "id": 21, 541 | "options": { 542 | "colorMode": "value", 543 | "graphMode": "none", 544 | "justifyMode": "auto", 545 | "orientation": "auto", 546 | "percentChangeColorMode": "standard", 547 | "reduceOptions": { 548 | "calcs": [ 549 | "lastNotNull" 550 | ], 551 | "fields": "", 552 | "values": false 553 | }, 554 | "showPercentChange": false, 555 | "textMode": "auto", 556 | "wideLayout": true 557 | }, 558 | "pluginVersion": "11.5.2", 559 | "targets": [ 560 | { 561 | "datasource": { 562 | "type": "prometheus", 563 | "uid": "PBFA97CFB590B2093" 564 | }, 565 | "editorMode": "code", 566 | "expr": "histogram_quantile(0.5, sum(rate(caddy_http_response_size_bytes_bucket{job=\"$job\",instance=\"$instance\"}[$__range])) by (le))", 567 | "instant": false, 568 | "legendFormat": "__auto", 569 | "range": true, 570 | "refId": "A" 571 | } 572 | ], 573 | "title": "Median response size", 574 | "type": "stat" 575 | }, 576 | { 577 | "datasource": { 578 | "type": "prometheus", 579 | "uid": "${datasource}" 580 | }, 581 | "description": "Sum of the sizes of all received requests in the selected time range.", 582 | "fieldConfig": { 583 | "defaults": { 584 | "color": { 585 | "mode": "fixed" 586 | }, 587 | "mappings": [], 588 | "thresholds": { 589 | "mode": "absolute", 590 | "steps": [ 591 | { 592 | "color": "green", 593 | "value": null 594 | } 595 | ] 596 | }, 597 | "unit": "bytes" 598 | }, 599 | "overrides": [] 600 | }, 601 | "gridPos": { 602 | "h": 5, 603 | "w": 4, 604 | "x": 8, 605 | "y": 6 606 | }, 607 | "id": 22, 608 | "options": { 609 | "colorMode": "value", 610 | "graphMode": "none", 611 | "justifyMode": "auto", 612 | "orientation": "auto", 613 | "percentChangeColorMode": "standard", 614 | "reduceOptions": { 615 | "calcs": [ 616 | "lastNotNull" 617 | ], 618 | "fields": "", 619 | "values": false 620 | }, 621 | "showPercentChange": false, 622 | "textMode": "auto", 623 | "wideLayout": true 624 | }, 625 | "pluginVersion": "11.5.2", 626 | "targets": [ 627 | { 628 | "datasource": { 629 | "type": "prometheus", 630 | "uid": "PBFA97CFB590B2093" 631 | }, 632 | "editorMode": "code", 633 | "expr": "sum(increase(caddy_http_request_size_bytes_sum{job=\"$job\",instance=\"$instance\"}[$__range]))", 634 | "instant": false, 635 | "legendFormat": "__auto", 636 | "range": true, 637 | "refId": "A" 638 | } 639 | ], 640 | "title": "Total requests size", 641 | "type": "stat" 642 | }, 643 | { 644 | "datasource": { 645 | "type": "prometheus", 646 | "uid": "${datasource}" 647 | }, 648 | "description": "Sum of sizes of all response bodies in the selected time range.", 649 | "fieldConfig": { 650 | "defaults": { 651 | "color": { 652 | "mode": "fixed" 653 | }, 654 | "mappings": [], 655 | "thresholds": { 656 | "mode": "absolute", 657 | "steps": [ 658 | { 659 | "color": "green", 660 | "value": null 661 | } 662 | ] 663 | }, 664 | "unit": "bytes" 665 | }, 666 | "overrides": [] 667 | }, 668 | "gridPos": { 669 | "h": 5, 670 | "w": 4, 671 | "x": 12, 672 | "y": 6 673 | }, 674 | "id": 23, 675 | "options": { 676 | "colorMode": "value", 677 | "graphMode": "none", 678 | "justifyMode": "auto", 679 | "orientation": "auto", 680 | "percentChangeColorMode": "standard", 681 | "reduceOptions": { 682 | "calcs": [ 683 | "lastNotNull" 684 | ], 685 | "fields": "", 686 | "values": false 687 | }, 688 | "showPercentChange": false, 689 | "textMode": "auto", 690 | "wideLayout": true 691 | }, 692 | "pluginVersion": "11.5.2", 693 | "targets": [ 694 | { 695 | "datasource": { 696 | "type": "prometheus", 697 | "uid": "PBFA97CFB590B2093" 698 | }, 699 | "editorMode": "code", 700 | "expr": "sum(increase(caddy_http_response_size_bytes_sum{job=\"$job\",instance=\"$instance\"}[$__range]))", 701 | "instant": false, 702 | "legendFormat": "__auto", 703 | "range": true, 704 | "refId": "A" 705 | } 706 | ], 707 | "title": "Total responses size", 708 | "type": "stat" 709 | }, 710 | { 711 | "datasource": { 712 | "type": "prometheus", 713 | "uid": "${datasource}" 714 | }, 715 | "description": "Percentage of responses with 4xx status code in all responses.", 716 | "fieldConfig": { 717 | "defaults": { 718 | "color": { 719 | "mode": "fixed" 720 | }, 721 | "mappings": [], 722 | "noValue": "0%", 723 | "thresholds": { 724 | "mode": "absolute", 725 | "steps": [ 726 | { 727 | "color": "green", 728 | "value": null 729 | } 730 | ] 731 | }, 732 | "unit": "percentunit" 733 | }, 734 | "overrides": [] 735 | }, 736 | "gridPos": { 737 | "h": 5, 738 | "w": 4, 739 | "x": 16, 740 | "y": 6 741 | }, 742 | "id": 24, 743 | "options": { 744 | "colorMode": "value", 745 | "graphMode": "none", 746 | "justifyMode": "auto", 747 | "orientation": "auto", 748 | "percentChangeColorMode": "standard", 749 | "reduceOptions": { 750 | "calcs": [ 751 | "lastNotNull" 752 | ], 753 | "fields": "", 754 | "values": false 755 | }, 756 | "showPercentChange": false, 757 | "textMode": "auto", 758 | "wideLayout": true 759 | }, 760 | "pluginVersion": "11.5.2", 761 | "targets": [ 762 | { 763 | "datasource": { 764 | "type": "prometheus", 765 | "uid": "PBFA97CFB590B2093" 766 | }, 767 | "disableTextWrap": false, 768 | "editorMode": "code", 769 | "expr": "sum(increase(caddy_http_response_duration_seconds_count{job=\"$job\",instance=\"$instance\", code=~\"4..\"}[$__range])) / sum(increase(caddy_http_response_duration_seconds_count{job=\"$job\",instance=\"$instance\"}[$__range]))", 770 | "fullMetaSearch": false, 771 | "includeNullMetadata": true, 772 | "instant": false, 773 | "legendFormat": "__auto", 774 | "range": true, 775 | "refId": "A", 776 | "useBackend": false 777 | } 778 | ], 779 | "title": "4xx response percentage", 780 | "type": "stat" 781 | }, 782 | { 783 | "datasource": { 784 | "type": "prometheus", 785 | "uid": "${datasource}" 786 | }, 787 | "description": "Percentage of responses with 4xx status code in all responses.", 788 | "fieldConfig": { 789 | "defaults": { 790 | "color": { 791 | "mode": "fixed" 792 | }, 793 | "mappings": [], 794 | "noValue": "0%", 795 | "thresholds": { 796 | "mode": "absolute", 797 | "steps": [ 798 | { 799 | "color": "green", 800 | "value": null 801 | } 802 | ] 803 | }, 804 | "unit": "percentunit" 805 | }, 806 | "overrides": [] 807 | }, 808 | "gridPos": { 809 | "h": 5, 810 | "w": 4, 811 | "x": 20, 812 | "y": 6 813 | }, 814 | "id": 25, 815 | "options": { 816 | "colorMode": "value", 817 | "graphMode": "none", 818 | "justifyMode": "auto", 819 | "orientation": "auto", 820 | "percentChangeColorMode": "standard", 821 | "reduceOptions": { 822 | "calcs": [ 823 | "lastNotNull" 824 | ], 825 | "fields": "", 826 | "values": false 827 | }, 828 | "showPercentChange": false, 829 | "textMode": "auto", 830 | "wideLayout": true 831 | }, 832 | "pluginVersion": "11.5.2", 833 | "targets": [ 834 | { 835 | "datasource": { 836 | "type": "prometheus", 837 | "uid": "PBFA97CFB590B2093" 838 | }, 839 | "disableTextWrap": false, 840 | "editorMode": "code", 841 | "expr": "sum(increase(caddy_http_response_duration_seconds_count{job=\"$job\",instance=\"$instance\", code=~\"5..\"}[$__range])) / sum(increase(caddy_http_response_duration_seconds_count{job=\"$job\",instance=\"$instance\"}[$__range]))", 842 | "fullMetaSearch": false, 843 | "includeNullMetadata": true, 844 | "instant": false, 845 | "legendFormat": "__auto", 846 | "range": true, 847 | "refId": "A", 848 | "useBackend": false 849 | } 850 | ], 851 | "title": "5xx response percentage", 852 | "type": "stat" 853 | }, 854 | { 855 | "collapsed": false, 856 | "gridPos": { 857 | "h": 1, 858 | "w": 24, 859 | "x": 0, 860 | "y": 11 861 | }, 862 | "id": 11, 863 | "panels": [], 864 | "title": "Detailed metrics", 865 | "type": "row" 866 | }, 867 | { 868 | "datasource": { 869 | "type": "prometheus", 870 | "uid": "${datasource}" 871 | }, 872 | "fieldConfig": { 873 | "defaults": { 874 | "color": { 875 | "mode": "palette-classic" 876 | }, 877 | "custom": { 878 | "axisBorderShow": false, 879 | "axisCenteredZero": false, 880 | "axisColorMode": "text", 881 | "axisLabel": "", 882 | "axisPlacement": "auto", 883 | "barAlignment": 0, 884 | "barWidthFactor": 0.6, 885 | "drawStyle": "line", 886 | "fillOpacity": 20, 887 | "gradientMode": "none", 888 | "hideFrom": { 889 | "legend": false, 890 | "tooltip": false, 891 | "viz": false 892 | }, 893 | "insertNulls": false, 894 | "lineInterpolation": "linear", 895 | "lineWidth": 1, 896 | "pointSize": 5, 897 | "scaleDistribution": { 898 | "type": "linear" 899 | }, 900 | "showPoints": "auto", 901 | "spanNulls": false, 902 | "stacking": { 903 | "group": "A", 904 | "mode": "normal" 905 | }, 906 | "thresholdsStyle": { 907 | "mode": "off" 908 | } 909 | }, 910 | "mappings": [], 911 | "thresholds": { 912 | "mode": "absolute", 913 | "steps": [ 914 | { 915 | "color": "green", 916 | "value": null 917 | } 918 | ] 919 | } 920 | }, 921 | "overrides": [ 922 | { 923 | "matcher": { 924 | "id": "byRegexp", 925 | "options": "^2\\d\\d$" 926 | }, 927 | "properties": [ 928 | { 929 | "id": "color", 930 | "value": { 931 | "fixedColor": "green", 932 | "mode": "shades" 933 | } 934 | } 935 | ] 936 | }, 937 | { 938 | "matcher": { 939 | "id": "byRegexp", 940 | "options": "^3\\d\\d$" 941 | }, 942 | "properties": [ 943 | { 944 | "id": "color", 945 | "value": { 946 | "fixedColor": "blue", 947 | "mode": "shades" 948 | } 949 | } 950 | ] 951 | }, 952 | { 953 | "matcher": { 954 | "id": "byRegexp", 955 | "options": "^4\\d\\d$" 956 | }, 957 | "properties": [ 958 | { 959 | "id": "color", 960 | "value": { 961 | "fixedColor": "orange", 962 | "mode": "shades" 963 | } 964 | } 965 | ] 966 | }, 967 | { 968 | "matcher": { 969 | "id": "byRegexp", 970 | "options": "^5\\d\\d$" 971 | }, 972 | "properties": [ 973 | { 974 | "id": "color", 975 | "value": { 976 | "fixedColor": "red", 977 | "mode": "shades" 978 | } 979 | } 980 | ] 981 | } 982 | ] 983 | }, 984 | "gridPos": { 985 | "h": 10, 986 | "w": 12, 987 | "x": 0, 988 | "y": 12 989 | }, 990 | "id": 26, 991 | "options": { 992 | "legend": { 993 | "calcs": [], 994 | "displayMode": "list", 995 | "placement": "bottom", 996 | "showLegend": true 997 | }, 998 | "tooltip": { 999 | "hideZeros": false, 1000 | "mode": "multi", 1001 | "sort": "desc" 1002 | } 1003 | }, 1004 | "pluginVersion": "11.5.2", 1005 | "targets": [ 1006 | { 1007 | "datasource": { 1008 | "type": "prometheus", 1009 | "uid": "PBFA97CFB590B2093" 1010 | }, 1011 | "editorMode": "code", 1012 | "expr": "sum(rate(caddy_http_request_duration_seconds_count{job=\"$job\",instance=\"$instance\"}[$interval])) by (method)", 1013 | "instant": false, 1014 | "legendFormat": "__auto", 1015 | "range": true, 1016 | "refId": "A" 1017 | } 1018 | ], 1019 | "title": "Rate of requests by HTTP method (stacked)", 1020 | "type": "timeseries" 1021 | }, 1022 | { 1023 | "datasource": { 1024 | "type": "prometheus", 1025 | "uid": "${datasource}" 1026 | }, 1027 | "fieldConfig": { 1028 | "defaults": { 1029 | "color": { 1030 | "mode": "palette-classic" 1031 | }, 1032 | "custom": { 1033 | "hideFrom": { 1034 | "legend": false, 1035 | "tooltip": false, 1036 | "viz": false 1037 | } 1038 | }, 1039 | "mappings": [] 1040 | }, 1041 | "overrides": [ 1042 | { 1043 | "matcher": { 1044 | "id": "byRegexp", 1045 | "options": "^2\\d\\d$" 1046 | }, 1047 | "properties": [ 1048 | { 1049 | "id": "color", 1050 | "value": { 1051 | "fixedColor": "green", 1052 | "mode": "shades" 1053 | } 1054 | } 1055 | ] 1056 | }, 1057 | { 1058 | "matcher": { 1059 | "id": "byRegexp", 1060 | "options": "^3\\d\\d$" 1061 | }, 1062 | "properties": [ 1063 | { 1064 | "id": "color", 1065 | "value": { 1066 | "fixedColor": "blue", 1067 | "mode": "shades" 1068 | } 1069 | } 1070 | ] 1071 | }, 1072 | { 1073 | "matcher": { 1074 | "id": "byRegexp", 1075 | "options": "^4\\d\\d$" 1076 | }, 1077 | "properties": [ 1078 | { 1079 | "id": "color", 1080 | "value": { 1081 | "fixedColor": "orange", 1082 | "mode": "shades" 1083 | } 1084 | } 1085 | ] 1086 | }, 1087 | { 1088 | "matcher": { 1089 | "id": "byRegexp", 1090 | "options": "^5\\d\\d$" 1091 | }, 1092 | "properties": [ 1093 | { 1094 | "id": "color", 1095 | "value": { 1096 | "fixedColor": "red", 1097 | "mode": "shades" 1098 | } 1099 | } 1100 | ] 1101 | } 1102 | ] 1103 | }, 1104 | "gridPos": { 1105 | "h": 10, 1106 | "w": 6, 1107 | "x": 12, 1108 | "y": 12 1109 | }, 1110 | "id": 15, 1111 | "options": { 1112 | "displayLabels": [], 1113 | "legend": { 1114 | "displayMode": "table", 1115 | "placement": "right", 1116 | "showLegend": true, 1117 | "values": [ 1118 | "value", 1119 | "percent" 1120 | ] 1121 | }, 1122 | "pieType": "pie", 1123 | "reduceOptions": { 1124 | "calcs": [ 1125 | "lastNotNull" 1126 | ], 1127 | "fields": "", 1128 | "values": false 1129 | }, 1130 | "tooltip": { 1131 | "hideZeros": false, 1132 | "mode": "single", 1133 | "sort": "none" 1134 | } 1135 | }, 1136 | "pluginVersion": "11.5.2", 1137 | "targets": [ 1138 | { 1139 | "datasource": { 1140 | "type": "prometheus", 1141 | "uid": "PBFA97CFB590B2093" 1142 | }, 1143 | "editorMode": "code", 1144 | "expr": "sum(increase(caddy_http_request_duration_seconds_count{job=\"$job\",instance=\"$instance\"}[$__range])) by (code)", 1145 | "instant": false, 1146 | "legendFormat": "__auto", 1147 | "range": true, 1148 | "refId": "A" 1149 | } 1150 | ], 1151 | "title": "HTTP status breakdown", 1152 | "type": "piechart" 1153 | }, 1154 | { 1155 | "datasource": { 1156 | "type": "prometheus", 1157 | "uid": "${datasource}" 1158 | }, 1159 | "fieldConfig": { 1160 | "defaults": { 1161 | "color": { 1162 | "mode": "palette-classic" 1163 | }, 1164 | "custom": { 1165 | "hideFrom": { 1166 | "legend": false, 1167 | "tooltip": false, 1168 | "viz": false 1169 | } 1170 | }, 1171 | "mappings": [] 1172 | }, 1173 | "overrides": [] 1174 | }, 1175 | "gridPos": { 1176 | "h": 10, 1177 | "w": 6, 1178 | "x": 18, 1179 | "y": 12 1180 | }, 1181 | "id": 16, 1182 | "options": { 1183 | "displayLabels": [], 1184 | "legend": { 1185 | "displayMode": "table", 1186 | "placement": "right", 1187 | "showLegend": true, 1188 | "values": [ 1189 | "value", 1190 | "percent" 1191 | ] 1192 | }, 1193 | "pieType": "pie", 1194 | "reduceOptions": { 1195 | "calcs": [ 1196 | "lastNotNull" 1197 | ], 1198 | "fields": "", 1199 | "values": false 1200 | }, 1201 | "tooltip": { 1202 | "hideZeros": false, 1203 | "mode": "single", 1204 | "sort": "none" 1205 | } 1206 | }, 1207 | "pluginVersion": "11.5.2", 1208 | "targets": [ 1209 | { 1210 | "datasource": { 1211 | "type": "prometheus", 1212 | "uid": "PBFA97CFB590B2093" 1213 | }, 1214 | "editorMode": "code", 1215 | "expr": "sum(increase(caddy_http_request_duration_seconds_count{job=\"$job\",instance=\"$instance\"}[$__range])) by (method)", 1216 | "instant": false, 1217 | "legendFormat": "__auto", 1218 | "range": true, 1219 | "refId": "A" 1220 | } 1221 | ], 1222 | "title": "HTTP method breakdown", 1223 | "type": "piechart" 1224 | }, 1225 | { 1226 | "datasource": { 1227 | "type": "prometheus", 1228 | "uid": "${datasource}" 1229 | }, 1230 | "fieldConfig": { 1231 | "defaults": { 1232 | "color": { 1233 | "mode": "palette-classic" 1234 | }, 1235 | "custom": { 1236 | "axisBorderShow": false, 1237 | "axisCenteredZero": false, 1238 | "axisColorMode": "text", 1239 | "axisLabel": "", 1240 | "axisPlacement": "auto", 1241 | "barAlignment": 0, 1242 | "barWidthFactor": 0.6, 1243 | "drawStyle": "line", 1244 | "fillOpacity": 0, 1245 | "gradientMode": "none", 1246 | "hideFrom": { 1247 | "legend": false, 1248 | "tooltip": false, 1249 | "viz": false 1250 | }, 1251 | "insertNulls": false, 1252 | "lineInterpolation": "linear", 1253 | "lineWidth": 1, 1254 | "pointSize": 5, 1255 | "scaleDistribution": { 1256 | "type": "linear" 1257 | }, 1258 | "showPoints": "auto", 1259 | "spanNulls": false, 1260 | "stacking": { 1261 | "group": "A", 1262 | "mode": "none" 1263 | }, 1264 | "thresholdsStyle": { 1265 | "mode": "off" 1266 | } 1267 | }, 1268 | "mappings": [], 1269 | "thresholds": { 1270 | "mode": "absolute", 1271 | "steps": [ 1272 | { 1273 | "color": "green", 1274 | "value": null 1275 | }, 1276 | { 1277 | "color": "red", 1278 | "value": 80 1279 | } 1280 | ] 1281 | }, 1282 | "unit": "s" 1283 | }, 1284 | "overrides": [] 1285 | }, 1286 | "gridPos": { 1287 | "h": 10, 1288 | "w": 12, 1289 | "x": 0, 1290 | "y": 22 1291 | }, 1292 | "id": 10, 1293 | "options": { 1294 | "legend": { 1295 | "calcs": [], 1296 | "displayMode": "list", 1297 | "placement": "bottom", 1298 | "showLegend": true 1299 | }, 1300 | "tooltip": { 1301 | "hideZeros": false, 1302 | "mode": "multi", 1303 | "sort": "desc" 1304 | } 1305 | }, 1306 | "pluginVersion": "11.5.2", 1307 | "targets": [ 1308 | { 1309 | "datasource": { 1310 | "type": "prometheus", 1311 | "uid": "PBFA97CFB590B2093" 1312 | }, 1313 | "editorMode": "code", 1314 | "expr": "histogram_quantile(0.99, sum(rate(caddy_http_request_duration_seconds_bucket{job=\"$job\",instance=\"$instance\"}[$interval])) by (le))", 1315 | "instant": false, 1316 | "legendFormat": "0.99", 1317 | "range": true, 1318 | "refId": "A" 1319 | }, 1320 | { 1321 | "datasource": { 1322 | "type": "prometheus", 1323 | "uid": "${datasource}" 1324 | }, 1325 | "editorMode": "code", 1326 | "expr": "histogram_quantile(0.95, sum(rate(caddy_http_request_duration_seconds_bucket{job=\"$job\",instance=\"$instance\"}[$interval])) by (le))", 1327 | "hide": false, 1328 | "instant": false, 1329 | "legendFormat": "0.95", 1330 | "range": true, 1331 | "refId": "B" 1332 | }, 1333 | { 1334 | "datasource": { 1335 | "type": "prometheus", 1336 | "uid": "PBFA97CFB590B2093" 1337 | }, 1338 | "editorMode": "code", 1339 | "expr": "histogram_quantile(0.90, sum(rate(caddy_http_request_duration_seconds_bucket{job=\"$job\",instance=\"$instance\"}[$interval])) by (le))", 1340 | "hide": false, 1341 | "instant": false, 1342 | "legendFormat": "0.90", 1343 | "range": true, 1344 | "refId": "C" 1345 | }, 1346 | { 1347 | "datasource": { 1348 | "type": "prometheus", 1349 | "uid": "${datasource}" 1350 | }, 1351 | "editorMode": "code", 1352 | "expr": "histogram_quantile(0.75, sum(rate(caddy_http_request_duration_seconds_bucket{job=\"$job\",instance=\"$instance\"}[$interval])) by (le))", 1353 | "hide": false, 1354 | "instant": false, 1355 | "legendFormat": "0.75", 1356 | "range": true, 1357 | "refId": "D" 1358 | }, 1359 | { 1360 | "datasource": { 1361 | "type": "prometheus", 1362 | "uid": "PBFA97CFB590B2093" 1363 | }, 1364 | "editorMode": "code", 1365 | "expr": "histogram_quantile(0.5, sum(rate(caddy_http_request_duration_seconds_bucket{job=\"$job\",instance=\"$instance\"}[$interval])) by (le))", 1366 | "hide": false, 1367 | "instant": false, 1368 | "legendFormat": "0.5", 1369 | "range": true, 1370 | "refId": "E" 1371 | } 1372 | ], 1373 | "title": "Request duration percentiles", 1374 | "type": "timeseries" 1375 | }, 1376 | { 1377 | "datasource": { 1378 | "type": "prometheus", 1379 | "uid": "${datasource}" 1380 | }, 1381 | "fieldConfig": { 1382 | "defaults": { 1383 | "color": { 1384 | "mode": "palette-classic" 1385 | }, 1386 | "custom": { 1387 | "axisBorderShow": false, 1388 | "axisCenteredZero": false, 1389 | "axisColorMode": "text", 1390 | "axisLabel": "", 1391 | "axisPlacement": "auto", 1392 | "barAlignment": 0, 1393 | "barWidthFactor": 0.6, 1394 | "drawStyle": "line", 1395 | "fillOpacity": 20, 1396 | "gradientMode": "none", 1397 | "hideFrom": { 1398 | "legend": false, 1399 | "tooltip": false, 1400 | "viz": false 1401 | }, 1402 | "insertNulls": false, 1403 | "lineInterpolation": "linear", 1404 | "lineWidth": 1, 1405 | "pointSize": 5, 1406 | "scaleDistribution": { 1407 | "type": "linear" 1408 | }, 1409 | "showPoints": "auto", 1410 | "spanNulls": false, 1411 | "stacking": { 1412 | "group": "A", 1413 | "mode": "normal" 1414 | }, 1415 | "thresholdsStyle": { 1416 | "mode": "off" 1417 | } 1418 | }, 1419 | "mappings": [], 1420 | "thresholds": { 1421 | "mode": "absolute", 1422 | "steps": [ 1423 | { 1424 | "color": "green", 1425 | "value": null 1426 | } 1427 | ] 1428 | }, 1429 | "unit": "bytes" 1430 | }, 1431 | "overrides": [ 1432 | { 1433 | "matcher": { 1434 | "id": "byRegexp", 1435 | "options": "^2\\d\\d$" 1436 | }, 1437 | "properties": [ 1438 | { 1439 | "id": "color", 1440 | "value": { 1441 | "fixedColor": "green", 1442 | "mode": "shades" 1443 | } 1444 | } 1445 | ] 1446 | }, 1447 | { 1448 | "matcher": { 1449 | "id": "byRegexp", 1450 | "options": "^3\\d\\d$" 1451 | }, 1452 | "properties": [ 1453 | { 1454 | "id": "color", 1455 | "value": { 1456 | "fixedColor": "blue", 1457 | "mode": "shades" 1458 | } 1459 | } 1460 | ] 1461 | }, 1462 | { 1463 | "matcher": { 1464 | "id": "byRegexp", 1465 | "options": "^4\\d\\d$" 1466 | }, 1467 | "properties": [ 1468 | { 1469 | "id": "color", 1470 | "value": { 1471 | "fixedColor": "orange", 1472 | "mode": "shades" 1473 | } 1474 | } 1475 | ] 1476 | }, 1477 | { 1478 | "matcher": { 1479 | "id": "byRegexp", 1480 | "options": "^5\\d\\d$" 1481 | }, 1482 | "properties": [ 1483 | { 1484 | "id": "color", 1485 | "value": { 1486 | "fixedColor": "red", 1487 | "mode": "shades" 1488 | } 1489 | } 1490 | ] 1491 | } 1492 | ] 1493 | }, 1494 | "gridPos": { 1495 | "h": 10, 1496 | "w": 12, 1497 | "x": 12, 1498 | "y": 22 1499 | }, 1500 | "id": 27, 1501 | "options": { 1502 | "legend": { 1503 | "calcs": [], 1504 | "displayMode": "list", 1505 | "placement": "bottom", 1506 | "showLegend": true 1507 | }, 1508 | "tooltip": { 1509 | "hideZeros": false, 1510 | "mode": "multi", 1511 | "sort": "desc" 1512 | } 1513 | }, 1514 | "pluginVersion": "11.5.2", 1515 | "targets": [ 1516 | { 1517 | "datasource": { 1518 | "type": "prometheus", 1519 | "uid": "PBFA97CFB590B2093" 1520 | }, 1521 | "editorMode": "code", 1522 | "expr": "sum(rate(caddy_http_request_size_bytes_sum{job=\"$job\",instance=\"$instance\"}[$interval]))", 1523 | "instant": false, 1524 | "legendFormat": "request", 1525 | "range": true, 1526 | "refId": "A" 1527 | }, 1528 | { 1529 | "datasource": { 1530 | "type": "prometheus", 1531 | "uid": "${datasource}" 1532 | }, 1533 | "editorMode": "code", 1534 | "expr": "-sum(rate(caddy_http_response_size_bytes_sum{job=\"$job\",instance=\"$instance\"}[$interval]))", 1535 | "hide": false, 1536 | "instant": false, 1537 | "legendFormat": "response", 1538 | "range": true, 1539 | "refId": "B" 1540 | } 1541 | ], 1542 | "title": "Data transfer rate", 1543 | "type": "timeseries" 1544 | }, 1545 | { 1546 | "datasource": { 1547 | "type": "prometheus", 1548 | "uid": "PBFA97CFB590B2093" 1549 | }, 1550 | "fieldConfig": { 1551 | "defaults": { 1552 | "color": { 1553 | "mode": "palette-classic" 1554 | }, 1555 | "custom": { 1556 | "axisBorderShow": false, 1557 | "axisCenteredZero": false, 1558 | "axisColorMode": "text", 1559 | "axisLabel": "", 1560 | "axisPlacement": "auto", 1561 | "barAlignment": 0, 1562 | "barWidthFactor": 0.6, 1563 | "drawStyle": "line", 1564 | "fillOpacity": 20, 1565 | "gradientMode": "none", 1566 | "hideFrom": { 1567 | "legend": false, 1568 | "tooltip": false, 1569 | "viz": false 1570 | }, 1571 | "insertNulls": false, 1572 | "lineInterpolation": "linear", 1573 | "lineWidth": 1, 1574 | "pointSize": 5, 1575 | "scaleDistribution": { 1576 | "type": "linear" 1577 | }, 1578 | "showPoints": "auto", 1579 | "spanNulls": false, 1580 | "stacking": { 1581 | "group": "A", 1582 | "mode": "none" 1583 | }, 1584 | "thresholdsStyle": { 1585 | "mode": "off" 1586 | } 1587 | }, 1588 | "mappings": [], 1589 | "thresholds": { 1590 | "mode": "absolute", 1591 | "steps": [ 1592 | { 1593 | "color": "green" 1594 | } 1595 | ] 1596 | } 1597 | }, 1598 | "overrides": [] 1599 | }, 1600 | "gridPos": { 1601 | "h": 10, 1602 | "w": 12, 1603 | "x": 0, 1604 | "y": 32 1605 | }, 1606 | "id": 9, 1607 | "options": { 1608 | "legend": { 1609 | "calcs": [], 1610 | "displayMode": "list", 1611 | "placement": "bottom", 1612 | "showLegend": true 1613 | }, 1614 | "tooltip": { 1615 | "hideZeros": false, 1616 | "mode": "multi", 1617 | "sort": "desc" 1618 | } 1619 | }, 1620 | "pluginVersion": "11.5.1", 1621 | "targets": [ 1622 | { 1623 | "datasource": { 1624 | "type": "prometheus", 1625 | "uid": "${datasource}" 1626 | }, 1627 | "editorMode": "code", 1628 | "expr": "sum(rate(caddy_http_request_duration_seconds_count{job=\"$job\",instance=\"$instance\", code=~\"4..|5..\"}[$interval])) by (code)", 1629 | "instant": false, 1630 | "legendFormat": "__auto", 1631 | "range": true, 1632 | "refId": "A" 1633 | } 1634 | ], 1635 | "title": "Rate of 4xx and 5xx responses", 1636 | "type": "timeseries" 1637 | }, 1638 | { 1639 | "datasource": { 1640 | "type": "prometheus", 1641 | "uid": "PBFA97CFB590B2093" 1642 | }, 1643 | "description": "", 1644 | "fieldConfig": { 1645 | "defaults": { 1646 | "color": { 1647 | "mode": "palette-classic" 1648 | }, 1649 | "custom": { 1650 | "axisBorderShow": false, 1651 | "axisCenteredZero": false, 1652 | "axisColorMode": "text", 1653 | "axisLabel": "", 1654 | "axisPlacement": "auto", 1655 | "barAlignment": 0, 1656 | "barWidthFactor": 0.6, 1657 | "drawStyle": "line", 1658 | "fillOpacity": 20, 1659 | "gradientMode": "none", 1660 | "hideFrom": { 1661 | "legend": false, 1662 | "tooltip": false, 1663 | "viz": false 1664 | }, 1665 | "insertNulls": false, 1666 | "lineInterpolation": "linear", 1667 | "lineWidth": 1, 1668 | "pointSize": 5, 1669 | "scaleDistribution": { 1670 | "type": "linear" 1671 | }, 1672 | "showPoints": "auto", 1673 | "spanNulls": false, 1674 | "stacking": { 1675 | "group": "A", 1676 | "mode": "none" 1677 | }, 1678 | "thresholdsStyle": { 1679 | "mode": "off" 1680 | } 1681 | }, 1682 | "mappings": [], 1683 | "thresholds": { 1684 | "mode": "absolute", 1685 | "steps": [ 1686 | { 1687 | "color": "green" 1688 | }, 1689 | { 1690 | "color": "red", 1691 | "value": 80 1692 | } 1693 | ] 1694 | } 1695 | }, 1696 | "overrides": [] 1697 | }, 1698 | "gridPos": { 1699 | "h": 10, 1700 | "w": 12, 1701 | "x": 12, 1702 | "y": 32 1703 | }, 1704 | "id": 14, 1705 | "options": { 1706 | "legend": { 1707 | "calcs": [], 1708 | "displayMode": "list", 1709 | "placement": "bottom", 1710 | "showLegend": false 1711 | }, 1712 | "tooltip": { 1713 | "hideZeros": false, 1714 | "mode": "single", 1715 | "sort": "none" 1716 | } 1717 | }, 1718 | "pluginVersion": "11.5.1", 1719 | "targets": [ 1720 | { 1721 | "datasource": { 1722 | "type": "prometheus", 1723 | "uid": "${datasource}" 1724 | }, 1725 | "editorMode": "code", 1726 | "expr": "rate(caddy_http_request_errors_total{job=\"$job\",instance=\"$instance\"}[$interval])", 1727 | "instant": false, 1728 | "legendFormat": "errors", 1729 | "range": true, 1730 | "refId": "A" 1731 | } 1732 | ], 1733 | "title": "Middleware error rate", 1734 | "type": "timeseries" 1735 | }, 1736 | { 1737 | "collapsed": false, 1738 | "gridPos": { 1739 | "h": 1, 1740 | "w": 24, 1741 | "x": 0, 1742 | "y": 42 1743 | }, 1744 | "id": 19, 1745 | "panels": [], 1746 | "title": "Heatmaps", 1747 | "type": "row" 1748 | }, 1749 | { 1750 | "datasource": { 1751 | "type": "prometheus", 1752 | "uid": "PBFA97CFB590B2093" 1753 | }, 1754 | "description": "Round-trip request duration heatmap.", 1755 | "fieldConfig": { 1756 | "defaults": { 1757 | "custom": { 1758 | "hideFrom": { 1759 | "legend": false, 1760 | "tooltip": false, 1761 | "viz": false 1762 | }, 1763 | "scaleDistribution": { 1764 | "type": "linear" 1765 | } 1766 | } 1767 | }, 1768 | "overrides": [] 1769 | }, 1770 | "gridPos": { 1771 | "h": 10, 1772 | "w": 12, 1773 | "x": 0, 1774 | "y": 43 1775 | }, 1776 | "id": 12, 1777 | "options": { 1778 | "calculate": false, 1779 | "calculation": { 1780 | "xBuckets": { 1781 | "value": "600000" 1782 | }, 1783 | "yBuckets": { 1784 | "value": "" 1785 | } 1786 | }, 1787 | "cellGap": 1, 1788 | "cellValues": { 1789 | "unit": "" 1790 | }, 1791 | "color": { 1792 | "exponent": 0.5, 1793 | "fill": "dark-orange", 1794 | "mode": "scheme", 1795 | "reverse": false, 1796 | "scale": "exponential", 1797 | "scheme": "Spectral", 1798 | "steps": 64 1799 | }, 1800 | "exemplars": { 1801 | "color": "rgba(255,0,255,0.7)" 1802 | }, 1803 | "filterValues": { 1804 | "le": 1e-9 1805 | }, 1806 | "legend": { 1807 | "show": true 1808 | }, 1809 | "rowsFrame": { 1810 | "layout": "auto" 1811 | }, 1812 | "tooltip": { 1813 | "mode": "single", 1814 | "showColorScale": false, 1815 | "yHistogram": false 1816 | }, 1817 | "yAxis": { 1818 | "axisPlacement": "left", 1819 | "reverse": false, 1820 | "unit": "s" 1821 | } 1822 | }, 1823 | "pluginVersion": "11.5.1", 1824 | "targets": [ 1825 | { 1826 | "datasource": { 1827 | "type": "prometheus", 1828 | "uid": "${datasource}" 1829 | }, 1830 | "editorMode": "code", 1831 | "expr": "sum(increase(caddy_http_request_duration_seconds_bucket{job=\"$job\",instance=\"$instance\"}[$__rate_interval])) by (le)", 1832 | "format": "heatmap", 1833 | "instant": false, 1834 | "interval": "$interval", 1835 | "legendFormat": "{{le}}", 1836 | "range": true, 1837 | "refId": "A" 1838 | } 1839 | ], 1840 | "title": "Request duration heatmap", 1841 | "type": "heatmap" 1842 | }, 1843 | { 1844 | "datasource": { 1845 | "type": "prometheus", 1846 | "uid": "PBFA97CFB590B2093" 1847 | }, 1848 | "fieldConfig": { 1849 | "defaults": { 1850 | "custom": { 1851 | "hideFrom": { 1852 | "legend": false, 1853 | "tooltip": false, 1854 | "viz": false 1855 | }, 1856 | "scaleDistribution": { 1857 | "type": "linear" 1858 | } 1859 | } 1860 | }, 1861 | "overrides": [] 1862 | }, 1863 | "gridPos": { 1864 | "h": 10, 1865 | "w": 12, 1866 | "x": 12, 1867 | "y": 43 1868 | }, 1869 | "id": 13, 1870 | "options": { 1871 | "calculate": false, 1872 | "calculation": { 1873 | "xBuckets": { 1874 | "value": "600000" 1875 | }, 1876 | "yBuckets": { 1877 | "value": "" 1878 | } 1879 | }, 1880 | "cellGap": 1, 1881 | "cellValues": { 1882 | "unit": "" 1883 | }, 1884 | "color": { 1885 | "exponent": 0.5, 1886 | "fill": "dark-orange", 1887 | "mode": "scheme", 1888 | "reverse": false, 1889 | "scale": "exponential", 1890 | "scheme": "Spectral", 1891 | "steps": 64 1892 | }, 1893 | "exemplars": { 1894 | "color": "rgba(255,0,255,0.7)" 1895 | }, 1896 | "filterValues": { 1897 | "le": 1e-9 1898 | }, 1899 | "legend": { 1900 | "show": true 1901 | }, 1902 | "rowsFrame": { 1903 | "layout": "auto" 1904 | }, 1905 | "tooltip": { 1906 | "mode": "single", 1907 | "showColorScale": false, 1908 | "yHistogram": false 1909 | }, 1910 | "yAxis": { 1911 | "axisPlacement": "left", 1912 | "reverse": false, 1913 | "unit": "bytes" 1914 | } 1915 | }, 1916 | "pluginVersion": "11.5.1", 1917 | "targets": [ 1918 | { 1919 | "datasource": { 1920 | "type": "prometheus", 1921 | "uid": "${datasource}" 1922 | }, 1923 | "editorMode": "code", 1924 | "exemplar": false, 1925 | "expr": "sum(increase(caddy_http_request_size_bytes_bucket{job=\"$job\",instance=\"$instance\"}[$__rate_interval])) by (le)", 1926 | "format": "heatmap", 1927 | "instant": false, 1928 | "interval": "$interval", 1929 | "legendFormat": "{{le}}", 1930 | "range": true, 1931 | "refId": "A" 1932 | } 1933 | ], 1934 | "title": "Request size heatmap", 1935 | "type": "heatmap" 1936 | }, 1937 | { 1938 | "datasource": { 1939 | "type": "prometheus", 1940 | "uid": "PBFA97CFB590B2093" 1941 | }, 1942 | "description": "Response time-to-first-byte heatmap.", 1943 | "fieldConfig": { 1944 | "defaults": { 1945 | "custom": { 1946 | "hideFrom": { 1947 | "legend": false, 1948 | "tooltip": false, 1949 | "viz": false 1950 | }, 1951 | "scaleDistribution": { 1952 | "type": "linear" 1953 | } 1954 | } 1955 | }, 1956 | "overrides": [] 1957 | }, 1958 | "gridPos": { 1959 | "h": 10, 1960 | "w": 12, 1961 | "x": 0, 1962 | "y": 53 1963 | }, 1964 | "id": 17, 1965 | "options": { 1966 | "calculate": false, 1967 | "calculation": { 1968 | "xBuckets": { 1969 | "value": "600000" 1970 | }, 1971 | "yBuckets": { 1972 | "value": "" 1973 | } 1974 | }, 1975 | "cellGap": 1, 1976 | "cellValues": { 1977 | "unit": "" 1978 | }, 1979 | "color": { 1980 | "exponent": 0.5, 1981 | "fill": "dark-orange", 1982 | "mode": "scheme", 1983 | "reverse": false, 1984 | "scale": "exponential", 1985 | "scheme": "Spectral", 1986 | "steps": 64 1987 | }, 1988 | "exemplars": { 1989 | "color": "rgba(255,0,255,0.7)" 1990 | }, 1991 | "filterValues": { 1992 | "le": 1e-9 1993 | }, 1994 | "legend": { 1995 | "show": true 1996 | }, 1997 | "rowsFrame": { 1998 | "layout": "auto" 1999 | }, 2000 | "tooltip": { 2001 | "mode": "single", 2002 | "showColorScale": false, 2003 | "yHistogram": false 2004 | }, 2005 | "yAxis": { 2006 | "axisPlacement": "left", 2007 | "reverse": false, 2008 | "unit": "s" 2009 | } 2010 | }, 2011 | "pluginVersion": "11.5.1", 2012 | "targets": [ 2013 | { 2014 | "datasource": { 2015 | "type": "prometheus", 2016 | "uid": "${datasource}" 2017 | }, 2018 | "editorMode": "code", 2019 | "expr": "sum(increase(caddy_http_response_duration_seconds_bucket{job=\"$job\",instance=\"$instance\"}[$__rate_interval])) by (le)", 2020 | "format": "heatmap", 2021 | "instant": false, 2022 | "interval": "$interval", 2023 | "legendFormat": "{{le}}", 2024 | "range": true, 2025 | "refId": "A" 2026 | } 2027 | ], 2028 | "title": "Response duration heatmap", 2029 | "type": "heatmap" 2030 | }, 2031 | { 2032 | "datasource": { 2033 | "type": "prometheus", 2034 | "uid": "PBFA97CFB590B2093" 2035 | }, 2036 | "fieldConfig": { 2037 | "defaults": { 2038 | "custom": { 2039 | "hideFrom": { 2040 | "legend": false, 2041 | "tooltip": false, 2042 | "viz": false 2043 | }, 2044 | "scaleDistribution": { 2045 | "type": "linear" 2046 | } 2047 | } 2048 | }, 2049 | "overrides": [] 2050 | }, 2051 | "gridPos": { 2052 | "h": 10, 2053 | "w": 12, 2054 | "x": 12, 2055 | "y": 53 2056 | }, 2057 | "id": 18, 2058 | "options": { 2059 | "calculate": false, 2060 | "calculation": { 2061 | "xBuckets": { 2062 | "value": "600000" 2063 | }, 2064 | "yBuckets": { 2065 | "value": "" 2066 | } 2067 | }, 2068 | "cellGap": 1, 2069 | "cellValues": { 2070 | "unit": "" 2071 | }, 2072 | "color": { 2073 | "exponent": 0.5, 2074 | "fill": "dark-orange", 2075 | "mode": "scheme", 2076 | "reverse": false, 2077 | "scale": "exponential", 2078 | "scheme": "Spectral", 2079 | "steps": 64 2080 | }, 2081 | "exemplars": { 2082 | "color": "rgba(255,0,255,0.7)" 2083 | }, 2084 | "filterValues": { 2085 | "le": 1e-9 2086 | }, 2087 | "legend": { 2088 | "show": true 2089 | }, 2090 | "rowsFrame": { 2091 | "layout": "auto" 2092 | }, 2093 | "tooltip": { 2094 | "mode": "single", 2095 | "showColorScale": false, 2096 | "yHistogram": false 2097 | }, 2098 | "yAxis": { 2099 | "axisPlacement": "left", 2100 | "reverse": false, 2101 | "unit": "bytes" 2102 | } 2103 | }, 2104 | "pluginVersion": "11.5.1", 2105 | "targets": [ 2106 | { 2107 | "datasource": { 2108 | "type": "prometheus", 2109 | "uid": "${datasource}" 2110 | }, 2111 | "editorMode": "code", 2112 | "exemplar": false, 2113 | "expr": "sum(increase(caddy_http_response_size_bytes_bucket{job=\"$job\",instance=\"$instance\"}[$__rate_interval])) by (le)", 2114 | "format": "heatmap", 2115 | "instant": false, 2116 | "interval": "$interval", 2117 | "legendFormat": "{{le}}", 2118 | "range": true, 2119 | "refId": "A" 2120 | } 2121 | ], 2122 | "title": "Response size heatmap", 2123 | "type": "heatmap" 2124 | } 2125 | ], 2126 | "preload": false, 2127 | "refresh": "1m", 2128 | "schemaVersion": 40, 2129 | "tags": [], 2130 | "templating": { 2131 | "list": [ 2132 | { 2133 | "current": { 2134 | "text": "Prometheus", 2135 | "value": "PBFA97CFB590B2093" 2136 | }, 2137 | "label": "Datasource", 2138 | "name": "datasource", 2139 | "options": [], 2140 | "query": "prometheus", 2141 | "refresh": 1, 2142 | "regex": "", 2143 | "type": "datasource" 2144 | }, 2145 | { 2146 | "current": { 2147 | "text": "caddy", 2148 | "value": "caddy" 2149 | }, 2150 | "datasource": { 2151 | "type": "prometheus", 2152 | "uid": "PBFA97CFB590B2093" 2153 | }, 2154 | "definition": "label_values(caddy_http_requests_total,job)", 2155 | "label": "Job", 2156 | "name": "job", 2157 | "options": [], 2158 | "query": { 2159 | "qryType": 1, 2160 | "query": "label_values(caddy_http_requests_total,job)", 2161 | "refId": "PrometheusVariableQueryEditor-VariableQuery" 2162 | }, 2163 | "refresh": 1, 2164 | "regex": "", 2165 | "type": "query" 2166 | }, 2167 | { 2168 | "current": { 2169 | "text": "caddy:2019", 2170 | "value": "caddy:2019" 2171 | }, 2172 | "datasource": { 2173 | "type": "prometheus", 2174 | "uid": "PBFA97CFB590B2093" 2175 | }, 2176 | "definition": "label_values(up{job=\"$job\"},instance)", 2177 | "description": "", 2178 | "label": "Instance", 2179 | "name": "instance", 2180 | "options": [], 2181 | "query": { 2182 | "qryType": 1, 2183 | "query": "label_values(up{job=\"$job\"},instance)", 2184 | "refId": "PrometheusVariableQueryEditor-VariableQuery" 2185 | }, 2186 | "refresh": 1, 2187 | "regex": "", 2188 | "type": "query" 2189 | }, 2190 | { 2191 | "auto": false, 2192 | "auto_count": 300, 2193 | "auto_min": "10s", 2194 | "current": { 2195 | "text": "10m", 2196 | "value": "10m" 2197 | }, 2198 | "label": "Interval", 2199 | "name": "interval", 2200 | "options": [ 2201 | { 2202 | "selected": false, 2203 | "text": "30s", 2204 | "value": "30s" 2205 | }, 2206 | { 2207 | "selected": false, 2208 | "text": "1m", 2209 | "value": "1m" 2210 | }, 2211 | { 2212 | "selected": false, 2213 | "text": "5m", 2214 | "value": "5m" 2215 | }, 2216 | { 2217 | "selected": true, 2218 | "text": "10m", 2219 | "value": "10m" 2220 | }, 2221 | { 2222 | "selected": false, 2223 | "text": "15m", 2224 | "value": "15m" 2225 | }, 2226 | { 2227 | "selected": false, 2228 | "text": "30m", 2229 | "value": "30m" 2230 | }, 2231 | { 2232 | "selected": false, 2233 | "text": "1h", 2234 | "value": "1h" 2235 | } 2236 | ], 2237 | "query": "30s,1m,5m,10m,15m,30m,1h", 2238 | "refresh": 2, 2239 | "type": "interval" 2240 | } 2241 | ] 2242 | }, 2243 | "time": { 2244 | "from": "now-24h", 2245 | "to": "now" 2246 | }, 2247 | "timepicker": {}, 2248 | "timezone": "browser", 2249 | "title": "Caddy", 2250 | "uid": "fed94ifiv8h6od", 2251 | "version": 1, 2252 | "weekStart": "" 2253 | } --------------------------------------------------------------------------------