Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ Two complementary read-only surfaces. When diagnosing database health or perform
```bash
pscale insights queries <database> <branch> --org <org> --format json --sort totalTime # top queries; sorts: totalTime, count, p99Latency, rowsRead, rowsReadPerReturned, errorCount, ...
pscale insights queries samples <database> <branch> <fingerprint> --org <org> --format json --keyspace <keyspace> # recent executions; keyspace from queries list
pscale insights queries traffic-budgets <database> <branch> <fingerprint> --org <org> --format json --keyspace <keyspace> # traffic budgets affecting a query fingerprint
pscale insights queries traffic-budgets <database> <branch> <fingerprint> --org <org> --format json --keyspace <keyspace> --page <n> --per-page <n> # traffic budgets affecting a query fingerprint
pscale insights queries show <database> <branch> <query-id> --org <org> --format json # one execution; query-id comes from the samples list
pscale insights queries summary <database> <branch> <fingerprint> --org <org> --format json --keyspace <keyspace> # aggregate stats for one query pattern
pscale insights errors <database> <branch> --org <org> --format json # failing queries with error messages
Expand Down
30 changes: 30 additions & 0 deletions internal/cmd/insights/queries_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,21 @@ func TestInsights_QueryShowCmd_Human(t *testing.T) {
c.Assert(buf.String(), qt.Contains, "select 1")
}

func TestInsights_QueryShowCmd_NotFoundNamesQueryExecution(t *testing.T) {
c := qt.New(t)
svc := &mock.QueryInsightsService{
GetQueryFn: func(context.Context, *ps.GetQueryRequest) (*ps.Query, error) {
return nil, &ps.Error{Code: ps.ErrNotFound}
},
}

cmd := QueryShowCmd(testHelper(&bytes.Buffer{}, printer.JSON, &ps.Client{QueryInsights: svc}))
cmd.SetArgs([]string{"mydb", "main", "missing-execution"})

err := cmd.Execute()
c.Assert(err, qt.ErrorMatches, "query execution missing-execution does not exist on branch main in database mydb .*")
}

func TestInsights_QuerySummaryCmd(t *testing.T) {
c := qt.New(t)
lastRunAt := time.Date(2026, 8, 25, 18, 0, 0, 0, time.UTC)
Expand Down Expand Up @@ -426,6 +441,21 @@ func TestInsights_QuerySummaryCmd_Human(t *testing.T) {
c.Assert(buf.String(), qt.Contains, "select 1")
}

func TestInsights_QuerySummaryCmd_NotFoundNamesFingerprint(t *testing.T) {
c := qt.New(t)
svc := &mock.QueryInsightsService{
GetQuerySummaryFn: func(context.Context, *ps.GetQuerySummaryRequest, ...ps.ListOption) (*ps.QuerySummary, error) {
return nil, &ps.Error{Code: ps.ErrNotFound}
},
}

cmd := QuerySummaryCmd(testHelper(&bytes.Buffer{}, printer.JSON, &ps.Client{QueryInsights: svc}))
cmd.SetArgs([]string{"mydb", "main", "missing-fingerprint", "--keyspace", "commerce"})

err := cmd.Execute()
c.Assert(err, qt.ErrorMatches, "query fingerprint missing-fingerprint does not exist in keyspace commerce on branch main in database mydb .*")
}

func TestInsights_QuerySummaryCmd_RequiresKeyspace(t *testing.T) {
c := qt.New(t)
svc := &mock.QueryInsightsService{}
Expand Down
4 changes: 4 additions & 0 deletions internal/cmd/insights/query_show.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ not the fingerprint used by the samples and summary commands.`,
QueryID: queryID,
})
if err != nil {
if cmdutil.ErrCode(err) == ps.ErrNotFound {
return fmt.Errorf("query execution %s does not exist on branch %s in database %s (organization: %s)",
printer.BoldBlue(queryID), printer.BoldBlue(branch), printer.BoldBlue(database), printer.BoldBlue(ch.Config.Organization))
}
return notFoundError(ch, err, database, branch)
}
end()
Expand Down
5 changes: 5 additions & 0 deletions internal/cmd/insights/query_summary.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ The fingerprint identifies a query pattern; it is not an execution/sample ID.`,
Fingerprint: fingerprint,
}, ps.WithKeyspace(flags.keyspace), ps.WithPeriod(flags.period), ps.WithTimeRange(flags.from, flags.to))
if err != nil {
if cmdutil.ErrCode(err) == ps.ErrNotFound {
return fmt.Errorf("query fingerprint %s does not exist in keyspace %s on branch %s in database %s (organization: %s)",
printer.BoldBlue(fingerprint), printer.BoldBlue(flags.keyspace), printer.BoldBlue(branch),
printer.BoldBlue(database), printer.BoldBlue(ch.Config.Organization))
}
return notFoundError(ch, err, database, branch)
}
end()
Expand Down
27 changes: 18 additions & 9 deletions internal/cmd/insights/query_traffic_budgets.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ import (
)

func QueryTrafficBudgetsCmd(ch *cmdutil.Helper) *cobra.Command {
var keyspace string
var flags struct {
keyspace string
page int
perPage int
}

cmd := &cobra.Command{
Use: "traffic-budgets <database> <branch> <fingerprint>",
Short: "List traffic budgets affecting a query fingerprint",
Aliases: []string{"ls"},
Args: cmdutil.RequiredArgs("database", "branch", "fingerprint"),
Use: "traffic-budgets <database> <branch> <fingerprint>",
Short: "List traffic budgets affecting a query fingerprint",
Args: cmdutil.RequiredArgs("database", "branch", "fingerprint"),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
database, branch, fingerprint := args[0], args[1], args[2]
Expand All @@ -37,23 +40,29 @@ func QueryTrafficBudgetsCmd(ch *cmdutil.Helper) *cobra.Command {
Database: database,
Branch: branch,
Fingerprint: fingerprint,
}, ps.WithKeyspace(keyspace))
}, ps.WithKeyspace(flags.keyspace), ps.WithPage(flags.page), ps.WithPerPage(flags.perPage))
if err != nil {
return notFoundError(ch, err, database, branch)
}
end()

if len(budgets) == 0 && ch.Printer.Format() == printer.Human {
ch.Printer.Printf("No traffic budgets affect fingerprint %s on %s/%s.\n",
printer.BoldBlue(fingerprint), printer.BoldBlue(database), printer.BoldBlue(branch))
if flags.page > 0 {
ch.Printer.Println("No traffic budgets found on this page.")
} else {
ch.Printer.Printf("No traffic budgets affect fingerprint %s on %s/%s.\n",
printer.BoldBlue(fingerprint), printer.BoldBlue(database), printer.BoldBlue(branch))
}
return nil
}

return ch.Printer.PrintResource(trafficcontrol.ToTrafficBudgets(budgets))
},
}

cmd.Flags().StringVar(&keyspace, "keyspace", "", "Keyspace for the fingerprint")
cmd.Flags().StringVar(&flags.keyspace, "keyspace", "", "Keyspace for the fingerprint")
cmd.Flags().IntVar(&flags.page, "page", 0, "Page number to fetch")
cmd.Flags().IntVar(&flags.perPage, "per-page", 25, "Number of results per page")
Comment thread
no-itsbackpack marked this conversation as resolved.
Resolved

return cmd
}
44 changes: 42 additions & 2 deletions internal/cmd/insights/query_traffic_budgets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ func TestQueryTrafficBudgetsCmd(t *testing.T) {
c.Assert(opt(listOpts), qt.IsNil)
}
c.Assert(values.Get("keyspace"), qt.Equals, "mydb")
c.Assert(values.Get("page"), qt.Equals, "3")
c.Assert(values.Get("per_page"), qt.Equals, "50")

return budgets, nil
},
Expand All @@ -47,16 +49,54 @@ func TestQueryTrafficBudgetsCmd(t *testing.T) {
ch := testHelper(&buf, printer.JSON, &ps.Client{QueryInsights: svc})

cmd := QueryTrafficBudgetsCmd(ch)
cmd.SetArgs([]string{"mydb", "main", "b129e8fa", "--keyspace", "mydb"})
cmd.SetArgs([]string{"mydb", "main", "b129e8fa", "--keyspace", "mydb", "--page", "3", "--per-page", "50"})
err := cmd.Execute()

c.Assert(err, qt.IsNil)
c.Assert(svc.ListQueryTrafficBudgetsFnInvoked, qt.IsTrue)
c.Assert(cmd.Aliases, qt.DeepEquals, []string{"ls"})
c.Assert(cmd.Aliases, qt.HasLen, 0)

var out []map[string]any
c.Assert(json.Unmarshal(buf.Bytes(), &out), qt.IsNil)
c.Assert(out, qt.HasLen, 1)
c.Assert(out[0]["id"], qt.Equals, "budget-1")
c.Assert(out[0]["name"], qt.Equals, "App queries")
}

func TestQueryTrafficBudgetsCmd_EmptyFirstPage(t *testing.T) {
c := qt.New(t)
svc := &mock.QueryInsightsService{
ListQueryTrafficBudgetsFn: func(context.Context, *ps.ListQueryTrafficBudgetsRequest, ...ps.ListOption) ([]*ps.TrafficBudget, error) {
return nil, nil
},
}

var buf bytes.Buffer
ch := testHelper(&buf, printer.Human, &ps.Client{QueryInsights: svc})
ch.Printer.SetHumanOutput(&buf)

cmd := QueryTrafficBudgetsCmd(ch)
cmd.SetArgs([]string{"mydb", "main", "b129e8fa"})
c.Assert(cmd.Execute(), qt.IsNil)
c.Assert(buf.String(), qt.Contains, "No traffic budgets affect fingerprint")
c.Assert(buf.String(), qt.Not(qt.Contains), "on this page")
}

func TestQueryTrafficBudgetsCmd_EmptyLaterPage(t *testing.T) {
c := qt.New(t)
svc := &mock.QueryInsightsService{
ListQueryTrafficBudgetsFn: func(context.Context, *ps.ListQueryTrafficBudgetsRequest, ...ps.ListOption) ([]*ps.TrafficBudget, error) {
return nil, nil
},
}

var buf bytes.Buffer
ch := testHelper(&buf, printer.Human, &ps.Client{QueryInsights: svc})
ch.Printer.SetHumanOutput(&buf)

cmd := QueryTrafficBudgetsCmd(ch)
cmd.SetArgs([]string{"mydb", "main", "b129e8fa", "--page", "4"})
c.Assert(cmd.Execute(), qt.IsNil)
c.Assert(buf.String(), qt.Contains, "No traffic budgets found on this page.")
c.Assert(buf.String(), qt.Not(qt.Contains), "No traffic budgets affect fingerprint")
}