telemetry.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. import asyncio
  2. import functools
  3. import inspect
  4. import os
  5. import threading
  6. import uuid
  7. from importlib.metadata import version
  8. from typing import Optional
  9. import asyncclick as click
  10. from posthog import Posthog
  11. TELEMETRY_DISABLED = (
  12. os.getenv("R2R_CLI_DISABLE_TELEMETRY", "false").lower() == "true"
  13. )
  14. posthog: Optional[Posthog] = None
  15. if not TELEMETRY_DISABLED:
  16. posthog = Posthog(
  17. project_api_key="phc_OPBbibOIErCGc4NDLQsOrMuYFTKDmRwXX6qxnTr6zpU",
  18. host="https://us.i.posthog.com",
  19. )
  20. posthog.debug = True
  21. def telemetry(command):
  22. if TELEMETRY_DISABLED or posthog is None:
  23. # Return the command unmodified
  24. return command
  25. original_callback = command.callback
  26. is_async = inspect.iscoroutinefunction(original_callback)
  27. if is_async:
  28. @functools.wraps(original_callback)
  29. async def tracked_callback(*args, **kwargs):
  30. command_name = command.name
  31. # Extract context from args[0] if it's a Click Context
  32. if args and isinstance(args[0], click.Context):
  33. ctx = args[0]
  34. command_args = ctx.args
  35. command_params = ctx.params
  36. else:
  37. ctx = None
  38. command_args = []
  39. command_params = {}
  40. distinct_id = str(uuid.uuid4())
  41. try:
  42. # Await the original async callback
  43. result = await original_callback(*args, **kwargs)
  44. # Run PostHog capture in a separate thread to avoid blocking
  45. await asyncio.to_thread(
  46. posthog.capture,
  47. distinct_id=distinct_id,
  48. event="cli_command",
  49. properties={
  50. "command": command_name,
  51. "status": "success",
  52. "args": command_args,
  53. "params": command_params,
  54. "version": version("r2r"),
  55. },
  56. )
  57. return result
  58. except Exception as e:
  59. await asyncio.to_thread(
  60. posthog.capture,
  61. distinct_id=distinct_id,
  62. event="cli_command",
  63. properties={
  64. "command": command_name,
  65. "status": "error",
  66. "error_type": type(e).__name__,
  67. "error_message": str(e),
  68. "args": command_args,
  69. "params": command_params,
  70. "version": version("r2r"),
  71. },
  72. )
  73. raise
  74. else:
  75. @functools.wraps(original_callback)
  76. def tracked_callback(*args, **kwargs):
  77. command_name = command.name
  78. # Extract context from args[0] if it's a Click Context
  79. if args and isinstance(args[0], click.Context):
  80. ctx = args[0]
  81. command_args = ctx.args
  82. command_params = ctx.params
  83. else:
  84. ctx = None
  85. command_args = []
  86. command_params = {}
  87. distinct_id = str(uuid.uuid4())
  88. try:
  89. result = original_callback(*args, **kwargs)
  90. # Run PostHog capture in a separate thread to avoid blocking
  91. thread = threading.Thread(
  92. target=posthog.capture,
  93. args=(
  94. distinct_id,
  95. "cli_command",
  96. {
  97. "command": command_name,
  98. "status": "success",
  99. "args": command_args,
  100. "params": command_params,
  101. "version": version("r2r"),
  102. },
  103. ),
  104. daemon=True,
  105. )
  106. thread.start()
  107. return result
  108. except Exception as e:
  109. # Run PostHog capture in a separate thread to avoid blocking
  110. thread = threading.Thread(
  111. target=posthog.capture,
  112. args=(
  113. distinct_id,
  114. "cli_command",
  115. {
  116. "command": command_name,
  117. "status": "error",
  118. "error_type": type(e).__name__,
  119. "error_message": str(e),
  120. "args": command_args,
  121. "params": command_params,
  122. "version": version("r2r"),
  123. },
  124. ),
  125. daemon=True,
  126. )
  127. thread.start()
  128. raise
  129. command.callback = tracked_callback
  130. return command