loadPreviewSpans loads the top N spans by duration for mini-waterfall preview.
(db *sql.DB, traceID string, txnStartTS sql.NullString, limit int)
| 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 { |
| 403 | rows, err := db.Query( |
| 404 | fmt.Sprintf(`SELECT span_id, op, description, start_ts, duration_ms, is_error, peer_type |
| 405 | FROM sentry_spans WHERE trace_id = ? ORDER BY duration_ms DESC LIMIT %d`, limit), traceID, |
| 406 | ) |
| 407 | if err != nil { |
| 408 | return []map[string]any{} |
| 409 | } |
| 410 | defer rows.Close() |
| 411 | |
| 412 | var result []map[string]any |
| 413 | for rows.Next() { |
| 414 | var ( |
| 415 | spanID, op string |
| 416 | description sql.NullString |
| 417 | sStartTS sql.NullString |
| 418 | durationMS sql.NullInt64 |
| 419 | isError int |
| 420 | peerType sql.NullString |
| 421 | ) |
| 422 | if err := rows.Scan(&spanID, &op, &description, &sStartTS, &durationMS, &isError, &peerType); err != nil { |
| 423 | continue |
| 424 | } |
| 425 | |
| 426 | startOffsetMS := computeOffsetMS(txnStartTS, sStartTS) |
| 427 | |
| 428 | result = append(result, map[string]any{ |
| 429 | "span_id": spanID, |
| 430 | "op": op, |
| 431 | "description": scanNullString(description), |
| 432 | "start_offset_ms": startOffsetMS, |
| 433 | "duration_ms": scanNullInt(durationMS), |
| 434 | "is_error": isError != 0, |
| 435 | "peer_type": scanNullString(peerType), |
| 436 | }) |
| 437 | } |
| 438 | |
| 439 | if result == nil { |
| 440 | result = []map[string]any{} |
| 441 | } |
| 442 | return result |
| 443 | } |
| 444 | |
| 445 | // computeOffsetMS calculates the offset in ms between two RFC3339 timestamps. |
| 446 | func computeOffsetMS(baseTSStr, spanTSStr sql.NullString) int { |
no test coverage detected