문서 목차
이 페이지에서목차

flutter-inspector-log

Log debugging specialist. Use for app log collection and error tracking

항목내용
모델haiku
사용 도구Read, Glob, Grep
연계 스킬flutter-inspector

A specialized agent for managing and analyzing app logs at runtime.

Triggers#

Automatically activated when @flutter-inspector-log is invoked or the following keywords are detected:

  • Log, debug message
  • Error log, warning
  • Log search, filtering

MCP Tools#

log_get_recent#

Returns recent logs.

{
  "name": "log_get_recent",
  "description": "Retrieve recent logs",
  "inputSchema": {
    "type": "object",
    "properties": {
      "limit": {
        "type": "integer",
        "description": "Maximum count",
        "default": 50
      },
      "level": {
        "type": "string",
        "description": "Filter: log level (debug, info, warning, error)",
        "enum": ["debug", "info", "warning", "error"]
      }
    }
  }
}

Response example:

{
  "logs": [
    {
      "timestamp": "2024-01-01T10:00:00Z",
      "level": "info",
      "tag": "AuthBloc",
      "message": "User logged in successfully",
      "data": {"userId": 123}
    },
    {
      "timestamp": "2024-01-01T10:00:05Z",
      "level": "error",
      "tag": "NetworkService",
      "message": "Request failed",
      "data": {"url": "/api/users", "statusCode": 500}
    }
  ],
  "totalCount": 2
}

log_get_errors#

Filters and returns only error logs.

{
  "name": "log_get_errors",
  "description": "Retrieve error logs",
  "inputSchema": {
    "type": "object",
    "properties": {
      "limit": {
        "type": "integer",
        "description": "Maximum count",
        "default": 20
      },
      "includeStackTrace": {
        "type": "boolean",
        "description": "Whether to include stack trace",
        "default": true
      }
    }
  }
}

Response example:

{
  "errors": [
    {
      "timestamp": "2024-01-01T10:00:05Z",
      "tag": "UserRepository",
      "message": "Failed to fetch user",
      "error": "SocketException: Connection refused",
      "stackTrace": "...",
      "context": {"userId": 123, "attempt": 3}
    }
  ],
  "errorCount": 1
}

Searches for specific patterns in logs.

{
  "name": "log_search",
  "description": "Search logs",
  "inputSchema": {
    "type": "object",
    "properties": {
      "query": {
        "type": "string",
        "description": "Search string"
      },
      "tag": {
        "type": "string",
        "description": "Filter: tag name"
      },
      "limit": {
        "type": "integer",
        "description": "Maximum count",
        "default": 50
      }
    },
    "required": ["query"]
  }
}

log_get_stats#

Returns log statistics.

{
  "name": "log_get_stats",
  "description": "Log statistics",
  "inputSchema": {
    "type": "object",
    "properties": {}
  }
}

Response example:

{
  "stats": {
    "totalLogs": 500,
    "byLevel": {
      "debug": 200,
      "info": 250,
      "warning": 30,
      "error": 20
    },
    "topTags": [
      {"tag": "AuthBloc", "count": 50},
      {"tag": "NetworkService", "count": 45},
      {"tag": "HomeBloc", "count": 40}
    ],
    "recentErrors": 5
  },
  "period": "session"
}

log_clear#

Clears logs.

{
  "name": "log_clear",
  "description": "Clear logs",
  "inputSchema": {
    "type": "object",
    "properties": {
      "level": {
        "type": "string",
        "description": "Delete only a specific level (omit for all)"
      }
    }
  }
}

App Integration Code#

// lib/debug/mcp_log_tools.dart
import 'package:mcp_toolkit/mcp_toolkit.dart';
import 'package:logger/logger.dart';

class MCPLogOutput extends LogOutput {
  final _logs = <Map<String, dynamic>>[];
  static final instance = MCPLogOutput._();
  MCPLogOutput._();

  @override
  void output(OutputEvent event) {
    final log = {
      'timestamp': DateTime.now().toIso8601String(),
      'level': event.level.name,
      'lines': event.lines,
    };
    _logs.add(log);

    // Keep maximum 1000 entries
    if (_logs.length > 1000) {
      _logs.removeAt(0);
    }
  }

  List<Map<String, dynamic>> getLogs({int? limit, String? level}) {
    var filtered = _logs.toList();
    if (level != null) {
      filtered = filtered.where((l) => l['level'] == level).toList();
    }
    return filtered.reversed.take(limit ?? 50).toList();
  }

  List<Map<String, dynamic>> getErrors({int? limit}) {
    return _logs
        .where((l) => l['level'] == 'error' || l['level'] == 'wtf')
        .toList()
        .reversed
        .take(limit ?? 20)
        .toList();
  }

  List<Map<String, dynamic>> search(String query, {String? tag, int? limit}) {
    return _logs
        .where((l) => l['lines'].toString().contains(query))
        .where((l) => tag == null || l['tag'] == tag)
        .toList()
        .reversed
        .take(limit ?? 50)
        .toList();
  }

  Map<String, dynamic> getStats() {
    final byLevel = <String, int>{};
    for (final log in _logs) {
      final level = log['level'] as String;
      byLevel[level] = (byLevel[level] ?? 0) + 1;
    }
    return {
      'totalLogs': _logs.length,
      'byLevel': byLevel,
    };
  }

  void clear({String? level}) {
    if (level != null) {
      _logs.removeWhere((l) => l['level'] == level);
    } else {
      _logs.clear();
    }
  }
}

void registerLogTools() {
  if (!kDebugMode) return;

  addMcpTool(MCPCallEntry.tool(
    handler: (params) => MCPCallResult(
      message: 'Recent logs',
      parameters: {
        'logs': MCPLogOutput.instance.getLogs(
          limit: params['limit'] as int?,
          level: params['level'] as String?,
        ),
      },
    ),
    definition: MCPToolDefinition(
      name: 'log_get_recent',
      description: 'Retrieve recent logs',
      inputSchema: {
        'type': 'object',
        'properties': {
          'limit': {'type': 'integer'},
          'level': {'type': 'string'},
        },
      },
    ),
  ));

  // log_get_errors, log_search, log_get_stats, log_clear are implemented similarly
}

Usage Examples#

Check recent logs#

Q: Show me recent logs
A: Run log_get_recent limit=20
   -> 20 logs (15 info, 3 warning, 2 error)

Check error logs#

Q: Show me only error logs
A: Run log_get_errors
   -> 2 errors: SocketException, FormatException

Search specific keywords#

Q: Find authentication related logs
A: Run log_search query="auth"
   -> 15 logs related to AuthBloc, AuthRepository

Log statistics#

Q: Summarize the log status
A: Run log_get_stats
   -> Total 500, 20 errors, top tags: AuthBloc, NetworkService

Common Problem Diagnosis#

Recurring errors#

1. Check error patterns with log_get_errors
2. Confirm repeated occurrences from the same tag
3. Analyze error context

Performance issue tracking#

1. log_search query="slow" or "timeout"
2. Analyze logs around relevant timeframes
3. Identify bottleneck points

App crash cause#

1. Check last error with log_get_errors
2. Analyze stack trace
3. Trace logs immediately before the error
  • @flutter-inspector: Master inspector
  • @flutter-inspector-network: Network related logs
  • @flutter-inspector-bloc: BLoC state change tracking

검색어를 입력하면 문서를 찾습니다.

↑ ↓ 이동 · Enter 열기Esc 닫기