Skip to content

Commit

Permalink
server,ui: show internal stats with new cluster setting
Browse files Browse the repository at this point in the history
Previously, we were not showing internal results on
fingerprint options on SQL Activity.
A new cluster setting created `sql.stats.response.show_internal`
can be set to `true` and internal statistics will be
displayed on SQL Activity page.

Fixes cockroachdb#79547

Release justification: low risk, high benefit change
Release note (sql change): New cluster setting
`sql.stats.response.show_internal` with default value of `false`
can be set to true, to display information about internal stats
on SQL Activity page, with fingerprint option.
  • Loading branch information
maryliag committed Aug 25, 2022
1 parent f81f08f commit a05ccc2
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 34 deletions.
1 change: 1 addition & 0 deletions docs/generated/settings/settings-for-tenants.txt
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ sql.stats.multi_column_collection.enabled boolean true multi-column statistics c
sql.stats.persisted_rows.max integer 1000000 maximum number of rows of statement and transaction statistics that will be persisted in the system tables
sql.stats.post_events.enabled boolean false if set, an event is logged for every CREATE STATISTICS job
sql.stats.response.max integer 20000 the maximum number of statements and transaction stats returned in a CombinedStatements request
sql.stats.response.show_internal.enabled boolean false controls if statistics for internal executions should be returned by the CombinedStatements endpoint. This endpoint is used to display statistics on the Statement and Transaction fingerprint pages under SQL Activity
sql.telemetry.query_sampling.enabled boolean false when set to true, executed queries will emit an event on the telemetry logging channel
sql.temp_object_cleaner.cleanup_interval duration 30m0s how often to clean up orphaned temporary objects
sql.temp_object_cleaner.wait_interval duration 30m0s how long after creation a temporary object will be cleaned up
Expand Down
1 change: 1 addition & 0 deletions docs/generated/settings/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@
<tr><td><code>sql.stats.persisted_rows.max</code></td><td>integer</td><td><code>1000000</code></td><td>maximum number of rows of statement and transaction statistics that will be persisted in the system tables</td></tr>
<tr><td><code>sql.stats.post_events.enabled</code></td><td>boolean</td><td><code>false</code></td><td>if set, an event is logged for every CREATE STATISTICS job</td></tr>
<tr><td><code>sql.stats.response.max</code></td><td>integer</td><td><code>20000</code></td><td>the maximum number of statements and transaction stats returned in a CombinedStatements request</td></tr>
<tr><td><code>sql.stats.response.show_internal.enabled</code></td><td>boolean</td><td><code>false</code></td><td>controls if statistics for internal executions should be returned by the CombinedStatements endpoint. This endpoint is used to display statistics on the Statement and Transaction fingerprint pages under SQL Activity</td></tr>
<tr><td><code>sql.telemetry.query_sampling.enabled</code></td><td>boolean</td><td><code>false</code></td><td>when set to true, executed queries will emit an event on the telemetry logging channel</td></tr>
<tr><td><code>sql.temp_object_cleaner.cleanup_interval</code></td><td>duration</td><td><code>30m0s</code></td><td>how often to clean up orphaned temporary objects</td></tr>
<tr><td><code>sql.temp_object_cleaner.wait_interval</code></td><td>duration</td><td><code>30m0s</code></td><td>how long after creation a temporary object will be cleaned up</td></tr>
Expand Down
10 changes: 10 additions & 0 deletions pkg/server/cluster_settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,13 @@ var SQLStatsResponseMax = settings.RegisterIntSetting(
20000,
settings.NonNegativeInt,
).WithPublic()

// SQLStatsShowInternal controls if statistics for internal executions should be returned by the
// CombinedStatements endpoint.
var SQLStatsShowInternal = settings.RegisterBoolSetting(
settings.TenantWritable,
"sql.stats.response.show_internal.enabled",
"controls if statistics for internal executions should be returned by the CombinedStatements endpoint. This "+
"endpoint is used to display statistics on the Statement and Transaction fingerprint pages under SQL Activity",
false,
).WithPublic()
32 changes: 24 additions & 8 deletions pkg/server/combined_statement_stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ func getCombinedStatementStats(
startTime := getTimeFromSeconds(req.Start)
endTime := getTimeFromSeconds(req.End)
limit := SQLStatsResponseMax.Get(&settings.SV)
whereClause, orderAndLimit, args := getCombinedStatementsQueryClausesAndArgs(startTime, endTime, limit, testingKnobs)
showInternal := SQLStatsShowInternal.Get(&settings.SV)
whereClause, orderAndLimit, args := getCombinedStatementsQueryClausesAndArgs(
startTime, endTime, limit, testingKnobs, showInternal)
statements, err := collectCombinedStatements(ctx, ie, whereClause, args, orderAndLimit)
if err != nil {
return nil, serverError(ctx, err)
Expand Down Expand Up @@ -98,13 +100,17 @@ func getCombinedStatementStats(
// The whereClause will be in the format `WHERE A = $1 AND B = $2` and
// args will return the list of arguments in order that will replace the actual values.
func getCombinedStatementsQueryClausesAndArgs(
start, end *time.Time, limit int64, testingKnobs *sqlstats.TestingKnobs,
start, end *time.Time, limit int64, testingKnobs *sqlstats.TestingKnobs, showInternal bool,
) (whereClause string, orderAndLimitClause string, args []interface{}) {
var buffer strings.Builder
buffer.WriteString(testingKnobs.GetAOSTClause())

// Filter out internal statements by app name.
buffer.WriteString(fmt.Sprintf(" WHERE app_name NOT LIKE '%s%%'", catconstants.InternalAppNamePrefix))
if showInternal {
buffer.WriteString(" WHERE true")
} else {
// Filter out internal statements by app name.
buffer.WriteString(fmt.Sprintf(" WHERE app_name NOT LIKE '%s%%'", catconstants.InternalAppNamePrefix))
}

if start != nil {
buffer.WriteString(" AND aggregated_ts >= $1")
Expand Down Expand Up @@ -357,7 +363,8 @@ func getStatementDetails(
testingKnobs *sqlstats.TestingKnobs,
) (*serverpb.StatementDetailsResponse, error) {
limit := SQLStatsResponseMax.Get(&settings.SV)
whereClause, args, err := getStatementDetailsQueryClausesAndArgs(req, testingKnobs)
showInternal := SQLStatsShowInternal.Get(&settings.SV)
whereClause, args, err := getStatementDetailsQueryClausesAndArgs(req, testingKnobs, showInternal)
if err != nil {
return nil, serverError(ctx, err)
}
Expand Down Expand Up @@ -407,7 +414,7 @@ func getStatementDetails(
// The whereClause will be in the format `WHERE A = $1 AND B = $2` and
// args will return the list of arguments in order that will replace the actual values.
func getStatementDetailsQueryClausesAndArgs(
req *serverpb.StatementDetailsRequest, testingKnobs *sqlstats.TestingKnobs,
req *serverpb.StatementDetailsRequest, testingKnobs *sqlstats.TestingKnobs, showInternal bool,
) (whereClause string, args []interface{}, err error) {
var buffer strings.Builder
buffer.WriteString(testingKnobs.GetAOSTClause())
Expand All @@ -420,18 +427,24 @@ func getStatementDetailsQueryClausesAndArgs(
args = append(args, sqlstatsutil.EncodeUint64ToBytes(fingerprintID))
buffer.WriteString(fmt.Sprintf(" WHERE fingerprint_id = $%d", len(args)))

// Filter out internal statements by app name.
buffer.WriteString(fmt.Sprintf(" AND app_name NOT LIKE '%s%%'", catconstants.InternalAppNamePrefix))
if !showInternal {
// Filter out internal statements by app name.
buffer.WriteString(fmt.Sprintf(" AND app_name NOT LIKE '%s%%'", catconstants.InternalAppNamePrefix))
}

// Statements are grouped ignoring the app name in the Statements/Transactions page, so when
// calling for the Statement Details endpoint, this value can be empty or a list of app names.
if len(req.AppNames) > 0 {
if !(len(req.AppNames) == 1 && req.AppNames[0] == "") {
hasInternal := false
buffer.WriteString(" AND (")
for i, app := range req.AppNames {
if app == "(unset)" {
app = ""
}
if strings.Contains(app, catconstants.InternalAppNamePrefix) {
hasInternal = true
}
if i != 0 {
args = append(args, app)
buffer.WriteString(fmt.Sprintf(" OR app_name = $%d", len(args)))
Expand All @@ -440,6 +453,9 @@ func getStatementDetailsQueryClausesAndArgs(
buffer.WriteString(fmt.Sprintf(" app_name = $%d", len(args)))
}
}
if hasInternal {
buffer.WriteString(fmt.Sprintf(" OR app_name LIKE '%s%%'", catconstants.InternalAppNamePrefix))
}
buffer.WriteString(" )")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,27 +62,28 @@ export const selectApps = createSelector(sqlStatsSelector, sqlStatsState => {
}

let sawBlank = false;
let sawInternal = false;
const apps: { [app: string]: boolean } = {};
sqlStatsState.data.statements.forEach(
(statement: ICollectedStatementStatistics) => {
const isNotInternalApp =
if (
sqlStatsState.data.internal_app_name_prefix &&
!statement.key.key_data.app.startsWith(
statement.key.key_data.app.startsWith(
sqlStatsState.data.internal_app_name_prefix,
);
if (
sqlStatsState.data.internal_app_name_prefix == undefined ||
isNotInternalApp
)
) {
if (statement.key.key_data.app) {
apps[statement.key.key_data.app] = true;
} else {
sawBlank = true;
}
sawInternal = true;
} else if (statement.key.key_data.app) {
apps[statement.key.key_data.app] = true;
} else {
sawBlank = true;
}
},
);
return [].concat(sawBlank ? [unset] : []).concat(Object.keys(apps).sort());
return []
.concat(sawInternal ? [sqlStatsState.data.internal_app_name_prefix] : [])
.concat(sawBlank ? [unset] : [])
.concat(Object.keys(apps).sort());
});

// selectDatabases returns the array of all databases with statement statistics present
Expand Down
10 changes: 7 additions & 3 deletions pkg/ui/workspaces/cluster-ui/src/transactionsPage/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,13 @@ export const getTrxAppFilterOptions = (
prefix: string,
): string[] => {
const uniqueAppNames = new Set(
transactions
.filter(t => !t.stats_data.app.startsWith(prefix))
.map(t => (t.stats_data.app ? t.stats_data.app : unset)),
transactions.map(t =>
t.stats_data.app
? t.stats_data.app.startsWith(prefix)
? prefix
: t.stats_data.app
: unset,
),
);

return Array.from(uniqueAppNames).sort();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,27 +168,26 @@ export const selectApps = createSelector(
}

let sawBlank = false;
let sawInternal = false;
const apps: { [app: string]: boolean } = {};
state.data.statements.forEach(
(statement: ICollectedStatementStatistics) => {
const isNotInternalApp =
if (
state.data.internal_app_name_prefix &&
!statement.key.key_data.app.startsWith(
statement.key.key_data.app.startsWith(
state.data.internal_app_name_prefix,
);
if (
state.data.internal_app_name_prefix == undefined ||
isNotInternalApp
)
) {
if (statement.key.key_data.app) {
apps[statement.key.key_data.app] = true;
} else {
sawBlank = true;
}
sawInternal = true;
} else if (statement.key.key_data.app) {
apps[statement.key.key_data.app] = true;
} else {
sawBlank = true;
}
},
);
return []
.concat(sawInternal ? [state.data.internal_app_name_prefix] : [])
.concat(sawBlank ? [unset] : [])
.concat(Object.keys(apps))
.sort();
Expand Down

0 comments on commit a05ccc2

Please sign in to comment.