Skip to main content
The Analytics class is the SDK surface for VectorShift’s observability data — the same runs, costs, latency, and traces you see in the platform dashboards, available as a chainable query API. Aggregate metrics, list and filter events, drill into a single trace, project a data table, or kick off a long-running export — directly from Python.
Prerequisites: Installed SDK · API key set · Python 3.10+.

Mental model

  • Everything that runs on VectorShift emits events (the wire format calls them spans). An event is one Pipeline run, Chatbot message, KB fetch, Form submission, Session message, etc. — each carrying status, latency, token counts, costs, and a trace_id that links it to siblings.
  • There’s one entry point: Analytics.query(...) returns an immutable, chainable Query. Scope it by object and event kind, refine it with .where(...) and .group_by(...), then call a terminal (.count(), .sum(...), .events(), .table(...), .export(...)) to make the HTTP call and get a typed result.
  • Time scoping is a .where() predicateq.where(EventField.EVENT_START_TIME > cutoff). There is no since= / start= / end= shortcut. Datetimes must be timezone-aware. Aggregations (sum, mean, percentile, raw_aggregate, …) require a lower time bound, or they raise AnalyticsInvalidQuery.
  • Scope is a single object. object= / object_ids= take one resource or one id. To analyse several, query each and merge client-side — passing more than one raises AnalyticsInvalidQuery.
  • Single-object lookups live outside the chain: Analytics.trace(trace_id), Analytics.event(event_id), and Analytics.run(object=…, run_id=…).
  • Every terminal has an async sibling (acount, aevents, asum, atable, aexport, …), and Analytics.aquery(...) returns a Query whose terminals route to them.
Pagination is the data-volume guardrail. Analytics.query(limit=50, offset=0) defaults flow through to every paginated terminal (events, traces, table) and cap how much comes back when no time filter is set. Always time-bound dashboards with .where(EventField.EVENT_START_TIME > …).

Quick start

Scoping a query

Passing a resource to object= reads its .id (and derives object_type from the class name) automatically. Scope resolves to a single object — object=[p1, p2] or object_ids=["a", "b"] raises AnalyticsInvalidQuery; loop and merge instead. Time is always a .where(EventField.EVENT_START_TIME …) predicate on top.

Terminals

Filtering

.where(...) accepts three intermixable forms:
  • Equality kwargsq.where(status="failure", interface_type="chatbot"). Shortest for the common case.
  • Operator overloading on EventFieldq.where(EventField.EVENT_START_TIME > cutoff, EventField.ERROR_MESSAGE.matches("rate limit")). SQLAlchemy / Peewee style.
  • Dataclass helpersFilter (scope fields), FieldFilter (data columns), and FilterGroup for OR groups via logical_op=LogicalOp.OR.
Chained .where() calls AND together. EventField.LATENCY, MODEL_ID, and NODE_TYPE are aggregation / group-by dimensions only — use them in .sum/.mean/.percentile or .group_by(...), not in .where(...).

What’s next

Reference

Every public method, filter, type, and enum.

Query basics example

Scope, time-bound, and run your first terminals.

Aggregations & group-by

Every aggregation terminal, single- and multi-dim.