Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions apps/api/src/services/TinybirdService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ import {
serviceDependencies,
serviceOverview,
servicesFacets,
spanAttributeKeys,
spanAttributeValues,
spanHierarchy,
tracesDurationStats,
tracesFacets,
Expand Down Expand Up @@ -91,6 +93,8 @@ export class TinybirdService extends Effect.Service<TinybirdService>()("Tinybird
custom_logs_breakdown: customLogsBreakdown,
custom_metrics_breakdown: customMetricsBreakdown,
service_dependencies: serviceDependencies,
span_attribute_keys: spanAttributeKeys,
span_attribute_values: spanAttributeValues,
},
})

Expand Down
77 changes: 77 additions & 0 deletions apps/api/src/tinybird/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2488,3 +2488,80 @@ export const serviceDependencies = defineEndpoint("service_dependencies", {

export type ServiceDependenciesParams = InferParams<typeof serviceDependencies>;
export type ServiceDependenciesOutput = InferOutputRow<typeof serviceDependencies>;

/**
* Span attribute keys endpoint - returns distinct span attribute key names
*/
export const spanAttributeKeys = defineEndpoint("span_attribute_keys", {
description: "List distinct span attribute keys with usage counts.",
params: {
org_id: p.string().optional().describe("Organization ID"),
start_time: p.dateTime().describe("Start of time range"),
end_time: p.dateTime().describe("End of time range"),
limit: p.int32().optional(200).describe("Maximum number of keys to return"),
},
nodes: [
node({
name: "span_attribute_keys_node",
sql: `
SELECT
arrayJoin(mapKeys(SpanAttributes)) AS attributeKey,
count() AS usageCount
FROM traces
WHERE OrgId = {{String(org_id, "")}}
AND Timestamp >= {{DateTime(start_time)}}
AND Timestamp <= {{DateTime(end_time)}}
AND SpanAttributes != map()
GROUP BY attributeKey
ORDER BY usageCount DESC
LIMIT {{Int32(limit, 200)}}
`,
}),
],
output: {
attributeKey: t.string(),
usageCount: t.uint64(),
},
});

export type SpanAttributeKeysParams = InferParams<typeof spanAttributeKeys>;
export type SpanAttributeKeysOutput = InferOutputRow<typeof spanAttributeKeys>;

/**
* Span attribute values endpoint - returns distinct values for a specific attribute key
*/
export const spanAttributeValues = defineEndpoint("span_attribute_values", {
description: "List distinct values for a specific span attribute key.",
params: {
org_id: p.string().optional().describe("Organization ID"),
start_time: p.dateTime().describe("Start of time range"),
end_time: p.dateTime().describe("End of time range"),
attribute_key: p.string().describe("The attribute key to get values for"),
limit: p.int32().optional(50).describe("Maximum number of values to return"),
},
nodes: [
node({
name: "span_attribute_values_node",
sql: `
SELECT
SpanAttributes[{{String(attribute_key)}}] AS attributeValue,
count() AS usageCount
FROM traces
WHERE OrgId = {{String(org_id, "")}}
AND Timestamp >= {{DateTime(start_time)}}
AND Timestamp <= {{DateTime(end_time)}}
AND SpanAttributes[{{String(attribute_key)}}] != ''
GROUP BY attributeValue
ORDER BY usageCount DESC
LIMIT {{Int32(limit, 50)}}
`,
}),
],
output: {
attributeValue: t.string(),
usageCount: t.uint64(),
},
});

export type SpanAttributeValuesParams = InferParams<typeof spanAttributeValues>;
export type SpanAttributeValuesOutput = InferOutputRow<typeof spanAttributeValues>;
3 changes: 1 addition & 2 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@
"tailwindcss": "^4.1.18",
"tw-animate-css": "^1.4.0",
"vaul": "^1.1.2",
"web-vitals": "^5.1.0",
"zod": "^3.25.76"
"web-vitals": "^5.1.0"
},
"devDependencies": {
"@cloudflare/vite-plugin": "^1.21.2",
Expand Down
Loading