hub v0.43.0: remote app-log diagnostics — copyable issues + context + on-demand log tails + range/dismissal fixes
- store: app_log_issues gains context/context_customer (first capture wins) + dismissed_at (resurface only on last_seen > dismissed_at); log_tail_requests (pending operator intents, consume-once) + app_log_tails (transient, keep last 2 per app) - api: /report ingests log_tails (stores + clears the request); ACK advertises log_tail_requests (same additive omit-when-empty pattern as escrow) - web: Known Issues rows click-to-expand (full copyable message + context with provenance + explicit affected-customers list); Dismiss replaces Delete; period selector now filters issues (F); ?customer= filtered view + customer-page drill-down links (H); per-app Request-log-tail button + pending badge + App Log Tails section + ordered tail view with line numbers + .log download; customer-visible log_tail_requested event - tests: store (context first-capture/late-adopt, range filter, dismissal old-window vs new-occurrence, tail request/fulfill/prune/scoping), api ACK round-trip, web render (expanded row, customer page sections, tail view + download + cross-customer 404) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -260,6 +260,8 @@ func (s *Server) handleCustomerUnified(w http.ResponseWriter, r *http.Request, c
|
||||
var eventCounts map[string]int
|
||||
|
||||
var appTelemetry []store.CustomerAppSummary
|
||||
var logTails []store.AppLogTail
|
||||
var pendingTails []string
|
||||
|
||||
if customer != nil {
|
||||
history, _ = s.store.GetCustomerHistory(customerID, 24*time.Hour)
|
||||
@@ -268,6 +270,8 @@ func (s *Server) handleCustomerUnified(w http.ResponseWriter, r *http.Request, c
|
||||
events, _ = s.store.GetRecentEvents(customerID, 50)
|
||||
eventCounts, _ = s.store.CountEventsBySeverity(customerID, time.Now().Add(-24*time.Hour))
|
||||
appTelemetry, _ = s.store.GetCustomerAppSummary(customerID, time.Now().Add(-7*24*time.Hour))
|
||||
logTails, _ = s.store.GetCustomerLogTails(customerID)
|
||||
pendingTails, _ = s.store.GetPendingLogTailRequests(customerID)
|
||||
}
|
||||
|
||||
type pageData struct {
|
||||
@@ -306,6 +310,12 @@ func (s *Server) handleCustomerUnified(w http.ResponseWriter, r *http.Request, c
|
||||
AppTelemetry []store.CustomerAppSummary
|
||||
HasAppTelemetry bool
|
||||
|
||||
// On-demand log tails (v0.43.0): received tails (last 2 per app) + apps with a
|
||||
// still-pending request (badge on the telemetry row).
|
||||
LogTails []store.AppLogTail
|
||||
HasLogTails bool
|
||||
PendingTails map[string]bool
|
||||
|
||||
HasDRRecipe bool
|
||||
DRRecipeUpdatedAt string
|
||||
DRRecipeHasHost bool
|
||||
@@ -320,6 +330,11 @@ func (s *Server) handleCustomerUnified(w http.ResponseWriter, r *http.Request, c
|
||||
ScriptVersion string
|
||||
}
|
||||
|
||||
pendingSet := make(map[string]bool, len(pendingTails))
|
||||
for _, app := range pendingTails {
|
||||
pendingSet[app] = true
|
||||
}
|
||||
|
||||
// DR recipe presence — show the secret-free reconstruction recipe panel + download link when
|
||||
// either half has landed (host-report and/or controller report).
|
||||
var hasDR, drHost, drApps bool
|
||||
@@ -366,6 +381,10 @@ func (s *Server) handleCustomerUnified(w http.ResponseWriter, r *http.Request, c
|
||||
AppTelemetry: appTelemetry,
|
||||
HasAppTelemetry: len(appTelemetry) > 0,
|
||||
|
||||
LogTails: logTails,
|
||||
HasLogTails: len(logTails) > 0,
|
||||
PendingTails: pendingSet,
|
||||
|
||||
HasDRRecipe: hasDR,
|
||||
DRRecipeUpdatedAt: drUpdated,
|
||||
DRRecipeHasHost: drHost,
|
||||
|
||||
Reference in New Issue
Block a user