Coverage for app/analytics/posthog.py: 93%

27 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2026-06-04 22:29 +0000

1import json 

2from urllib.error import HTTPError, URLError 

3from urllib.request import Request, urlopen 

4from uuid import uuid4 

5 

6from app.core.config import settings 

7from app.core.logger import logger 

8from app.normalization import normalize_package_name 

9 

10 

11def capture_package_requested_events( 

12 packages: list[str], 

13 time_range: str, 

14 show_percentage: bool, 

15 hx_trigger: str | None, 

16 request_id: str | None = None, 

17) -> None: 

18 if not settings.ENABLE_SERVER_ANALYTICS: 

19 return 

20 

21 if settings.POSTHOG_API_KEY is None: 

22 logger.warning("Skipping PostHog package analytics: missing API key") 

23 return 

24 

25 normalized_packages = sorted( 

26 normalize_package_name(package) for package in packages if package.strip() 

27 ) 

28 

29 if not normalized_packages: 

30 return 

31 

32 normalized_request_id = request_id or str(uuid4()) 

33 

34 capture_url = f"{str(settings.POSTHOG_HOST).rstrip('/')}/capture/" 

35 

36 for package in normalized_packages: 

37 payload = { 

38 "api_key": settings.POSTHOG_API_KEY, 

39 "event": "package_requested", 

40 "distinct_id": "server", 

41 "properties": { 

42 "package": package, 

43 "packages": normalized_packages, 

44 "time_range": time_range, 

45 "show_percentage": show_percentage, 

46 "hx_trigger": hx_trigger, 

47 "request_id": normalized_request_id, 

48 "source": "server_htmx", 

49 }, 

50 } 

51 

52 try: 

53 req = Request( 

54 capture_url, 

55 data=json.dumps(payload).encode("utf-8"), 

56 headers={"Content-Type": "application/json"}, 

57 method="POST", 

58 ) 

59 with urlopen(req, timeout=2): 

60 pass 

61 logger.info( 

62 "Submitted PostHog package_requested event " 

63 f"for package='{package}', packages={normalized_packages}, " 

64 f"time_range='{time_range}', hx_trigger='{hx_trigger}', " 

65 f"request_id='{normalized_request_id}'" 

66 ) 

67 except (HTTPError, URLError, TimeoutError) as e: 

68 logger.warning( 

69 f"Failed to capture PostHog event for package '{package}': {e}" 

70 )