From 991522cd38dcac010e26c3f5d4fc6b42b0d83a0a Mon Sep 17 00:00:00 2001 From: Sebastian Kanis Date: Thu, 21 Dec 2023 14:35:46 +0100 Subject: [PATCH 01/10] changed from whitelisting devices to blacklisting devices --- README.md | 2 +- build.sh | 2 +- exporter.py | 132 +++++++++++++++++++--------------------------------- 3 files changed, 51 insertions(+), 85 deletions(-) diff --git a/README.md b/README.md index 6399250..a7332eb 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,6 @@ Feel free to open issues for unsupported items. ## Build -For multi-architecture builds (x86, arm, arm64), e.g. use `docker buildx build --platform linux/amd64,linux/arm/v7,linux/arm64 -t sfudeus/homematic_exporter:latest .` or use `build.sh`. +For multi-architecture builds (x86, arm, arm64), e.g. use `docker buildx build --platform linux/amd64,linux/arm/v7,linux/arm64 -t s0riak/homematic_exporter:latest .` or use `build.sh`. You can usually find an up-to-date image for amd64, arm and arm64 at sfudeus/homematic_exporter:latest in [docker hub](https://hub.docker.com/r/sfudeus/homematic_exporter). Additionally, they are tagged with their build date to have a stable reference. diff --git a/build.sh b/build.sh index dcc188d..a8a67e6 100755 --- a/build.sh +++ b/build.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash -REPO=sfudeus/homematic_exporter +REPO=s0riak/homematic_exporter docker buildx build --platform linux/amd64 --platform linux/arm/v7 --platform linux/arm64 -t $REPO:"$(date +%F)" -t $REPO:latest --push . diff --git a/exporter.py b/exporter.py index c533f7e..66d9c27 100755 --- a/exporter.py +++ b/exporter.py @@ -17,65 +17,9 @@ class HomematicMetricsProcessor(threading.Thread): - METRICS_NAMESPACE = 'homematic' - # Supported Homematic (BidcosRF and IP) device types - DEFAULT_SUPPORTED_TYPES = [ - 'HmIP-eTRV-2', - 'HmIP-eTRV-C', - 'HmIP-eTRV-C-2', - 'HmIP-FSM', - 'HmIP-MIOB', - 'HMIP-PS', - 'HMIP-PSM', - 'HmIP-RCV-1', - 'HmIP-STH', - 'HmIP-STHD', - 'HmIP-STHO', - 'HmIP-STE2-PCB', - 'HmIP-SWD', - 'HMIP-SWDO', - 'HmIP-SWSD', - 'HmIP-SWO-PL', - 'HmIP-SWO-PR', - 'HmIP-WTH-2', - 'HmIP-BSL', - 'HM-CC-RT-DN', - 'HM-Dis-EP-WM55', - 'HM-Dis-WM55', - 'HM-ES-PMSw1-Pl-DN-R5', - 'HM-ES-TX-WM', - 'HM-LC-Bl1-FM', - 'HM-LC-Dim1PWM-CV', - 'HM-LC-Dim1T-FM', - 'HM-LC-RGBW-WM', - 'HM-LC-Sw1-Pl-DN-R5', - 'HM-LC-Sw1-FM', - 'HM-LC-Sw2-FM', - 'HM-OU-CFM-Pl', - 'HM-OU-CFM-TW', - 'HM-PBI-4-FM', - 'HM-PB-2-WM55', - 'HM-PB-6-WM55', - 'HM-RC-P1', - 'HM-RC-4-2', - 'HM-RC-8', - 'HM-Sec-MDIR-2', - 'HM-Sec-SCo', - 'HM-Sec-SC-2', - 'HM-Sec-SD-2', - 'HM-Sec-TiS', - 'HM-Sen-LI-O', - 'HM-Sen-MDIR-O', - 'HM-Sen-MDIR-WM55', - 'HM-SwI-3-FM', - 'HM-TC-IT-WM-W-EU', - 'HM-WDS10-TH-O', - 'HM-WDS100-C6-O-2', - 'HM-WDS30-OT2-SM', - 'HM-WDS40-TH-I', - 'HM-WDS40-TH-I-2', - ] + # Unsupported Homematic (BidcosRF and IP) device types + UNDEFAULT_SUPPORTED_TYPES = [] # A list with channel numbers for devices where getParamset # never works, or only sometimes works (e.g. if the device sent @@ -106,7 +50,7 @@ class HomematicMetricsProcessor(threading.Thread): reload_names_active = False reload_names_interval = 30 # reload names every 60 gatherings mapped_names = {} - supported_device_types = DEFAULT_SUPPORTED_TYPES + unsupported_device_types = UNDEFAULT_SUPPORTED_TYPES channels_with_errors_allowed = DEFAULT_CHANNELS_WITH_ERRORS_ALLOWED device_count = None @@ -115,13 +59,18 @@ class HomematicMetricsProcessor(threading.Thread): def run(self): logging.info("Starting thread for data gathering") logging.info("Mapping {} devices with custom names".format(len(self.mapped_names))) - logging.info("Supporting {} device types: {}".format(len(self.supported_device_types), ",".join(self.supported_device_types))) - - gathering_counter = Counter('gathering_count', 'Amount of gathering runs', labelnames=['ccu'], namespace=self.METRICS_NAMESPACE) - error_counter = Counter('gathering_errors', 'Amount of failed gathering runs', labelnames=['ccu'], namespace=self.METRICS_NAMESPACE) + logging.info("The following {} device types are NOT supported: {}".format(len(self.unsupported_device_types), + ",".join( + self.unsupported_device_types))) + + gathering_counter = Counter('gathering_count', 'Amount of gathering runs', labelnames=['ccu'], + namespace=self.METRICS_NAMESPACE) + error_counter = Counter('gathering_errors', 'Amount of failed gathering runs', labelnames=['ccu'], + namespace=self.METRICS_NAMESPACE) generate_metrics_summary = Summary('generate_metrics_seconds', 'Time spent in gathering runs', labelnames=['ccu'], namespace=self.METRICS_NAMESPACE) - read_names_summary = Summary('read_names_seconds', 'Time spent reading names from CCU', labelnames=['ccu'], namespace=self.METRICS_NAMESPACE) + read_names_summary = Summary('read_names_seconds', 'Time spent reading names from CCU', labelnames=['ccu'], + namespace=self.METRICS_NAMESPACE) gathering_loop_counter = 1 @@ -170,8 +119,9 @@ def __init__(self, ccu_host, ccu_port, auth, gathering_interval, reload_names_in logging.info("Processing config file {}".format(config_filename)) config = json.load(config_file) self.mapped_names = config.get('device_mapping', {}) - self.supported_device_types = config.get('supported_device_types', self.DEFAULT_SUPPORTED_TYPES) - self.channels_with_errors_allowed = config.get('channels_with_errors_allowed', self.DEFAULT_CHANNELS_WITH_ERRORS_ALLOWED) + self.unsupported_device_types = config.get('unsupported_device_types', self.UNDEFAULT_SUPPORTED_TYPES) + self.channels_with_errors_allowed = config.get('channels_with_errors_allowed', + self.DEFAULT_CHANNELS_WITH_ERRORS_ALLOWED) self.ccu_host = ccu_host self.ccu_port = ccu_port @@ -182,7 +132,8 @@ def __init__(self, ccu_host, ccu_port, auth, gathering_interval, reload_names_in self.ccu_url = "http://{}:{}".format(ccu_host, ccu_port) self.gathering_interval = int(gathering_interval) self.reload_names_interval = int(reload_names_interval) - self.devicecount = Gauge('devicecount', 'Number of processed/supported devices', labelnames=['ccu'], namespace=self.METRICS_NAMESPACE) + self.devicecount = Gauge('devicecount', 'Number of processed/supported devices', labelnames=['ccu'], + namespace=self.METRICS_NAMESPACE) def generate_metrics(self): logging.info("Gathering metrics") @@ -193,14 +144,16 @@ def generate_metrics(self): devParentAddress = device.get('PARENT') devAddress = device.get('ADDRESS') if devParentAddress == '': - if devType in self.supported_device_types: + if not devType in self.unsupported_device_types: devChildcount = len(device.get('CHILDREN')) - logging.info("Found top-level device {} of type {} with {} children".format(devAddress, devType, devChildcount)) + logging.info("Found top-level device {} of type {} with {} children".format(devAddress, devType, + devChildcount)) logging.debug(pformat(device)) else: logging.info("Found unsupported top-level device {} of type {}".format(devAddress, devType)) - if devParentType in self.supported_device_types: - logging.debug("Found device {} of type {} in supported parent type {}".format(devAddress, devType, devParentType)) + if not devParentType in self.unsupported_device_types: + logging.debug( + "Found device {} of type {} in supported parent type {}".format(devAddress, devType, devParentType)) logging.debug(pformat(device)) allowFailedChannel = False @@ -216,18 +169,21 @@ def generate_metrics(self): paramset = self.fetch_param_set(devAddress) except xmlrpc.client.Fault: if allowFailedChannel: - logging.debug("Error reading paramset for device {} of type {} in parent type {} (expected)".format( - devAddress, devType, devParentType)) + logging.debug( + "Error reading paramset for device {} of type {} in parent type {} (expected)".format( + devAddress, devType, devParentType)) else: - logging.debug("Error reading paramset for device {} of type {} in parent type {} (unexpected)".format( - devAddress, devType, devParentType)) + logging.debug( + "Error reading paramset for device {} of type {} in parent type {} (unexpected)".format( + devAddress, devType, devParentType)) raise for key in paramsetDescription: paramDesc = paramsetDescription.get(key) paramType = paramDesc.get('TYPE') if paramType in ['FLOAT', 'INTEGER', 'BOOL']: - self.process_single_value(devAddress, devType, devParentAddress, devParentType, paramType, key, paramset.get(key)) + self.process_single_value(devAddress, devType, devParentAddress, devParentType, paramType, + key, paramset.get(key)) elif paramType == 'ENUM': logging.debug("Found {}: desc: {} key: {}".format(paramType, paramDesc, paramset.get(key))) self.process_enum(devAddress, devType, devParentAddress, devParentType, @@ -235,7 +191,8 @@ def generate_metrics(self): else: # ATM Unsupported like HEATING_CONTROL_HMIP.PARTY_TIME_START, # HEATING_CONTROL_HMIP.PARTY_TIME_END, COMBINED_PARAMETER or ACTION - logging.debug("Unknown paramType {}, desc: {}, key: {}".format(paramType, paramDesc, paramset.get(key))) + logging.debug("Unknown paramType {}, desc: {}, key: {}".format(paramType, paramDesc, + paramset.get(key))) if paramset: logging.debug("ParamsetDescription for {}".format(devAddress)) @@ -276,7 +233,8 @@ def resolve_mapped_name(self, deviceAddress, parentDeviceAddress): else: return deviceAddress - def process_single_value(self, deviceAddress, deviceType, parentDeviceAddress, parentDeviceType, paramType, key, value): + def process_single_value(self, deviceAddress, deviceType, parentDeviceAddress, parentDeviceType, paramType, key, + value): logging.debug("Found {} param {} with value {}".format(paramType, key, value)) if value == '' or value is None: @@ -285,7 +243,9 @@ def process_single_value(self, deviceAddress, deviceType, parentDeviceAddress, p gaugename = key.lower() if not self.metrics.get(gaugename): self.metrics[gaugename] = Gauge(gaugename, 'Metrics for ' + key, labelnames=['ccu', 'device', 'device_type', - 'parent_device_type', 'mapped_name'], namespace=self.METRICS_NAMESPACE) + 'parent_device_type', + 'mapped_name'], + namespace=self.METRICS_NAMESPACE) gauge = self.metrics.get(gaugename) gauge.labels( ccu=self.ccu_host, @@ -304,7 +264,10 @@ def process_enum(self, deviceAddress, deviceType, parentDeviceAddress, parentDev if not self.metrics.get(gaugename): self.metrics[gaugename] = Enum(gaugename, 'Metrics for ' + key, states=istates, labelnames=['ccu', 'device', - 'device_type', 'parent_device_type', 'mapped_name'], namespace=self.METRICS_NAMESPACE) + 'device_type', + 'parent_device_type', + 'mapped_name'], + namespace=self.METRICS_NAMESPACE) gauge = self.metrics.get(gaugename) mapped_name_v = self.resolve_mapped_name(deviceAddress, parentDeviceAddress) state = istates[int(value)] @@ -380,7 +343,8 @@ def start_http_server(port, addr='', registry=core.REGISTRY): PARSER = argparse.ArgumentParser() PARSER.add_argument("--ccu_host", help="The hostname of the ccu instance", required=True) - PARSER.add_argument("--ccu_port", help="The port for the xmlrpc service (2001 for BidcosRF, 2010 for HmIP)", default=2010) + PARSER.add_argument("--ccu_port", help="The port for the xmlrpc service (2001 for BidcosRF, 2010 for HmIP)", + default=2010) PARSER.add_argument("--ccu_user", help="The username for the CCU (if authentication is enabled)") PARSER.add_argument("--ccu_pass", help="The password for the CCU (if authentication is enabled)") PARSER.add_argument("--interval", help="The interval between two gathering runs in seconds", default=60) @@ -390,7 +354,8 @@ def start_http_server(port, addr='', registry=core.REGISTRY): PARSER.add_argument("--debug", action="store_true") PARSER.add_argument("--dump_devices", help="Do not start exporter, just dump device list", action="store_true") PARSER.add_argument("--dump_parameters", help="Do not start exporter, just dump device parameters of given device") - PARSER.add_argument("--dump_device_names", help="Do not start exporter, just dump device names", action="store_true") + PARSER.add_argument("--dump_device_names", help="Do not start exporter, just dump device names", + action="store_true") ARGS = PARSER.parse_args() if ARGS.debug: @@ -402,7 +367,8 @@ def start_http_server(port, addr='', registry=core.REGISTRY): if ARGS.ccu_user and ARGS.ccu_pass: auth = (ARGS.ccu_user, ARGS.ccu_pass) - PROCESSOR = HomematicMetricsProcessor(ARGS.ccu_host, ARGS.ccu_port, auth, ARGS.interval, ARGS.namereload, ARGS.config_file) + PROCESSOR = HomematicMetricsProcessor(ARGS.ccu_host, ARGS.ccu_port, auth, ARGS.interval, ARGS.namereload, + ARGS.config_file) if ARGS.dump_devices: print(pformat(PROCESSOR.fetch_devices_list())) From 793bed478abe40d0f0234d7cd97aad8374db3e5c Mon Sep 17 00:00:00 2001 From: Sebastian Kanis Date: Tue, 2 Jan 2024 06:52:34 +0100 Subject: [PATCH 02/10] created compose.yml to start Homematic and Homematic IP instance of homematic_exporter --- compose.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 compose.yml diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..e4efbb0 --- /dev/null +++ b/compose.yml @@ -0,0 +1,18 @@ +version: '3' + +services: + homematic_exporter_hmip: + build: ./ + container_name: homematic_exporter_hmip + restart: unless-stopped + command: --ccu_host debmatic.fritz.box --ccu_port 2010 --port 9020 --interval 300 + ports: + - "9020:9020" + homematic_exporter_hm: + build: ./ + container_name: homematic_exporter_hm + restart: unless-stopped + command: --ccu_host debmatic.fritz.box --ccu_port 2001 --port 9021 --interval 300 + ports: + - "9021:9021" + From 83e09c88fa9c9553b4ba3397fe23d8ff305768a8 Mon Sep 17 00:00:00 2001 From: Sebastian Kanis Date: Tue, 2 Jan 2024 06:58:34 +0100 Subject: [PATCH 03/10] moved parameters to .env file --- .env | 6 ++++++ compose.yml | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 .env diff --git a/.env b/.env new file mode 100644 index 0000000..f8cf67e --- /dev/null +++ b/.env @@ -0,0 +1,6 @@ +CCU_HOST=debmatic.fritz.box +CCU_HMIP_PORT=2010 +CCU_HM_PORT=2001 +EXPORTER_HMIP_PORT=9020 +EXPORTER_HM_PORT=9021 +SCRAPPING_INTERVAL=300 diff --git a/compose.yml b/compose.yml index e4efbb0..fc9eae8 100644 --- a/compose.yml +++ b/compose.yml @@ -5,14 +5,14 @@ services: build: ./ container_name: homematic_exporter_hmip restart: unless-stopped - command: --ccu_host debmatic.fritz.box --ccu_port 2010 --port 9020 --interval 300 + command: --ccu_host ${CCU_HOST} --ccu_port ${CCU_HMIP_PORT} --port ${EXPORTER_HMIP_PORT} --interval ${SCRAPPING_INTERVAL} ports: - - "9020:9020" + - ${EXPORTER_HMIP_PORT}:${EXPORTER_HMIP_PORT} homematic_exporter_hm: build: ./ container_name: homematic_exporter_hm restart: unless-stopped - command: --ccu_host debmatic.fritz.box --ccu_port 2001 --port 9021 --interval 300 + command: --ccu_host ${CCU_HOST} --ccu_port ${CCU_HM_PORT} --port ${EXPORTER_HM_PORT} --interval ${SCRAPPING_INTERVAL} ports: - - "9021:9021" + - ${EXPORTER_HM_PORT}:${EXPORTER_HM_PORT} From e296c3b149ccd24960f6a61ac31d03e6f8469576 Mon Sep 17 00:00:00 2001 From: Sebastian Kanis Date: Wed, 3 Jan 2024 22:04:36 +0100 Subject: [PATCH 04/10] switched to network of monitoring main project --- compose.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/compose.yml b/compose.yml index fc9eae8..c424782 100644 --- a/compose.yml +++ b/compose.yml @@ -6,13 +6,15 @@ services: container_name: homematic_exporter_hmip restart: unless-stopped command: --ccu_host ${CCU_HOST} --ccu_port ${CCU_HMIP_PORT} --port ${EXPORTER_HMIP_PORT} --interval ${SCRAPPING_INTERVAL} - ports: - - ${EXPORTER_HMIP_PORT}:${EXPORTER_HMIP_PORT} + homematic_exporter_hm: build: ./ container_name: homematic_exporter_hm restart: unless-stopped command: --ccu_host ${CCU_HOST} --ccu_port ${CCU_HM_PORT} --port ${EXPORTER_HM_PORT} --interval ${SCRAPPING_INTERVAL} - ports: - - ${EXPORTER_HM_PORT}:${EXPORTER_HM_PORT} + +networks: + default: + name: monitoring_prometheus_grafana_default + external: true From bcb84babd45a8b6ba3e01c7c89eb3edc4b9a4deb Mon Sep 17 00:00:00 2001 From: Sebastian Kanis Date: Sat, 27 Jan 2024 09:33:47 +0100 Subject: [PATCH 05/10] improved homematic script for better channel names for devices with channels --- exporter.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/exporter.py b/exporter.py index 66d9c27..43a6de6 100755 --- a/exporter.py +++ b/exporter.py @@ -298,7 +298,13 @@ def read_mapped_names(self): string chId; foreach(chId, device.Channels()) { var ch=dom.GetObject(chId); - WriteLine("C\t" # ch.Address() # "\t" # ch.Name() # "\t" # chId); + var chNumber = ch.Name().Substr(ch.Name().Length() - 1); + if (chNumber == "0"){ + var channelName = ch.Name(); + }else{ + var channelName = device.Name() # ":" # chNumber; + } + WriteLine("C\t" # ch.Address() # "\t" # channelName # "\t" # chId); } } } @@ -356,6 +362,7 @@ def start_http_server(port, addr='', registry=core.REGISTRY): PARSER.add_argument("--dump_parameters", help="Do not start exporter, just dump device parameters of given device") PARSER.add_argument("--dump_device_names", help="Do not start exporter, just dump device names", action="store_true") + PARSER.add_argument("--dump_sysvars", help="Do not start exporter, just dump system variables", action="store_true") ARGS = PARSER.parse_args() if ARGS.debug: From 78e47632104a2e28c1e7ab465eb2fdba16f9d7e3 Mon Sep 17 00:00:00 2001 From: Sebastian Kanis Date: Sat, 27 Jan 2024 22:09:57 +0100 Subject: [PATCH 06/10] removed omitting mapping names when adress is default adress --- exporter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporter.py b/exporter.py index 43a6de6..2d15bff 100755 --- a/exporter.py +++ b/exporter.py @@ -226,7 +226,7 @@ def is_default_device_address(self, deviceAddress): return re.match("^[0-9a-f]{14}:[0-9]+$", deviceAddress, re.IGNORECASE) def resolve_mapped_name(self, deviceAddress, parentDeviceAddress): - if deviceAddress in self.mapped_names and not self.is_default_device_address(deviceAddress): + if deviceAddress in self.mapped_names: # and not self.is_default_device_address(deviceAddress): return self.mapped_names[deviceAddress] elif parentDeviceAddress in self.mapped_names: return self.mapped_names[parentDeviceAddress] From 53239a8f237b4225b0835eaeb456b5a502638598 Mon Sep 17 00:00:00 2001 From: Sebastian Kanis Date: Sun, 28 Jan 2024 09:33:31 +0100 Subject: [PATCH 07/10] added channelnames as names in case they are customized and falling back to device names in case they are not customized (starting with 'HM-', 'Hm-', 'HMIP-', 'HmIP-') --- exporter.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/exporter.py b/exporter.py index 2d15bff..ec503e5 100755 --- a/exporter.py +++ b/exporter.py @@ -299,13 +299,14 @@ def read_mapped_names(self): foreach(chId, device.Channels()) { var ch=dom.GetObject(chId); var chNumber = ch.Name().Substr(ch.Name().Length() - 1); - if (chNumber == "0"){ - var channelName = ch.Name(); + var chNamePrefix3 = ch.Name().Substr(0,3); + var chNamePrefix5 = ch.Name().Substr(0,5); + if ((chNamePrefix3 == "HM-") || (chNamePrefix3 == "Hm-") || (chNamePrefix5 == "HMIP-") || (chNamePrefix5 == "HmIP-")){ + WriteLine("C\t" # ch.Address() # "\t" # device.Name() # ":" # chNumber # "\t" # chId); }else{ - var channelName = device.Name() # ":" # chNumber; - } - WriteLine("C\t" # ch.Address() # "\t" # channelName # "\t" # chId); - } + WriteLine("C\t" # ch.Address() # "\t" # ch.Name() # "\t" # chId); + } + } } } } From 73cea24c6a1ef68a99d971da57b494206db82510 Mon Sep 17 00:00:00 2001 From: Stephan Fudeus Date: Sat, 23 Dec 2023 13:16:47 +0100 Subject: [PATCH 08/10] Prepare for python 3.12 --- .github/workflows/python-build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-build.yaml b/.github/workflows/python-build.yaml index a55a9c5..7c07c02 100644 --- a/.github/workflows/python-build.yaml +++ b/.github/workflows/python-build.yaml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] + python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12'] steps: - uses: actions/checkout@v3 From 1a386bebe1f6fe9b7590064015c5552deca185d9 Mon Sep 17 00:00:00 2001 From: Stephan Fudeus Date: Sat, 23 Dec 2023 14:16:56 +0100 Subject: [PATCH 09/10] Fix threading issue in 3.12 by explicitly keeping the main thread alive --- exporter.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/exporter.py b/exporter.py index ec503e5..8ed0975 100755 --- a/exporter.py +++ b/exporter.py @@ -13,7 +13,7 @@ from http.server import HTTPServer from pprint import pformat import requests -from prometheus_client import Gauge, Counter, Enum, MetricsHandler, core, Summary +from prometheus_client import Gauge, Counter, Enum, MetricsHandler, core, Summary, start_http_server class HomematicMetricsProcessor(threading.Thread): @@ -338,14 +338,6 @@ class _ThreadingSimpleServer(ThreadingMixIn, HTTPServer): """Thread per request HTTP server.""" -def start_http_server(port, addr='', registry=core.REGISTRY): - """Starts an HTTP server for prometheus metrics as a daemon thread""" - httpd = _ThreadingSimpleServer((addr, port), MetricsHandler.factory(registry)) - thread = threading.Thread(target=httpd.serve_forever) - thread.daemon = False - thread.start() - - if __name__ == '__main__': PARSER = argparse.ArgumentParser() @@ -392,3 +384,5 @@ def start_http_server(port, addr='', registry=core.REGISTRY): # Start up the server to expose the metrics. logging.info("Exposing metrics on port {}".format(ARGS.port)) start_http_server(int(ARGS.port)) + # Wait until the main loop terminates + PROCESSOR.join() From eadefaf7eca6adce61800b72c841a46d0bc3c49e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 23 Dec 2023 13:20:05 +0000 Subject: [PATCH 10/10] Bump python from 3.11-slim-bookworm to 3.12-slim-bookworm Bumps python from 3.11-slim-bookworm to 3.12-slim-bookworm. --- updated-dependencies: - dependency-name: python dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 3db1257..83039dc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11-slim-bookworm +FROM python:3.12-slim-bookworm COPY requirements.txt /tmp RUN pip3 install --no-cache-dir -r /tmp/requirements.txt