diff --git a/app/lib/main.dart b/app/lib/main.dart index 635e6072..b3ae9927 100644 --- a/app/lib/main.dart +++ b/app/lib/main.dart @@ -24,9 +24,10 @@ import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart' - show GeckoBrowserService, LogLevel; + show GeckoBrowserService, GeckoLoggingService, LogLevel; import 'package:home_widget/home_widget.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:logger/logger.dart'; import 'package:weblibre/core/error_observer.dart'; import 'package:weblibre/core/logger.dart'; import 'package:weblibre/core/providers/defaults.dart'; @@ -58,6 +59,16 @@ void main() async { //Ensure everything is ready await Future.delayed(Duration.zero); + + GeckoLoggingService.setUp((level, message) { + logger.log(switch (level) { + LogLevel.debug => Level.debug, + LogLevel.info => Level.info, + LogLevel.warn => Level.warning, + LogLevel.error => Level.error, + }, message); + }); + await GeckoBrowserService().initialize( kDebugMode ? LogLevel.debug : LogLevel.warn, ); diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/api/GeckoBrowserApiImpl.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/api/GeckoBrowserApiImpl.kt index 5138d669..772c4d9b 100644 --- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/api/GeckoBrowserApiImpl.kt +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/api/GeckoBrowserApiImpl.kt @@ -27,6 +27,7 @@ import eu.weblibre.flutter_mozilla_components.pigeons.GeckoDownloadsApi import eu.weblibre.flutter_mozilla_components.pigeons.GeckoEngineSettingsApi import eu.weblibre.flutter_mozilla_components.pigeons.GeckoFindApi import eu.weblibre.flutter_mozilla_components.pigeons.GeckoIconsApi +import eu.weblibre.flutter_mozilla_components.pigeons.GeckoLogging import eu.weblibre.flutter_mozilla_components.pigeons.GeckoMlApi import eu.weblibre.flutter_mozilla_components.pigeons.GeckoPrefApi import eu.weblibre.flutter_mozilla_components.pigeons.GeckoSelectionActionController @@ -44,13 +45,15 @@ import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding import mozilla.components.browser.state.action.SystemAction import mozilla.components.feature.addons.logger +import mozilla.components.support.base.ext.getStacktraceAsString import mozilla.components.support.base.log.Log import mozilla.components.support.base.log.sink.AndroidLogSink import mozilla.components.support.base.log.sink.LogSink +import org.mozilla.gecko.util.ThreadUtils.runOnUiThread class PriorityAwareLogSink( private val minLogPriority: Log.Priority, - private val androidLogSink: LogSink, + private val geckoLogging: GeckoLogging ) : LogSink { override fun log( @@ -63,7 +66,22 @@ class PriorityAwareLogSink( return } - androidLogSink.log(priority, tag, throwable, message) + val level = when(priority) { + Log.Priority.DEBUG -> LogLevel.DEBUG + Log.Priority.INFO -> LogLevel.INFO + Log.Priority.WARN -> LogLevel.WARN + Log.Priority.ERROR -> LogLevel.ERROR + }; + + val logMessage: String = if (throwable != null) { + "$message\n${throwable.getStacktraceAsString()}" + } else { + message + } + + runOnUiThread { + geckoLogging.onLog(level, logMessage) { _ -> } + } } } @@ -118,6 +136,8 @@ class GeckoBrowserApiImpl : GeckoBrowserApi { override fun initialize(logLevel: LogLevel) { synchronized(this) { if(!isGeckoInitialized) { + val geckoLogging = GeckoLogging(_flutterPluginBinding.binaryMessenger) + val level = when(logLevel) { LogLevel.DEBUG -> Log.Priority.DEBUG LogLevel.INFO -> Log.Priority.INFO @@ -125,7 +145,7 @@ class GeckoBrowserApiImpl : GeckoBrowserApi { LogLevel.ERROR -> Log.Priority.ERROR }; - Log.addSink(PriorityAwareLogSink(level, AndroidLogSink("WebLibre"))) + Log.addSink(PriorityAwareLogSink(level, geckoLogging)) setupGeckoEngine(level) isGeckoInitialized = true diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/pigeons/Gecko.g.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/pigeons/Gecko.g.kt index f109206e..2e9ba203 100644 --- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/pigeons/Gecko.g.kt +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/pigeons/Gecko.g.kt @@ -3999,6 +3999,32 @@ class GeckoStateEvents(private val binaryMessenger: BinaryMessenger, private val } } } +/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */ +class GeckoLogging(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") { + companion object { + /** The codec used by GeckoLogging. */ + val codec: MessageCodec by lazy { + GeckoPigeonCodec() + } + } + fun onLog(levelArg: LogLevel, messageArg: String, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.flutter_mozilla_components.GeckoLogging.onLog$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(levelArg, messageArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(GeckoPigeonUtils.createConnectionError(channelName))) + } + } + } +} /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ interface ReaderViewEvents { fun onToggleReaderView(enable: Boolean) diff --git a/packages/flutter_mozilla_components/lib/flutter_mozilla_components.dart b/packages/flutter_mozilla_components/lib/flutter_mozilla_components.dart index b5351849..58a9346c 100644 --- a/packages/flutter_mozilla_components/lib/flutter_mozilla_components.dart +++ b/packages/flutter_mozilla_components/lib/flutter_mozilla_components.dart @@ -18,6 +18,7 @@ export 'src/domain/services/gecko_engine_settings.dart'; export 'src/domain/services/gecko_event.dart'; export 'src/domain/services/gecko_find_in_page.dart'; export 'src/domain/services/gecko_icon.dart'; +export 'src/domain/services/gecko_logging.dart'; export 'src/domain/services/gecko_ml.dart'; export 'src/domain/services/gecko_pref.dart'; export 'src/domain/services/gecko_readerable.dart'; diff --git a/packages/flutter_mozilla_components/lib/src/domain/services/gecko_logging.dart b/packages/flutter_mozilla_components/lib/src/domain/services/gecko_logging.dart new file mode 100644 index 00000000..c2957b15 --- /dev/null +++ b/packages/flutter_mozilla_components/lib/src/domain/services/gecko_logging.dart @@ -0,0 +1,29 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import 'package:flutter/services.dart'; +import 'package:flutter_mozilla_components/src/pigeons/gecko.g.dart'; + +class GeckoLoggingService extends GeckoLogging { + final void Function(LogLevel level, String message) handleLog; + + GeckoLoggingService.setUp( + this.handleLog, { + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) { + GeckoLogging.setUp( + this, + binaryMessenger: binaryMessenger, + messageChannelSuffix: messageChannelSuffix, + ); + } + + @override + void onLog(LogLevel level, String message) { + handleLog(level, message); + } +} diff --git a/packages/flutter_mozilla_components/lib/src/pigeons/gecko.g.dart b/packages/flutter_mozilla_components/lib/src/pigeons/gecko.g.dart index ad4c88e2..8b5339fa 100644 --- a/packages/flutter_mozilla_components/lib/src/pigeons/gecko.g.dart +++ b/packages/flutter_mozilla_components/lib/src/pigeons/gecko.g.dart @@ -4753,6 +4753,44 @@ abstract class GeckoStateEvents { } } +abstract class GeckoLogging { + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + void onLog(LogLevel level, String message); + + static void setUp(GeckoLogging? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.flutter_mozilla_components.GeckoLogging.onLog$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.flutter_mozilla_components.GeckoLogging.onLog was null.'); + final List args = (message as List?)!; + final LogLevel? arg_level = (args[0] as LogLevel?); + assert(arg_level != null, + 'Argument for dev.flutter.pigeon.flutter_mozilla_components.GeckoLogging.onLog was null, expected non-null LogLevel.'); + final String? arg_message = (args[1] as String?); + assert(arg_message != null, + 'Argument for dev.flutter.pigeon.flutter_mozilla_components.GeckoLogging.onLog was null, expected non-null String.'); + try { + api.onLog(arg_level!, arg_message!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + } +} + class ReaderViewEvents { /// Constructor for [ReaderViewEvents]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default diff --git a/packages/flutter_mozilla_components/pigeons/gecko.dart b/packages/flutter_mozilla_components/pigeons/gecko.dart index ca7c4367..ece7f7f0 100644 --- a/packages/flutter_mozilla_components/pigeons/gecko.dart +++ b/packages/flutter_mozilla_components/pigeons/gecko.dart @@ -1052,6 +1052,11 @@ abstract class GeckoStateEvents { void onLongPress(int timestamp, String id, HitResult hitResult); } +@FlutterApi() +abstract class GeckoLogging { + void onLog(LogLevel level, String message); +} + @HostApi() abstract class ReaderViewEvents { void onToggleReaderView(bool enable);