SEBWIN-226: Implemented global log severity threshold.

This commit is contained in:
dbuechel 2019-01-23 08:12:15 +01:00
parent 06c32ee359
commit 6436f98e3f
17 changed files with 87 additions and 61 deletions

View file

@ -117,8 +117,8 @@ namespace SafeExamBrowser.Browser
private CefSettings InitializeCefSettings() private CefSettings InitializeCefSettings()
{ {
var warning = appConfig.LogLevel == LogLevel.Warning; var warning = logger.LogLevel == LogLevel.Warning;
var error = appConfig.LogLevel == LogLevel.Error; var error = logger.LogLevel == LogLevel.Error;
var cefSettings = new CefSettings var cefSettings = new CefSettings
{ {
CachePath = appConfig.BrowserCachePath, CachePath = appConfig.BrowserCachePath,

View file

@ -49,6 +49,7 @@ namespace SafeExamBrowser.Client
internal class CompositionRoot internal class CompositionRoot
{ {
private string logFilePath; private string logFilePath;
private LogLevel logLevel;
private string runtimeHostUri; private string runtimeHostUri;
private Guid startupToken; private Guid startupToken;
@ -131,25 +132,27 @@ namespace SafeExamBrowser.Client
private void ValidateCommandLineArguments() private void ValidateCommandLineArguments()
{ {
var args = Environment.GetCommandLineArgs(); 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 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 hasLogLevel = Enum.TryParse(args[2], out LogLevel level);
var hasToken = Guid.TryParse(args?[3], out Guid token); 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]; logFilePath = args[1];
runtimeHostUri = args[2]; logLevel = level;
startupToken = Guid.Parse(args[3]); runtimeHostUri = args[3];
startupToken = token;
return; return;
} }
} }
throw new ArgumentException("Invalid arguments! Required: SafeExamBrowser.Client.exe <logfile path> <host URI> <token>"); throw new ArgumentException("Invalid arguments! Required: SafeExamBrowser.Client.exe <logfile path> <log level> <host URI> <token>");
} }
private void InitializeLogging() private void InitializeLogging()
@ -157,6 +160,7 @@ namespace SafeExamBrowser.Client
var logFileWriter = new LogFileWriter(new DefaultLogFormatter(), logFilePath); var logFileWriter = new LogFileWriter(new DefaultLogFormatter(), logFilePath);
logFileWriter.Initialize(); logFileWriter.Initialize();
logger.LogLevel = logLevel;
logger.Subscribe(logFileWriter); logger.Subscribe(logFileWriter);
} }

View file

@ -7,6 +7,7 @@
*/ */
using SafeExamBrowser.Contracts.Configuration.Settings; using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Configuration.ConfigurationData 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) private void MapQuitPasswordHash(Settings settings, object value)
{ {
if (value is string hash) if (value is string hash)

View file

@ -51,6 +51,9 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
case Keys.General.AdminPasswordHash: case Keys.General.AdminPasswordHash:
MapAdminPasswordHash(settings, value); MapAdminPasswordHash(settings, value);
break; break;
case Keys.General.LogLevel:
MapLogLevel(settings, value);
break;
case Keys.General.QuitPasswordHash: case Keys.General.QuitPasswordHash:
MapQuitPasswordHash(settings, value); MapQuitPasswordHash(settings, value);
break; break;

View file

@ -56,7 +56,6 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
appConfig.ConfigurationFileExtension = ".seb"; appConfig.ConfigurationFileExtension = ".seb";
appConfig.DefaultSettingsFileName = "SebClientSettings.seb"; appConfig.DefaultSettingsFileName = "SebClientSettings.seb";
appConfig.DownloadDirectory = Path.Combine(appDataFolder, "Downloads"); appConfig.DownloadDirectory = Path.Combine(appDataFolder, "Downloads");
appConfig.LogLevel = LogLevel.Debug;
appConfig.ProgramCopyright = programCopyright; appConfig.ProgramCopyright = programCopyright;
appConfig.ProgramDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), nameof(SafeExamBrowser)); appConfig.ProgramDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), nameof(SafeExamBrowser));
appConfig.ProgramTitle = programTitle; appConfig.ProgramTitle = programTitle;
@ -122,6 +121,8 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
settings.KioskMode = KioskMode.CreateNewDesktop; settings.KioskMode = KioskMode.CreateNewDesktop;
settings.LogLevel = LogLevel.Debug;
settings.Mouse.AllowMiddleButton = false; settings.Mouse.AllowMiddleButton = false;
settings.Mouse.AllowRightButton = true; settings.Mouse.AllowRightButton = true;

View file

@ -45,6 +45,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
internal static class General internal static class General
{ {
internal const string AdminPasswordHash = "hashedAdminPassword"; internal const string AdminPasswordHash = "hashedAdminPassword";
internal const string LogLevel = "logLevel";
internal const string QuitPasswordHash = "hashedQuitPassword"; internal const string QuitPasswordHash = "hashedQuitPassword";
internal const string StartUrl = "startURL"; internal const string StartUrl = "startURL";
} }

View file

@ -7,7 +7,6 @@
*/ */
using System; using System;
using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Contracts.Configuration namespace SafeExamBrowser.Contracts.Configuration
{ {
@ -72,11 +71,6 @@ namespace SafeExamBrowser.Contracts.Configuration
/// </summary> /// </summary>
public string DownloadDirectory { get; set; } public string DownloadDirectory { get; set; }
/// <summary>
/// The currently active, global log severity threshold.
/// </summary>
public LogLevel LogLevel { get; set; }
/// <summary> /// <summary>
/// The copyright information for the application (i.e. the executing assembly). /// The copyright information for the application (i.e. the executing assembly).
/// </summary> /// </summary>

View file

@ -7,6 +7,7 @@
*/ */
using System; using System;
using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Contracts.Configuration.Settings namespace SafeExamBrowser.Contracts.Configuration.Settings
{ {
@ -41,6 +42,11 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
/// </summary> /// </summary>
public KioskMode KioskMode { get; set; } public KioskMode KioskMode { get; set; }
/// <summary>
/// The global log severity to be used.
/// </summary>
public LogLevel LogLevel { get; set; }
/// <summary> /// <summary>
/// All mouse-related settings. /// All mouse-related settings.
/// </summary> /// </summary>

View file

@ -16,6 +16,11 @@ namespace SafeExamBrowser.Contracts.Logging
/// </summary> /// </summary>
public interface ILogger public interface ILogger
{ {
/// <summary>
/// The currently active severity threshold. All messages with a lower severity won't be logged!
/// </summary>
LogLevel LogLevel { get; set; }
/// <summary> /// <summary>
/// Logs the given message with severity <see cref="LogLevel.Debug"/>. /// Logs the given message with severity <see cref="LogLevel.Debug"/>.
/// </summary> /// </summary>
@ -53,12 +58,6 @@ namespace SafeExamBrowser.Contracts.Logging
/// <exception cref="ArgumentNullException" /> /// <exception cref="ArgumentNullException" />
void Log(string message); void Log(string message);
/// <summary>
/// Appends the given content to the log.
/// </summary>
/// <exception cref="ArgumentNullException" />
void Log(ILogContent content);
/// <summary> /// <summary>
/// Subscribes an observer to the application log. /// Subscribes an observer to the application log.
/// </summary> /// </summary>

View file

@ -13,9 +13,9 @@ namespace SafeExamBrowser.Contracts.Logging
/// </summary> /// </summary>
public enum LogLevel public enum LogLevel
{ {
Debug = 1, Debug,
Info = 2, Info,
Warning = 3, Warning,
Error = 4 Error
} }
} }

View file

@ -11,7 +11,6 @@ using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq; using Moq;
using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Logging;
namespace SafeExamBrowser.Logging.UnitTests namespace SafeExamBrowser.Logging.UnitTests
{ {
@ -29,7 +28,6 @@ namespace SafeExamBrowser.Logging.UnitTests
var exceptionMessage = "I'm an exception message"; var exceptionMessage = "I'm an exception message";
var exception = new Exception(exceptionMessage); var exception = new Exception(exceptionMessage);
var message = "I'm a simple text message"; var message = "I'm a simple text message";
var content = new LogText("I'm some raw log text...");
sut.Debug(debug); sut.Debug(debug);
sut.Info(info); sut.Info(info);
@ -37,11 +35,10 @@ namespace SafeExamBrowser.Logging.UnitTests
sut.Error(error); sut.Error(error);
sut.Error(error, exception); sut.Error(error, exception);
sut.Log(message); sut.Log(message);
sut.Log(content);
var log = sut.GetLog(); 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(debug.Equals((log[0] as ILogMessage).Message));
Assert.IsTrue((log[0] as ILogMessage).Severity == LogLevel.Debug); 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((log[5] as ILogText).Text.Contains(exceptionMessage));
Assert.IsTrue(message.Equals((log[6] as ILogText).Text)); Assert.IsTrue(message.Equals((log[6] as ILogText).Text));
Assert.IsTrue(content.Text.Equals((log[7] as ILogText).Text));
} }
[TestMethod] [TestMethod]
@ -122,7 +117,6 @@ namespace SafeExamBrowser.Logging.UnitTests
Assert.ThrowsException<ArgumentNullException>(() => sut.Error("Hello world!", null)); Assert.ThrowsException<ArgumentNullException>(() => sut.Error("Hello world!", null));
Assert.ThrowsException<ArgumentNullException>(() => sut.Error(null, new Exception())); Assert.ThrowsException<ArgumentNullException>(() => sut.Error(null, new Exception()));
Assert.ThrowsException<ArgumentNullException>(() => sut.Log((string) null)); Assert.ThrowsException<ArgumentNullException>(() => sut.Log((string) null));
Assert.ThrowsException<ArgumentNullException>(() => sut.Log((ILogContent) null));
} }
[TestMethod] [TestMethod]

View file

@ -45,7 +45,6 @@ namespace SafeExamBrowser.Logging.UnitTests
sut.Error("Error"); sut.Error("Error");
sut.Error("Error", exception); sut.Error("Error", exception);
sut.Log("Raw text"); sut.Log("Raw text");
sut.Log(logText);
sut.Subscribe(logObserverMock.Object); sut.Subscribe(logObserverMock.Object);
sut.Unsubscribe(logObserverMock.Object); sut.Unsubscribe(logObserverMock.Object);
sut.GetLog(); 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"), Times.Once);
loggerMock.Verify(l => l.Error($"[{nameof(ModuleLoggerTests)}] Error", exception), 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("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.Subscribe(logObserverMock.Object), Times.Once);
loggerMock.Verify(l => l.Unsubscribe(logObserverMock.Object), Times.Once); loggerMock.Verify(l => l.Unsubscribe(logObserverMock.Object), Times.Once);
loggerMock.Verify(l => l.GetLog(), Times.Once); loggerMock.Verify(l => l.GetLog(), Times.Once);

View file

@ -24,6 +24,8 @@ namespace SafeExamBrowser.Logging
private readonly IList<ILogContent> log = new List<ILogContent>(); private readonly IList<ILogContent> log = new List<ILogContent>();
private readonly IList<ILogObserver> observers = new List<ILogObserver>(); private readonly IList<ILogObserver> observers = new List<ILogObserver>();
public LogLevel LogLevel { get; set; }
public void Debug(string message) public void Debug(string message)
{ {
if (message == null) if (message == null)
@ -31,7 +33,10 @@ namespace SafeExamBrowser.Logging
throw new ArgumentNullException(nameof(message)); throw new ArgumentNullException(nameof(message));
} }
Add(LogLevel.Debug, message); if (LogLevel <= LogLevel.Debug)
{
Add(LogLevel.Debug, message);
}
} }
public void Info(string message) public void Info(string message)
@ -41,7 +46,10 @@ namespace SafeExamBrowser.Logging
throw new ArgumentNullException(nameof(message)); throw new ArgumentNullException(nameof(message));
} }
Add(LogLevel.Info, message); if (LogLevel <= LogLevel.Info)
{
Add(LogLevel.Info, message);
}
} }
public void Warn(string message) public void Warn(string message)
@ -51,7 +59,10 @@ namespace SafeExamBrowser.Logging
throw new ArgumentNullException(nameof(message)); throw new ArgumentNullException(nameof(message));
} }
Add(LogLevel.Warning, message); if (LogLevel <= LogLevel.Warning)
{
Add(LogLevel.Warning, message);
}
} }
public void Error(string message) public void Error(string message)
@ -61,7 +72,10 @@ namespace SafeExamBrowser.Logging
throw new ArgumentNullException(nameof(message)); throw new ArgumentNullException(nameof(message));
} }
Add(LogLevel.Error, message); if (LogLevel <= LogLevel.Error)
{
Add(LogLevel.Error, message);
}
} }
public void Error(string message, Exception exception) public void Error(string message, Exception exception)
@ -101,8 +115,11 @@ namespace SafeExamBrowser.Logging
} }
} }
Add(LogLevel.Error, message); if (LogLevel <= LogLevel.Error)
Add(new LogText(details.ToString())); {
Add(LogLevel.Error, message);
Add(new LogText(details.ToString()));
}
} }
public void Log(string text) public void Log(string text)
@ -115,16 +132,6 @@ namespace SafeExamBrowser.Logging
Add(new LogText(text)); Add(new LogText(text));
} }
public void Log(ILogContent content)
{
if (content == null)
{
throw new ArgumentNullException(nameof(content));
}
Add(content.Clone() as ILogContent);
}
public IList<ILogContent> GetLog() public IList<ILogContent> GetLog()
{ {
lock (@lock) lock (@lock)

View file

@ -17,6 +17,12 @@ namespace SafeExamBrowser.Logging
private ILogger logger; private ILogger logger;
private string moduleInfo; private string moduleInfo;
public LogLevel LogLevel
{
get { return logger.LogLevel; }
set { logger.LogLevel = value; }
}
public ModuleLogger(ILogger logger, string moduleInfo) public ModuleLogger(ILogger logger, string moduleInfo)
{ {
this.logger = logger; this.logger = logger;
@ -58,11 +64,6 @@ namespace SafeExamBrowser.Logging
logger.Log(message); logger.Log(message);
} }
public void Log(ILogContent content)
{
logger.Log(content);
}
public void Subscribe(ILogObserver observer) public void Subscribe(ILogObserver observer)
{ {
logger.Subscribe(observer); logger.Subscribe(observer);

View file

@ -134,6 +134,7 @@ namespace SafeExamBrowser.Runtime
var logFileWriter = new LogFileWriter(new DefaultLogFormatter(), appConfig.RuntimeLogFile); var logFileWriter = new LogFileWriter(new DefaultLogFormatter(), appConfig.RuntimeLogFile);
logFileWriter.Initialize(); logFileWriter.Initialize();
logger.LogLevel = LogLevel.Debug;
logger.Subscribe(logFileWriter); logger.Subscribe(logFileWriter);
} }

View file

@ -102,13 +102,14 @@ namespace SafeExamBrowser.Runtime.Operations
var clientExecutable = Context.Next.AppConfig.ClientExecutablePath; var clientExecutable = Context.Next.AppConfig.ClientExecutablePath;
var clientLogFile = $"{'"' + Context.Next.AppConfig.ClientLogFile + '"'}"; var clientLogFile = $"{'"' + Context.Next.AppConfig.ClientLogFile + '"'}";
var hostUri = Context.Next.AppConfig.RuntimeAddress; var clientLogLevel = logger.LogLevel.ToString();
var token = Context.Next.StartupToken.ToString("D"); var runtimeHostUri = Context.Next.AppConfig.RuntimeAddress;
var startupToken = Context.Next.StartupToken.ToString("D");
logger.Info("Starting new client process..."); logger.Info("Starting new client process...");
runtimeHost.AllowConnection = true; runtimeHost.AllowConnection = true;
runtimeHost.ClientReady += clientReadyEventHandler; 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..."); logger.Info("Waiting for client to complete initialization...");
clientReady = clientReadyEvent.WaitOne(timeout_ms); clientReady = clientReadyEvent.WaitOne(timeout_ms);

View file

@ -142,6 +142,11 @@ namespace SafeExamBrowser.Runtime.Operations
Context.Next.Settings = settings; Context.Next.Settings = settings;
if (settings != null)
{
logger.LogLevel = settings.LogLevel;
}
return HandleLoadResult(uri, settings, status, passwordParams); return HandleLoadResult(uri, settings, status, passwordParams);
} }