search_logs
Search and filter SolarWinds Observability logs by time, group, entity, or keywords to troubleshoot issues and analyze system events.
Instructions
Search SolarWinds Observability logs with optional filtering
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| filter | No | A search query string. Use AND/OR operators to combine terms (e.g., "error AND timeout"). The search is performed across all fields including message, hostname, program, and nested JSON fields like Context.CorrelationId. Field-specific queries like "field:value" are not supported. | |
| group | No | Filter logs by a specific group name | |
| entityId | No | Filter logs by a specific entity ID | |
| startTime | No | UTC start time (ISO 8601 format) | |
| endTime | No | UTC end time (ISO 8601 format) | |
| direction | No | Sort order: backward (oldest to newest), forward (newest to oldest), or tail (oldest to newest) | backward |
| pageSize | No | Maximum messages to return per page | |
| skipToken | No | Token to skip to the next page of results |
Implementation Reference
- src/tools/index.ts:14-42 (registration)Registers the 'search_logs' MCP tool with description, input schema, and error-handling wrapper that delegates to searchLogs function.server.tool( 'search_logs', 'Search SolarWinds Observability logs with optional filtering', searchParamsSchema, async (args) => { try { const result = await searchLogs(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 searching logs: ${message}`, }, ], isError: true, }; } } );
- src/tools/search-logs.ts:10-89 (handler)Core implementation of the search_logs tool: processes arguments, calls API, formats output with parameters, tips, metadata, and log entries.export async function searchLogs( 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); // Validate and convert arguments to search parameters const params: SolarWindsSearchParams = { // Default limit to 50 results pageSize: args.pageSize !== undefined ? args.pageSize : 50, // Default direction to backward (oldest to newest) direction: args.direction || 'backward' }; // Only add time parameters if explicitly provided // This allows API calls to work without time constraints if (args.startTime !== undefined) { params.startTime = args.startTime; } if (args.endTime !== undefined) { params.endTime = args.endTime; } // Add optional parameters if provided if (args.filter !== undefined) params.filter = args.filter; if (args.group !== undefined) params.group = args.group; if (args.entityId !== undefined) params.entityId = args.entityId; if (args.skipToken !== undefined) params.skipToken = args.skipToken; // Perform the search const response = await apiClient.searchEvents(params); // Format the response let result = ''; // Add search parameters result += 'Search Parameters:\n'; if (params.filter) result += `Query: ${params.filter}\n`; if (params.entityId) result += `Entity ID: ${params.entityId}\n`; if (params.group) result += `Group: ${params.group}\n`; if (params.startTime) result += `Start Time: ${params.startTime}\n`; if (params.endTime) result += `End Time: ${params.endTime}\n`; if (params.direction) result += `Direction: ${params.direction}\n`; if (params.pageSize) result += `Page Size: ${params.pageSize}\n`; result += '\n'; // Add search tips result += 'Search Tips:\n'; result += '- The search is performed across all fields, including nested JSON fields in the message.\n'; result += '- Use AND/OR operators to combine terms (e.g., "error AND timeout").\n'; result += '- The search does not support field-specific queries like "field:value".\n'; result += '- To search for logs with a specific ID in a nested field (like Context.CorrelationId),\n'; result += ' simply include the ID in your search query.\n'; result += '\n'; // Add search metadata result += `Found ${response.logs.length} logs\n`; if (response.pageInfo.nextPage) result += 'More logs available. Use skipToken to get the next page.\n'; result += '\n'; // Add events if (response.logs.length === 0) { result += 'No logs found matching the search criteria.\n'; } else { result += 'Logs:\n'; for (const log of response.logs) { result += `[${log.time}] ${log.hostname} ${log.program || ''}: ${log.message}\n`; } } return result; } catch (error) { throw error; } }
- src/utils/types.ts:18-27 (schema)Zod schema defining input parameters for the search_logs tool, including descriptions for MCP tool interface.export const searchParamsSchema = { filter: z.string().optional().describe('A search query string. Use AND/OR operators to combine terms (e.g., "error AND timeout"). The search is performed across all fields including message, hostname, program, and nested JSON fields like Context.CorrelationId. Field-specific queries like "field:value" are not supported.'), group: z.string().optional().describe('Filter logs by a specific group name'), entityId: z.string().optional().describe('Filter logs by a specific entity ID'), startTime: z.string().optional().describe('UTC start time (ISO 8601 format)'), endTime: z.string().optional().describe('UTC end time (ISO 8601 format)'), direction: z.enum(['backward', 'forward', 'tail']).default('backward').describe('Sort order: backward (oldest to newest), forward (newest to oldest), or tail (oldest to newest)'), pageSize: z.number().optional().default(50).describe('Maximum messages to return per page'), skipToken: z.string().optional().describe('Token to skip to the next page of results') } as const;