diff --git a/monitoring/.env.example b/monitoring/.env.example new file mode 100644 index 000000000..752cdbbb8 --- /dev/null +++ b/monitoring/.env.example @@ -0,0 +1,10 @@ +# URLs of your CommonsBooking WordPress instances (no trailing slash). +# Add more pairs (URL_3, URL_4, …) and duplicate the blocks in telegraf.conf. +# If you only have one site, set URL_2 to the same value as URL_1. +COMMONSBOOKING_URL_1=https://site-one.example.com +COMMONSBOOKING_URL_2=https://site-two.example.com + +# InfluxDB credentials — change before first run +INFLUXDB_ADMIN_USER=admin +INFLUXDB_ADMIN_PASSWORD=change-me-please +INFLUXDB_TOKEN=change-me-to-a-long-random-secret diff --git a/monitoring/README.md b/monitoring/README.md new file mode 100644 index 000000000..123644f42 --- /dev/null +++ b/monitoring/README.md @@ -0,0 +1,2 @@ + +https://docs.influxdata.com/telegraf/v1/configuration/ diff --git a/monitoring/docker-compose.yml b/monitoring/docker-compose.yml new file mode 100644 index 000000000..ace46cb43 --- /dev/null +++ b/monitoring/docker-compose.yml @@ -0,0 +1,38 @@ +services: + influxdb: + image: influxdb:2.7 + container_name: commonsbooking_influxdb + restart: unless-stopped + ports: + - "8086:8086" + environment: + DOCKER_INFLUXDB_INIT_MODE: setup + DOCKER_INFLUXDB_INIT_USERNAME: ${INFLUXDB_ADMIN_USER:-admin} + DOCKER_INFLUXDB_INIT_PASSWORD: ${INFLUXDB_ADMIN_PASSWORD:?set INFLUXDB_ADMIN_PASSWORD in .env} + DOCKER_INFLUXDB_INIT_ORG: commonsbooking + DOCKER_INFLUXDB_INIT_BUCKET: gbfs + DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: ${INFLUXDB_TOKEN:?set INFLUXDB_TOKEN in .env} + volumes: + - influxdb_data:/var/lib/influxdb2 + healthcheck: + test: ["CMD", "influx", "ping"] + interval: 30s + timeout: 10s + retries: 5 + + telegraf: + image: telegraf:1.30 + container_name: commonsbooking_telegraf + restart: unless-stopped + depends_on: + influxdb: + condition: service_healthy + volumes: + - ./telegraf/telegraf.conf:/etc/telegraf/telegraf.conf:ro + environment: + COMMONSBOOKING_URL_1: ${COMMONSBOOKING_URL_1:?set COMMONSBOOKING_URL_1 in .env} + COMMONSBOOKING_URL_2: ${COMMONSBOOKING_URL_2:-} + INFLUXDB_TOKEN: ${INFLUXDB_TOKEN:?set INFLUXDB_TOKEN in .env} + +volumes: + influxdb_data: diff --git a/monitoring/telegraf/telegraf.conf b/monitoring/telegraf/telegraf.conf new file mode 100644 index 000000000..d1d85795f --- /dev/null +++ b/monitoring/telegraf/telegraf.conf @@ -0,0 +1,329 @@ +[agent] + interval = "5m" + round_interval = true + metric_batch_size = 1000 + metric_buffer_limit = 10000 + flush_interval = "10s" + hostname = "" + omit_hostname = true + +[[outputs.influxdb_v2]] + urls = ["http://influxdb:8086"] + token = "${INFLUXDB_TOKEN}" + organization = "commonsbooking" + bucket = "gbfs" + +# =========================================================================== +# HOW TO ADD MORE INSTANCES +# +# Duplicate the three blocks below (station_status, station_info, +# system_info) for each additional WordPress / CommonsBooking site. +# Set a unique `instance` tag so metrics from different sites don't collide. +# Add the corresponding URL variable to your .env file. +# =========================================================================== + +[[inputs.http]] + +urls = ["https://gbfs.nextbike.net/maps/gbfs/v2/nextbike_bn/de/station_status.json"] + +interval = "1m" + +name_override = 'gbfs_station_status' + +tagexclude = ['url', 'host'] + +data_format = "json_v2" + + [inputs.http.tags] + instance = "nextbike_berlin" + + [[inputs.http.json_v2]] + + [[inputs.http.json_v2.tag]] + path = "version" + rename = "gbfs_version" + + [[inputs.http.json_v2.object]] + + path = "data.stations" + + # Set station metadata as tags + tags = ["station_id"] + + included_keys = ["station_id", "num_bikes_available", "is_installed", "is_renting", "is_returning"] + fields = {num_bikes_available = "int", is_installed = "bool", is_renting = "bool", is_returning = "bool"} + + +[[inputs.http]] + +urls = ["https://gbfs.nextbike.net/maps/gbfs/v2/nextbike_wr/de/station_status.json"] + +interval = "1m" + +name_override = 'gbfs_station_status' + +tagexclude = ['url', 'host'] + +data_format = "json_v2" + + [inputs.http.tags] + instance = "nextbike_vienna" + + [[inputs.http.json_v2]] + + [[inputs.http.json_v2.tag]] + path = "version" + rename = "gbfs_version" + + [[inputs.http.json_v2.object]] + + path = "data.stations" + + # Set station metadata as tags + tags = ["station_id"] + + included_keys = ["station_id", "num_bikes_available", "is_installed", "is_renting", "is_returning"] + fields = {num_bikes_available = "int", is_installed = "bool", is_renting = "bool", is_returning = "bool"} + + +[[inputs.http]] + +urls = ["https://freie-lasten.org/wp-json/commonsbooking/v1/station_status.json"] + +name_override = 'gbfs_station_status' + +tagexclude = ['url', 'host'] + +data_format = "json_v2" + + [inputs.http.tags] + instance = "freie-lasten.org" + + [[inputs.http.json_v2]] + + [[inputs.http.json_v2.tag]] + path = "version" + rename = "gbfs_version" + + [[inputs.http.json_v2.object]] + + path = "data.stations" + + # Set station metadata as tags + tags = ["station_id"] + + included_keys = ["station_id", "num_vehicles_available", "is_installed", "is_renting", "is_returning"] + fields = {num_vehicles_available = "int", is_installed = "bool", is_renting = "bool", is_returning = "bool"} + + + +[[inputs.http]] + +urls = ["https://gbfs.citibikenyc.com/gbfs/en/station_status.json"] + +interval = "1m" + +name_override = 'gbfs_station_status' + +tagexclude = ['url', 'host'] + +data_format = "json_v2" + +[inputs.http.tags] + instance = "citibikenyc.com" + + [[inputs.http.json_v2]] + + + [[inputs.http.json_v2.tag]] + path = "version" + rename = "gbfs_version" + + [[inputs.http.json_v2.object]] + + path = "data.stations" + + # Set station metadata as tags + tags = ["station_id"] + + included_keys = ["station_id", "num_bikes_available", "is_installed", "is_renting", "is_returning"] + fields = {num_bikes_available = "int", is_installed = "bool", is_renting = "bool", is_returning = "bool"} + + + +[[inputs.http]] + +urls = ["https://www.kasimir-lastenrad.de/wp-json/commonsbooking/v1/station_status.json"] + +name_override = 'gbfs_station_status' + +tagexclude = ['url', 'host'] + +data_format = "json_v2" + +[inputs.http.tags] + instance = "kasimir-lastenrad.de" + + [[inputs.http.json_v2]] + + + [[inputs.http.json_v2.tag]] + path = "version" + rename = "gbfs_version" + + [[inputs.http.json_v2.object]] + + path = "data.stations.#.data" + + # Set station metadata as tags + tags = ["station_id"] + + included_keys = ["station_id", "num_bikes_available", "is_installed", "is_renting", "is_returning"] + fields = {num_bikes_available = "int", is_installed = "bool", is_renting = "bool", is_returning = "bool"} + + + + +[[inputs.http]] + +urls = ["https://dein-rudolf.de/wp-json/commonsbooking/v1/station_status.json"] + +name_override = 'gbfs_station_status' + +tagexclude = ['url', 'host'] + +data_format = "json_v2" + +[inputs.http.tags] + instance = "dein-rudolf.de" + + [[inputs.http.json_v2]] + + + [[inputs.http.json_v2.tag]] + path = "version" + rename = "gbfs_version" + + [[inputs.http.json_v2.object]] + + path = "data.stations.#.data" + + # Set station metadata as tags + tags = ["station_id"] + + included_keys = ["station_id", "num_bikes_available", "is_installed", "is_renting", "is_returning"] + fields = {num_bikes_available = "int", is_installed = "bool", is_renting = "bool", is_returning = "bool"} + +[[inputs.http]] + +urls = ["https://hilde-lastenrad.de/wp-json/commonsbooking/v1/station_status.json"] + +timeout = "60s" + +name_override = 'gbfs_station_status' + +tagexclude = ['url', 'host'] + +data_format = "json_v2" + +[inputs.http.tags] + instance = "hilde-lastenrad.de" + + [[inputs.http.json_v2]] + + + [[inputs.http.json_v2.tag]] + path = "version" + rename = "gbfs_version" + + [[inputs.http.json_v2.object]] + + path = "data.stations.#.data" + + # Set station metadata as tags + tags = ["station_id"] + + included_keys = ["station_id", "num_bikes_available", "is_installed", "is_renting", "is_returning"] + fields = {num_bikes_available = "int", is_installed = "bool", is_renting = "bool", is_returning = "bool"} + +[[inputs.http]] + +urls = ["https://helge-lastenrad.de/wp-json/commonsbooking/v1/station_status.json"] + +timeout = "60s" + +name_override = 'gbfs_station_status' + +tagexclude = ['url', 'host'] + +data_format = "json_v2" + +[inputs.http.tags] + instance = "helge-lastenrad.de" + + [[inputs.http.json_v2]] + + + [[inputs.http.json_v2.tag]] + path = "version" + rename = "gbfs_version" + + [[inputs.http.json_v2.object]] + + path = "data.stations.#.data" + + # Set station metadata as tags + tags = ["station_id"] + + included_keys = ["station_id", "num_bikes_available", "is_installed", "is_renting", "is_returning"] + fields = {num_bikes_available = "int", is_installed = "bool", is_renting = "bool", is_returning = "bool"} + +[[inputs.http]] + +urls = ["https://freie-lastenradl.de/wp-json/commonsbooking/v1/station_status.json"] + +timeout = "60s" + +name_override = 'gbfs_station_status' + +tagexclude = ['url', 'host'] + +data_format = "json_v2" + +[inputs.http.tags] + instance = "freie-lastenradl.de" + + [[inputs.http.json_v2]] + + + [[inputs.http.json_v2.tag]] + path = "version" + rename = "gbfs_version" + + [[inputs.http.json_v2.object]] + + path = "data.stations.#.data" + + # Set station metadata as tags + tags = ["station_id"] + + included_keys = ["station_id", "num_bikes_available", "is_installed", "is_renting", "is_returning"] + fields = {num_bikes_available = "int", is_installed = "bool", is_renting = "bool", is_returning = "bool"} + +[[inputs.http_response]] + urls = [ + "https://dasallrad.org", + "https://freie-lasten.org", + "https://freie-lastenradl.de", + "https://flotte-berlin.de", + "https://www.kasimir-lastenrad.de" + ] + response_timeout = "5s" + interval = "1m" + method = "GET" + follow_redirects = true + # Optional: confirm WordPress is actually rendering, not a generic 200 from a reverse proxy + # response_string_match = "wordpress" + # Tags for filtering in your dashboard + [inputs.http_response.tags] + check_type = "wordpress_uptime"