fix: harden workbench runtime session summary query (#1843)

This commit is contained in:
Lyon
2026-06-21 22:08:41 +08:00
committed by GitHub
parent e568e32fc7
commit 4b7a06e299
2 changed files with 58 additions and 7 deletions
+35 -1
View File
@@ -174,7 +174,7 @@ func (s *Server) withOtelInternalSpan(ctx context.Context, name string, attrs ma
err := fn(ctx)
errorCode := ""
if err != nil {
errorCode = otelFirst(queryErrorStage(err), sqlErrorCode(err), "query_failed")
errorCode = otelFirst(sqlErrorCode(err), sqlCauseCode(err), queryErrorStage(err), "query_failed")
}
attributes := map[string]any{
"hwlab.runtime.stage": name,
@@ -185,10 +185,44 @@ func (s *Server) withOtelInternalSpan(ctx context.Context, name string, attrs ma
attributes[key] = value
}
}
addOtelErrorCauseAttributes(attributes, err)
s.emitOtelSpanAsync(name, trace, spanID, trace.ServerSpanID, otelSpanKindInternal, startedAt, attributes, 0, errorCode)
return err
}
func addOtelErrorCauseAttributes(attributes map[string]any, err error) {
if err == nil {
return
}
if stage := queryErrorStage(err); stage != "" {
attributes["causeStage"] = stage
}
if code := sqlErrorCode(err); code != "" {
attributes["causeCode"] = code
return
}
if code := sqlCauseCode(err); code != "" {
attributes["causeCode"] = code
}
}
func sqlCauseCode(err error) string {
if err == nil {
return ""
}
message := strings.ToLower(err.Error())
switch {
case strings.Contains(message, "invalid input syntax for type json"):
return "invalid_json_text"
case strings.Contains(message, "cannot cast") && strings.Contains(message, "json"):
return "invalid_json_cast"
case strings.Contains(message, "context deadline exceeded"):
return "query_timeout"
default:
return ""
}
}
func (s *Server) emitOtelSpanAsync(name string, trace otelTraceContext, spanID string, parentSpanID string, kind int, startedAt time.Time, attrs map[string]any, httpStatus int, errorCode string) {
go s.emitOtelSpan(context.Background(), name, trace, spanID, parentSpanID, kind, startedAt, attrs, httpStatus, errorCode)
}
+23 -6
View File
@@ -520,11 +520,11 @@ func (s *Server) querySessionSummaries(ctx context.Context, stage string, sqlTex
}
defer rows.Close()
for rows.Next() {
var sessionID, ownerUserID, projectID, conversationID, threadID, status, lastTraceID, sourceEventID, providerProfile sql.NullString
var sessionID, ownerUserID, projectID, conversationID, threadID, status, lastTraceID, sourceEventID, sessionJSON sql.NullString
var projectedSeq, sourceSeq sql.NullInt64
var terminal, sealed sql.NullBool
var createdAt, updatedAt sql.NullTime
if err := rows.Scan(&sessionID, &ownerUserID, &projectID, &conversationID, &threadID, &status, &lastTraceID, &projectedSeq, &sourceSeq, &sourceEventID, &terminal, &sealed, &createdAt, &updatedAt, &providerProfile); err != nil {
if err := rows.Scan(&sessionID, &ownerUserID, &projectID, &conversationID, &threadID, &status, &lastTraceID, &projectedSeq, &sourceSeq, &sourceEventID, &terminal, &sealed, &createdAt, &updatedAt, &sessionJSON); err != nil {
return err
}
if !sessionID.Valid || strings.TrimSpace(sessionID.String) == "" {
@@ -549,9 +549,9 @@ func (s *Server) querySessionSummaries(ctx context.Context, stage string, sqlTex
"valuesPrinted": false,
"valuesRedacted": true,
}
if providerProfile.Valid && strings.TrimSpace(providerProfile.String) != "" {
item["providerProfile"] = providerProfile.String
item["sessionJson"] = map[string]any{"providerProfile": providerProfile.String, "valuesRedacted": true, "secretMaterialStored": false}
if providerProfile := providerProfileFromSessionJSON(sessionJSON); providerProfile != "" {
item["providerProfile"] = providerProfile
item["sessionJson"] = map[string]any{"providerProfile": providerProfile, "valuesRedacted": true, "secretMaterialStored": false}
}
result = append(result, item)
}
@@ -820,10 +820,27 @@ func sessionSummarySelectClause() string {
"sealed",
"created_at",
"updated_at",
"COALESCE(NULLIF(session_json::jsonb ->> 'providerProfile', ''), NULLIF(session_json::jsonb #>> '{sessionJson,providerProfile}', '')) AS provider_profile",
"session_json",
}, ", ")
}
func providerProfileFromSessionJSON(raw sql.NullString) string {
if !raw.Valid || strings.TrimSpace(raw.String) == "" {
return ""
}
var payload map[string]any
if err := json.Unmarshal([]byte(raw.String), &payload); err != nil {
return ""
}
if value := strings.TrimSpace(text(payload["providerProfile"])); value != "" {
return value
}
if value := strings.TrimSpace(text(objectMap(payload["sessionJson"])["providerProfile"])); value != "" {
return value
}
return ""
}
func boundedLimit(value int, fallback int, max int) int {
if value <= 0 {
return fallback