Skip to content

Tracing

obspec_utils.wrappers.TracingReadableStore

Bases: ReadableStore

A wrapper that traces all requests made to an underlying store.

This wrapper records all get/get_range/get_ranges calls for later analysis.

Examples:

import obstore as obs
from obspec_utils.wrappers import TracingReadableStore, RequestTrace

# Create the underlying store
store = obs.store.from_url("s3://bucket", region="us-east-1")

# Wrap with tracing
trace = RequestTrace()
traced_store = TracingReadableStore(store, trace)

# Use traced_store in place of store
# ... do operations ...

# Analyze the trace
df = trace.to_dataframe()
print(trace.summary())

__getattr__

__getattr__(name: str) -> Any

Forward unknown attributes to the underlying store.

This ensures TracingReadableStore is transparent for any additional methods the underlying store may have (e.g., head() for the Head protocol).

__init__

__init__(
    store: ReadableStore,
    trace: RequestTrace,
    *,
    on_request: Callable[[RequestRecord], None] | None = None,
) -> None

Create a tracing wrapper around a store.

Parameters:

get

get(path: str, *, options: GetOptions | None = None) -> GetResult

Get entire file (delegates to underlying store).

get_async async

get_async(path: str, *, options: GetOptions | None = None) -> GetResultAsync

Get entire file async (delegates to underlying store).

get_range

get_range(
    path: str, *, start: int, end: int | None = None, length: int | None = None
) -> Buffer

Get a byte range (delegates to underlying store).

get_range_async async

get_range_async(
    path: str, *, start: int, end: int | None = None, length: int | None = None
) -> Buffer

Get a byte range async (delegates to underlying store).

get_ranges

get_ranges(
    path: str,
    *,
    starts: Sequence[int],
    ends: Sequence[int] | None = None,
    lengths: Sequence[int] | None = None,
) -> Sequence[Buffer]

Get multiple byte ranges (delegates to underlying store).

get_ranges_async async

get_ranges_async(
    path: str,
    *,
    starts: Sequence[int],
    ends: Sequence[int] | None = None,
    lengths: Sequence[int] | None = None,
) -> Sequence[Buffer]

Get multiple byte ranges async (delegates to underlying store).

head

head(path: str) -> ObjectMeta

Get file metadata (delegates to underlying store).

head_async async

head_async(path: str) -> ObjectMeta

Get file metadata async (delegates to underlying store).

obspec_utils.wrappers.RequestTrace dataclass

Collection of request records with analysis methods.

total_bytes property

total_bytes: int

Total bytes requested.

total_requests property

total_requests: int

Total number of requests.

add

add(
    path: str,
    start: int,
    length: int,
    timestamp: float,
    duration: float | None = None,
    method: Literal["get", "get_range", "get_ranges", "head"] = "get_range",
    range_style: Literal["end", "length"] | None = None,
) -> None

Add a request record.

clear

clear() -> None

Clear all recorded requests.

summary

summary() -> dict[str, Any]

Get summary statistics.

to_dataframe

to_dataframe()

Convert to pandas DataFrame.

obspec_utils.wrappers.RequestRecord dataclass

Record of a single range request.

Note

The duration field measures the time spent in the store method call. For get_range and get_ranges, this includes the actual data transfer. For get and get_async, the duration may not include the full transfer time if the underlying store returns a lazy GetResult whose data is only fetched when .buffer() is called.