visualize_logs
Generate histogram visualizations of log events over time to identify patterns and trends in SolarWinds Observability data.
Instructions
Generate a histogram visualization of log events
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| interval | No | Time interval for histogram buckets | hour |
| startTime | No | UTC start time (ISO 8601 format), defaults to 24 hours ago | |
| endTime | No | UTC end time (ISO 8601 format), defaults to current time | |
| filter | No | A search query string | |
| group | No | Filter logs by a specific group name | |
| entityId | No | Filter logs by a specific entity ID | |
| pageSize | No | Maximum messages to analyze | |
| use_utc | No | Use UTC time instead of local time | |
| format | No | Output format: text for ASCII chart, json for Claude visualization | text |
Implementation Reference
- src/tools/visualize-logs.ts:11-115 (handler)The main execution logic for the visualize_logs tool: searches logs using provided parameters, generates histogram data, produces ASCII chart or JSON output.export async function visualizeLogs( apiClient: SolarWindsApiClient, args: Record<string, any> ): Promise<string> { try { // Get current date/time const now = new Date(); const oneDayAgo = new Date(now); oneDayAgo.setDate(oneDayAgo.getDate() - 1); // Set up search parameters const searchParams: SolarWindsSearchParams = { filter: args.filter, entityId: args.entityId, group: args.group, pageSize: args.pageSize || 1000, direction: 'backward', // Always use backward for visualization to get oldest to newest // Histograms always need a time range to be meaningful startTime: args.startTime !== undefined ? args.startTime : oneDayAgo.toISOString(), endTime: args.endTime !== undefined ? args.endTime : now.toISOString() }; // Set up histogram options const histogramOptions: HistogramOptions = { interval: (args.interval as 'minute' | 'hour' | 'day') || 'hour', useUtc: args.use_utc || false, }; // Perform the search const response = await apiClient.searchEvents(searchParams); // Convert the logs to a format compatible with the histogram generator const events = response.logs.map(log => ({ id: log.id, received_at: log.time, display_received_at: log.time, hostname: log.hostname, program: log.program, message: log.message, // Add other required fields with placeholder values generated_at: log.time, source_name: log.hostname, source_id: 0, source_ip: '', facility: '', severity: log.severity })); // Generate histogram data const histogramData = generateHistogram(events, histogramOptions); // Check if the user wants JSON output for Claude visualization if (args.format === 'json') { // Format the data for Claude visualization const timeRanges = histogramData.data.map(point => point.time); const counts = histogramData.data.map(point => point.count); const claudeVisualizationData = { timeRanges, counts, total: histogramData.total, queryParams: { query: searchParams.filter || '', startTime: searchParams.startTime, endTime: searchParams.endTime } }; return JSON.stringify(claudeVisualizationData, null, 2); } // Generate ASCII chart for text output const chart = generateAsciiChart(histogramData); // Format the response let result = ''; // Add search parameters result += 'Visualization Parameters:\n'; if (searchParams.filter) result += `Query: ${searchParams.filter}\n`; if (searchParams.entityId) result += `Entity ID: ${searchParams.entityId}\n`; if (searchParams.group) result += `Group: ${searchParams.group}\n`; result += `Start Time: ${searchParams.startTime}\n`; result += `End Time: ${searchParams.endTime}\n`; result += `Interval: ${histogramOptions.interval}\n`; result += `Timezone: ${histogramOptions.useUtc ? 'UTC' : 'Local'}\n`; result += `Page Size: ${searchParams.pageSize}\n`; result += '\n'; // Add search metadata result += `Analyzed ${response.logs.length} logs\n`; if (response.pageInfo.nextPage) result += 'Note: More logs available. Results may be incomplete.\n'; result += '\n'; // Add chart result += chart; // Add note about JSON format result += '\n\nTip: Add "format": "json" to get data in a format that Claude can visualize as a chart.\n'; return result; } catch (error) { throw error; } }
- src/utils/types.ts:128-138 (schema)Zod schema defining input parameters for the visualize_logs tool, including interval, time range, filters, and output format.export const histogramOptionsSchema = { interval: z.enum(['minute', 'hour', 'day']).default('hour').describe('Time interval for histogram buckets'), startTime: z.string().optional().describe('UTC start time (ISO 8601 format), defaults to 24 hours ago'), endTime: z.string().optional().describe('UTC end time (ISO 8601 format), defaults to current time'), filter: z.string().optional().describe('A search query string'), group: z.string().optional().describe('Filter logs by a specific group name'), entityId: z.string().optional().describe('Filter logs by a specific entity ID'), pageSize: z.number().optional().default(1000).describe('Maximum messages to analyze'), use_utc: z.boolean().optional().default(false).describe('Use UTC time instead of local time'), format: z.enum(['text', 'json']).optional().default('text').describe('Output format: text for ASCII chart, json for Claude visualization') } as const;
- src/tools/index.ts:44-73 (registration)MCP tool registration for 'visualize_logs' using server.tool(), linking schema and handler with error handling.// Register visualize_logs tool server.tool( 'visualize_logs', 'Generate a histogram visualization of log events', histogramOptionsSchema, async (args) => { try { const result = await visualizeLogs(apiClient, args); return { content: [ { type: 'text', text: result, }, ], }; } catch (error) { const message = error instanceof Error ? error.message : String(error); return { content: [ { type: 'text', text: `Error visualizing logs: ${message}`, }, ], isError: true, }; } } );