11import re
22import warnings
33from collections .abc import Callable
4- from dataclasses import dataclass , field
4+ from dataclasses import asdict , dataclass , field
55from datetime import datetime , timedelta , timezone
66from enum import Enum
77from functools import lru_cache
1010from uuid import UUID
1111
1212import boto3
13+ import pandas as pd
1314from google .cloud .storage import Client as GoogleStorageClient
1415from google .cloud .storage .bucket import Bucket
1516from google .protobuf .duration_pb2 import Duration
@@ -542,6 +543,12 @@ def to_message(self) -> logs_pb2.ResourceLogs:
542543 )
543544
544545
546+ class LogRecords (list [LogRecord ]):
547+ def to_pandas (self ) -> Any :
548+ """Convert log records to a pandas DataFrame."""
549+ return pd .DataFrame ([asdict (record ) for record in self ])
550+
551+
545552@dataclass
546553class Span :
547554 start_time : datetime
@@ -614,6 +621,17 @@ def to_message(self) -> trace_pb2.ResourceSpans:
614621 )
615622
616623
624+ class Spans (list [Span ]):
625+ def to_pandas (self ) -> Any :
626+ """Convert spans to a pandas DataFrame."""
627+ rows = []
628+ for span in self :
629+ row = asdict (span )
630+ row ["duration" ] = span .duration
631+ rows .append (row )
632+ return pd .DataFrame (rows )
633+
634+
617635def _datetime_from_unix_nanos (unix_nanos : int ) -> datetime :
618636 return datetime .fromtimestamp (unix_nanos / 1_000_000_000 , tz = timezone .utc )
619637
@@ -635,7 +653,7 @@ def _any_value_to_python(value: common_pb2.AnyValue) -> Any: # noqa: PLR0911
635653 case "bytes_value" :
636654 return value .bytes_value
637655 case "array_value" :
638- return [_any_value_to_python (item ) for item in value .array_value .values ]
656+ return [_any_value_to_python (item ) for item in value .array_value .values ] # noqa: PD011
639657 case "kvlist_value" :
640658 return _key_values_to_dict (value .kvlist_value .values )
641659 case _:
@@ -691,26 +709,26 @@ def _span_event_to_message(event: dict[str, Any]) -> trace_pb2.Span.Event:
691709
692710@dataclass (frozen = True )
693711class QueryJobLogsResponse :
694- logs : list [ LogRecord ]
712+ logs : LogRecords
695713 next_page : Pagination
696714
697715 @classmethod
698716 def from_message (cls , page : Any ) -> "QueryJobLogsResponse" :
699717 return cls (
700- logs = [ LogRecord .from_message (log_record ) for log_record in page .resource_logs ] ,
718+ logs = LogRecords ( LogRecord .from_message (log_record ) for log_record in page .resource_logs ) ,
701719 next_page = Pagination .from_message (page .next_page ),
702720 )
703721
704722
705723@dataclass (frozen = True )
706724class QueryJobSpansResponse :
707- spans : list [ Span ]
725+ spans : Spans
708726 next_page : Pagination
709727
710728 @classmethod
711729 def from_message (cls , page : Any ) -> "QueryJobSpansResponse" :
712730 return cls (
713- spans = [ Span .from_message (span ) for span in page .resource_spans ] ,
731+ spans = Spans ( Span .from_message (span ) for span in page .resource_spans ) ,
714732 next_page = Pagination .from_message (page .next_page ),
715733 )
716734
0 commit comments