Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ui: move events endpoint to use sql-over-http #91745

Merged
merged 1 commit into from
Nov 21, 2022
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
108 changes: 108 additions & 0 deletions pkg/ui/workspaces/cluster-ui/src/api/eventsApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright 2022 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.

import {
executeInternalSql,
LARGE_RESULT_SIZE,
SqlExecutionRequest,
sqlResultsAreEmpty,
SqlStatement,
} from "./sqlApi";
import { withTimeout } from "./util";
import moment from "moment";

// defaultEventsNumLimit is the default number of events to be returned.
export const defaultEventsNumLimit = 1000;

export type EventColumns = {
timestamp: string;
eventType: string;
reportingID: string;
info: string;
uniqueID: string;
};

export type NonRedactedEventsRequest = {
type?: string;
limit?: number;
offset?: number;
};

export type EventsResponse = EventColumns[];

export const baseEventsQuery = `SELECT timestamp, "eventType", "reportingID", info, "uniqueID" FROM system.eventlog`;

function buildEventStatement({
type,
limit,
offset,
}: NonRedactedEventsRequest): SqlStatement {
let placeholder = 1;
const eventsStmt: SqlStatement = {
sql: baseEventsQuery,
arguments: [],
};
if (type) {
eventsStmt.sql += ` WHERE "eventType" = ` + type;
eventsStmt.arguments.push(type);
}
eventsStmt.sql += ` ORDER BY timestamp DESC`;
if (!limit || limit <= 0) {
limit = defaultEventsNumLimit;
}
if (limit > 0) {
eventsStmt.sql += ` LIMIT $${placeholder}`;
eventsStmt.arguments.push(limit);
placeholder++;
}
if (offset && offset > 0) {
eventsStmt.sql += ` OFFSET $${placeholder}`;
eventsStmt.arguments.push(offset);
}
eventsStmt.sql += ";";
return eventsStmt;
}

export function buildEventsSQLRequest(
req: NonRedactedEventsRequest,
): SqlExecutionRequest {
const eventsStmt: SqlStatement = buildEventStatement(req);
return {
statements: [eventsStmt],
execute: true,
max_result_size: LARGE_RESULT_SIZE,
};
}

// getNonRedactedEvents fetches events logs from the database. Callers of
// getNonRedactedEvents from cluster-ui will need to pass a timeout argument for
// promise timeout handling (callers from db-console already have promise
// timeout handling as part of the cacheDataReducer).
// Note that this endpoint is not able to redact event log information.
export function getNonRedactedEvents(
req: NonRedactedEventsRequest = {},
timeout?: moment.Duration,
): Promise<EventsResponse> {
const eventsRequest: SqlExecutionRequest = buildEventsSQLRequest(req);
return withTimeout(
executeInternalSql<EventColumns>(eventsRequest),
timeout,
).then(result => {
// If request succeeded but query failed, throw error (caught by saga/cacheDataReducer).
if (result.error) {
throw result.error;
}

if (sqlResultsAreEmpty(result)) {
return [];
}
return result.execution.txn_results[0].rows;
});
}
1 change: 1 addition & 0 deletions pkg/ui/workspaces/cluster-ui/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ export * from "./schedulesApi";
export * from "./sqlApi";
export * from "./tracezApi";
export * from "./databasesApi";
export * from "./eventsApi";
20 changes: 10 additions & 10 deletions pkg/ui/workspaces/db-console/src/app.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
// licenses/APL.txt.

import { stubComponentInModule } from "./test-utils/mockComponent";
stubComponentInModule("src/views/cluster/containers/nodeGraphs", "default");
stubComponentInModule("src/views/cluster/containers/events", "EventPage");
stubComponentInModule("src/views/databases/databasesPage", "DatabasesPage");
stubComponentInModule(
"src/views/databases/databaseDetailsPage",
Expand Down Expand Up @@ -57,11 +59,9 @@ import { AdminUIState, createAdminUIStore } from "src/redux/state";

const CLUSTER_OVERVIEW_CAPACITY_LABEL = "Capacity Usage";
const CLUSTER_VIZ_NODE_MAP_LABEL = "Node Map";
const METRICS_HEADER = "Metrics";
const NODE_LIST_LABEL = /Nodes \([\d]\)/;
const LOADING_CLUSTER_STATUS = /Loading cluster status.*/;
const NODE_LOG_HEADER = /Logs Node.*/;
const EVENTS_HEADER = "Events";
const JOBS_HEADER = "Jobs";
const SQL_ACTIVITY_HEADER = "SQL Activity";
const TRANSACTION_DETAILS_HEADER = "Transaction Details";
Expand Down Expand Up @@ -142,7 +142,7 @@ describe("Routing to", () => {
describe("'/metrics' path", () => {
test("routes to <NodeGraphs> component", () => {
navigateToPath("/metrics");
screen.getByText(METRICS_HEADER, { selector: "h3" });
screen.getByTestId("nodeGraphs");
});

test("redirected to '/metrics/overview/cluster'", () => {
Expand All @@ -154,21 +154,21 @@ describe("Routing to", () => {
describe("'/metrics/overview/cluster' path", () => {
test("routes to <NodeGraphs> component", () => {
navigateToPath("/metrics/overview/cluster");
screen.getByText(METRICS_HEADER, { selector: "h3" });
screen.getByTestId("nodeGraphs");
});
});

describe("'/metrics/overview/node' path", () => {
test("routes to <NodeGraphs> component", () => {
navigateToPath("/metrics/overview/node");
screen.getByText(METRICS_HEADER, { selector: "h3" });
screen.getByTestId("nodeGraphs");
});
});

describe("'/metrics/:dashboardNameAttr' path", () => {
test("routes to <NodeGraphs> component", () => {
navigateToPath("/metrics/some-dashboard");
screen.getByText(METRICS_HEADER, { selector: "h3" });
screen.getByTestId("nodeGraphs");
});

test("redirected to '/metrics/:${dashboardNameAttr}/cluster'", () => {
Expand All @@ -180,14 +180,14 @@ describe("Routing to", () => {
describe("'/metrics/:dashboardNameAttr/cluster' path", () => {
test("routes to <NodeGraphs> component", () => {
navigateToPath("/metrics/some-dashboard/cluster");
screen.getByText(METRICS_HEADER, { selector: "h3" });
screen.getByTestId("nodeGraphs");
});
});

describe("'/metrics/:dashboardNameAttr/node' path", () => {
test("routes to <NodeGraphs> component", () => {
navigateToPath("/metrics/some-dashboard/node");
screen.getByText(METRICS_HEADER, { selector: "h3" });
screen.getByTestId("nodeGraphs");
});

test("redirected to '/metrics/:${dashboardNameAttr}/cluster'", () => {
Expand All @@ -199,7 +199,7 @@ describe("Routing to", () => {
describe("'/metrics/:dashboardNameAttr/node/:nodeIDAttr' path", () => {
test("routes to <NodeGraphs> component", () => {
navigateToPath("/metrics/some-dashboard/node/123");
screen.getByText(METRICS_HEADER, { selector: "h3" });
screen.getByTestId("nodeGraphs");
});
});

Expand Down Expand Up @@ -238,7 +238,7 @@ describe("Routing to", () => {
describe("'/events' path", () => {
test("routes to <EventPageUnconnected> component", () => {
navigateToPath("/events");
screen.getByText(EVENTS_HEADER, { selector: "h1" });
screen.getByTestId("EventPage");
});
});

Expand Down
4 changes: 2 additions & 2 deletions pkg/ui/workspaces/db-console/src/redux/apiReducers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const clusterReducerObj = new CachedDataReducer(
export const refreshCluster = clusterReducerObj.refresh;

const eventsReducerObj = new CachedDataReducer(
api.getEvents,
clusterUiApi.getNonRedactedEvents,
"events",
moment.duration(10, "s"),
);
Expand Down Expand Up @@ -515,7 +515,7 @@ export const refreshSnapshot = snapshotReducerObj.refresh;

export interface APIReducersState {
cluster: CachedDataReducerState<api.ClusterResponseMessage>;
events: CachedDataReducerState<api.EventsResponseMessage>;
events: CachedDataReducerState<clusterUiApi.EventsResponse>;
health: HealthState;
nodes: CachedDataReducerState<INodeStatus[]>;
raft: CachedDataReducerState<api.RaftDebugResponseMessage>;
Expand Down
2 changes: 1 addition & 1 deletion pkg/ui/workspaces/db-console/src/redux/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { AdminUIState } from "src/redux/state";
* eventsSelector selects the list of events from the store.
*/
export function eventsSelector(state: AdminUIState) {
return state.cachedData.events.data && state.cachedData.events.data.events;
return state.cachedData.events.data;
}

/**
Expand Down
Loading