20
20
import platform
21
21
import uuid
22
22
import locale
23
+ from abc import ABC , abstractmethod
23
24
24
25
25
- class TelemetryClient :
26
- def __init__ (
27
- self ,
28
- telemetry_enabled ,
29
- batch_size ,
30
- connection_uuid ,
31
- ** kwargs
32
- ):
26
+ class BaseTelemetryClient (ABC ):
27
+ @abstractmethod
28
+ def export_initial_telemetry_log (self , ** kwargs ):
29
+ pass
30
+
31
+ @abstractmethod
32
+ def close (self ):
33
+ pass
34
+
35
+
36
+ class NoopTelemetryClient (BaseTelemetryClient ):
37
+ _instance = None
38
+
39
+ def __new__ (cls ):
40
+ if cls ._instance is None :
41
+ cls ._instance = super (NoopTelemetryClient , cls ).__new__ (cls )
42
+ return cls ._instance
43
+
44
+ def export_initial_telemetry_log (self , ** kwargs ):
45
+ pass
46
+
47
+ def close (self ):
48
+ pass
49
+
50
+
51
+ class TelemetryClient (BaseTelemetryClient ):
52
+ def __init__ (self , telemetry_enabled , batch_size , connection_uuid , ** kwargs ):
33
53
self .telemetry_enabled = telemetry_enabled
34
54
self .batch_size = batch_size
35
55
self .connection_uuid = connection_uuid
@@ -55,11 +75,12 @@ def flush(self):
55
75
self .events_batch = []
56
76
57
77
if events_to_flush :
58
- telemetry_manager ._send_telemetry (events_to_flush , self .host_url , self .is_authenticated , self .auth_provider )
59
-
60
- def close (self ):
61
- """Flush remaining events before closing"""
62
- self .flush ()
78
+ telemetry_client_factory ._send_telemetry (
79
+ events_to_flush ,
80
+ self .host_url ,
81
+ self .is_authenticated ,
82
+ self .auth_provider ,
83
+ )
63
84
64
85
def export_initial_telemetry_log (self , ** kwargs ):
65
86
http_path = kwargs .get ("http_path" , None )
@@ -94,35 +115,28 @@ def export_initial_telemetry_log(self, **kwargs):
94
115
entry = FrontendLogEntry (
95
116
sql_driver_log = TelemetryEvent (
96
117
session_id = self .connection_uuid ,
97
- system_configuration = TelemetryManager .getDriverSystemConfiguration (),
118
+ system_configuration = telemetry_client_factory .getDriverSystemConfiguration (),
98
119
driver_connection_params = self .DriverConnectionParameters ,
99
120
)
100
121
),
101
122
)
102
123
103
124
self .export_event (telemetry_frontend_log )
104
125
126
+ def close (self ):
127
+ """Flush remaining events before closing"""
128
+ self .flush ()
129
+ telemetry_client_factory .close (self .connection_uuid )
105
130
106
- class TelemetryManager :
107
- """A singleton manager class that handles telemetry operations for SQL connections.
108
-
109
- This class maintains a map of connection_uuid to TelemetryClient instances. The initialize()
110
- method is only called from the connection class when telemetry is enabled for that connection.
111
- All telemetry operations (initial logs, failure logs, latency logs) first check if the
112
- connection_uuid exists in the map. If it doesn't exist (meaning telemetry was not enabled
113
- for that connection), the operation is skipped. If it exists, the operation is delegated
114
- to the corresponding TelemetryClient instance.
115
131
116
- This design ensures that telemetry operations are only performed for connections where
117
- telemetry was explicitly enabled during initialization.
118
- """
132
+ class TelemetryClientFactory :
119
133
120
134
_instance = None
121
135
_DRIVER_SYSTEM_CONFIGURATION = None
122
136
123
137
def __new__ (cls ):
124
138
if cls ._instance is None :
125
- cls ._instance = super (TelemetryManager , cls ).__new__ (cls )
139
+ cls ._instance = super (TelemetryClientFactory , cls ).__new__ (cls )
126
140
cls ._instance ._initialized = False
127
141
return cls ._instance
128
142
@@ -131,15 +145,13 @@ def __init__(self):
131
145
return
132
146
133
147
self ._clients = {} # Map of connection_uuid -> TelemetryClient
134
- self .executor = ThreadPoolExecutor (max_workers = 10 ) # Thread pool for async operations TODO: Decide on max workers
148
+ self .executor = ThreadPoolExecutor (
149
+ max_workers = 10
150
+ ) # Thread pool for async operations TODO: Decide on max workers
135
151
self ._initialized = True
136
152
137
- def initialize_telemetry_client (
138
- self ,
139
- telemetry_enabled ,
140
- batch_size ,
141
- connection_uuid ,
142
- ** kwargs
153
+ def get_telemetry_client (
154
+ self , telemetry_enabled , batch_size , connection_uuid , ** kwargs
143
155
):
144
156
"""Initialize a telemetry client for a specific connection if telemetry is enabled"""
145
157
if telemetry_enabled :
@@ -148,8 +160,11 @@ def initialize_telemetry_client(
148
160
telemetry_enabled = telemetry_enabled ,
149
161
batch_size = batch_size ,
150
162
connection_uuid = connection_uuid ,
151
- ** kwargs
163
+ ** kwargs ,
152
164
)
165
+ return self ._clients [connection_uuid ]
166
+ else :
167
+ return NoopTelemetryClient ()
153
168
154
169
def _send_telemetry (self , events , host_url , is_authenticated , auth_provider ):
155
170
"""Send telemetry events to the server"""
@@ -168,20 +183,9 @@ def _send_telemetry(self, events, host_url, is_authenticated, auth_provider):
168
183
auth_provider .add_headers (headers )
169
184
170
185
self .executor .submit (
171
- requests .post ,
172
- url ,
173
- data = json .dumps (request ),
174
- headers = headers ,
175
- timeout = 10
186
+ requests .post , url , data = json .dumps (request ), headers = headers , timeout = 10
176
187
)
177
188
178
- def export_initial_telemetry_log (
179
- self , connection_uuid , ** kwargs
180
- ):
181
- """Export initial telemetry for a specific connection"""
182
- if connection_uuid in self ._clients :
183
- self ._clients [connection_uuid ].export_initial_telemetry_log (** kwargs )
184
-
185
189
@classmethod
186
190
def getDriverSystemConfiguration (cls ) -> DriverSystemConfiguration :
187
191
if cls ._DRIVER_SYSTEM_CONFIGURATION is None :
@@ -202,17 +206,13 @@ def getDriverSystemConfiguration(cls) -> DriverSystemConfiguration:
202
206
)
203
207
return cls ._DRIVER_SYSTEM_CONFIGURATION
204
208
205
- def close_telemetry_client (self , connection_uuid ):
206
- """Close telemetry client"""
207
- if connection_uuid :
208
- if connection_uuid in self ._clients :
209
- self ._clients [connection_uuid ].close ()
210
- del self ._clients [connection_uuid ]
211
-
209
+ def close (self , connection_uuid ):
210
+ del self ._clients [connection_uuid ]
211
+
212
212
# Shutdown executor if no more clients
213
213
if not self ._clients :
214
214
self .executor .shutdown (wait = True )
215
215
216
216
217
217
# Create a global instance
218
- telemetry_manager = TelemetryManager ()
218
+ telemetry_client_factory = TelemetryClientFactory ()
0 commit comments