@@ -174,7 +174,8 @@ def wrapper(*args, **kwargs):
174174 full_method_name = f"{ base_name .lower ()} -{ api_method_name } "
175175 # Track directly called methods
176176 if len (_call_stack ) == 0 :
177- add_api_method (full_method_name )
177+ session = _find_session (* args , ** kwargs )
178+ add_api_method (full_method_name , session = session )
178179
179180 _call_stack .append (full_method_name )
180181
@@ -220,7 +221,8 @@ def wrapped(*args, **kwargs):
220221 full_property_name = f"{ class_name .lower ()} -{ property_name .lower ()} "
221222
222223 if len (_call_stack ) == 0 :
223- add_api_method (full_property_name )
224+ session = _find_session (* args , ** kwargs )
225+ add_api_method (full_property_name , session = session )
224226
225227 _call_stack .append (full_property_name )
226228 try :
@@ -250,25 +252,41 @@ def wrapper(func):
250252 return wrapper
251253
252254
253- def add_api_method (api_method_name ):
255+ def add_api_method (api_method_name , session = None ):
254256 global _lock
255257 global _api_methods
256- with _lock :
257- # Push the method to the front of the _api_methods list
258- _api_methods .insert (0 , api_method_name .replace ("<" , "" ).replace (">" , "" ))
259- # Keep the list length within the maximum limit (adjust MAX_LABELS_COUNT as needed)
260- _api_methods = _api_methods [:MAX_LABELS_COUNT ]
261258
259+ clean_method_name = api_method_name .replace ("<" , "" ).replace (">" , "" )
260+
261+ if session is not None and _is_session_initialized (session ):
262+ with session ._api_methods_lock :
263+ session ._api_methods .insert (0 , clean_method_name )
264+ session ._api_methods = session ._api_methods [:MAX_LABELS_COUNT ]
265+ else :
266+ with _lock :
267+ # Push the method to the front of the _api_methods list
268+ _api_methods .insert (0 , clean_method_name )
269+ # Keep the list length within the maximum limit (adjust MAX_LABELS_COUNT as needed)
270+ _api_methods = _api_methods [:MAX_LABELS_COUNT ]
262271
263- def get_and_reset_api_methods (dry_run : bool = False ):
272+
273+ def get_and_reset_api_methods (dry_run : bool = False , session = None ):
264274 global _lock
275+ methods = []
276+
277+ if session is not None and _is_session_initialized (session ):
278+ with session ._api_methods_lock :
279+ methods .extend (session ._api_methods )
280+ if not dry_run :
281+ session ._api_methods .clear ()
282+
265283 with _lock :
266- previous_api_methods = list (_api_methods )
284+ methods . extend (_api_methods )
267285
268286 # dry_run might not make a job resource, so only reset the log on real queries.
269287 if not dry_run :
270288 _api_methods .clear ()
271- return previous_api_methods
289+ return methods
272290
273291
274292def _get_bq_client (* args , ** kwargs ):
@@ -283,3 +301,36 @@ def _get_bq_client(*args, **kwargs):
283301 return kwargv ._block .session .bqclient
284302
285303 return None
304+
305+
306+ def _is_session_initialized (session ):
307+ """Return True if fully initialized.
308+
309+ Because the method logger could get called before Session.__init__ has a
310+ chance to run, we use the globals in that case.
311+ """
312+ return hasattr (session , "_api_methods_lock" ) and hasattr (session , "_api_methods" )
313+
314+
315+ def _find_session (* args , ** kwargs ):
316+ # This function cannot import Session at the top level because Session
317+ # imports log_adapter.
318+ from bigframes .session import Session
319+
320+ session = args [0 ] if args else None
321+ if (
322+ session is not None
323+ and isinstance (session , Session )
324+ and _is_session_initialized (session )
325+ ):
326+ return session
327+
328+ session = kwargs .get ("session" )
329+ if (
330+ session is not None
331+ and isinstance (session , Session )
332+ and _is_session_initialized (session )
333+ ):
334+ return session
335+
336+ return None
0 commit comments