From 8280ac3a92fc71cc9bcd7299a37e693f6c5cc970 Mon Sep 17 00:00:00 2001 From: dbuechel Date: Fri, 31 Aug 2018 15:29:36 +0200 Subject: [PATCH] SEBWIN-220: Implemented basic logging for browser modules. --- .../BrowserApplicationController.cs | 9 +++---- .../BrowserApplicationInstance.cs | 22 +++++++++++++---- SafeExamBrowser.Browser/BrowserControl.cs | 16 ++++++++++--- .../Handlers/DownloadHandler.cs | 18 ++++++++++++-- SafeExamBrowser.Client/CompositionRoot.cs | 24 +++++++++---------- .../Logging/IModuleLogger.cs | 21 ++++++++++++++++ .../SafeExamBrowser.Contracts.csproj | 1 + .../ModuleLoggerTests.cs | 17 +++++++++++-- SafeExamBrowser.Logging/ModuleLogger.cs | 8 +++---- .../Communication/ProxyFactory.cs | 2 +- SafeExamBrowser.Runtime/CompositionRoot.cs | 10 ++++---- 11 files changed, 110 insertions(+), 38 deletions(-) create mode 100644 SafeExamBrowser.Contracts/Logging/IModuleLogger.cs diff --git a/SafeExamBrowser.Browser/BrowserApplicationController.cs b/SafeExamBrowser.Browser/BrowserApplicationController.cs index da7a6592..e9dbb924 100644 --- a/SafeExamBrowser.Browser/BrowserApplicationController.cs +++ b/SafeExamBrowser.Browser/BrowserApplicationController.cs @@ -10,9 +10,9 @@ using System; using System.Collections.Generic; using System.Linq; using CefSharp; -using SafeExamBrowser.Contracts.Core; using SafeExamBrowser.Contracts.Browser; using SafeExamBrowser.Contracts.Configuration; +using SafeExamBrowser.Contracts.Core; using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.UserInterface; @@ -29,7 +29,7 @@ namespace SafeExamBrowser.Browser private AppConfig appConfig; private IApplicationButton button; private IList instances; - private ILogger logger; + private IModuleLogger logger; private IMessageBox messageBox; private BrowserSettings settings; private IText text; @@ -40,7 +40,7 @@ namespace SafeExamBrowser.Browser public BrowserApplicationController( AppConfig appConfig, BrowserSettings settings, - ILogger logger, + IModuleLogger logger, IMessageBox messageBox, IText text, IUserInterfaceFactory uiFactory) @@ -92,7 +92,8 @@ namespace SafeExamBrowser.Browser { var id = new BrowserInstanceIdentifier(++instanceIdCounter); var isMainInstance = instances.Count == 0; - var instance = new BrowserApplicationInstance(appConfig, settings, id, isMainInstance, text, uiFactory); + var instanceLogger = logger.CloneFor($"BrowserInstance {id}"); + var instance = new BrowserApplicationInstance(appConfig, settings, id, isMainInstance, instanceLogger, text, uiFactory); instance.Initialize(); instance.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args); diff --git a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs index 408eb4b1..279578c3 100644 --- a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs +++ b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs @@ -7,12 +7,13 @@ */ using SafeExamBrowser.Browser.Handlers; -using SafeExamBrowser.Contracts.Core; -using SafeExamBrowser.Contracts.Core.Events; using SafeExamBrowser.Contracts.Browser; using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.Configuration.Settings; +using SafeExamBrowser.Contracts.Core; +using SafeExamBrowser.Contracts.Core.Events; using SafeExamBrowser.Contracts.I18n; +using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.UserInterface.Browser; using SafeExamBrowser.Contracts.UserInterface.Windows; @@ -25,6 +26,7 @@ namespace SafeExamBrowser.Browser private IBrowserControl control; private IBrowserWindow window; private bool isMainInstance; + private IModuleLogger logger; private BrowserSettings settings; private IText text; private IUserInterfaceFactory uiFactory; @@ -42,12 +44,14 @@ namespace SafeExamBrowser.Browser BrowserSettings settings, InstanceIdentifier id, bool isMainInstance, + IModuleLogger logger, IText text, IUserInterfaceFactory uiFactory) { this.appConfig = appConfig; this.Id = id; this.isMainInstance = isMainInstance; + this.logger = logger; this.settings = settings; this.text = text; this.uiFactory = uiFactory; @@ -55,17 +59,21 @@ namespace SafeExamBrowser.Browser internal void Initialize() { - var downloadHandler = new DownloadHandler(appConfig, settings); + var controlLogger = logger.CloneFor($"{nameof(BrowserControl)} {Id}"); + var downloadLogger = logger.CloneFor($"{nameof(DownloadHandler)} {Id}"); + var downloadHandler = new DownloadHandler(appConfig, settings, downloadLogger); downloadHandler.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args); - control = new BrowserControl(appConfig, settings, text); + control = new BrowserControl(appConfig, settings, controlLogger, text); control.AddressChanged += Control_AddressChanged; control.LoadingStateChanged += Control_LoadingStateChanged; control.TitleChanged += Control_TitleChanged; (control as BrowserControl).DownloadHandler = downloadHandler; (control as BrowserControl).Initialize(); + logger.Debug("Initialized browser control."); + window = uiFactory.CreateBrowserWindow(control, settings); window.IsMainWindow = isMainInstance; window.Closing += () => Terminated?.Invoke(Id); @@ -73,6 +81,8 @@ namespace SafeExamBrowser.Browser window.ReloadRequested += Window_ReloadRequested; window.BackwardNavigationRequested += Window_BackwardNavigationRequested; window.ForwardNavigationRequested += Window_ForwardNavigationRequested; + + logger.Debug("Initialized browser window."); } private void Control_AddressChanged(string address) @@ -93,21 +103,25 @@ namespace SafeExamBrowser.Browser private void Window_AddressChanged(string address) { + logger.Debug($"The user requested to navigate to '{address}'."); control.NavigateTo(address); } private void Window_ReloadRequested() { + logger.Debug($"The user requested to reload the current page."); control.Reload(); } private void Window_BackwardNavigationRequested() { + logger.Debug($"The user requested to navigate backwards."); control.NavigateBackwards(); } private void Window_ForwardNavigationRequested() { + logger.Debug($"The user requested to navigate forwards."); control.NavigateForwards(); } } diff --git a/SafeExamBrowser.Browser/BrowserControl.cs b/SafeExamBrowser.Browser/BrowserControl.cs index f11bfcfc..1e3a1a04 100644 --- a/SafeExamBrowser.Browser/BrowserControl.cs +++ b/SafeExamBrowser.Browser/BrowserControl.cs @@ -7,10 +7,12 @@ */ using System; +using CefSharp; using CefSharp.WinForms; using SafeExamBrowser.Browser.Handlers; using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.I18n; +using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.UserInterface.Browser; using SafeExamBrowser.Contracts.UserInterface.Browser.Events; using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.BrowserSettings; @@ -21,6 +23,7 @@ namespace SafeExamBrowser.Browser { private AppConfig appConfig; private BrowserSettings settings; + private ILogger logger; private IText text; private AddressChangedEventHandler addressChanged; @@ -45,16 +48,17 @@ namespace SafeExamBrowser.Browser remove { titleChanged -= value; } } - public BrowserControl(AppConfig appConfig, BrowserSettings settings, IText text) : base(settings.StartUrl) + public BrowserControl(AppConfig appConfig, BrowserSettings settings, ILogger logger, IText text) : base(settings.StartUrl) { this.appConfig = appConfig; + this.logger = logger; this.settings = settings; this.text = text; } public void Initialize() { - AddressChanged += (o, args) => addressChanged?.Invoke(args.Address); + AddressChanged += BrowserControl_AddressChanged; LoadingStateChanged += (o, args) => loadingStateChanged?.Invoke(args.IsLoading); TitleChanged += (o, args) => titleChanged?.Invoke(args.Title); @@ -62,7 +66,7 @@ namespace SafeExamBrowser.Browser MenuHandler = new ContextMenuHandler(settings, text); RequestHandler = new RequestHandler(appConfig); } - + public void NavigateBackwards() { GetBrowser().GoBack(); @@ -85,5 +89,11 @@ namespace SafeExamBrowser.Browser { GetBrowser().Reload(); } + + private void BrowserControl_AddressChanged(object sender, AddressChangedEventArgs args) + { + logger.Debug($"Navigated to '{args.Address}'."); + addressChanged?.Invoke(args.Address); + } } } diff --git a/SafeExamBrowser.Browser/Handlers/DownloadHandler.cs b/SafeExamBrowser.Browser/Handlers/DownloadHandler.cs index 6972d94c..38ee5709 100644 --- a/SafeExamBrowser.Browser/Handlers/DownloadHandler.cs +++ b/SafeExamBrowser.Browser/Handlers/DownloadHandler.cs @@ -13,6 +13,7 @@ using System.Threading.Tasks; using CefSharp; using SafeExamBrowser.Contracts.Browser; using SafeExamBrowser.Contracts.Configuration; +using SafeExamBrowser.Contracts.Logging; using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.BrowserSettings; namespace SafeExamBrowser.Browser.Handlers @@ -25,13 +26,15 @@ namespace SafeExamBrowser.Browser.Handlers private AppConfig appConfig; private BrowserSettings settings; private ConcurrentDictionary callbacks; + private ILogger logger; public event DownloadRequestedEventHandler ConfigurationDownloadRequested; - public DownloadHandler(AppConfig appConfig, BrowserSettings settings) + public DownloadHandler(AppConfig appConfig, BrowserSettings settings, ILogger logger) { this.appConfig = appConfig; this.callbacks = new ConcurrentDictionary(); + this.logger = logger; this.settings = settings; } @@ -41,17 +44,25 @@ namespace SafeExamBrowser.Browser.Handlers var extension = Path.GetExtension(uri.AbsolutePath); var isConfigFile = String.Equals(extension, appConfig.ConfigurationFileExtension, StringComparison.InvariantCultureIgnoreCase); + logger.Debug($"Handling download request for '{uri}'."); + if (isConfigFile) { Task.Run(() => RequestConfigurationFileDownload(downloadItem, callback)); } - else if (!isConfigFile && settings.AllowDownloads) + else if (settings.AllowDownloads) { + logger.Debug($"Starting download of '{uri}'..."); + using (callback) { callback.Continue(null, true); } } + else + { + logger.Info($"Aborted download request for '{uri}', as downloading is not allowed."); + } } public void OnDownloadUpdated(IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback) @@ -62,6 +73,8 @@ namespace SafeExamBrowser.Browser.Handlers { Task.Run(() => finished.Invoke(downloadItem.IsComplete, downloadItem.FullPath)); } + + logger.Debug($"Download of '{downloadItem.Url}' {(downloadItem.IsComplete ? "is complete" : "was cancelled")}."); } } @@ -70,6 +83,7 @@ namespace SafeExamBrowser.Browser.Handlers var args = new DownloadEventArgs(); ConfigurationDownloadRequested?.Invoke(downloadItem.SuggestedFileName, args); + logger.Debug($"Download of configuration file '{downloadItem.Url}' was {(args.AllowDownload ? "granted" : "denied")}."); if (args.AllowDownload) { diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index 09a99a4b..d39cfcf6 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -80,15 +80,15 @@ namespace SafeExamBrowser.Client InitializeText(); messageBox = new MessageBox(text); - processMonitor = new ProcessMonitor(new ModuleLogger(logger, typeof(ProcessMonitor)), nativeMethods); + processMonitor = new ProcessMonitor(new ModuleLogger(logger, nameof(ProcessMonitor)), nativeMethods); uiFactory = new UserInterfaceFactory(text); - runtimeProxy = new RuntimeProxy(runtimeHostUri, new ProxyObjectFactory(), new ModuleLogger(logger, typeof(RuntimeProxy))); + runtimeProxy = new RuntimeProxy(runtimeHostUri, new ProxyObjectFactory(), new ModuleLogger(logger, nameof(RuntimeProxy))); - var displayMonitor = new DisplayMonitor(new ModuleLogger(logger, typeof(DisplayMonitor)), nativeMethods); - var explorerShell = new ExplorerShell(new ModuleLogger(logger, typeof(ExplorerShell)), nativeMethods); - var windowMonitor = new WindowMonitor(new ModuleLogger(logger, typeof(WindowMonitor)), nativeMethods); + var displayMonitor = new DisplayMonitor(new ModuleLogger(logger, nameof(DisplayMonitor)), nativeMethods); + var explorerShell = new ExplorerShell(new ModuleLogger(logger, nameof(ExplorerShell)), nativeMethods); + var windowMonitor = new WindowMonitor(new ModuleLogger(logger, nameof(WindowMonitor)), nativeMethods); - Taskbar = new Taskbar(new ModuleLogger(logger, typeof(Taskbar))); + Taskbar = new Taskbar(new ModuleLogger(logger, nameof(Taskbar))); var operations = new Queue(); @@ -181,7 +181,7 @@ namespace SafeExamBrowser.Client { var processId = Process.GetCurrentProcess().Id; var factory = new HostObjectFactory(); - var host = new ClientHost(configuration.AppConfig.ClientAddress, factory, new ModuleLogger(logger, typeof(ClientHost)), processId); + var host = new ClientHost(configuration.AppConfig.ClientAddress, factory, new ModuleLogger(logger, nameof(ClientHost)), processId); var operation = new CommunicationOperation(host, logger); clientHost = host; @@ -192,7 +192,7 @@ namespace SafeExamBrowser.Client private IOperation BuildKeyboardInterceptorOperation() { - var keyboardInterceptor = new KeyboardInterceptor(configuration.Settings.Keyboard, new ModuleLogger(logger, typeof(KeyboardInterceptor))); + var keyboardInterceptor = new KeyboardInterceptor(configuration.Settings.Keyboard, new ModuleLogger(logger, nameof(KeyboardInterceptor))); var operation = new KeyboardInterceptorOperation(keyboardInterceptor, logger, nativeMethods); return operation; @@ -200,7 +200,7 @@ namespace SafeExamBrowser.Client private IOperation BuildMouseInterceptorOperation() { - var mouseInterceptor = new MouseInterceptor(new ModuleLogger(logger, typeof(MouseInterceptor)), configuration.Settings.Mouse); + var mouseInterceptor = new MouseInterceptor(new ModuleLogger(logger, nameof(MouseInterceptor)), configuration.Settings.Mouse); var operation = new MouseInterceptorOperation(logger, mouseInterceptor, nativeMethods); return operation; @@ -213,11 +213,11 @@ namespace SafeExamBrowser.Client private IOperation BuildTaskbarOperation() { - var keyboardLayout = new KeyboardLayout(new ModuleLogger(logger, typeof(KeyboardLayout)), text); + var keyboardLayout = new KeyboardLayout(new ModuleLogger(logger, nameof(KeyboardLayout)), text); var logController = new LogNotificationController(logger, uiFactory); var logInfo = new LogNotificationInfo(text); - var powerSupply = new PowerSupply(new ModuleLogger(logger, typeof(PowerSupply)), text); - var wirelessNetwork = new WirelessNetwork(new ModuleLogger(logger, typeof(WirelessNetwork)), text); + var powerSupply = new PowerSupply(new ModuleLogger(logger, nameof(PowerSupply)), text); + var wirelessNetwork = new WirelessNetwork(new ModuleLogger(logger, nameof(WirelessNetwork)), text); var operation = new TaskbarOperation(logger, logInfo, logController, keyboardLayout, powerSupply, wirelessNetwork, systemInfo, Taskbar, configuration.Settings.Taskbar, text, uiFactory); return operation; diff --git a/SafeExamBrowser.Contracts/Logging/IModuleLogger.cs b/SafeExamBrowser.Contracts/Logging/IModuleLogger.cs new file mode 100644 index 00000000..831c56cc --- /dev/null +++ b/SafeExamBrowser.Contracts/Logging/IModuleLogger.cs @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) + * + * 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 http://mozilla.org/MPL/2.0/. + */ + +namespace SafeExamBrowser.Contracts.Logging +{ + /// + /// An implementation of which automatically appends information about the module from which messages are logged. + /// + public interface IModuleLogger : ILogger + { + /// + /// Creates a new instance which will automatically append the given module information. + /// + IModuleLogger CloneFor(string moduleInfo); + } +} diff --git a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj index aa03c755..b2e26c86 100644 --- a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj +++ b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj @@ -129,6 +129,7 @@ + diff --git a/SafeExamBrowser.Logging.UnitTests/ModuleLoggerTests.cs b/SafeExamBrowser.Logging.UnitTests/ModuleLoggerTests.cs index 9f0aff5d..1257f0d2 100644 --- a/SafeExamBrowser.Logging.UnitTests/ModuleLoggerTests.cs +++ b/SafeExamBrowser.Logging.UnitTests/ModuleLoggerTests.cs @@ -10,13 +10,26 @@ using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using SafeExamBrowser.Contracts.Logging; -using SafeExamBrowser.Logging; namespace SafeExamBrowser.Logging.UnitTests { [TestClass] public class ModuleLoggerTests { + [TestMethod] + public void MustCorrectlyClone() + { + var loggerMock = new Mock(); + var sut = new ModuleLogger(loggerMock.Object, nameof(ModuleLoggerTests)); + var clone = sut.CloneFor("blubb"); + + sut.Debug("Debug"); + clone.Debug("Debug"); + + loggerMock.Verify(l => l.Debug($"[{nameof(ModuleLoggerTests)}] Debug"), Times.Once); + loggerMock.Verify(l => l.Debug($"[blubb] Debug"), Times.Once); + } + [TestMethod] public void MustCorrectlyForwardCalls() { @@ -24,7 +37,7 @@ namespace SafeExamBrowser.Logging.UnitTests var loggerMock = new Mock(); var logObserverMock = new Mock(); var logText = new LogText("Log text"); - var sut = new ModuleLogger(loggerMock.Object, typeof(ModuleLoggerTests)); + var sut = new ModuleLogger(loggerMock.Object, nameof(ModuleLoggerTests)); sut.Debug("Debug"); sut.Info("Info"); diff --git a/SafeExamBrowser.Logging/ModuleLogger.cs b/SafeExamBrowser.Logging/ModuleLogger.cs index b366dcfc..d8e0a757 100644 --- a/SafeExamBrowser.Logging/ModuleLogger.cs +++ b/SafeExamBrowser.Logging/ModuleLogger.cs @@ -12,10 +12,7 @@ using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Logging { - /// - /// Wraps an implementation of in order to append information about the module from which messages are logged. - /// - public class ModuleLogger : ILogger + public class ModuleLogger : IModuleLogger { private ILogger logger; private string moduleInfo; @@ -26,8 +23,9 @@ namespace SafeExamBrowser.Logging this.moduleInfo = moduleInfo; } - public ModuleLogger(ILogger logger, Type module) : this(logger, module.Name) + public IModuleLogger CloneFor(string moduleInfo) { + return new ModuleLogger(logger, moduleInfo); } public void Debug(string message) diff --git a/SafeExamBrowser.Runtime/Communication/ProxyFactory.cs b/SafeExamBrowser.Runtime/Communication/ProxyFactory.cs index a9c52b08..7eafb523 100644 --- a/SafeExamBrowser.Runtime/Communication/ProxyFactory.cs +++ b/SafeExamBrowser.Runtime/Communication/ProxyFactory.cs @@ -26,7 +26,7 @@ namespace SafeExamBrowser.Runtime.Communication public IClientProxy CreateClientProxy(string address) { - return new ClientProxy(address, factory, new ModuleLogger(logger, typeof(ClientProxy))); + return new ClientProxy(address, factory, new ModuleLogger(logger, nameof(ClientProxy))); } } } diff --git a/SafeExamBrowser.Runtime/CompositionRoot.cs b/SafeExamBrowser.Runtime/CompositionRoot.cs index 51409b8e..103fdd30 100644 --- a/SafeExamBrowser.Runtime/CompositionRoot.cs +++ b/SafeExamBrowser.Runtime/CompositionRoot.cs @@ -55,13 +55,13 @@ namespace SafeExamBrowser.Runtime InitializeText(); var messageBox = new MessageBox(text); - var desktopFactory = new DesktopFactory(new ModuleLogger(logger, typeof(DesktopFactory))); - var explorerShell = new ExplorerShell(new ModuleLogger(logger, typeof(ExplorerShell)), nativeMethods); - var processFactory = new ProcessFactory(new ModuleLogger(logger, typeof(ProcessFactory))); + var desktopFactory = new DesktopFactory(new ModuleLogger(logger, nameof(DesktopFactory))); + var explorerShell = new ExplorerShell(new ModuleLogger(logger, nameof(ExplorerShell)), nativeMethods); + var processFactory = new ProcessFactory(new ModuleLogger(logger, nameof(ProcessFactory))); var proxyFactory = new ProxyFactory(new ProxyObjectFactory(), logger); var resourceLoader = new ResourceLoader(); - var runtimeHost = new RuntimeHost(appConfig.RuntimeAddress, configuration, new HostObjectFactory(), new ModuleLogger(logger, typeof(RuntimeHost))); - var serviceProxy = new ServiceProxy(appConfig.ServiceAddress, new ProxyObjectFactory(), new ModuleLogger(logger, typeof(ServiceProxy))); + var runtimeHost = new RuntimeHost(appConfig.RuntimeAddress, configuration, new HostObjectFactory(), new ModuleLogger(logger, nameof(RuntimeHost))); + var serviceProxy = new ServiceProxy(appConfig.ServiceAddress, new ProxyObjectFactory(), new ModuleLogger(logger, nameof(ServiceProxy))); var uiFactory = new UserInterfaceFactory(text); var bootstrapOperations = new Queue();