Skip to main content
Glama

get_logs

Retrieve and filter application logs from Tauri desktop applications to monitor performance and debug issues.

Instructions

Get application logs with filtering. Filters can be combined (e.g., ["build", "error"] for build errors only).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
filterNoFilters to apply (empty = all logs)
limitNoMax entries
clearNoClear logs after reading
windowNoWindow label for frontend logs (default: focused window)

Implementation Reference

  • Main handler implementation for get_logs tool. Parses filters into source and level filters, retrieves backend logs from TauriManager and frontend logs from SocketManager, merges them, applies filtering, and returns entries with summary and buildHealth status.
    get_logs: async (args: { filter?: string[]; limit?: number; clear?: boolean; window?: string }) => { const filters = args.filter ?? []; const limit = args.limit ?? 50; const clear = args.clear ?? false; const windowLabel = args.window; // Parse filters into source and level filters const sourceFilters = new Set<string>(); const levelFilters = new Set<string>(); for (const f of filters) { if (['error', 'warning', 'info'].includes(f)) { levelFilters.add(f); } else { sourceFilters.add(f); } } // Helper to check if entry matches filters const matchesFilters = (entry: { category: string; level: string }) => { // If no filters, match all if (filters.length === 0) return true; // Check source filter let sourceMatch = sourceFilters.size === 0; // No source filter = match all sources if (!sourceMatch) { if (sourceFilters.has('build') && entry.category.startsWith('build-')) sourceMatch = true; if (sourceFilters.has('build-frontend') && entry.category === 'build-frontend') sourceMatch = true; if (sourceFilters.has('build-backend') && entry.category === 'build-backend') sourceMatch = true; if (sourceFilters.has('runtime') && entry.category.startsWith('runtime-')) sourceMatch = true; if (sourceFilters.has('runtime-frontend') && entry.category === 'runtime-frontend') sourceMatch = true; if (sourceFilters.has('runtime-backend') && entry.category === 'runtime-backend') sourceMatch = true; if (sourceFilters.has('runtime-frontend-network') && entry.category === 'runtime-frontend-network') sourceMatch = true; } // Check level filter let levelMatch = levelFilters.size === 0; // No level filter = match all levels if (!levelMatch) { if (levelFilters.has(entry.level)) levelMatch = true; } // Both must match (AND logic when both types are specified) return sourceMatch && levelMatch; }; // Get backend logs from TauriManager (get all, filter later) const backendResult = tauriManager.getUnifiedLogs({ filter: 'all', limit: 1000, clear }); // Get frontend logs from socket if app is running let frontendLogs: { consoleLogs: Array<{ source: string; category: string; level: string; message: string; timestamp: number }>; buildLogs: Array<{ source: string; category: string; level: string; message: string; timestamp: number; details?: { file?: string; line?: number; column?: number } }>; networkLogs: Array<{ source: string; category: string; level: string; message: string; timestamp: number; details?: { url?: string; method?: string; status?: number; duration?: number } }>; hmrStatus: { connected: boolean; status: string; lastSuccess: number | null }; } | null = null; try { frontendLogs = await socketManager.getFrontendLogs(clear, windowLabel); } catch { // App not running or socket not available } // Merge all logs let allEntries = [ ...backendResult.entries, ...(frontendLogs?.consoleLogs ?? []) as typeof backendResult.entries, ...(frontendLogs?.buildLogs ?? []) as typeof backendResult.entries, ...(frontendLogs?.networkLogs ?? []) as typeof backendResult.entries, ]; // Apply filters allEntries = allEntries.filter(matchesFilters); // Sort by timestamp and limit allEntries.sort((a, b) => a.timestamp - b.timestamp); allEntries = allEntries.slice(-limit); // Calculate summary const summary = { total: allEntries.length, errors: allEntries.filter(e => e.level === 'error').length, warnings: allEntries.filter(e => e.level === 'warning').length, }; // Build health status const buildHealth = { frontend: frontendLogs?.buildLogs.some(e => e.level === 'error') ? 'error' as const : frontendLogs ? 'healthy' as const : 'unknown' as const, backend: backendResult.entries.some(e => e.level === 'error' && e.category.startsWith('build-')) ? 'error' as const : 'healthy' as const, hmrConnected: frontendLogs?.hmrStatus.connected ?? false, lastSuccessfulBuild: frontendLogs?.hmrStatus.lastSuccess ?? undefined, }; return { content: [ { type: 'text' as const, text: JSON.stringify({ entries: allEntries, summary, buildHealth }, null, 2), }, ], }; },
  • Zod schema definition for get_logs tool. Defines input parameters: filter (array of source/level filters), limit (max entries), clear (clear logs after reading), and window (for frontend logs).
    get_logs: { name: 'get_logs', description: 'Get application logs with filtering. Filters can be combined (e.g., ["build", "error"] for build errors only).', inputSchema: z.object({ filter: z.array(z.enum([ // Source filters 'build', 'build-frontend', 'build-backend', 'runtime', 'runtime-frontend', 'runtime-backend', 'runtime-frontend-network', // Level filters 'error', 'warning', 'info', ])).optional().default([]).describe('Filters to apply (empty = all logs)'), limit: z.number().optional().default(50).describe('Max entries'), clear: z.boolean().optional().default(false).describe('Clear logs after reading'), window: z.string().optional().describe('Window label for frontend logs (default: focused window)'), }), },
  • MCP tool request handler registration. Dispatches CallToolRequestSchema requests to the appropriate tool handler from this.toolHandlers, which includes get_logs.
    this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; if (!(name in this.toolHandlers)) { throw new Error(`Unknown tool: ${name}`); } const handler = this.toolHandlers[name as ToolName]; try { return await handler(args as never); } catch (error) { return { content: [ { type: 'text' as const, text: `Error: ${(error as Error).message}`, }, ], isError: true, }; } });
  • getUnifiedLogs helper method in TauriManager. Parses backend logs (stdout/stderr) into structured LogEntry objects and applies filtering by category (build, runtime, etc.) and level (error, warning).
    getUnifiedLogs(options: { filter?: string; limit?: number; clear?: boolean; } = {}): { entries: LogEntry[]; summary: { total: number; errors: number; warnings: number } } { const { filter = 'all', limit = 50, clear = false } = options; let entries = this.parseBackendLogs(this.outputBuffer); // Apply filter if (filter !== 'all') { switch (filter) { case 'build': entries = entries.filter(e => e.category.startsWith('build-')); break; case 'build-frontend': entries = entries.filter(e => e.category === 'build-frontend'); break; case 'build-backend': entries = entries.filter(e => e.category === 'build-backend'); break; case 'runtime': entries = entries.filter(e => e.category.startsWith('runtime-')); break; case 'runtime-backend': entries = entries.filter(e => e.category === 'runtime-backend'); break; case 'errors-and-warnings': entries = entries.filter(e => e.level === 'error' || e.level === 'warning'); break; } } // Apply limit entries = entries.slice(-limit); // Calculate summary const summary = { total: entries.length, errors: entries.filter(e => e.level === 'error').length, warnings: entries.filter(e => e.level === 'warning').length, }; if (clear) { this.outputBuffer = []; } return { entries, summary }; }
  • parseBackendLogs helper method. Parses raw log lines from stdout/stderr and detects various error types including Rust errors, TypeScript errors, Vite errors, and generic errors, converting them to structured LogEntry objects.
    parseBackendLogs(rawLogs: string[]): LogEntry[] { const entries: LogEntry[] = []; const now = Date.now(); for (const line of rawLogs) { // Rust compile error: error[E0425]: cannot find value `x` const rustError = line.match(/error\[E(\d+)\]:\s*(.+)/); if (rustError) { entries.push({ source: 'rust', category: 'build-backend', level: 'error', message: `E${rustError[1]}: ${rustError[2]}`, timestamp: now, }); continue; } // Rust compile error with file location: --> src/main.rs:10:5 const rustLocation = line.match(/-->\s+(.+?):(\d+):(\d+)/); if (rustLocation && entries.length > 0) { const lastEntry = entries[entries.length - 1]; if (lastEntry.source === 'rust' && !lastEntry.details?.file) { lastEntry.details = { file: rustLocation[1], line: parseInt(rustLocation[2]), column: parseInt(rustLocation[3]), }; } continue; } // Vite error: [vite] Internal server error: ... const viteError = line.match(/\[vite\].*error:?\s*(.+)/i); if (viteError) { entries.push({ source: 'vite', category: 'build-frontend', level: 'error', message: viteError[1], timestamp: now, }); continue; } // TypeScript error: src/App.tsx(45,12): error TS2345: ... // Or: src/App.tsx:45:12 - error TS2345: ... const tsError = line.match(/(.+?)[:\(](\d+)[,:](\d+)\)?:?\s*error\s*(TS\d+):\s*(.+)/); if (tsError) { entries.push({ source: 'typescript', category: 'build-frontend', level: 'error', message: `${tsError[4]}: ${tsError[5]}`, timestamp: now, details: { file: tsError[1], line: parseInt(tsError[2]), column: parseInt(tsError[3]), }, }); continue; } // Rust warning: warning[...] const rustWarning = line.match(/warning\[?.*\]?:\s*(.+)/); if (rustWarning) { entries.push({ source: 'rust', category: 'build-backend', level: 'warning', message: rustWarning[1], timestamp: now, }); continue; } // Generic error lines (case insensitive) if (/\berror\b/i.test(line) && !/\[tauri-plugin-mcp\]/.test(line)) { entries.push({ source: 'tauri', category: 'runtime-backend', level: 'error', message: line.replace(/^\[(?:stdout|stderr)\]\s*/, ''), timestamp: now, }); } } return entries; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/DaveDev42/tauri-plugin-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server