mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
fix(otel): identify Hermes resources safely
This commit is contained in:
parent
16e774f223
commit
98a0260b0a
4 changed files with 66 additions and 11 deletions
|
|
@ -72,6 +72,20 @@ def _safe_resource_attributes(raw: Any) -> Dict[str, str]:
|
|||
return attrs
|
||||
|
||||
|
||||
def _runtime_resource_attributes(
|
||||
config: Dict[str, Any], *, telemetry_scope: str
|
||||
) -> Dict[str, str]:
|
||||
"""Build the safe OTLP resource shared by metrics and diagnostic logs."""
|
||||
gh = _gateway_health_config(config)
|
||||
attrs = _safe_resource_attributes(gh.get("resource_attributes"))
|
||||
from agent.monitoring.gateway_health import _safe_instance_id
|
||||
|
||||
attrs["service.name"] = "hermes-gateway"
|
||||
attrs["service.instance.id"] = _safe_instance_id(_install_id(config))
|
||||
attrs["telemetry.scope"] = telemetry_scope
|
||||
return attrs
|
||||
|
||||
|
||||
def _diagnostic_log_attributes(event: Dict[str, Any]) -> Dict[str, Any]:
|
||||
attrs: Dict[str, Any] = {}
|
||||
for key in _DIAGNOSTIC_ATTRIBUTE_KEYS:
|
||||
|
|
@ -299,9 +313,9 @@ def _start_metric_provider(config: Dict[str, Any], sdk: Dict[str, Any]) -> Any:
|
|||
exporter = sdk["OTLPMetricExporter"](endpoint=endpoint, headers=headers or None)
|
||||
interval_ms = max(5, int(gh.get("export_interval_seconds", 60))) * 1000
|
||||
reader = sdk["PeriodicExportingMetricReader"](exporter, export_interval_millis=interval_ms)
|
||||
resource_attrs = _safe_resource_attributes(gh.get("resource_attributes"))
|
||||
resource_attrs["service.name"] = "hermes-gateway"
|
||||
resource_attrs["telemetry.scope"] = "gateway_health"
|
||||
resource_attrs = _runtime_resource_attributes(
|
||||
config, telemetry_scope="gateway_health"
|
||||
)
|
||||
provider = sdk["MeterProvider"](
|
||||
metric_readers=[reader],
|
||||
resource=sdk["Resource"].create(resource_attrs),
|
||||
|
|
@ -354,12 +368,11 @@ class GatewayDiagnosticLogStreamer:
|
|||
|
||||
def __init__(self, config: Dict[str, Any], sdk: Dict[str, Any]):
|
||||
otlp = _otlp_config(config)
|
||||
gh = _gateway_health_config(config)
|
||||
headers = _resolve_headers(otlp.get("headers_env"))
|
||||
endpoint = _logs_endpoint(str(otlp.get("endpoint")))
|
||||
resource_attrs = _safe_resource_attributes(gh.get("resource_attributes"))
|
||||
resource_attrs["service.name"] = "hermes-gateway"
|
||||
resource_attrs["telemetry.scope"] = "gateway_diagnostics"
|
||||
resource_attrs = _runtime_resource_attributes(
|
||||
config, telemetry_scope="gateway_diagnostics"
|
||||
)
|
||||
self._provider = sdk["LoggerProvider"](resource=sdk["Resource"].create(resource_attrs))
|
||||
self._processor = sdk["BatchLogRecordProcessor"](
|
||||
sdk["OTLPLogExporter"](endpoint=endpoint, headers=headers or None)
|
||||
|
|
|
|||
|
|
@ -115,12 +115,20 @@ def build_exporter(config: Dict[str, Any]):
|
|||
return sdk["OTLPSpanExporter"](endpoint=endpoint, headers=headers or None)
|
||||
|
||||
|
||||
def _resource_attributes(config: Dict[str, Any]) -> Dict[str, str]:
|
||||
from agent.monitoring.gateway_health import _safe_instance_id
|
||||
from agent.monitoring.policy import ensure_install_id
|
||||
|
||||
return {
|
||||
"service.name": "hermes-gateway",
|
||||
"service.instance.id": _safe_instance_id(ensure_install_id(config)),
|
||||
"telemetry.scope": "gateway_monitoring",
|
||||
}
|
||||
|
||||
|
||||
def _make_provider(config: Dict[str, Any]):
|
||||
sdk = _require_sdk()
|
||||
resource = sdk["Resource"].create({
|
||||
"service.name": "hermes-gateway",
|
||||
"telemetry.scope": "gateway_monitoring",
|
||||
})
|
||||
resource = sdk["Resource"].create(_resource_attributes(config))
|
||||
provider = sdk["TracerProvider"](resource=resource)
|
||||
processor = sdk["BatchSpanProcessor"](build_exporter(config))
|
||||
provider.add_span_processor(processor)
|
||||
|
|
|
|||
|
|
@ -299,6 +299,28 @@ def test_instance_id_hash_is_stable_and_distinguishes_instances():
|
|||
assert "install-1" not in first
|
||||
|
||||
|
||||
def test_runtime_resource_attributes_include_stable_hashed_instance():
|
||||
from agent.monitoring.gateway_health_export import _runtime_resource_attributes
|
||||
|
||||
config = {
|
||||
"monitoring": {
|
||||
"install_id": "private-install-id",
|
||||
"gateway_health_export": {
|
||||
"resource_attributes": {"deployment.environment.name": "staging"}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
attrs = _runtime_resource_attributes(config, telemetry_scope="gateway_health")
|
||||
|
||||
assert attrs["service.name"] == "hermes-gateway"
|
||||
assert attrs["service.instance.id"].startswith("sha256:")
|
||||
assert len(attrs["service.instance.id"]) == len("sha256:") + 24
|
||||
assert "private-install-id" not in str(attrs)
|
||||
assert attrs["deployment.environment.name"] == "staging"
|
||||
assert attrs["telemetry.scope"] == "gateway_health"
|
||||
|
||||
|
||||
def test_diagnostic_log_attributes_are_allowlisted_redacted_and_profile_free():
|
||||
from agent.monitoring.gateway_health_export import _diagnostic_log_attributes
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,18 @@ def test_is_enabled_requires_endpoint_and_flag():
|
|||
assert not OE.is_enabled({})
|
||||
|
||||
|
||||
def test_trace_resource_includes_stable_hashed_instance():
|
||||
attrs = OE._resource_attributes(
|
||||
{"monitoring": {"install_id": "private-install-id"}}
|
||||
)
|
||||
|
||||
assert attrs["service.name"] == "hermes-gateway"
|
||||
assert attrs["service.instance.id"].startswith("sha256:")
|
||||
assert len(attrs["service.instance.id"]) == len("sha256:") + 24
|
||||
assert "private-install-id" not in str(attrs)
|
||||
assert attrs["telemetry.scope"] == "gateway_monitoring"
|
||||
|
||||
|
||||
def test_export_otlp_feature_specs_match_pyproject():
|
||||
from tools.lazy_deps import LAZY_DEPS
|
||||
import re
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue