executeImpl method
Implement the actual tool logic
params are the validated parameters (never null here)
Returns the result data to send in the response
Implementation
@override
Future<dynamic> executeImpl(Map<String, dynamic> params) async {
final project = ServerPodLocator.getProject();
if (project == null || !project.isValid) {
return {
'error': 'Not a valid ServerPod project',
'message': 'Could not locate ServerPod project',
};
}
// Get parameters
final filePattern = params['file'] as String? ?? 'serverpod.log';
final lines = (params['lines'] as int?) ?? 100;
final levelFilter = params['level'] as String? ?? 'ALL';
final regexPattern = params['pattern'] as String?;
// Find log directory
final logDir = _findLogDirectory(project);
if (logDir == null) {
return {
'error': 'Log directory not found',
'message': 'Could not locate logs/ directory in ServerPod project',
'searchedPaths': _getSearchedLogPaths(project),
};
}
// Find log files matching pattern
final logFiles = _findLogFiles(logDir, filePattern);
if (logFiles.isEmpty) {
return {
'error': 'No log files found',
'pattern': filePattern,
'logDirectory': logDir.path,
'message': 'No log files match the specified pattern',
};
}
// Use the most recent log file (by modification time)
logFiles.sort((a, b) => b.statSync().modified.compareTo(a.statSync().modified));
final primaryLogFile = logFiles.first;
try {
// Read and parse log entries
final entries = await _readLogEntries(
primaryLogFile,
maxEntries: lines,
levelFilter: levelFilter,
patternFilter: regexPattern,
);
return {
'entries': entries.map((e) => e.toJson()).toList(),
'file': p.basename(primaryLogFile.path),
'path': primaryLogFile.path,
'relativePath': p.relative(primaryLogFile.path, from: project.rootPath),
'totalEntries': entries.length,
'requestedLines': lines,
'levelFilter': levelFilter,
'patternFilter': regexPattern,
'logDirectory': logDir.path,
};
} catch (e) {
return {
'error': 'Failed to read log file',
'file': primaryLogFile.path,
'message': e.toString(),
};
}
}