Track token usage
This query helps you monitor token consumption across your application.Analyze cost breakdown
Useestimated_cost_component() to break total cost into its components. This is useful for understanding how much of your spend comes from cached reads vs. uncached prompt tokens vs. completions.
For models with two-tier cache creation (e.g. Anthropic), replace
promptCacheCreationTokensCost with promptCacheCreation5mTokensCost and promptCacheCreation1hTokensCost to split by tier.estimated_cost_breakdown() when you want all components at once as a JSON object, for example to export or inspect the full breakdown per span.
Monitor model quality
Track model performance across different versions and configurations.Analyze errors
Identify and investigate errors in your application.Analyze latency
Monitor and optimize response times.Analyze prompts
Analyze prompt effectiveness and patterns.Analyze based on tags
Use tags to track and analyze specific behaviors. In SQL mode, useIN and NOT IN to filter tags by exact membership:
tags IN ('needs-review') matches rows where needs-review is one of the tags, and tags NOT IN ('resolved') matches rows without the resolved tag. NOT IN excludes rows where tags is null or absent.
MATCH (tags MATCH 'feedback') is a fuzzy approximation. It tokenizes text, so it also matches tags that contain the term as a token, such as feedback-given.INCLUDES is not supported in SQL mode. The examples below use BTQL syntax, which supports INCLUDES for exact array membership:
Analyze based on tags and scores
A common pattern is filtering traces by both tags and scores when automated scorers apply scores at the span level while tags exist on root spans. Use separateANY_SPAN() clauses to match traces where any span contains the tag AND any span contains the score.
Each ANY_SPAN() clause evaluates independently across all spans in a trace. The conditions don’t need to match on the same span. The first ANY_SPAN() finds traces where at least one span has the tag, while the second finds traces where at least one span has the score.
Analyze traces with span filters
Use single span filters with aggregations to analyze traces based on span-level conditions. This is useful for understanding patterns across complex, multi-step operations.FILTER_SPANS() to analyze only the spans that match specific criteria:
Extract data from JSON strings
Usejson_extract to pull values out of a field whose value is a JSON-encoded string (rather than a native SQL object). The second argument is a JSONPath expression that supports nested object keys, array indexing (including negative indices), and an optional $ root prefix.
json_extract returns null for invalid JSON or missing keys rather than raising an error, making it safe to use in filters and aggregations. Because the path is a JSONPath expression, dots and brackets are interpreted as traversal: a.b descends into key a then key b, and a[0] indexes into an array. A JSON key whose name literally contains a dot or bracket can’t be addressed this way.Query by classifications
Classifications are categorical labels generated by topics automations (for example,classifications.Task[0].label). Each classification object has these nested fields, accessed as classifications.<name>[<i>].<field>:
classifications.<name>[<i>].label: the category label.classifications.<name>[<i>].metadata.distance: distance metric for the classification.classifications.<name>[<i>].source: source of the classification.
Analyze facet distributions
Facets are AI-extracted attributes that summarize logs (e.g.,facets.task, facets.sentiment). They’re generated by topics automations.
Query logs by facet values to identify patterns and issues.
Combine facets and classifications
Analyze relationships between facets and classifications to gain deeper insights.Next steps
- Learn how to structure queries in the SQL reference.
- Look up syntax in Functions and operators.
- Optimize slow or incorrect queries with SQL best practices.