implemented getLogs on Android

This commit is contained in:
Adam Velebil 2022-05-11 15:47:35 +02:00
parent 87ad07fe7c
commit 89d632390a
No known key found for this signature in database
GPG Key ID: AC6D6B9D715FC084
6 changed files with 54 additions and 22 deletions

View File

@ -5,8 +5,13 @@ import io.flutter.plugin.common.MethodChannel
class FlutterLog(messenger: BinaryMessenger) { class FlutterLog(messenger: BinaryMessenger) {
private val _buffer = arrayListOf<String>()
private var _channel = MethodChannel(messenger, "android.log.redirect") private var _channel = MethodChannel(messenger, "android.log.redirect")
companion object {
const val MAX_BUFFER_SIZE = 1000
}
init { init {
_channel.setMethodCallHandler { call, result -> _channel.setMethodCallHandler { call, result ->
@ -21,7 +26,7 @@ class FlutterLog(messenger: BinaryMessenger) {
if (level == null) { if (level == null) {
loggerError("Invalid level for message from [$loggerName]: $levelValue") loggerError("Invalid level for message from [$loggerName]: $levelValue")
} else if (loggerName != null && message != null) { } else if (loggerName != null && message != null) {
Log.log(level, loggerName, message, error) log(level, loggerName, message, error)
result.success(null) result.success(null)
} else { } else {
result.error("-1", "Invalid log parameters", null) result.error("-1", "Invalid log parameters", null)
@ -35,6 +40,13 @@ class FlutterLog(messenger: BinaryMessenger) {
} else { } else {
loggerError("Invalid log level requested: $levelArgValue") loggerError("Invalid log level requested: $levelArgValue")
} }
result.success(null)
}
"getLogs" -> {
result.success(_buffer)
}
else -> {
result.notImplemented()
} }
} }
} }
@ -44,6 +56,14 @@ class FlutterLog(messenger: BinaryMessenger) {
Log.LogLevel.values().firstOrNull { it.name == argValue?.uppercase() } Log.LogLevel.values().firstOrNull { it.name == argValue?.uppercase() }
private fun loggerError(message: String) { private fun loggerError(message: String) {
Log.e("FlutterLog", message, null) log(Log.LogLevel.ERROR,"FlutterLog", message, null)
}
private fun log(level: Log.LogLevel, loggerName: String, message: String, error: String?) {
if (_buffer.size > MAX_BUFFER_SIZE) {
_buffer.removeAt(0)
}
_buffer.addAll(Log.log(level, loggerName, message, error))
} }
} }

View File

@ -47,12 +47,16 @@ object Log {
} }
@Suppress("unused") @Suppress("unused")
fun log(level: LogLevel, loggerName: String, message: String, error: String?) { fun log(level: LogLevel, loggerName: String, message: String, error: String?) : List<String> {
if (level < this.level) { if (level < this.level) {
return return listOf()
} }
val logMessage = "[$loggerName] ${level.name}: $message" val lines = mutableListOf<String>()
val logMessage = "[$loggerName] ${level.name}: $message".also {
lines.add(it)
}
when (level) { when (level) {
LogLevel.TRAFFIC -> Log.v(TAG, logMessage) LogLevel.TRAFFIC -> Log.v(TAG, logMessage)
@ -63,8 +67,12 @@ object Log {
} }
error?.let { error?.let {
Log.e(TAG, "[$loggerName] ${level.name}: $error") Log.e(TAG, "[$loggerName] ${level.name}: $error".also {
lines.add(it)
})
} }
return lines
} }
@Suppress("unused") @Suppress("unused")

View File

@ -83,9 +83,8 @@ class LoggingPanel extends ConsumerWidget {
child: const Text('Copy log'), child: const Text('Copy log'),
onPressed: () async { onPressed: () async {
_log.info('Copying log to clipboard...'); _log.info('Copying log to clipboard...');
final logs = final logs = await ref.read(logLevelProvider.notifier).getLogs();
ref.read(logLevelProvider.notifier).getLogs().join('\n'); await Clipboard.setData(ClipboardData(text: logs.join('\n')));
await Clipboard.setData(ClipboardData(text: logs));
showMessage(context, 'Log copied to clipboard'); showMessage(context, 'Log copied to clipboard');
}, },
), ),

View File

@ -23,8 +23,6 @@ import 'qr_scanner/qr_scanner_provider.dart';
import 'state.dart'; import 'state.dart';
import 'views/tap_request_dialog.dart'; import 'views/tap_request_dialog.dart';
final androidLogger = AndroidLogger();
Future<Widget> initialize() async { Future<Widget> initialize() async {
if (kDebugMode) { if (kDebugMode) {
Logger.root.level = Levels.DEBUG; Logger.root.level = Levels.DEBUG;
@ -36,6 +34,7 @@ Future<Widget> initialize() async {
Application.oath, Application.oath,
]), ]),
prefProvider.overrideWithValue(await SharedPreferences.getInstance()), prefProvider.overrideWithValue(await SharedPreferences.getInstance()),
logLevelProvider.overrideWithProvider(androidLogProvider),
attachedDevicesProvider attachedDevicesProvider
.overrideWithProvider(androidAttachedDevicesProvider), .overrideWithProvider(androidAttachedDevicesProvider),
currentDeviceDataProvider.overrideWithProvider(androidDeviceDataProvider), currentDeviceDataProvider.overrideWithProvider(androidDeviceDataProvider),
@ -56,14 +55,6 @@ Future<Widget> initialize() async {
// activates window state provider // activates window state provider
ref.read(androidWindowStateProvider); ref.read(androidWindowStateProvider);
ref.listen(logLevelProvider, (oldLevel, newLevel) {
if (oldLevel != newLevel && newLevel is Level) {
androidLogger.setLogLevel(newLevel);
}
});
androidLogger.setLogLevel(Logger.root.level);
/// initializes global handler for dialogs /// initializes global handler for dialogs
FDialogApi.setup(FDialogApiImpl(ref.watch(withContextProvider))); FDialogApi.setup(FDialogApiImpl(ref.watch(withContextProvider)));
return const MainPage(); return const MainPage();

View File

@ -1,12 +1,17 @@
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:yubico_authenticator/app/logging.dart';
final _log = Logger('android.logger'); final _log = Logger('android.logger');
class AndroidLogger { final androidLogProvider =
StateNotifierProvider<LogLevelNotifier, Level>((ref) => AndroidLogger());
class AndroidLogger extends LogLevelNotifier {
final MethodChannel _channel = const MethodChannel('android.log.redirect'); final MethodChannel _channel = const MethodChannel('android.log.redirect');
AndroidLogger() { AndroidLogger() : super() {
Logger.root.onRecord.listen((record) { Logger.root.onRecord.listen((record) {
if (record.level >= Logger.root.level) { if (record.level >= Logger.root.level) {
log(record); log(record);
@ -15,12 +20,21 @@ class AndroidLogger {
_log.info('Logging initialized, outputting to Android/logcat'); _log.info('Logging initialized, outputting to Android/logcat');
} }
@override
void setLogLevel(Level level) { void setLogLevel(Level level) {
super.setLogLevel(level);
_channel.invokeMethod('setLevel', { _channel.invokeMethod('setLevel', {
'level': level.name, 'level': level.name,
}); });
} }
@override
Future<List<String>> getLogs() async {
_log.debug('Getting logs...');
var buffer = await _channel.invokeMethod('getLogs', {});
return List.unmodifiable(buffer);
}
void log(LogRecord record) { void log(LogRecord record) {
_channel.invokeMethod('log', { _channel.invokeMethod('log', {
'loggerName': record.loggerName, 'loggerName': record.loggerName,

View File

@ -60,7 +60,7 @@ class LogLevelNotifier extends StateNotifier<Level> {
Logger.root.level = level; Logger.root.level = level;
} }
List<String> getLogs() { Future<List<String>> getLogs() async {
return List.unmodifiable(_buffer); return List.unmodifiable(_buffer);
} }
} }