11import { LogId } from "../logger.js" ;
22import type { ApiClient } from "./apiClient.js" ;
33import { getProcessIdFromCluster } from "./cluster.js" ;
4+ import type { components } from "./openapi.js" ;
45
5- export enum PerformanceAdvisorOperation {
6- SUGGESTED_INDEXES = "suggestedIndexes" ,
7- DROP_INDEX_SUGGESTIONS = "dropIndexSuggestions" ,
8- SLOW_QUERY_LOGS = "slowQueryLogs" ,
9- SCHEMA_SUGGESTIONS = "schemaSuggestions" ,
10- }
6+ export type SuggestedIndex = components [ "schemas" ] [ "PerformanceAdvisorIndex" ] ;
117
12- export interface SuggestedIndex {
13- avgObjSize ?: number ;
14- id ?: string ;
15- impact ?: Array < string > ;
16- index ?: Array < { [ key : string ] : 1 | - 1 } > ;
17- namespace ?: string ;
18- weight ?: number ;
19- }
8+ export type DropIndexSuggestion = components [ "schemas" ] [ "DropIndexSuggestionsIndex" ] ;
9+
10+ export type SlowQueryLogMetrics = components [ "schemas" ] [ "PerformanceAdvisorSlowQueryMetrics" ] ;
11+
12+ export type SlowQueryLog = components [ "schemas" ] [ "PerformanceAdvisorSlowQuery" ] ;
2013
2114interface SuggestedIndexesResponse {
2215 content : {
@@ -42,16 +35,6 @@ interface SlowQueriesResponse {
4235 slowQueries ?: Array < SlowQueryLog > ;
4336}
4437
45- export interface DropIndexSuggestion {
46- accessCount ?: number ;
47- index ?: Array < { [ key : string ] : 1 | - 1 } > ;
48- name ?: string ;
49- namespace ?: string ;
50- shards ?: Array < string > ;
51- since ?: string ;
52- sizeBytes ?: number ;
53- }
54-
5538export type SchemaTriggerType =
5639 | "PERCENT_QUERIES_USE_LOOKUP"
5740 | "NUMBER_OF_QUERIES_USE_LOOKUP"
@@ -102,28 +85,6 @@ export interface SchemaRecommendation {
10285 recommendation ?: SchemaRecommedationType ;
10386}
10487
105- interface SlowQueryLogMetrics {
106- docsExamined ?: number ;
107- docsExaminedReturnedRatio ?: number ;
108- docsReturned ?: number ;
109- fromUserConnection ?: boolean ;
110- hasIndexCoverage ?: boolean ;
111- hasSort ?: boolean ;
112- keysExamined ?: number ;
113- keysExaminedReturnedRatio ?: number ;
114- numYields ?: number ;
115- operationExecutionTime ?: number ;
116- responseLength ?: number ;
117- }
118-
119- export interface SlowQueryLog {
120- line ?: string ;
121- metrics ?: SlowQueryLogMetrics ;
122- namespace ?: string ;
123- opType ?: string ;
124- replicaState ?: string ;
125- }
126-
12788export interface PerformanceAdvisorData {
12889 suggestedIndexes : Array < SuggestedIndex > ;
12990 dropIndexSuggestions : {
@@ -253,106 +214,3 @@ export async function getSlowQueries(
253214 throw new Error ( `Failed to list slow query logs: ${ err instanceof Error ? err . message : String ( err ) } ` ) ;
254215 }
255216}
256-
257- export function formatSuggestedIndexesTable ( suggestedIndexes : Array < SuggestedIndex > ) : string {
258- if ( suggestedIndexes . length === 0 ) return "No suggested indexes found." ;
259-
260- const rows = suggestedIndexes
261- . map ( ( index , i ) => {
262- const namespace = index . namespace ?? "N/A" ;
263- const weight = index . weight ?? "N/A" ;
264- const avgObjSize = index . avgObjSize ?? "N/A" ;
265- const indexKeys = index . index ? index . index . map ( ( key ) => Object . keys ( key ) [ 0 ] ) . join ( ", " ) : "N/A" ;
266- return `${ i + 1 } | ${ namespace } | ${ weight } | ${ avgObjSize } | ${ indexKeys } ` ;
267- } )
268- . join ( "\n" ) ;
269-
270- return `# | Namespace | Weight | Avg Obj Size | Index Keys
271- ---|-----------|--------|--------------|------------
272- ${ rows } `;
273- }
274-
275- export function formatDropIndexesTable ( dropIndexSuggestions : {
276- hiddenIndexes : Array < DropIndexSuggestion > ;
277- redundantIndexes : Array < DropIndexSuggestion > ;
278- unusedIndexes : Array < DropIndexSuggestion > ;
279- } ) : string {
280- const allIndexes = [
281- ...dropIndexSuggestions . hiddenIndexes . map ( ( index ) => ( { ...index , type : "Hidden" } ) ) ,
282- ...dropIndexSuggestions . redundantIndexes . map ( ( index ) => ( { ...index , type : "Redundant" } ) ) ,
283- ...dropIndexSuggestions . unusedIndexes . map ( ( index ) => ( { ...index , type : "Unused" } ) ) ,
284- ] ;
285-
286- if ( allIndexes . length === 0 ) return "No drop index suggestions found." ;
287-
288- const rows = allIndexes
289- . map ( ( index , i ) => {
290- const name = index . name ?? "N/A" ;
291- const namespace = index . namespace ?? "N/A" ;
292- const type = index . type ?? "N/A" ;
293- const sizeBytes = index . sizeBytes ?? "N/A" ;
294- const accessCount = index . accessCount ?? "N/A" ;
295- return `${ i + 1 } | ${ name } | ${ namespace } | ${ type } | ${ sizeBytes } | ${ accessCount } ` ;
296- } )
297- . join ( "\n" ) ;
298-
299- return `# | Index Name | Namespace | Type | Size (bytes) | Access Count
300- ---|------------|-----------|------|--------------|-------------
301- ${ rows } `;
302- }
303-
304- export function formatSlowQueriesTable ( slowQueryLogs : Array < SlowQueryLog > ) : string {
305- if ( slowQueryLogs . length === 0 ) return "No slow query logs found." ;
306-
307- const rows = slowQueryLogs
308- . map ( ( log , i ) => {
309- const namespace = log . namespace ?? "N/A" ;
310- const opType = log . opType ?? "N/A" ;
311- const executionTime = log . metrics ?. operationExecutionTime ?? "N/A" ;
312- const docsExamined = log . metrics ?. docsExamined ?? "N/A" ;
313- const docsReturned = log . metrics ?. docsReturned ?? "N/A" ;
314- return `${ i + 1 } | ${ namespace } | ${ opType } | ${ executionTime } ms | ${ docsExamined } | ${ docsReturned } ` ;
315- } )
316- . join ( "\n" ) ;
317-
318- return `# | Namespace | Operation | Execution Time | Docs Examined | Docs Returned
319- ---|-----------|-----------|---------------|---------------|---------------
320- ${ rows } `;
321- }
322-
323- function getTriggerDescription ( triggerType : SchemaTriggerType | undefined ) : string {
324- if ( ! triggerType ) return "N/A" ;
325- return SCHEMA_TRIGGER_DESCRIPTIONS [ triggerType ] ?? triggerType ;
326- }
327-
328- function getNamespaceTriggerDescriptions ( namespace : { triggers ?: Array < { triggerType ?: SchemaTriggerType } > } ) : string {
329- if ( ! namespace . triggers ) return "N/A" ;
330-
331- return namespace . triggers . map ( ( trigger ) => getTriggerDescription ( trigger . triggerType ) ) . join ( ", " ) ;
332- }
333-
334- function getTriggerDescriptions ( suggestion : SchemaRecommendation ) : string {
335- if ( ! suggestion . affectedNamespaces ) return "N/A" ;
336-
337- return suggestion . affectedNamespaces . map ( ( namespace ) => getNamespaceTriggerDescriptions ( namespace ) ) . join ( ", " ) ;
338- }
339-
340- export function formatSchemaSuggestionsTable ( schemaSuggestions : Array < SchemaRecommendation > ) : string {
341- if ( schemaSuggestions . length === 0 ) return "No schema suggestions found." ;
342-
343- const rows = schemaSuggestions
344- . map ( ( suggestion : SchemaRecommendation , i ) => {
345- const recommendation = suggestion . recommendation
346- ? ( SCHEMA_RECOMMENDATION_DESCRIPTIONS [ suggestion . recommendation ] ?? suggestion . recommendation )
347- : "N/A" ;
348- const description = suggestion . description ?? "N/A" ;
349- const triggeredBy = getTriggerDescriptions ( suggestion ) ;
350- const affectedNamespaces = suggestion . affectedNamespaces ?. length ?? 0 ;
351- return `${ i + 1 } | ${ recommendation } | ${ description } | ${ triggeredBy } | ${ affectedNamespaces } namespaces` ;
352- } )
353- . join ( "\n" ) ;
354-
355- return `# | Recommendation | Description | Triggered By | Affected Namespaces
356- ---|---------------|-------------|----------|-------------------
357- ${ rows } `;
358- }
0 commit comments