Initial curated ITWorx_MCP_Hub source from 368fba691ea8d23403b4d56b53b5ec670d7c5020
This commit is contained in:
commit
cb5be898ea
663 files changed
+82674
No files matched your search
@@ -0,0 +1,78 @@
|
||||
"""Minimal internal OTLP/HTTP collector for the optional observer profile.
|
||||
|
||||
It accepts bounded trace batches, keeps only counters in memory, and exposes
|
||||
Prometheus text metrics. It never logs request bodies or trace attributes.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from http import HTTPStatus
|
||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||
from threading import Lock
|
||||
|
||||
MAX_BODY = 1024 * 1024
|
||||
_lock = Lock()
|
||||
_spans = 0
|
||||
_batches = 0
|
||||
|
||||
|
||||
class CollectorHandler(BaseHTTPRequestHandler):
|
||||
server_version = "ITWorxOTLPCollector/1.0"
|
||||
|
||||
def do_GET(self) -> None: # noqa: N802
|
||||
if self.path == "/healthz":
|
||||
self._write(
|
||||
HTTPStatus.OK,
|
||||
b'{"status":"ok","component":"observability-collector"}',
|
||||
"application/json",
|
||||
)
|
||||
return
|
||||
if self.path == "/metrics":
|
||||
with _lock:
|
||||
body = (
|
||||
f"itworx_otel_batches_total {_batches}\\nitworx_otel_spans_total {_spans}\\n"
|
||||
).encode()
|
||||
self._write(HTTPStatus.OK, body, "text/plain; version=0.0.4")
|
||||
return
|
||||
self.send_error(HTTPStatus.NOT_FOUND)
|
||||
|
||||
def do_POST(self) -> None: # noqa: N802
|
||||
global _batches, _spans
|
||||
if self.path != "/v1/traces":
|
||||
self.send_error(HTTPStatus.NOT_FOUND)
|
||||
return
|
||||
length = int(self.headers.get("Content-Length", "0"))
|
||||
if length <= 0 or length > MAX_BODY:
|
||||
self.send_error(HTTPStatus.REQUEST_ENTITY_TOO_LARGE)
|
||||
return
|
||||
try:
|
||||
document = json.loads(self.rfile.read(length))
|
||||
batches = document.get("resourceSpans", [])
|
||||
spans = sum(
|
||||
len(scope.get("spans", []))
|
||||
for batch in batches
|
||||
for scope in batch.get("scopeSpans", [])
|
||||
)
|
||||
except (ValueError, TypeError, AttributeError):
|
||||
self.send_error(HTTPStatus.BAD_REQUEST)
|
||||
return
|
||||
with _lock:
|
||||
_batches += 1
|
||||
_spans += spans
|
||||
self._write(HTTPStatus.ACCEPTED, b"", "text/plain")
|
||||
|
||||
def _write(self, status: HTTPStatus, body: bytes, content_type: str) -> None:
|
||||
self.send_response(status)
|
||||
self.send_header("Content-Type", content_type)
|
||||
self.send_header("Content-Length", str(len(body)))
|
||||
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", 4318), CollectorHandler).serve_forever() # noqa: S104
|
||||
Reference in new issue
Block a user