SEBWIN-220: Implemented basic logging for browser modules.

This commit is contained in:
dbuechel 2018-08-31 15:29:36 +02:00
parent c4d7ff5a06
commit 8280ac3a92
11 changed files with 110 additions and 38 deletions

View file

@ -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<IApplicationInstance> 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);

View file

@ -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();
}
}

View file

@ -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);
}
}
}

View file

@ -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<int, DownloadFinishedCallback> 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<int, DownloadFinishedCallback>();
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)
{

View file

@ -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<IOperation>();
@ -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;

View file

@ -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
{
/// <summary>
/// An implementation of <see cref="ILogger"/> which automatically appends information about the module from which messages are logged.
/// </summary>
public interface IModuleLogger : ILogger
{
/// <summary>
/// Creates a new instance which will automatically append the given module information.
/// </summary>
IModuleLogger CloneFor(string moduleInfo);
}
}

View file

@ -129,6 +129,7 @@
<Compile Include="Logging\ILogMessage.cs" />
<Compile Include="Logging\ILogObserver.cs" />
<Compile Include="Logging\ILogText.cs" />
<Compile Include="Logging\IModuleLogger.cs" />
<Compile Include="Logging\IThreadInfo.cs" />
<Compile Include="Logging\LogLevel.cs" />
<Compile Include="Monitoring\Events\DisplayChangedEventHandler.cs" />

View file

@ -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<ILogger>();
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<ILogger>();
var logObserverMock = new Mock<ILogObserver>();
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");

View file

@ -12,10 +12,7 @@ using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Logging
{
/// <summary>
/// Wraps an implementation of <see cref="ILogger"/> in order to append information about the module from which messages are logged.
/// </summary>
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)

View file

@ -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)));
}
}
}

View file

@ -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<IOperation>();