Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions openhands/automation/telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
import json
import logging
import uuid
from functools import lru_cache
from importlib.metadata import PackageNotFoundError
from typing import Any

import httpx
from fastapi import Request
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker

from openhands.automation import __version__
from openhands.automation.auth import AuthenticatedUser
from openhands.automation.config import get_config
from openhands.automation.middleware import (
Expand All @@ -22,7 +25,11 @@
set_service_metadata,
)
from openhands.automation.utils.time import ensure_utc
from openhands.automation.utils.version import get_server_version_info
from openhands.automation.utils.version import (
ServerVersionInfo,
get_sdk_version,
get_server_version_info,
)


logger = logging.getLogger("automation.telemetry")
Expand Down Expand Up @@ -238,6 +245,20 @@ def _resolve_distinct_id(
)


@lru_cache(maxsize=1)
def _installed_sdk_version() -> str:
# Only successful lookups are cached: lru_cache does not memoize exceptions.
return get_sdk_version()


def _server_version_properties() -> ServerVersionInfo:
try:
sdk_version = _installed_sdk_version()
except PackageNotFoundError:
return get_server_version_info(missing_sdk_version="unknown")
return {"package_version": __version__, "sdk_version": sdk_version}


def _base_properties(
*,
request_context: TelemetryRequestContext,
Expand All @@ -251,7 +272,7 @@ def _base_properties(
"deployment_mode": "local" if settings.is_local_mode else "cloud",
"deployment_kind": "local" if settings.is_local_mode else "remote",
"automation_service": "openhands_automation",
**get_server_version_info(missing_sdk_version="unknown"),
**_server_version_properties(),
}

properties[AUTOMATION_BACKEND_ID_PROPERTY] = backend_distinct_id
Expand Down
40 changes: 39 additions & 1 deletion tests/test_telemetry.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import importlib.metadata
import uuid
from datetime import UTC, datetime, timedelta
from typing import ClassVar
Expand All @@ -24,7 +25,10 @@
from openhands.automation.schemas import TelemetryConsentRequest
from openhands.automation.telemetry_router import set_telemetry_consent
from openhands.automation.utils.run import create_pending_run
from openhands.automation.utils.version import get_server_version_info
from openhands.automation.utils.version import (
SDK_PACKAGE_NAME,
get_server_version_info,
)
from openhands.automation.utils.webhook import create_automation_run


Expand Down Expand Up @@ -613,3 +617,37 @@ async def test_backend_distinct_id_is_db_backed_and_stable():
assert stored == first
finally:
await engine.dispose()


def test_server_version_properties_cache_package_metadata_lookup(monkeypatch):
calls = 0

def package_version(name: str) -> str:
nonlocal calls
calls += 1
assert name == SDK_PACKAGE_NAME
return "1.2.3"

monkeypatch.setattr(importlib.metadata, "version", package_version)
telemetry._installed_sdk_version.cache_clear()
try:
assert telemetry._server_version_properties()["sdk_version"] == "1.2.3"
assert telemetry._server_version_properties()["sdk_version"] == "1.2.3"
assert calls == 1
finally:
telemetry._installed_sdk_version.cache_clear()


def test_server_version_properties_do_not_cache_missing_sdk(monkeypatch):
def missing_package_version(name: str) -> str:
raise importlib.metadata.PackageNotFoundError(name)

monkeypatch.setattr(importlib.metadata, "version", missing_package_version)
telemetry._installed_sdk_version.cache_clear()
try:
assert telemetry._server_version_properties()["sdk_version"] == "unknown"

monkeypatch.setattr(importlib.metadata, "version", lambda name: "1.2.3")
assert telemetry._server_version_properties()["sdk_version"] == "1.2.3"
finally:
telemetry._installed_sdk_version.cache_clear()
Loading