Skip to content

Commit

Permalink
roachpb, server, ui: add fingerprint ID to details pages
Browse files Browse the repository at this point in the history
Previously, there was no easy way to get a statement or
fingerprint id from their respective details pages,
allowing then the value to be found on our internal tables
using cli.
This commit adds the fingerprint id on the response of
the statement details page.
It also adds the fingeprint ID to the Statement Details
page and Transaction Details page.

Fixes #91763

Release note (ui change): Add fingerprint ID in hex format
to the Statement Details page and Transaction Details page.
  • Loading branch information
maryliag committed Nov 15, 2022
1 parent e3447ad commit 66730b8
Show file tree
Hide file tree
Showing 13 changed files with 80 additions and 34 deletions.
1 change: 1 addition & 0 deletions pkg/roachpb/app_stats.proto
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ message AggregatedStatementMetadata {
optional int64 full_scan_count = 10 [(gogoproto.nullable) = false];
optional int64 vec_count = 11 [(gogoproto.nullable) = false];
optional int64 total_count = 12 [(gogoproto.nullable) = false];
optional string fingerprint_id = 13 [(gogoproto.nullable) = false, (gogoproto.customname) = "FingerprintID"];
}

// CollectedStatementStatistics wraps collected timings and metadata for some
Expand Down
12 changes: 8 additions & 4 deletions pkg/server/combined_statement_stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ func getStatementDetailsQueryClausesAndArgs(
return whereClause, args, nil
}

// getTotalStatementDetails return all the statistics for the selectec statement combined.
// getTotalStatementDetails return all the statistics for the selected statement combined.
func getTotalStatementDetails(
ctx context.Context, ie *sql.InternalExecutor, whereClause string, args []interface{},
) (serverpb.StatementDetailsResponse_CollectedStatementSummary, error) {
Expand All @@ -490,13 +490,15 @@ func getTotalStatementDetails(
aggregation_interval,
array_agg(app_name) as app_names,
crdb_internal.merge_statement_stats(array_agg(statistics)) AS statistics,
max(sampled_plan) as sampled_plan
max(sampled_plan) as sampled_plan,
encode(fingerprint_id, 'hex') as fingerprint_id
FROM crdb_internal.statement_statistics %s
GROUP BY
aggregation_interval
aggregation_interval,
fingerprint_id
LIMIT 1`, whereClause)

const expectedNumDatums = 5
const expectedNumDatums = 6
var statement serverpb.StatementDetailsResponse_CollectedStatementSummary

row, err := ie.QueryRowEx(ctx, "combined-stmts-details-total", nil,
Expand Down Expand Up @@ -552,6 +554,8 @@ func getTotalStatementDetails(
cfg.LineWidth = tree.ConsoleLineWidth
aggregatedMetadata.FormattedQuery = cfg.Pretty(queryTree.AST)

aggregatedMetadata.FingerprintID = string(tree.MustBeDString(row[5]))

statement = serverpb.StatementDetailsResponse_CollectedStatementSummary{
Metadata: aggregatedMetadata,
AggregationInterval: time.Duration(aggInterval.Nanos()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,9 @@ func BuildTxnStatisticsJSON(statistics *roachpb.CollectedTransactionStatistics)
// "properties": {
// "stmtType": { "type": "string" },
// "query": { "type": "string" },
// "fingerprintID": { "type": "string" },
// "querySummary": { "type": "string" },
// "formattedQuery": { "type": "string" },
// "implicitTxn": { "type": "boolean" },
// "distSQLCount": { "type": "number" },
// "failedCount": { "type": "number" },
Expand All @@ -280,6 +282,12 @@ func BuildTxnStatisticsJSON(statistics *roachpb.CollectedTransactionStatistics)
// "type": "string"
// }
// },
// "appNames": {
// "type": "array",
// "items": {
// "type": "string"
// }
// },
// }
// }
func BuildStmtDetailsMetadataJSON(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,8 @@ func TestSQLStatsJsonEncoding(t *testing.T) {
"fullScanCount": {{.Int64}},
"totalCount": {{.Int64}},
"db": [{{joinStrings .StringArray}}],
"appNames": [{{joinStrings .StringArray}}]
"appNames": [{{joinStrings .StringArray}}],
"fingerprintID": "{{.String}}"
}
`
expectedAggregatedMetadataStr := fillTemplate(t, expectedAggregatedMetadataStrTemplate, data)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ func (s *aggregatedMetadata) jsonFields() jsonFields {
{"stmtType", (*jsonString)(&s.StmtType)},
{"vecCount", (*jsonInt)(&s.VecCount)},
{"totalCount", (*jsonInt)(&s.TotalCount)},
{"fingerprintID", (*jsonString)(&s.FingerprintID)},
}
}

Expand Down
27 changes: 19 additions & 8 deletions pkg/ui/workspaces/cluster-ui/src/api/insightsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
} from "src/insights";
import moment from "moment";
import { INTERNAL_APP_NAME_PREFIX } from "src/activeExecutions/activeStatementUtils";
import { CheckHexValue } from "../util";
import { FixFingerprintHexValue } from "../util";

// Transaction contention insight events.

Expand Down Expand Up @@ -87,7 +87,9 @@ function formatTxnContentionResults(

return response.execution.txn_results[0].rows.map(row => ({
transactionID: row.waiting_txn_id,
transactionFingerprintID: CheckHexValue(row.waiting_txn_fingerprint_id),
transactionFingerprintID: FixFingerprintHexValue(
row.waiting_txn_fingerprint_id,
),
startTime: moment(row.collection_ts).utc(),
contentionDuration: moment.duration(row.contention_duration),
contentionThreshold: moment.duration(row.threshold).asMilliseconds(),
Expand Down Expand Up @@ -134,7 +136,9 @@ function formatTxnFingerprintsResults(
}

return response.execution.txn_results[0].rows.map(row => ({
transactionFingerprintID: CheckHexValue(row.transaction_fingerprint_id),
transactionFingerprintID: FixFingerprintHexValue(
row.transaction_fingerprint_id,
),
queryIDs: row.query_ids,
application: row.app_name,
}));
Expand Down Expand Up @@ -169,7 +173,10 @@ function createStmtFingerprintToQueryMap(
return idToQuery;
}
response.execution.txn_results[0].rows.forEach(row => {
idToQuery.set(CheckHexValue(row.statement_fingerprint_id), row.query);
idToQuery.set(
FixFingerprintHexValue(row.statement_fingerprint_id),
row.query,
);
});

return idToQuery;
Expand Down Expand Up @@ -364,7 +371,7 @@ function formatTxnContentionDetailsResponse(
totalContentionTime += contentionTimeInMs;
blockingContentionDetails[idx] = {
blockingExecutionID: value.blocking_txn_id,
blockingTxnFingerprintID: CheckHexValue(
blockingTxnFingerprintID: FixFingerprintHexValue(
value.blocking_txn_fingerprint_id,
),
blockingQueries: null,
Expand All @@ -385,7 +392,9 @@ function formatTxnContentionDetailsResponse(
const contentionThreshold = moment.duration(row.threshold).asMilliseconds();
return {
transactionExecutionID: row.waiting_txn_id,
transactionFingerprintID: CheckHexValue(row.waiting_txn_fingerprint_id),
transactionFingerprintID: FixFingerprintHexValue(
row.waiting_txn_fingerprint_id,
),
startTime: moment(row.collection_ts).utc(),
totalContentionTimeMs: totalContentionTime,
blockingContentionDetails: blockingContentionDetails,
Expand Down Expand Up @@ -551,7 +560,9 @@ function organizeExecutionInsightsResponseIntoTxns(
if (!txnInsight) {
txnInsight = {
transactionExecutionID: row.txn_id,
transactionFingerprintID: CheckHexValue(row.txn_fingerprint_id),
transactionFingerprintID: FixFingerprintHexValue(
row.txn_fingerprint_id,
),
implicitTxn: row.implicit_txn,
databaseName: row.database_name,
application: row.app_name,
Expand All @@ -575,7 +586,7 @@ function organizeExecutionInsightsResponseIntoTxns(
endTime: end,
elapsedTimeMillis: end.diff(start, "milliseconds"),
statementExecutionID: row.stmt_id,
statementFingerprintID: CheckHexValue(row.stmt_fingerprint_id),
statementFingerprintID: FixFingerprintHexValue(row.stmt_fingerprint_id),
isFullScan: row.full_scan,
rowsRead: row.rows_read,
rowsWritten: row.rows_written,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { AlignedData, Options } from "uplot";
import {
appAttr,
appNamesAttr,
FixFingerprintHexValue,
DATE_FORMAT_24_UTC,
intersperse,
queryByName,
Expand Down Expand Up @@ -72,7 +73,6 @@ import {
import { Delayed } from "../delayed";
import moment from "moment";
import {
CancelStmtDiagnosticRequest,
InsertStmtDiagnosticRequest,
StatementDiagnosticsReport,
} from "../api";
Expand Down Expand Up @@ -514,6 +514,7 @@ export class StatementDetails extends React.Component<
const {
app_names,
databases,
fingerprint_id,
failed_count,
full_scan_count,
vec_count,
Expand Down Expand Up @@ -651,6 +652,10 @@ export class StatementDetails extends React.Component<
", ",
)}
/>
<SummaryCardItem
label="Fingerprint ID"
value={FixFingerprintHexValue(fingerprint_id)}
/>
</SummaryCard>
</Col>
<Col className="gutter-row" span={12}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { createSelector } from "reselect";
import {
aggregateStatementStats,
appAttr,
CheckHexValue,
FixFingerprintHexValue,
combineStatementStats,
ExecutionStatistics,
flattenStatementStats,
Expand Down Expand Up @@ -178,7 +178,7 @@ export const selectStatements = createSelector(
if (!(key in statsByStatementKey)) {
statsByStatementKey[key] = {
statementFingerprintID: stmt.statement_fingerprint_id?.toString(),
statementFingerprintHexID: CheckHexValue(
statementFingerprintHexID: FixFingerprintHexValue(
stmt.statement_fingerprint_id?.toString(16),
),
statement: stmt.statement,
Expand All @@ -199,7 +199,7 @@ export const selectStatements = createSelector(
const stmt = statsByStatementKey[key];
return {
aggregatedFingerprintID: stmt.statementFingerprintID,
aggregatedFingerprintHexID: CheckHexValue(
aggregatedFingerprintHexID: FixFingerprintHexValue(
stmt.statementFingerprintHexID,
),
label: stmt.statement,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { SummaryCard, SummaryCardItem } from "../summaryCard";
import {
Bytes,
calculateTotalWorkload,
FixFingerprintHexValue,
Duration,
formatNumberForDisplay,
unset,
Expand Down Expand Up @@ -410,6 +411,14 @@ export class TransactionDetails extends React.Component<
: unset
}
/>
<SummaryCardItem
label="Fingerprint ID"
value={FixFingerprintHexValue(
transaction?.stats_data.transaction_fingerprint_id.toString(
16,
),
)}
/>
<p
className={summaryCardStylesCx(
"summary--card__divider",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { statisticsTableTitles } from "../statsTableUtil/statsTableUtil";
import { tableClasses } from "./transactionsTableClasses";
import { transactionLink } from "./transactionsCells";
import {
CheckHexValue,
FixFingerprintHexValue,
Count,
FixLong,
longToInt,
Expand Down Expand Up @@ -250,7 +250,9 @@ export function makeTransactionsColumns(
name: "transactionFingerprintId",
title: statisticsTableTitles.transactionFingerprintId(statType),
cell: (item: TransactionInfo) =>
CheckHexValue(item.stats_data?.transaction_fingerprint_id.toString(16)),
FixFingerprintHexValue(
item.stats_data?.transaction_fingerprint_id.toString(16),
),
sort: (item: TransactionInfo) =>
item.stats_data?.transaction_fingerprint_id.toString(16),
showByDefault: false,
Expand Down
18 changes: 11 additions & 7 deletions pkg/ui/workspaces/cluster-ui/src/util/format.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
BytesFitScale,
byteUnits,
HexStringToInt64String,
CheckHexValue,
FixFingerprintHexValue,
} from "./format";

describe("Format utils", () => {
Expand Down Expand Up @@ -61,13 +61,17 @@ describe("Format utils", () => {
});
});

describe("CheckHexValue", () => {
describe("FixFingerprintHexValue", () => {
it("add leading 0 to hex values", () => {
expect(CheckHexValue(undefined)).toBe("");
expect(CheckHexValue(null)).toBe("");
expect(CheckHexValue("fb9111f22f2213b7")).toBe("fb9111f22f2213b7");
expect(CheckHexValue("b9111f22f2213b7")).toBe("0b9111f22f2213b7");
expect(CheckHexValue("9111f22f2213b7")).toBe("009111f22f2213b7");
expect(FixFingerprintHexValue(undefined)).toBe("");
expect(FixFingerprintHexValue(null)).toBe("");
expect(FixFingerprintHexValue("fb9111f22f2213b7")).toBe(
"fb9111f22f2213b7",
);
expect(FixFingerprintHexValue("b9111f22f2213b7")).toBe(
"0b9111f22f2213b7",
);
expect(FixFingerprintHexValue("9111f22f2213b7")).toBe("009111f22f2213b7");
});
});
});
12 changes: 6 additions & 6 deletions pkg/ui/workspaces/cluster-ui/src/util/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,15 +256,15 @@ export function HexStringToInt64String(s: string): string {
return dec;
}

// CheckHexValue adds the leading 0 on strings with hex value that
// have a length < 16.
export function CheckHexValue(s: string): string {
// FixFingerprintHexValue adds the leading 0 on strings with hex value that
// have a length < 16. This can occur because it was returned like this from the DB
// or because the hex value was generated using `.toString(16)` (which removes the
// leading zeros).
// The zeros need to be added back to match the value on our sql stats tables.
export function FixFingerprintHexValue(s: string): string {
if (s === undefined || s === null || s.length === 0) {
return "";
}
if (s?.length === 16) {
return s;
}
while (s.length < 16) {
s = `0${s}`;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export const selectStatements = createSelector(
if (!(key in statsByStatementKey)) {
statsByStatementKey[key] = {
statementFingerprintID: stmt.statement_fingerprint_id?.toString(),
statementFingerprintHexID: util.CheckHexValue(
statementFingerprintHexID: util.FixFingerprintHexValue(
stmt.statement_fingerprint_id?.toString(16),
),
statement: stmt.statement,
Expand All @@ -163,7 +163,7 @@ export const selectStatements = createSelector(
const stmt = statsByStatementKey[key];
return {
aggregatedFingerprintID: stmt.statementFingerprintID,
aggregatedFingerprintHexID: util.CheckHexValue(
aggregatedFingerprintHexID: util.FixFingerprintHexValue(
stmt.statementFingerprintHexID,
),
label: stmt.statement,
Expand Down

0 comments on commit 66730b8

Please sign in to comment.