(db *sql.DB, traceID string)
| 365 | } |
| 366 | |
| 367 | func loadTraceSummary(db *sql.DB, traceID string) map[string]any { |
| 368 | // Load transaction for this trace. |
| 369 | var ( |
| 370 | txnName sql.NullString |
| 371 | op sql.NullString |
| 372 | durationMS sql.NullInt64 |
| 373 | startTS sql.NullString |
| 374 | ) |
| 375 | |
| 376 | err := db.QueryRow( |
| 377 | `SELECT transaction_name, op, duration_ms, start_ts |
| 378 | FROM sentry_transactions WHERE trace_id = ? ORDER BY start_ts LIMIT 1`, traceID, |
| 379 | ).Scan(&txnName, &op, &durationMS, &startTS) |
| 380 | if err != nil { |
| 381 | return nil |
| 382 | } |
| 383 | |
| 384 | // Get span count. |
| 385 | var spanCount int |
| 386 | db.QueryRow(`SELECT COUNT(*) FROM sentry_spans WHERE trace_id = ?`, traceID).Scan(&spanCount) |
| 387 | |
| 388 | // Load top 3 spans by duration for preview. |
| 389 | previewSpans := loadPreviewSpans(db, traceID, startTS, 3) |
| 390 | |
| 391 | return map[string]any{ |
| 392 | "trace_id": traceID, |
| 393 | "transaction_name": scanNullString(txnName), |
| 394 | "op": scanNullString(op), |
| 395 | "duration_ms": scanNullInt(durationMS), |
| 396 | "span_count": spanCount, |
| 397 | "preview_spans": previewSpans, |
| 398 | } |
| 399 | } |
| 400 | |
| 401 | // loadPreviewSpans loads the top N spans by duration for mini-waterfall preview. |
| 402 | func loadPreviewSpans(db *sql.DB, traceID string, txnStartTS sql.NullString, limit int) []map[string]any { |
no test coverage detected