Applies to:
- Plan - Pro and Enterprise for custom SQL charts
- Deployment - Any
- Use case - How to build accurate multi-project cost dashboards and SQL charts that filter by root-span metadata (user_id) while aggregating estimated_cost() across traces/projects
Summary
Use Cross-trace filtering for cost charts filtered by root-span metadata so contributing child spans remain included.What is happening
Span filtering matches individual spans. A filter on a field that exists on a different span will exclude those measured spans. Cross-trace filtering includes all spans from traces where any span matches the filter.Fix or suggestion
For unattributed cost across projects, use a per-trace aggregation pattern. Group byroot_span_id, surface metadata with any_value(), sum estimated_cost() for the selected spans, then filter for missing user_id and aggregate in an outer query.
Example per-trace rollup across projects:
Option 1: Use spans shape and WHERE is_root for root-only inspection
Use this when you only need root-span rows. WHERE is_root = true is also valid.
Example: count root spans and roots with user_id for one project.
Option 2: Use traces or summary shape with ANY_SPAN(...)
Use this when you need the traces or summary shape but must restrict traces by a root-span condition.
Example: match traces whose root span has a metadata.user_id value of 123.
How to confirm it worked
- Use the root-count query to inspect where
user_idis present. Roots withoutuser_idwill still have zeroroot_spans_with_user_id. - Compare summed
estimated_cost()before and after switching to Cross-trace filtering. Totals can change because additional spans contribute. Each span’s estimated cost calculation remains unchanged.
Notes
- Select projects by passing their IDs to
project_logs()becauseproject_idis not guaranteed as a row field. - For a per-project breakdown, query each project separately. Passing multiple project IDs combines their data.