telemetry: pluggable Unity sender; add MCP_DISABLE_TELEMETRY; server reads version file; locks for milestones
parent
f6a5568865
commit
2abca24e9d
|
|
@ -12,6 +12,7 @@ namespace MCPForUnity.Editor.Helpers
|
|||
{
|
||||
private const string TELEMETRY_DISABLED_KEY = "MCPForUnity.TelemetryDisabled";
|
||||
private const string CUSTOMER_UUID_KEY = "MCPForUnity.CustomerUUID";
|
||||
private static Action<Dictionary<string, object>> s_sender;
|
||||
|
||||
/// <summary>
|
||||
/// Check if telemetry is enabled (can be disabled via Environment Variable or EditorPrefs)
|
||||
|
|
@ -35,6 +36,14 @@ namespace MCPForUnity.Editor.Helpers
|
|||
return false;
|
||||
}
|
||||
|
||||
// Honor protocol-wide opt-out as well
|
||||
var mcpDisable = Environment.GetEnvironmentVariable("MCP_DISABLE_TELEMETRY");
|
||||
if (!string.IsNullOrEmpty(mcpDisable) &&
|
||||
(mcpDisable.Equals("true", StringComparison.OrdinalIgnoreCase) || mcpDisable == "1"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check EditorPrefs
|
||||
return !UnityEditor.EditorPrefs.GetBool(TELEMETRY_DISABLED_KEY, false);
|
||||
}
|
||||
|
|
@ -110,6 +119,14 @@ namespace MCPForUnity.Editor.Helpers
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows the bridge to register a concrete sender for telemetry payloads.
|
||||
/// </summary>
|
||||
public static void RegisterTelemetrySender(Action<Dictionary<string, object>> sender)
|
||||
{
|
||||
s_sender = sender;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Record bridge startup event
|
||||
/// </summary>
|
||||
|
|
@ -162,15 +179,28 @@ namespace MCPForUnity.Editor.Helpers
|
|||
|
||||
private static void SendTelemetryToPythonServer(Dictionary<string, object> telemetryData)
|
||||
{
|
||||
// This would integrate with the existing bridge communication system
|
||||
// For now, we'll just log it when debug is enabled
|
||||
var sender = s_sender;
|
||||
if (sender != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
sender(telemetryData);
|
||||
return;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (IsDebugEnabled())
|
||||
{
|
||||
Debug.LogWarning($"Telemetry sender error (non-blocking): {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: log when debug is enabled
|
||||
if (IsDebugEnabled())
|
||||
{
|
||||
Debug.Log($"<b><color=#2EA3FF>MCP-TELEMETRY</color></b>: {telemetryData["event_type"]}");
|
||||
}
|
||||
|
||||
// TODO: Integrate with MCPForUnityBridge command system
|
||||
// We would send this as a special telemetry command to the Python server
|
||||
}
|
||||
|
||||
private static bool IsDebugEnabled()
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
3.3.0
|
||||
|
|
@ -27,8 +27,15 @@ async def server_lifespan(server: FastMCP) -> AsyncIterator[Dict[str, Any]]:
|
|||
|
||||
# Record server startup telemetry
|
||||
start_time = time.time()
|
||||
start_clk = time.perf_counter()
|
||||
try:
|
||||
from pathlib import Path
|
||||
ver_path = Path(__file__).parent / "server-version.txt"
|
||||
server_version = ver_path.read_text(encoding="utf-8").strip()
|
||||
except Exception:
|
||||
server_version = "unknown"
|
||||
record_telemetry(RecordType.STARTUP, {
|
||||
"server_version": "3.0.2",
|
||||
"server_version": server_version,
|
||||
"startup_time": start_time
|
||||
})
|
||||
|
||||
|
|
@ -45,15 +52,23 @@ async def server_lifespan(server: FastMCP) -> AsyncIterator[Dict[str, Any]]:
|
|||
"connection_time_ms": (time.time() - start_time) * 1000
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not connect to Unity on startup: {str(e)}")
|
||||
except ConnectionError as e:
|
||||
logger.warning("Could not connect to Unity on startup: %s", e)
|
||||
_unity_connection = None
|
||||
|
||||
# Record connection failure
|
||||
record_telemetry(RecordType.UNITY_CONNECTION, {
|
||||
"status": "failed",
|
||||
"error": str(e)[:200],
|
||||
"connection_time_ms": (time.time() - start_time) * 1000
|
||||
"connection_time_ms": (time.perf_counter() - start_clk) * 1000
|
||||
})
|
||||
except Exception as e:
|
||||
logger.warning("Unexpected error connecting to Unity on startup: %s", e)
|
||||
_unity_connection = None
|
||||
record_telemetry(RecordType.UNITY_CONNECTION, {
|
||||
"status": "failed",
|
||||
"error": str(e)[:200],
|
||||
"connection_time_ms": (time.perf_counter() - start_clk) * 1000
|
||||
})
|
||||
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ class TelemetryCollector:
|
|||
self.config = TelemetryConfig()
|
||||
self._customer_uuid: Optional[str] = None
|
||||
self._milestones: Dict[str, Dict[str, Any]] = {}
|
||||
self._lock: threading.Lock = threading.Lock()
|
||||
self._load_persistent_data()
|
||||
|
||||
def _load_persistent_data(self):
|
||||
|
|
@ -199,16 +200,14 @@ class TelemetryCollector:
|
|||
"""Record a milestone event, returns True if this is the first occurrence"""
|
||||
if not self.config.enabled:
|
||||
return False
|
||||
|
||||
milestone_key = milestone.value
|
||||
with self._lock:
|
||||
if milestone_key in self._milestones:
|
||||
return False # Already recorded
|
||||
|
||||
milestone_data = {
|
||||
"timestamp": time.time(),
|
||||
"data": data or {}
|
||||
"data": data or {},
|
||||
}
|
||||
|
||||
self._milestones[milestone_key] = milestone_data
|
||||
self._save_milestones()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue