diff --git a/SafeExamBrowser.Browser/BrowserApplicationController.cs b/SafeExamBrowser.Browser/BrowserApplicationController.cs index 405ca764..dd058be4 100644 --- a/SafeExamBrowser.Browser/BrowserApplicationController.cs +++ b/SafeExamBrowser.Browser/BrowserApplicationController.cs @@ -117,8 +117,8 @@ namespace SafeExamBrowser.Browser private CefSettings InitializeCefSettings() { - var warning = appConfig.LogLevel == LogLevel.Warning; - var error = appConfig.LogLevel == LogLevel.Error; + var warning = logger.LogLevel == LogLevel.Warning; + var error = logger.LogLevel == LogLevel.Error; var cefSettings = new CefSettings { CachePath = appConfig.BrowserCachePath, diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index 58cde198..838dec42 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -49,6 +49,7 @@ namespace SafeExamBrowser.Client internal class CompositionRoot { private string logFilePath; + private LogLevel logLevel; private string runtimeHostUri; private Guid startupToken; @@ -131,25 +132,27 @@ namespace SafeExamBrowser.Client private void ValidateCommandLineArguments() { var args = Environment.GetCommandLineArgs(); - var hasFour = args?.Length == 4; + var hasFive = args?.Length == 5; - if (hasFour) + if (hasFive) { - var hasLogfilePath = Uri.TryCreate(args?[1], UriKind.Absolute, out Uri filePath) && filePath.IsFile; - var hasHostUri = Uri.TryCreate(args?[2], UriKind.Absolute, out Uri hostUri) && hostUri.IsWellFormedOriginalString(); - var hasToken = Guid.TryParse(args?[3], out Guid token); + var hasLogfilePath = Uri.TryCreate(args[1], UriKind.Absolute, out Uri filePath) && filePath.IsFile; + var hasLogLevel = Enum.TryParse(args[2], out LogLevel level); + var hasHostUri = Uri.TryCreate(args[3], UriKind.Absolute, out Uri hostUri) && hostUri.IsWellFormedOriginalString(); + var hasToken = Guid.TryParse(args[4], out Guid token); - if (hasLogfilePath && hasHostUri && hasToken) + if (hasLogfilePath && hasLogLevel && hasHostUri && hasToken) { logFilePath = args[1]; - runtimeHostUri = args[2]; - startupToken = Guid.Parse(args[3]); + logLevel = level; + runtimeHostUri = args[3]; + startupToken = token; return; } } - throw new ArgumentException("Invalid arguments! Required: SafeExamBrowser.Client.exe "); + throw new ArgumentException("Invalid arguments! Required: SafeExamBrowser.Client.exe "); } private void InitializeLogging() @@ -157,6 +160,7 @@ namespace SafeExamBrowser.Client var logFileWriter = new LogFileWriter(new DefaultLogFormatter(), logFilePath); logFileWriter.Initialize(); + logger.LogLevel = logLevel; logger.Subscribe(logFileWriter); } diff --git a/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.General.cs b/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.General.cs index 5d1f7046..4d2d514a 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.General.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.General.cs @@ -7,6 +7,7 @@ */ using SafeExamBrowser.Contracts.Configuration.Settings; +using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Configuration.ConfigurationData { @@ -20,6 +21,16 @@ namespace SafeExamBrowser.Configuration.ConfigurationData } } + private void MapLogLevel(Settings settings, object value) + { + const int ERROR = 0, WARNING = 1, INFO = 2; + + if (value is int level) + { + settings.LogLevel = level == ERROR ? LogLevel.Error : (level == WARNING ? LogLevel.Warning : (level == INFO ? LogLevel.Info : LogLevel.Debug)); + } + } + private void MapQuitPasswordHash(Settings settings, object value) { if (value is string hash) diff --git a/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.cs b/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.cs index 8ad44a6d..4e233184 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/DataMapper.cs @@ -51,6 +51,9 @@ namespace SafeExamBrowser.Configuration.ConfigurationData case Keys.General.AdminPasswordHash: MapAdminPasswordHash(settings, value); break; + case Keys.General.LogLevel: + MapLogLevel(settings, value); + break; case Keys.General.QuitPasswordHash: MapQuitPasswordHash(settings, value); break; diff --git a/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs b/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs index c9049ee8..44a90512 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs @@ -56,7 +56,6 @@ namespace SafeExamBrowser.Configuration.ConfigurationData appConfig.ConfigurationFileExtension = ".seb"; appConfig.DefaultSettingsFileName = "SebClientSettings.seb"; appConfig.DownloadDirectory = Path.Combine(appDataFolder, "Downloads"); - appConfig.LogLevel = LogLevel.Debug; appConfig.ProgramCopyright = programCopyright; appConfig.ProgramDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), nameof(SafeExamBrowser)); appConfig.ProgramTitle = programTitle; @@ -122,6 +121,8 @@ namespace SafeExamBrowser.Configuration.ConfigurationData settings.KioskMode = KioskMode.CreateNewDesktop; + settings.LogLevel = LogLevel.Debug; + settings.Mouse.AllowMiddleButton = false; settings.Mouse.AllowRightButton = true; diff --git a/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs b/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs index 967b8234..6377a547 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/Keys.cs @@ -45,6 +45,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData internal static class General { internal const string AdminPasswordHash = "hashedAdminPassword"; + internal const string LogLevel = "logLevel"; internal const string QuitPasswordHash = "hashedQuitPassword"; internal const string StartUrl = "startURL"; } diff --git a/SafeExamBrowser.Contracts/Configuration/AppConfig.cs b/SafeExamBrowser.Contracts/Configuration/AppConfig.cs index cb373d5f..5ca634db 100644 --- a/SafeExamBrowser.Contracts/Configuration/AppConfig.cs +++ b/SafeExamBrowser.Contracts/Configuration/AppConfig.cs @@ -7,7 +7,6 @@ */ using System; -using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Contracts.Configuration { @@ -72,11 +71,6 @@ namespace SafeExamBrowser.Contracts.Configuration /// public string DownloadDirectory { get; set; } - /// - /// The currently active, global log severity threshold. - /// - public LogLevel LogLevel { get; set; } - /// /// The copyright information for the application (i.e. the executing assembly). /// diff --git a/SafeExamBrowser.Contracts/Configuration/Settings/Settings.cs b/SafeExamBrowser.Contracts/Configuration/Settings/Settings.cs index bc9bdd03..139f3707 100644 --- a/SafeExamBrowser.Contracts/Configuration/Settings/Settings.cs +++ b/SafeExamBrowser.Contracts/Configuration/Settings/Settings.cs @@ -7,6 +7,7 @@ */ using System; +using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Contracts.Configuration.Settings { @@ -41,6 +42,11 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings /// public KioskMode KioskMode { get; set; } + /// + /// The global log severity to be used. + /// + public LogLevel LogLevel { get; set; } + /// /// All mouse-related settings. /// diff --git a/SafeExamBrowser.Contracts/Logging/ILogger.cs b/SafeExamBrowser.Contracts/Logging/ILogger.cs index cd6a279e..e64ea887 100644 --- a/SafeExamBrowser.Contracts/Logging/ILogger.cs +++ b/SafeExamBrowser.Contracts/Logging/ILogger.cs @@ -16,6 +16,11 @@ namespace SafeExamBrowser.Contracts.Logging /// public interface ILogger { + /// + /// The currently active severity threshold. All messages with a lower severity won't be logged! + /// + LogLevel LogLevel { get; set; } + /// /// Logs the given message with severity . /// @@ -53,12 +58,6 @@ namespace SafeExamBrowser.Contracts.Logging /// void Log(string message); - /// - /// Appends the given content to the log. - /// - /// - void Log(ILogContent content); - /// /// Subscribes an observer to the application log. /// diff --git a/SafeExamBrowser.Contracts/Logging/LogLevel.cs b/SafeExamBrowser.Contracts/Logging/LogLevel.cs index b88ba958..a1ede219 100644 --- a/SafeExamBrowser.Contracts/Logging/LogLevel.cs +++ b/SafeExamBrowser.Contracts/Logging/LogLevel.cs @@ -13,9 +13,9 @@ namespace SafeExamBrowser.Contracts.Logging /// public enum LogLevel { - Debug = 1, - Info = 2, - Warning = 3, - Error = 4 + Debug, + Info, + Warning, + Error } } diff --git a/SafeExamBrowser.Logging.UnitTests/LoggerTests.cs b/SafeExamBrowser.Logging.UnitTests/LoggerTests.cs index c8fc3406..587b4bb2 100644 --- a/SafeExamBrowser.Logging.UnitTests/LoggerTests.cs +++ b/SafeExamBrowser.Logging.UnitTests/LoggerTests.cs @@ -11,7 +11,6 @@ using System.Collections.Generic; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using SafeExamBrowser.Contracts.Logging; -using SafeExamBrowser.Logging; namespace SafeExamBrowser.Logging.UnitTests { @@ -29,7 +28,6 @@ namespace SafeExamBrowser.Logging.UnitTests var exceptionMessage = "I'm an exception message"; var exception = new Exception(exceptionMessage); var message = "I'm a simple text message"; - var content = new LogText("I'm some raw log text..."); sut.Debug(debug); sut.Info(info); @@ -37,11 +35,10 @@ namespace SafeExamBrowser.Logging.UnitTests sut.Error(error); sut.Error(error, exception); sut.Log(message); - sut.Log(content); var log = sut.GetLog(); - Assert.IsTrue(log.Count == 8); + Assert.IsTrue(log.Count == 7); Assert.IsTrue(debug.Equals((log[0] as ILogMessage).Message)); Assert.IsTrue((log[0] as ILogMessage).Severity == LogLevel.Debug); @@ -60,8 +57,6 @@ namespace SafeExamBrowser.Logging.UnitTests Assert.IsTrue((log[5] as ILogText).Text.Contains(exceptionMessage)); Assert.IsTrue(message.Equals((log[6] as ILogText).Text)); - - Assert.IsTrue(content.Text.Equals((log[7] as ILogText).Text)); } [TestMethod] @@ -122,7 +117,6 @@ namespace SafeExamBrowser.Logging.UnitTests Assert.ThrowsException(() => sut.Error("Hello world!", null)); Assert.ThrowsException(() => sut.Error(null, new Exception())); Assert.ThrowsException(() => sut.Log((string) null)); - Assert.ThrowsException(() => sut.Log((ILogContent) null)); } [TestMethod] diff --git a/SafeExamBrowser.Logging.UnitTests/ModuleLoggerTests.cs b/SafeExamBrowser.Logging.UnitTests/ModuleLoggerTests.cs index 8d89a113..83e5449c 100644 --- a/SafeExamBrowser.Logging.UnitTests/ModuleLoggerTests.cs +++ b/SafeExamBrowser.Logging.UnitTests/ModuleLoggerTests.cs @@ -45,7 +45,6 @@ namespace SafeExamBrowser.Logging.UnitTests sut.Error("Error"); sut.Error("Error", exception); sut.Log("Raw text"); - sut.Log(logText); sut.Subscribe(logObserverMock.Object); sut.Unsubscribe(logObserverMock.Object); sut.GetLog(); @@ -56,7 +55,6 @@ namespace SafeExamBrowser.Logging.UnitTests loggerMock.Verify(l => l.Error($"[{nameof(ModuleLoggerTests)}] Error"), Times.Once); loggerMock.Verify(l => l.Error($"[{nameof(ModuleLoggerTests)}] Error", exception), Times.Once); loggerMock.Verify(l => l.Log("Raw text"), Times.Once); - loggerMock.Verify(l => l.Log(logText), Times.Once); loggerMock.Verify(l => l.Subscribe(logObserverMock.Object), Times.Once); loggerMock.Verify(l => l.Unsubscribe(logObserverMock.Object), Times.Once); loggerMock.Verify(l => l.GetLog(), Times.Once); diff --git a/SafeExamBrowser.Logging/Logger.cs b/SafeExamBrowser.Logging/Logger.cs index 86dd9511..3819ef05 100644 --- a/SafeExamBrowser.Logging/Logger.cs +++ b/SafeExamBrowser.Logging/Logger.cs @@ -24,6 +24,8 @@ namespace SafeExamBrowser.Logging private readonly IList log = new List(); private readonly IList observers = new List(); + public LogLevel LogLevel { get; set; } + public void Debug(string message) { if (message == null) @@ -31,7 +33,10 @@ namespace SafeExamBrowser.Logging throw new ArgumentNullException(nameof(message)); } - Add(LogLevel.Debug, message); + if (LogLevel <= LogLevel.Debug) + { + Add(LogLevel.Debug, message); + } } public void Info(string message) @@ -41,7 +46,10 @@ namespace SafeExamBrowser.Logging throw new ArgumentNullException(nameof(message)); } - Add(LogLevel.Info, message); + if (LogLevel <= LogLevel.Info) + { + Add(LogLevel.Info, message); + } } public void Warn(string message) @@ -51,7 +59,10 @@ namespace SafeExamBrowser.Logging throw new ArgumentNullException(nameof(message)); } - Add(LogLevel.Warning, message); + if (LogLevel <= LogLevel.Warning) + { + Add(LogLevel.Warning, message); + } } public void Error(string message) @@ -61,7 +72,10 @@ namespace SafeExamBrowser.Logging throw new ArgumentNullException(nameof(message)); } - Add(LogLevel.Error, message); + if (LogLevel <= LogLevel.Error) + { + Add(LogLevel.Error, message); + } } public void Error(string message, Exception exception) @@ -101,8 +115,11 @@ namespace SafeExamBrowser.Logging } } - Add(LogLevel.Error, message); - Add(new LogText(details.ToString())); + if (LogLevel <= LogLevel.Error) + { + Add(LogLevel.Error, message); + Add(new LogText(details.ToString())); + } } public void Log(string text) @@ -115,16 +132,6 @@ namespace SafeExamBrowser.Logging Add(new LogText(text)); } - public void Log(ILogContent content) - { - if (content == null) - { - throw new ArgumentNullException(nameof(content)); - } - - Add(content.Clone() as ILogContent); - } - public IList GetLog() { lock (@lock) diff --git a/SafeExamBrowser.Logging/ModuleLogger.cs b/SafeExamBrowser.Logging/ModuleLogger.cs index e7eeb14c..1d7f7f48 100644 --- a/SafeExamBrowser.Logging/ModuleLogger.cs +++ b/SafeExamBrowser.Logging/ModuleLogger.cs @@ -17,6 +17,12 @@ namespace SafeExamBrowser.Logging private ILogger logger; private string moduleInfo; + public LogLevel LogLevel + { + get { return logger.LogLevel; } + set { logger.LogLevel = value; } + } + public ModuleLogger(ILogger logger, string moduleInfo) { this.logger = logger; @@ -58,11 +64,6 @@ namespace SafeExamBrowser.Logging logger.Log(message); } - public void Log(ILogContent content) - { - logger.Log(content); - } - public void Subscribe(ILogObserver observer) { logger.Subscribe(observer); diff --git a/SafeExamBrowser.Runtime/CompositionRoot.cs b/SafeExamBrowser.Runtime/CompositionRoot.cs index 550402fe..69031af4 100644 --- a/SafeExamBrowser.Runtime/CompositionRoot.cs +++ b/SafeExamBrowser.Runtime/CompositionRoot.cs @@ -134,6 +134,7 @@ namespace SafeExamBrowser.Runtime var logFileWriter = new LogFileWriter(new DefaultLogFormatter(), appConfig.RuntimeLogFile); logFileWriter.Initialize(); + logger.LogLevel = LogLevel.Debug; logger.Subscribe(logFileWriter); } diff --git a/SafeExamBrowser.Runtime/Operations/ClientOperation.cs b/SafeExamBrowser.Runtime/Operations/ClientOperation.cs index 7ab8413f..c140e5ea 100644 --- a/SafeExamBrowser.Runtime/Operations/ClientOperation.cs +++ b/SafeExamBrowser.Runtime/Operations/ClientOperation.cs @@ -102,13 +102,14 @@ namespace SafeExamBrowser.Runtime.Operations var clientExecutable = Context.Next.AppConfig.ClientExecutablePath; var clientLogFile = $"{'"' + Context.Next.AppConfig.ClientLogFile + '"'}"; - var hostUri = Context.Next.AppConfig.RuntimeAddress; - var token = Context.Next.StartupToken.ToString("D"); + var clientLogLevel = logger.LogLevel.ToString(); + var runtimeHostUri = Context.Next.AppConfig.RuntimeAddress; + var startupToken = Context.Next.StartupToken.ToString("D"); logger.Info("Starting new client process..."); runtimeHost.AllowConnection = true; runtimeHost.ClientReady += clientReadyEventHandler; - ClientProcess = processFactory.StartNew(clientExecutable, clientLogFile, hostUri, token); + ClientProcess = processFactory.StartNew(clientExecutable, clientLogFile, clientLogLevel, runtimeHostUri, startupToken); logger.Info("Waiting for client to complete initialization..."); clientReady = clientReadyEvent.WaitOne(timeout_ms); diff --git a/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs b/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs index 1b5df5ca..14b8cebd 100644 --- a/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs +++ b/SafeExamBrowser.Runtime/Operations/ConfigurationOperation.cs @@ -142,6 +142,11 @@ namespace SafeExamBrowser.Runtime.Operations Context.Next.Settings = settings; + if (settings != null) + { + logger.LogLevel = settings.LogLevel; + } + return HandleLoadResult(uri, settings, status, passwordParams); }