diff --git a/.build/dockerfiles/Dockerfile b/.build/dockerfiles/Dockerfile index f40c325..d6b1608 100644 --- a/.build/dockerfiles/Dockerfile +++ b/.build/dockerfiles/Dockerfile @@ -3,7 +3,7 @@ # # Dev image used for local development # -FROM zcscompany/python:3.11-dev AS dev +FROM zcscompany/python:3.13-dev AS dev ARG FIX_UID ARG FIX_GID @@ -24,7 +24,7 @@ USER ${DOCKER_USER} # # Image used for application distribution # -FROM zcscompany/python:3.11-dist AS dist +FROM zcscompany/python:3.13-dist AS dist ARG DOCKER_USER=bob ARG DOCKER_GROUP=bob diff --git a/.github/workflows/pr_build-and-test.yaml b/.github/workflows/pr_build-and-test.yaml index 894600d..86edf8d 100644 --- a/.github/workflows/pr_build-and-test.yaml +++ b/.github/workflows/pr_build-and-test.yaml @@ -16,7 +16,7 @@ jobs: steps: - id: checkout name: Checkout project - uses: actions/checkout@v4 + uses: actions/checkout@v6 - id: build name: Build dist docker image diff --git a/.github/workflows/publish-tag.yaml b/.github/workflows/publish-tag.yaml index c4938a7..455ecdf 100644 --- a/.github/workflows/publish-tag.yaml +++ b/.github/workflows/publish-tag.yaml @@ -49,7 +49,7 @@ jobs: run: python -m build - name: 'Set up Cloud SDK' - uses: 'google-github-actions/setup-gcloud@v2' + uses: google-github-actions/setup-gcloud@v3 with: version: '>= 363.0.0' @@ -71,7 +71,7 @@ jobs: fi - name: Create GitHub Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v3 with: generate_release_notes: true prerelease: ${{ steps.check_prerelease.outputs.prerelease }} \ No newline at end of file diff --git a/app/requirements.txt b/app/requirements.txt index 7d2c031..d326b7a 100644 --- a/app/requirements.txt +++ b/app/requirements.txt @@ -1,4 +1,5 @@ -build==1.2.1 -pytest==8.3.3 +build==1.5.0 +pytest==9.1.1 -pydantic_settings==2.14.1 +pydantic_settings==2.14.2 +prometheus_client==0.25.0 diff --git a/app/src/zcs/core/telemetry/zcs_telemetry.py b/app/src/zcs/core/telemetry/zcs_telemetry.py index 72124f1..7e9d9af 100644 --- a/app/src/zcs/core/telemetry/zcs_telemetry.py +++ b/app/src/zcs/core/telemetry/zcs_telemetry.py @@ -71,7 +71,7 @@ def get_tracer(self): def is_telemetry_enabled(self) -> bool: return self._telemetry_initialized - def counter_create(self, name, unit, description): + def counter_create(self, name, unit, description, label_names=None): if not self._telemetry_initialized: self._logger.warning("Telemetry is not initialized - cannot create counter") return @@ -89,7 +89,7 @@ def counter_create(self, name, unit, description): try: from prometheus_client import Counter as PrometheusCounter safe_name = name.replace(".", "_").replace("-", "_") - self._prometheus_counters[name] = PrometheusCounter(safe_name, description) + self._prometheus_counters[name] = PrometheusCounter(safe_name, description, label_names or []) except ImportError: self._logger.warning("prometheus_client is not installed - Alloy Prometheus counter skipped") diff --git a/app/tests/zcs/core/telemetry/telemetry_test.py b/app/tests/zcs/core/telemetry/telemetry_test.py index ef4b1db..288dab6 100644 --- a/app/tests/zcs/core/telemetry/telemetry_test.py +++ b/app/tests/zcs/core/telemetry/telemetry_test.py @@ -1,4 +1,7 @@ +import logging + from zcs.core.settings.telemetry_settings import TelemetrySettings +from zcs.core.telemetry.zcs_telemetry import ZcsTelemetry def test_telemetry_settings_otlp_and_loki_flags() -> None: @@ -10,3 +13,43 @@ def test_telemetry_settings_otlp_and_loki_flags() -> None: assert settings.has_otlp_config assert settings.has_loki_config + + +def _prometheus_alloy_telemetry() -> ZcsTelemetry: + telemetry = object.__new__(ZcsTelemetry) + telemetry._telemetry_initialized = True + telemetry._alloy_metrics_via_prometheus = True + telemetry._meters = {} + telemetry._custom_metrics = {} + telemetry._prometheus_counters = {} + telemetry._logger = logging.getLogger(__name__) + return telemetry + + +def test_counter_create_with_label_names_allows_labeled_counter_add() -> None: + telemetry = _prometheus_alloy_telemetry() + + telemetry.counter_create( + name="labeled_counter_test", + unit="1", + description="test counter with labels", + label_names=["sender"], + ) + telemetry.counter_add("labeled_counter_test", {"sender": "123"}) + + counter = telemetry._prometheus_counters["labeled_counter_test"] + assert counter.labels(sender="123")._value.get() == 1 + + +def test_counter_create_without_label_names_allows_unlabeled_counter_add() -> None: + telemetry = _prometheus_alloy_telemetry() + + telemetry.counter_create( + name="unlabeled_counter_test", + unit="1", + description="test counter without labels", + ) + telemetry.counter_add("unlabeled_counter_test") + + counter = telemetry._prometheus_counters["unlabeled_counter_test"] + assert counter._value.get() == 1