fix(goldfish): support nulls in mismatch_cause (#21082)

mismatch_cause can be NULL, in this case goldfish ui API (e.g., /ui/api/v1/goldfish/queries) will return {"error":"failed to retrieve sampled queries"} due to a failure of converting NULL to string value.
This commit is contained in:
Ivan Kalita
2026-03-06 12:26:28 +01:00
committed by GitHub
parent f5baa1468b
commit 26d903163b
3 changed files with 14 additions and 3 deletions

View File

@@ -301,9 +301,9 @@ func (s *MySQLStorage) GetSampledQueries(ctx context.Context, page, pageSize int
var cellAResultURI, cellBResultURI sql.NullString
var cellAResultCompression, cellBResultCompression sql.NullString
var cellAResultSize, cellBResultSize sql.NullInt64
var mismatchCause sql.NullString
err := rows.Scan(
&q.CorrelationID, &q.TenantID, &q.User, &q.Issuer, &q.Query, &q.QueryType, &q.StartTime, &q.EndTime, &stepDurationMs,
&q.CellAStats.ExecTimeMs, &q.CellBStats.ExecTimeMs, &q.CellAStats.QueueTimeMs, &q.CellBStats.QueueTimeMs,
&q.CellAStats.BytesProcessed, &q.CellBStats.BytesProcessed, &q.CellAStats.LinesProcessed, &q.CellBStats.LinesProcessed,
@@ -318,7 +318,7 @@ func (s *MySQLStorage) GetSampledQueries(ctx context.Context, page, pageSize int
&cellASpanID, &cellBSpanID,
&q.CellAUsedNewEngine, &q.CellBUsedNewEngine,
&q.SampledAt, &createdAt,
&q.ComparisonStatus, &q.MatchWithinTolerance, &q.MismatchCause,
&q.ComparisonStatus, &q.MatchWithinTolerance, &mismatchCause,
)
if err != nil {
return nil, err
@@ -349,6 +349,9 @@ func (s *MySQLStorage) GetSampledQueries(ctx context.Context, page, pageSize int
if cellBResultCompression.Valid {
q.CellBResultCompression = cellBResultCompression.String
}
if mismatchCause.Valid {
q.MismatchCause = mismatchCause.String
}
// Convert step duration from milliseconds to Duration
q.Step = time.Duration(stepDurationMs) * time.Millisecond
@@ -405,6 +408,7 @@ func (s *MySQLStorage) GetQueryByCorrelationID(ctx context.Context, correlationI
var cellAResultURI, cellBResultURI sql.NullString
var cellAResultCompression, cellBResultCompression sql.NullString
var cellAResultSize, cellBResultSize sql.NullInt64
var mismatchCause sql.NullString
err := s.db.QueryRowContext(ctx, query, correlationID).Scan(
&q.CorrelationID, &q.TenantID, &q.User, &q.Issuer, &q.Query, &q.QueryType, &q.StartTime, &q.EndTime, &stepDurationMs,
@@ -420,7 +424,7 @@ func (s *MySQLStorage) GetQueryByCorrelationID(ctx context.Context, correlationI
&q.CellATraceID, &q.CellBTraceID,
&cellASpanID, &cellBSpanID,
&q.CellAUsedNewEngine, &q.CellBUsedNewEngine,
&q.SampledAt, &createdAt, &q.ComparisonStatus, &q.MatchWithinTolerance, &q.MismatchCause,
&q.SampledAt, &createdAt, &q.ComparisonStatus, &q.MatchWithinTolerance, &mismatchCause,
)
if err != nil {
@@ -455,6 +459,9 @@ func (s *MySQLStorage) GetQueryByCorrelationID(ctx context.Context, correlationI
if cellBResultCompression.Valid {
q.CellBResultCompression = cellBResultCompression.String
}
if mismatchCause.Valid {
q.MismatchCause = mismatchCause.String
}
// Convert step duration from milliseconds to Duration
q.Step = time.Duration(stepDurationMs) * time.Millisecond

View File

@@ -101,6 +101,7 @@ type SampledQuery struct {
// Comparison outcome - computed by backend logic
ComparisonStatus string `json:"comparisonStatus" db:"comparison_status"`
MatchWithinTolerance bool `json:"matchWithinTolerance" db:"match_within_tolerance"`
MismatchCause string `json:"mismatchCause" db:"mismatch_cause"`
// UI-only fields - generated based on configuration, not stored in database
CellATraceLink *string `json:"cellATraceLink,omitempty"`
@@ -258,6 +259,7 @@ func (s *Service) GetSampledQueriesWithContext(ctx context.Context, page, pageSi
// Use comparison status and match within tolerance from database
uiQuery.ComparisonStatus = string(q.ComparisonStatus)
uiQuery.MatchWithinTolerance = q.MatchWithinTolerance
uiQuery.MismatchCause = q.MismatchCause
// Add trace ID explore links if explore is configured
if s.cfg.Goldfish.GrafanaURL != "" && s.cfg.Goldfish.TracesDatasourceUID != "" {

View File

@@ -105,6 +105,7 @@ func TestSampledQueryJSONMarshaling(t *testing.T) {
CellATraceLink: strPtr("https://grafana.com/explore?trace-a"),
CellBTraceLink: strPtr("https://grafana.com/explore?trace-b"),
ComparisonStatus: "mismatch",
MismatchCause: "stream_entry_count_mismatch",
}
// Marshal to JSON
@@ -122,6 +123,7 @@ func TestSampledQueryJSONMarshaling(t *testing.T) {
require.Equal(t, "{job=\"test\"}", result["query"])
require.Equal(t, "range", result["queryType"])
require.Equal(t, "mismatch", result["comparisonStatus"])
require.Equal(t, "stream_entry_count_mismatch", result["mismatchCause"])
// Verify performance stats are flattened
require.Equal(t, float64(100), result["cellAExecTimeMs"])