from __future__ import annotations import json import os import sys from http import HTTPStatus from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from packages.hub_observability import build_telemetry, trace_from_headers, valid_trace_id from packages.hub_runtime.secret_files import SecretFileError, validate_required_secret_paths from services.observability.health import DependencyHealth, aggregate_health def _validate_startup() -> None: try: validate_required_secret_paths(os.environ.get("REQUIRED_SECRET_FILES", "")) except (SecretFileError, ValueError): sys.stderr.write("required runtime secret validation failed\n") raise SystemExit(78) from None _validate_startup() _telemetry = build_telemetry(os.environ.get("SERVICE_NAME", "unknown")) def _trace_id(handler: BaseHTTPRequestHandler) -> str: candidate = handler.headers.get("X-Trace-Id", "") if valid_trace_id(candidate): return candidate.lower() return trace_from_headers({"traceparent": handler.headers.get("traceparent", "")}).trace_id def _dependencies() -> list[DependencyHealth]: raw = os.environ.get("DEPENDENCY_HEALTH_JSON", "") if not raw: return [DependencyHealth(os.environ.get("SERVICE_NAME", "unknown"), "healthy")] try: document = json.loads(raw) except ValueError: return [ DependencyHealth( "configuration", "unhealthy", detail="invalid dependency health configuration" ) ] if not isinstance(document, dict): return [ DependencyHealth( "configuration", "unhealthy", detail="dependency health must be an object" ) ] values = [] for name, value in document.items(): if not isinstance(value, dict): continue values.append( DependencyHealth( str(name)[:64], str(value.get("status", "unknown")), bool(value.get("required", True)), bool(value.get("authoritative", True)), str(value.get("detail", "")), ) ) return values or [ DependencyHealth("configuration", "unhealthy", detail="no dependencies configured") ] class HealthHandler(BaseHTTPRequestHandler): server_version = "ITWorxHealth/0.2" def do_GET(self) -> None: # noqa: N802 trace_id = _trace_id(self) if self.path == "/metrics": body = _telemetry.metrics.render_prometheus().encode("utf-8") self._write(HTTPStatus.OK, body, "text/plain; version=0.0.4", trace_id) return if self.path == "/health/aggregate": aggregate = aggregate_health(_dependencies()) status = ( HTTPStatus.OK if aggregate.status != "unhealthy" else HTTPStatus.SERVICE_UNAVAILABLE ) self._write_json( status, aggregate.payload( service=os.environ.get("SERVICE_NAME", "unknown"), trace_id=trace_id ), trace_id, ) return if self.path not in {"/health", "/healthz", "/ready"}: self.send_error(HTTPStatus.NOT_FOUND) return _telemetry.metrics.inc("itworx_health_requests_total", labels={"path": self.path}) _telemetry.logger.emit("HEALTH_REQUEST", trace_id, fields={"path": self.path}) self._write_json( HTTPStatus.OK, { "status": "ok", "service": os.environ.get("SERVICE_NAME", "unknown"), "traceId": trace_id, }, trace_id, ) def _write_json(self, status: HTTPStatus, payload: dict[str, object], trace_id: str) -> None: self._write( status, json.dumps(payload, separators=(",", ":")).encode("utf-8"), "application/json", trace_id, ) def _write(self, status: HTTPStatus, body: bytes, content_type: str, trace_id: str) -> None: self.send_response(status) self.send_header("Content-Type", content_type) self.send_header("Content-Length", str(len(body))) self.send_header("X-Trace-Id", trace_id) self.end_headers() if body: self.wfile.write(body) def log_message(self, _format: str, *_args: object) -> None: return if __name__ == "__main__": ThreadingHTTPServer(("0.0.0.0", 8080), HealthHandler).serve_forever() # noqa: S104