diff options
24 files changed, 774 insertions, 681 deletions
diff --git a/win/CS/HandBrake.ApplicationServices/HandBrake.ApplicationServices.csproj b/win/CS/HandBrake.ApplicationServices/HandBrake.ApplicationServices.csproj index c6fddcfb7..91342b059 100644 --- a/win/CS/HandBrake.ApplicationServices/HandBrake.ApplicationServices.csproj +++ b/win/CS/HandBrake.ApplicationServices/HandBrake.ApplicationServices.csproj @@ -181,7 +181,9 @@ <Compile Include="Interop\Model\VideoQualityLimits.cs" />
<Compile Include="Model\HBConfiguration.cs" />
<Compile Include="Model\VideoScaler.cs" />
- <Compile Include="Services\Logging\LogHelper.cs" />
+ <Compile Include="Services\Logging\EventArgs\LogEventArgs.cs" />
+ <Compile Include="Services\Logging\Interfaces\ILog.cs" />
+ <Compile Include="Services\Logging\LogService.cs" />
<Compile Include="Services\Logging\Model\LogLevel.cs" />
<Compile Include="Services\Logging\Model\LogMessage.cs" />
<Compile Include="Services\Logging\Model\LogMessageType.cs" />
diff --git a/win/CS/HandBrake.ApplicationServices/Interop/HandBrakeInstance.cs b/win/CS/HandBrake.ApplicationServices/Interop/HandBrakeInstance.cs index a862dc1e6..633c4e1fb 100644 --- a/win/CS/HandBrake.ApplicationServices/Interop/HandBrakeInstance.cs +++ b/win/CS/HandBrake.ApplicationServices/Interop/HandBrakeInstance.cs @@ -34,6 +34,7 @@ namespace HandBrake.ApplicationServices.Interop using HandBrake.ApplicationServices.Interop.Model.Encoding;
using HandBrake.ApplicationServices.Interop.Model.Preview;
using HandBrake.ApplicationServices.Services.Logging;
+ using HandBrake.ApplicationServices.Services.Logging.Interfaces;
using HandBrake.ApplicationServices.Services.Logging.Model;
using Newtonsoft.Json;
@@ -55,6 +56,8 @@ namespace HandBrake.ApplicationServices.Interop /// </summary>
private const double EncodePollIntervalMs = 250;
+ private readonly ILog log = LogService.GetLogger();
+
/// <summary>
/// The native handle to the HandBrake instance.
/// </summary>
@@ -502,7 +505,7 @@ namespace HandBrake.ApplicationServices.Interop {
IntPtr json = HBFunctions.hb_get_state_json(this.hbHandle);
string statusJson = Marshal.PtrToStringAnsi(json);
- LogHelper.LogMessage(new LogMessage(statusJson, LogMessageType.progressJson, LogLevel.debug));
+ this.log.LogMessage(statusJson, LogMessageType.Progress, LogLevel.Trace);
JsonState state = JsonConvert.DeserializeObject<JsonState>(statusJson);
if (state != null && state.State == NativeConstants.HB_STATE_SCANNING)
@@ -516,7 +519,7 @@ namespace HandBrake.ApplicationServices.Interop {
var jsonMsg = HBFunctions.hb_get_title_set_json(this.hbHandle);
string scanJson = InteropUtilities.ToStringFromUtf8Ptr(jsonMsg);
- LogHelper.LogMessage(new LogMessage(scanJson, LogMessageType.scanJson, LogLevel.debug));
+ this.log.LogMessage(scanJson, LogMessageType.Progress, LogLevel.Trace);
this.titles = JsonConvert.DeserializeObject<JsonScanObject>(scanJson);
this.featureTitle = this.titles.MainFeature;
@@ -541,7 +544,7 @@ namespace HandBrake.ApplicationServices.Interop IntPtr json = HBFunctions.hb_get_state_json(this.hbHandle);
string statusJson = Marshal.PtrToStringAnsi(json);
- LogHelper.LogMessage(new LogMessage(statusJson, LogMessageType.progressJson, LogLevel.debug));
+ this.log.LogMessage(statusJson, LogMessageType.Progress, LogLevel.Trace);
JsonState state = JsonConvert.DeserializeObject<JsonState>(statusJson);
diff --git a/win/CS/HandBrake.ApplicationServices/Interop/HandBrakePresetService.cs b/win/CS/HandBrake.ApplicationServices/Interop/HandBrakePresetService.cs index fcc6d61da..7e1f95d3e 100644 --- a/win/CS/HandBrake.ApplicationServices/Interop/HandBrakePresetService.cs +++ b/win/CS/HandBrake.ApplicationServices/Interop/HandBrakePresetService.cs @@ -18,6 +18,7 @@ namespace HandBrake.ApplicationServices.Interop using HandBrake.ApplicationServices.Interop.Helpers;
using HandBrake.ApplicationServices.Interop.Json.Presets;
using HandBrake.ApplicationServices.Services.Logging;
+ using HandBrake.ApplicationServices.Services.Logging.Interfaces;
using HandBrake.ApplicationServices.Services.Logging.Model;
using Newtonsoft.Json;
@@ -27,6 +28,8 @@ namespace HandBrake.ApplicationServices.Interop /// </summary>
public class HandBrakePresetService
{
+ private static readonly ILog log = LogService.GetLogger();
+
/// <summary>
/// The get built in presets.
/// Requires an hb_init to have been invoked.
@@ -39,7 +42,7 @@ namespace HandBrake.ApplicationServices.Interop IntPtr presets = HBFunctions.hb_presets_builtin_get_json();
string presetJson = Marshal.PtrToStringAnsi(presets);
- LogHelper.LogMessage(new LogMessage(presetJson, LogMessageType.progressJson, LogLevel.debug));
+ log.LogMessage(presetJson, LogMessageType.API, LogLevel.Debug);
IList<PresetCategory> presetList = JsonConvert.DeserializeObject<IList<PresetCategory>>(presetJson);
@@ -60,7 +63,7 @@ namespace HandBrake.ApplicationServices.Interop IntPtr presetStringPointer = HBFunctions.hb_presets_read_file_json(InteropUtilities.ToUtf8PtrFromString(filename));
string presetJson = Marshal.PtrToStringAnsi(presetStringPointer);
- LogHelper.LogMessage(new LogMessage(presetJson, LogMessageType.libhb, LogLevel.debug));
+ log.LogMessage(presetJson, LogMessageType.API, LogLevel.Debug);
PresetTransportContainer preset = JsonConvert.DeserializeObject<PresetTransportContainer>(presetJson);
diff --git a/win/CS/HandBrake.ApplicationServices/Interop/HandBrakeUtils.cs b/win/CS/HandBrake.ApplicationServices/Interop/HandBrakeUtils.cs index 3540bb368..ef98f3f86 100644 --- a/win/CS/HandBrake.ApplicationServices/Interop/HandBrakeUtils.cs +++ b/win/CS/HandBrake.ApplicationServices/Interop/HandBrakeUtils.cs @@ -11,7 +11,6 @@ namespace HandBrake.ApplicationServices.Interop {
using System;
using System.Collections.Generic;
- using System.Diagnostics;
using System.Runtime.InteropServices;
using HandBrake.ApplicationServices.Interop.EventArgs;
@@ -19,6 +18,7 @@ namespace HandBrake.ApplicationServices.Interop using HandBrake.ApplicationServices.Interop.Json.Anamorphic;
using HandBrake.ApplicationServices.Interop.Json.Shared;
using HandBrake.ApplicationServices.Services.Logging;
+ using HandBrake.ApplicationServices.Services.Logging.Interfaces;
using HandBrake.ApplicationServices.Services.Logging.Model;
using Newtonsoft.Json;
@@ -28,6 +28,8 @@ namespace HandBrake.ApplicationServices.Interop /// </summary>
public static class HandBrakeUtils
{
+ private static readonly ILog log = LogService.GetLogger();
+
/// <summary>
/// The callback for log messages from HandBrake.
/// </summary>
@@ -301,7 +303,7 @@ namespace HandBrake.ApplicationServices.Interop public static Geometry GetAnamorphicSize(AnamorphicGeometry anamorphicGeometry)
{
string encode = JsonConvert.SerializeObject(anamorphicGeometry, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
- LogHelper.LogMessage(new LogMessage(encode, LogMessageType.encodeJson, LogLevel.debug));
+ log.LogMessage(encode, LogMessageType.API, LogLevel.Debug);
IntPtr json = HBFunctions.hb_set_anamorphic_size_json(Marshal.StringToHGlobalAnsi(encode));
string result = Marshal.PtrToStringAnsi(json);
return JsonConvert.DeserializeObject<Geometry>(result);
@@ -317,10 +319,9 @@ namespace HandBrake.ApplicationServices.Interop {
if (MessageLogged != null)
{
+ log.LogMessage(message, LogMessageType.ScanOrEncode, LogLevel.Info);
MessageLogged(null, new MessageLoggedEventArgs(message));
}
-
- Debug.WriteLine(message);
}
/// <summary>
@@ -333,10 +334,9 @@ namespace HandBrake.ApplicationServices.Interop {
if (ErrorLogged != null)
{
+ log.LogMessage(message, LogMessageType.ScanOrEncode, LogLevel.Error);
ErrorLogged(null, new MessageLoggedEventArgs(message));
}
-
- Debug.WriteLine("ERROR: " + message);
}
}
}
diff --git a/win/CS/HandBrake.ApplicationServices/Services/Logging/EventArgs/LogEventArgs.cs b/win/CS/HandBrake.ApplicationServices/Services/Logging/EventArgs/LogEventArgs.cs new file mode 100644 index 000000000..b9691e4a3 --- /dev/null +++ b/win/CS/HandBrake.ApplicationServices/Services/Logging/EventArgs/LogEventArgs.cs @@ -0,0 +1,37 @@ +// -------------------------------------------------------------------------------------------------------------------- +// <copyright file="LogEventArgs.cs" company="HandBrake Project (http://handbrake.fr)"> +// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. +// </copyright> +// <summary> +// Defines the LogEventArgs type. +// </summary> +// -------------------------------------------------------------------------------------------------------------------- + +namespace HandBrake.ApplicationServices.Services.Logging.EventArgs +{ + using System; + + using Model; + + /// <summary> + /// The Message Logged Event Args + /// </summary> + public class LogEventArgs : EventArgs + { + /// <summary> + /// Initializes a new instance of the <see cref="LogEventArgs"/> class. + /// </summary> + /// <param name="message"> + /// The message. + /// </param> + public LogEventArgs(LogMessage message) + { + this.Log = message; + } + + /// <summary> + /// Gets the Message. + /// </summary> + public LogMessage Log { get; private set; } + } +} diff --git a/win/CS/HandBrake.ApplicationServices/Services/Logging/Interfaces/ILog.cs b/win/CS/HandBrake.ApplicationServices/Services/Logging/Interfaces/ILog.cs new file mode 100644 index 000000000..dc0b3c08b --- /dev/null +++ b/win/CS/HandBrake.ApplicationServices/Services/Logging/Interfaces/ILog.cs @@ -0,0 +1,87 @@ +// -------------------------------------------------------------------------------------------------------------------- +// <copyright file="ILog.cs" company="HandBrake Project (http://handbrake.fr)"> +// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. +// </copyright> +// <summary> +// Defines the ILog type. +// </summary> +// -------------------------------------------------------------------------------------------------------------------- + +namespace HandBrake.ApplicationServices.Services.Logging.Interfaces +{ + using System; + using System.Collections.Generic; + + using EventArgs; + + using Model; + + /// <summary> + /// The Log interface. + /// </summary> + public interface ILog + { + /// <summary> + /// The message logged. + /// </summary> + event EventHandler<LogEventArgs> MessageLogged; + + /// <summary> + /// The log reset event + /// </summary> + event EventHandler LogReset; + + /// <summary> + /// Gets the log messages. + /// </summary> + IEnumerable<LogMessage> LogMessages { get; } + + /// <summary> + /// Gets the activity log. + /// </summary> + string ActivityLog { get; } + + /// <summary> + /// The reset. + /// </summary> + void Reset(); + + /// <summary> + /// The enable. + /// </summary> + void Enable(); + + /// <summary> + /// Log a message. + /// </summary> + /// <param name="content"> + /// The content of the log message, + /// </param> + /// <param name="type"> + /// The Message Type. (i.e. where it came from) + /// </param> + /// <param name="level"> + /// The log level + /// </param> + void LogMessage(string content, LogMessageType type, LogLevel level); + + /// <summary> + /// Enable Logging to Disk + /// </summary> + /// <param name="logFile"> + /// The log file to write to. + /// </param> + /// <param name="deleteCurrentLogFirst"> + /// Delete the current log file if it exists. + /// </param> + void EnableLoggingToDisk(string logFile, bool deleteCurrentLogFirst); + + /// <summary> + /// The setup log header. + /// </summary> + /// <param name="header"> + /// The header. + /// </param> + void SetupLogHeader(string header); + } +}
\ No newline at end of file diff --git a/win/CS/HandBrake.ApplicationServices/Services/Logging/LogHelper.cs b/win/CS/HandBrake.ApplicationServices/Services/Logging/LogHelper.cs deleted file mode 100644 index 44ccc757c..000000000 --- a/win/CS/HandBrake.ApplicationServices/Services/Logging/LogHelper.cs +++ /dev/null @@ -1,53 +0,0 @@ -// --------------------------------------------------------------------------------------------------------------------
-// <copyright file="LogHelper.cs" company="HandBrake Project (http://handbrake.fr)">
-// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
-// </copyright>
-// <summary>
-// The log service.
-// For now, this is just a simple logging service but we could provide support for a formal logging library later.
-// Also, we can consider providing the UI layer with more functional logging. (i.e levels, time/date, highlighting etc)
-// The Interop Classes are not very OO friendly, so this is going to be a static class.
-// </summary>
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace HandBrake.ApplicationServices.Services.Logging
-{
- using System.Diagnostics;
-
- using HandBrake.ApplicationServices.Services.Logging.Model;
-
- /// <summary>
- /// The log helper.
- /// </summary>
- public static class LogHelper
- {
- private static LogLevel currentLogLevel = LogLevel.debug; // TODO default to Info when this class is implimented.
-
- /// <summary>
- /// Log message.
- /// </summary>
- /// <param name="message">
- /// The message.
- /// </param>
- public static void LogMessage(LogMessage message)
- {
- if (message.LogLevel <= currentLogLevel)
- {
- //Debug.WriteLine(message.Content);
- }
-
- // TODO cache logging.
- }
-
- /// <summary>
- /// The set log level. Default: Info.
- /// </summary>
- /// <param name="level">
- /// The level.
- /// </param>
- public static void SetLogLevel(LogLevel level)
- {
- currentLogLevel = level;
- }
- }
-}
diff --git a/win/CS/HandBrake.ApplicationServices/Services/Logging/LogService.cs b/win/CS/HandBrake.ApplicationServices/Services/Logging/LogService.cs new file mode 100644 index 000000000..cd0d5a483 --- /dev/null +++ b/win/CS/HandBrake.ApplicationServices/Services/Logging/LogService.cs @@ -0,0 +1,361 @@ +// -------------------------------------------------------------------------------------------------------------------- +// <copyright file="LogService.cs" company="HandBrake Project (http://handbrake.fr)"> +// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. +// </copyright> +// <summary> +// The log service. +// For now, this is just a simple logging service but we could provide support for a formal logging library later. +// Also, we can consider providing the UI layer with more functional logging. (i.e levels, time/date, highlighting etc) +// The Interop Classes are not very OO friendly, so this is going to be a static class. +// </summary> +// -------------------------------------------------------------------------------------------------------------------- + +namespace HandBrake.ApplicationServices.Services.Logging +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.IO; + using System.Text; + + using HandBrake.ApplicationServices.Services.Logging.EventArgs; + using HandBrake.ApplicationServices.Services.Logging.Interfaces; + using HandBrake.ApplicationServices.Services.Logging.Model; + + /// <summary> + /// The log helper. + /// </summary> + public class LogService : ILog + { + // TODO List. + // Maybe make the event weak? + // Make this class Thread Safe. + private static ILog loggerInstance; + private readonly object lockObject = new object(); + private readonly object FileWriterLock = new object(); + private readonly StringBuilder logBuilder = new StringBuilder(); + + private LogLevel currentLogLevel = LogLevel.Error; + private bool isLoggingEnabled; + private List<LogMessage> logMessages = new List<LogMessage>(); + private long messageIndex; + private string diskLogPath; + private bool deleteLogFirst; + private bool isDiskLoggingEnabled; + private StreamWriter fileWriter; + private string logHeader; + + /// <summary> + /// Fires when a new QueueTask starts + /// </summary> + public event EventHandler<LogEventArgs> MessageLogged; + + /// <summary> + /// The log reset event + /// </summary> + public event EventHandler LogReset; + + /// <summary> + /// Gets the log messages. + /// </summary> + public IEnumerable<LogMessage> LogMessages + { + get + { + lock (this.lockObject) + { + return this.logMessages; + } + } + } + + /// <summary> + /// Gets the Activity Log as a string. + /// </summary> + public string ActivityLog + { + get + { + lock (this.lockObject) + { + return this.logBuilder.ToString(); + } + } + } + + /// <summary> + /// Log message. + /// </summary> + /// <param name="content"> + /// The content. + /// </param> + /// <param name="type"> + /// The type. + /// </param> + /// <param name="level"> + /// The level. + /// </param> + public void LogMessage(string content, LogMessageType type, LogLevel level) + { + if (!this.isLoggingEnabled) + { + return; + } + + if (level >= this.currentLogLevel) + { + return; + } + + LogMessage msg = new LogMessage(content, type, level, this.messageIndex); + lock (this.lockObject) + { + this.messageIndex = this.messageIndex + 1; + this.logMessages.Add(msg); + this.logBuilder.AppendLine(msg.Content); + this.LogMessageToDisk(msg); + + if (this.logMessages.Count > 50000) + { + this.messageIndex = this.messageIndex + 1; + msg = new LogMessage( + "Log Service Pausing. Too Many Log messages. This may indicate a problem with your encode.", + LogMessageType.Vital, + LogLevel.Error, + this.messageIndex); + this.logMessages.Add(msg); + this.logBuilder.AppendLine(msg.Content); + this.LogMessageToDisk(msg); + + this.Disable(); + } + } + + this.OnMessageLogged(msg); // Must be outside lock to be thread safe. + } + + /// <summary> + /// Gets an shared instance of the logger. Logging is enabled by default + /// You can turn it off by calling Disable() if you don't want it. + /// </summary> + /// <returns> + /// An instance of this logger. + /// </returns> + public static ILog GetLogger() + { + return loggerInstance ?? (loggerInstance = new LogService()); + } + + /// <summary> + /// The set log level. Default: Info. + /// </summary> + /// <param name="level"> + /// The level. + /// </param> + public void SetLogLevel(LogLevel level) + { + this.currentLogLevel = level; + } + + /// <summary> + /// The enable. + /// </summary> + public void Enable() + { + this.isLoggingEnabled = true; + } + + /// <summary> + /// Enable Logging to Disk + /// </summary> + /// <param name="logFile"> + /// The log file to write to. + /// </param> + /// <param name="deleteCurrentLogFirst"> + /// Delete the current log file if it exists. + /// </param> + public void EnableLoggingToDisk(string logFile, bool deleteCurrentLogFirst) + { + if (this.isDiskLoggingEnabled) + { + throw new Exception("Disk Logging already enabled!"); + } + + try + { + if (!Directory.Exists(Path.GetDirectoryName(logFile))) + { + throw new Exception("Log Directory does not exist. This service will not create it for you!"); + } + + if (deleteCurrentLogFirst && File.Exists(logFile)) + { + File.Delete(logFile); + } + + this.diskLogPath = logFile; + this.isDiskLoggingEnabled = true; + this.deleteLogFirst = deleteCurrentLogFirst; + + lock (this.FileWriterLock) + { + this.fileWriter = new StreamWriter(logFile) { AutoFlush = true }; + } + } + catch (Exception exc) + { + this.LogMessage("Failed to Initialise Disk Logging. " + Environment.NewLine + exc, LogMessageType.Vital, LogLevel.Error); + + if (this.fileWriter != null) + { + lock (this.FileWriterLock) + { + this.fileWriter.Flush(); + this.fileWriter.Close(); + this.fileWriter.Dispose(); + } + } + } + } + + /// <summary> + /// The setup log header. + /// </summary> + /// <param name="header"> + /// The header. + /// </param> + public void SetupLogHeader(string header) + { + this.logHeader = header; + this.LogMessage(header, LogMessageType.Vital, LogLevel.Info); + } + + /// <summary> + /// The disable. + /// </summary> + public void Disable() + { + this.isLoggingEnabled = false; + } + + /// <summary> + /// Clear the log messages collection. + /// </summary> + public void Reset() + { + lock (this.lockObject) + { + this.logMessages.Clear(); + this.logBuilder.Clear(); + this.messageIndex = 0; + + try + { + lock (this.FileWriterLock) + { + if (this.fileWriter != null) + { + this.fileWriter.Flush(); + this.fileWriter.Close(); + this.fileWriter.Dispose(); + } + + this.fileWriter = null; + } + } + catch (Exception exc) + { + Debug.WriteLine(exc); + } + + if (this.fileWriter == null) + { + this.isDiskLoggingEnabled = false; + this.EnableLoggingToDisk(this.diskLogPath, this.deleteLogFirst); + } + + if (!string.IsNullOrEmpty(this.logHeader)) + { + this.SetupLogHeader(this.logHeader); + } + + this.OnLogReset(); + } + } + + /// <summary> + /// Helper method for logging content to disk + /// </summary> + /// <param name="msg"> + /// Log message to write. + /// </param> + private void LogMessageToDisk(LogMessage msg) + { + if (!this.isDiskLoggingEnabled) + { + return; + } + + try + { + lock (this.FileWriterLock) + { + if (this.fileWriter != null && this.fileWriter.BaseStream.CanWrite) + { + this.fileWriter.WriteLine(msg.Content); + } + } + } + catch (Exception exc) + { + Debug.WriteLine(exc); // This exception doesn't warrent user interaction, but it should be logged + } + } + + /// <summary> + /// Called when a log message is created. + /// </summary> + /// <param name="msg"> + /// The Log Message + /// </param> + protected virtual void OnMessageLogged(LogMessage msg) + { + var onMessageLogged = this.MessageLogged; + if (onMessageLogged != null) + { + onMessageLogged.Invoke(this, new LogEventArgs(msg)); + } + } + + /// <summary> + /// Shutdown and Dispose of the File Writer. + /// </summary> + protected void ShutdownFileWriter() + { + try + { + lock (this.FileWriterLock) + { + if (this.fileWriter != null) + { + this.fileWriter.Flush(); + this.fileWriter.Close(); + this.fileWriter.Dispose(); + } + + this.fileWriter = null; + } + } + catch (Exception exc) + { + Debug.WriteLine(exc); // This exception doesn't warrent user interaction, but it should be logged + } + } + + // Trigger the Event to notify any subscribers that the log has been reset. + protected virtual void OnLogReset() + { + this.LogReset?.Invoke(this, System.EventArgs.Empty); + } + } +} diff --git a/win/CS/HandBrake.ApplicationServices/Services/Logging/Model/LogLevel.cs b/win/CS/HandBrake.ApplicationServices/Services/Logging/Model/LogLevel.cs index c2e2b8f0a..a319ae385 100644 --- a/win/CS/HandBrake.ApplicationServices/Services/Logging/Model/LogLevel.cs +++ b/win/CS/HandBrake.ApplicationServices/Services/Logging/Model/LogLevel.cs @@ -17,21 +17,26 @@ namespace HandBrake.ApplicationServices.Services.Logging.Model /// <summary>
/// The info.
/// </summary>
- info,
+ Info,
/// <summary>
/// The warning.
/// </summary>
- warning,
+ Warning,
/// <summary>
/// The error.
/// </summary>
- error,
+ Error,
/// <summary>
/// The debug.
/// </summary>
- debug,
+ Debug,
+
+ /// <summary>
+ /// Trace Level Logging.
+ /// </summary>
+ Trace,
}
}
diff --git a/win/CS/HandBrake.ApplicationServices/Services/Logging/Model/LogMessage.cs b/win/CS/HandBrake.ApplicationServices/Services/Logging/Model/LogMessage.cs index 9179e2fa5..edf071ba1 100644 --- a/win/CS/HandBrake.ApplicationServices/Services/Logging/Model/LogMessage.cs +++ b/win/CS/HandBrake.ApplicationServices/Services/Logging/Model/LogMessage.cs @@ -10,7 +10,7 @@ namespace HandBrake.ApplicationServices.Services.Logging.Model
{
/// <summary>
- /// The json message.
+ /// An Immutable Log Entry.
/// </summary>
public class LogMessage
{
@@ -26,11 +26,15 @@ namespace HandBrake.ApplicationServices.Services.Logging.Model /// <param name="logLevel">
/// The log level.
/// </param>
- public LogMessage(string content, LogMessageType messageType, LogLevel logLevel)
+ /// <param name="messageIndex">
+ /// The message Index.
+ /// </param>
+ public LogMessage(string content, LogMessageType messageType, LogLevel logLevel, long messageIndex)
{
this.Content = content;
this.MessageType = messageType;
this.LogLevel = logLevel;
+ this.MessageIndex = messageIndex;
}
/// <summary>
@@ -48,5 +52,10 @@ namespace HandBrake.ApplicationServices.Services.Logging.Model /// Gets the log level.
/// </summary>
public LogLevel LogLevel { get; private set; }
+
+ /// <summary>
+ /// Gets the message index.
+ /// </summary>
+ public long MessageIndex { get; private set; }
}
}
diff --git a/win/CS/HandBrake.ApplicationServices/Services/Logging/Model/LogMessageType.cs b/win/CS/HandBrake.ApplicationServices/Services/Logging/Model/LogMessageType.cs index df0ce0fc3..47302a872 100644 --- a/win/CS/HandBrake.ApplicationServices/Services/Logging/Model/LogMessageType.cs +++ b/win/CS/HandBrake.ApplicationServices/Services/Logging/Model/LogMessageType.cs @@ -14,10 +14,9 @@ namespace HandBrake.ApplicationServices.Services.Logging.Model /// </summary>
public enum LogMessageType
{
- scanJson,
- encodeJson,
- anamorphicJson,
- progressJson,
- libhb,
+ ScanOrEncode,
+ API,
+ Progress,
+ Vital,
}
}
diff --git a/win/CS/HandBrake.ApplicationServices/Utilities/LanguageUtilities.cs b/win/CS/HandBrake.ApplicationServices/Utilities/LanguageUtilities.cs index 1acc9cccc..12665c062 100644 --- a/win/CS/HandBrake.ApplicationServices/Utilities/LanguageUtilities.cs +++ b/win/CS/HandBrake.ApplicationServices/Utilities/LanguageUtilities.cs @@ -277,6 +277,15 @@ namespace HandBrake.ApplicationServices.Utilities return iso6392Codes;
}
+ /// <summary>
+ /// The get language names.
+ /// </summary>
+ /// <param name="languageCodes">
+ /// The language codes.
+ /// </param>
+ /// <returns>
+ /// The <see cref="List"/>.
+ /// </returns>
public static List<string> GetLanguageNames(IList<string> languageCodes)
{
// Translate to Iso Codes
diff --git a/win/CS/HandBrakeWPF/HandBrakeWPF.csproj b/win/CS/HandBrakeWPF/HandBrakeWPF.csproj index 4b4dd7b81..c2dd50a54 100644 --- a/win/CS/HandBrakeWPF/HandBrakeWPF.csproj +++ b/win/CS/HandBrakeWPF/HandBrakeWPF.csproj @@ -157,6 +157,7 @@ <Compile Include="EventArgs\SettingChangedEventArgs.cs" />
<Compile Include="Exceptions\GeneralApplicationException.cs" />
<Compile Include="Extensions\StringExtensions.cs" />
+ <Compile Include="Helpers\LogManager.cs" />
<Compile Include="Helpers\MP4Helper.cs" />
<Compile Include="Helpers\TimeSpanHelper.cs" />
<Compile Include="Helpers\Validate.cs" />
diff --git a/win/CS/HandBrakeWPF/Helpers/LogManager.cs b/win/CS/HandBrakeWPF/Helpers/LogManager.cs new file mode 100644 index 000000000..4e883f8ee --- /dev/null +++ b/win/CS/HandBrakeWPF/Helpers/LogManager.cs @@ -0,0 +1,49 @@ +// -------------------------------------------------------------------------------------------------------------------- +// <copyright file="LogManager.cs" company="HandBrake Project (http://handbrake.fr)"> +// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. +// </copyright> +// <summary> +// The log manager. +// </summary> +// -------------------------------------------------------------------------------------------------------------------- + +namespace HandBrakeWPF.Helpers +{ + using System; + using System.IO; + + using HandBrake.ApplicationServices.Interop; + using HandBrake.ApplicationServices.Services.Logging; + using HandBrake.ApplicationServices.Services.Logging.Interfaces; + + using HandBrakeWPF.Utilities; + + /// <summary> + /// Tempory Class to Initialise the logging. + /// </summary> + public static class LogManager + { + /// <summary> + /// The init. + /// </summary> + public static void Init() + { + ILog log = LogService.GetLogger(); + string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs"; + string logFile = Path.Combine(logDir, string.Format("activity_log{0}.txt", GeneralUtilities.ProcessId)); + log.Enable(); + log.SetupLogHeader(GeneralUtilities.CreateLogHeader().ToString()); + log.EnableLoggingToDisk(logFile, true); + HandBrakeUtils.MessageLogged += HandBrakeUtils_MessageLogged; + HandBrakeUtils.ErrorLogged += HandBrakeUtils_ErrorLogged; + } + + private static void HandBrakeUtils_ErrorLogged(object sender, HandBrake.ApplicationServices.Interop.EventArgs.MessageLoggedEventArgs e) + { + } + + private static void HandBrakeUtils_MessageLogged(object sender, HandBrake.ApplicationServices.Interop.EventArgs.MessageLoggedEventArgs e) + { + } + } +}
\ No newline at end of file diff --git a/win/CS/HandBrakeWPF/Services/Encode/EncodeBase.cs b/win/CS/HandBrakeWPF/Services/Encode/EncodeBase.cs index 9ae0398ee..801a8c9cc 100644 --- a/win/CS/HandBrakeWPF/Services/Encode/EncodeBase.cs +++ b/win/CS/HandBrakeWPF/Services/Encode/EncodeBase.cs @@ -13,11 +13,10 @@ namespace HandBrakeWPF.Services.Encode using System.Diagnostics; using System.Globalization; using System.IO; - using System.Text; using HandBrake.ApplicationServices.Model; - - using HandBrakeWPF.Utilities; + using HandBrake.ApplicationServices.Services.Logging; + using HandBrake.ApplicationServices.Services.Logging.Interfaces; using EncodeCompletedEventArgs = HandBrakeWPF.Services.Encode.EventArgs.EncodeCompletedEventArgs; using EncodeCompletedStatus = HandBrakeWPF.Services.Encode.Interfaces.EncodeCompletedStatus; @@ -31,38 +30,11 @@ namespace HandBrakeWPF.Services.Encode /// </summary> public class EncodeBase { - #region Private Variables - - /// <summary> - /// A Lock for the filewriter - /// </summary> - private static readonly object FileWriterLock = new object(); - - /// <summary> - /// The Log File Header - /// </summary> - private readonly StringBuilder header; - - /// <summary> - /// The Log Buffer - /// </summary> - private StringBuilder logBuffer; - - /// <summary> - /// The Log file writer - /// </summary> - private StreamWriter fileWriter; - - #endregion - /// <summary> /// Initializes a new instance of the <see cref="EncodeBase"/> class. /// </summary> public EncodeBase() - { - this.logBuffer = new StringBuilder(); - this.header = GeneralUtilities.CreateLogHeader(); - this.LogIndex = 0; + { } #region Events @@ -91,39 +63,6 @@ namespace HandBrakeWPF.Services.Encode /// </summary> public bool IsEncoding { get; protected set; } - /// <summary> - /// Gets ActivityLog. - /// </summary> - public string ActivityLog - { - get - { - string noLog = "There is no log information to display." + Environment.NewLine + Environment.NewLine - + "This window will only display logging information after you have started an encode." + Environment.NewLine - + Environment.NewLine + "You can find previous log files in the log directory or by clicking the 'Open Log Directory' button above."; - - return string.IsNullOrEmpty(this.logBuffer.ToString()) - ? noLog - : this.header + this.logBuffer.ToString(); - } - } - - /// <summary> - /// Gets the log index. - /// </summary> - public int LogIndex { get; private set; } - - /// <summary> - /// Gets LogBuffer. - /// </summary> - public StringBuilder LogBuffer - { - get - { - return this.logBuffer; - } - } - #endregion #region Invoke Events @@ -156,8 +95,6 @@ namespace HandBrakeWPF.Services.Encode { handler(this, e); } - - this.LogIndex = 0; // Reset } /// <summary> @@ -186,6 +123,9 @@ namespace HandBrakeWPF.Services.Encode /// <param name="destination"> /// The Destination File Path /// </param> + /// <param name="isPreview"> + /// The is Preview. + /// </param> /// <param name="configuration"> /// The configuration. /// </param> @@ -193,15 +133,12 @@ namespace HandBrakeWPF.Services.Encode { try { - string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + - "\\HandBrake\\logs"; - - string tempLogFile = Path.Combine(logDir, isPreview ? $"preview_encode_log{GeneralUtilities.ProcessId}.txt" : string.Format("last_encode_log{0}.txt", GeneralUtilities.ProcessId)); - + string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs"; string encodeDestinationPath = Path.GetDirectoryName(destination); string destinationFile = Path.GetFileName(destination); - string encodeLogFile = destinationFile + " " + - DateTime.Now.ToString(CultureInfo.InvariantCulture).Replace("/", "-").Replace(":", "-") + ".txt"; + string encodeLogFile = destinationFile + " " + DateTime.Now.ToString(CultureInfo.InvariantCulture).Replace("/", "-").Replace(":", "-") + ".txt"; + ILog log = LogService.GetLogger(); + string logContent = log.ActivityLog; // Make sure the log directory exists. if (!Directory.Exists(logDir)) @@ -210,19 +147,18 @@ namespace HandBrakeWPF.Services.Encode } // Copy the Log to HandBrakes log folder in the users applciation data folder. - File.Copy(tempLogFile, Path.Combine(logDir, encodeLogFile)); + this.WriteFile(logContent, Path.Combine(logDir, encodeLogFile)); // Save a copy of the log file in the same location as the enocde. if (configuration.SaveLogWithVideo) { - File.Copy(tempLogFile, Path.Combine(encodeDestinationPath, encodeLogFile)); + this.WriteFile(logContent, Path.Combine(encodeDestinationPath, encodeLogFile)); } // Save a copy of the log file to a user specified location if (Directory.Exists(configuration.SaveLogCopyDirectory) && configuration.SaveLogToCopyDirectory) { - File.Copy( - tempLogFile, Path.Combine(configuration.SaveLogCopyDirectory, encodeLogFile)); + this.WriteFile(logContent, Path.Combine(configuration.SaveLogCopyDirectory, encodeLogFile)); } } catch (Exception exc) @@ -232,116 +168,26 @@ namespace HandBrakeWPF.Services.Encode } /// <summary> - /// Setup the logging. + /// The write file. /// </summary> - protected void SetupLogging(bool isPreviewEncode) - { - this.ShutdownFileWriter(); - string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs"; - string logFile = Path.Combine(logDir, isPreviewEncode ? $"preview_last_encode_log{GeneralUtilities.ProcessId}.txt" : $"last_encode_log{GeneralUtilities.ProcessId}.txt"); - - try - { - this.logBuffer = new StringBuilder(); - - this.logBuffer.AppendLine(); - - // Clear the current Encode Logs) - if (File.Exists(logFile)) - { - File.Delete(logFile); - } - - lock (FileWriterLock) - { - this.fileWriter = new StreamWriter(logFile) { AutoFlush = true }; - this.fileWriter.WriteLine(this.header); - this.fileWriter.WriteLine(); - } - } - catch (Exception) - { - if (this.fileWriter != null) - { - lock (FileWriterLock) - { - this.fileWriter.Flush(); - this.fileWriter.Close(); - this.fileWriter.Dispose(); - } - } - - throw; - } - } - - /// <summary> - /// The service log message. - /// </summary> - /// <param name="message"> - /// The message. + /// <param name="fileName"> + /// The file name. /// </param> - protected void ServiceLogMessage(string message) - { - this.ProcessLogMessage(string.Format("# {0}", message)); - } - - /// <summary> - /// Process an Incomming Log Message. - /// </summary> - /// <param name="message"> - /// The message. + /// <param name="content"> + /// The content. /// </param> - protected void ProcessLogMessage(string message) - { - if (!string.IsNullOrEmpty(message)) - { - try - { - this.LogIndex = this.LogIndex + 1; - - lock (this.LogBuffer) - { - this.LogBuffer.AppendLine(message); - } - - lock (FileWriterLock) - { - if (this.fileWriter != null && this.fileWriter.BaseStream.CanWrite) - { - this.fileWriter.WriteLine(message); - } - } - } - catch (Exception exc) - { - Debug.WriteLine(exc); // This exception doesn't warrent user interaction, but it should be logged - } - } - } - - /// <summary> - /// Shutdown and Dispose of the File Writer. - /// </summary> - protected void ShutdownFileWriter() + private void WriteFile(string fileName, string content) { try { - lock (FileWriterLock) + using (StreamWriter fileWriter = new StreamWriter(fileName) { AutoFlush = true }) { - if (this.fileWriter != null) - { - this.fileWriter.Flush(); - this.fileWriter.Close(); - this.fileWriter.Dispose(); - } - - this.fileWriter = null; + fileWriter.WriteLineAsync(content); } } catch (Exception exc) { - Debug.WriteLine(exc); // This exception doesn't warrent user interaction, but it should be logged + Debug.WriteLine(exc); } } diff --git a/win/CS/HandBrakeWPF/Services/Encode/Interfaces/IEncode.cs b/win/CS/HandBrakeWPF/Services/Encode/Interfaces/IEncode.cs index 691df1500..b9a5f0aff 100644 --- a/win/CS/HandBrakeWPF/Services/Encode/Interfaces/IEncode.cs +++ b/win/CS/HandBrakeWPF/Services/Encode/Interfaces/IEncode.cs @@ -65,16 +65,6 @@ namespace HandBrakeWPF.Services.Encode.Interfaces bool IsEncoding { get; } /// <summary> - /// Gets ActivityLog. - /// </summary> - string ActivityLog { get; } - - /// <summary> - /// Gets the log index. The current log row counter. - /// </summary> - int LogIndex { get; } - - /// <summary> /// Gets a value indicating whether is pasued. /// </summary> bool IsPasued { get; } diff --git a/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs b/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs index 4bf64e5e1..e8b920c57 100644 --- a/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs +++ b/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs @@ -16,6 +16,9 @@ namespace HandBrakeWPF.Services.Encode using HandBrake.ApplicationServices.Interop.EventArgs; using HandBrake.ApplicationServices.Interop.Interfaces; using HandBrake.ApplicationServices.Model; + using HandBrake.ApplicationServices.Services.Logging; + using HandBrake.ApplicationServices.Services.Logging.Interfaces; + using HandBrake.ApplicationServices.Services.Logging.Model; using HandBrakeWPF.Exceptions; using HandBrakeWPF.Services.Encode.Factories; @@ -30,7 +33,7 @@ namespace HandBrakeWPF.Services.Encode { #region Private Variables - private static readonly object LogLock = new object(); + private ILog log = LogService.GetLogger(); private IHandBrakeInstance instance; private DateTime startTime; private EncodeTask currentTask; @@ -70,8 +73,6 @@ namespace HandBrakeWPF.Services.Encode // Create a new HandBrake instance // Setup the HandBrake Instance - HandBrakeUtils.MessageLogged += this.HandBrakeInstanceMessageLogged; - HandBrakeUtils.ErrorLogged += this.HandBrakeInstanceErrorLogged; this.instance = task.IsPreviewEncode ? HandBrakeInstanceManager.GetPreviewInstance(configuration.Verbosity) : HandBrakeInstanceManager.GetEncodeInstance(configuration.Verbosity); this.instance.EncodeCompleted += this.InstanceEncodeCompleted; @@ -79,11 +80,11 @@ namespace HandBrakeWPF.Services.Encode this.IsEncoding = true; this.isPreviewInstance = task.IsPreviewEncode; - this.SetupLogging(task.IsPreviewEncode); // Verify the Destination Path Exists, and if not, create it. this.VerifyEncodeDestinationPath(task); + this.log.Reset(); // Reset so we have a clean log for the start of the encode. this.ServiceLogMessage("Starting Encode ..."); // Get an EncodeJob object for the Interop Library @@ -97,7 +98,7 @@ namespace HandBrakeWPF.Services.Encode this.IsEncoding = false; this.ServiceLogMessage("Failed to start encoding ..." + Environment.NewLine + exc); - this.InvokeEncodeCompleted(new HandBrakeWPF.Services.Encode.EventArgs.EncodeCompletedEventArgs(false, exc, "Unable to start encoding", task.Source)); + this.InvokeEncodeCompleted(new EventArgs.EncodeCompletedEventArgs(false, exc, "Unable to start encoding", task.Source)); } } @@ -150,40 +151,6 @@ namespace HandBrakeWPF.Services.Encode #region HandBrakeInstance Event Handlers. /// <summary> - /// Log a message - /// </summary> - /// <param name="sender"> - /// The sender. - /// </param> - /// <param name="e"> - /// The MessageLoggedEventArgs. - /// </param> - private void HandBrakeInstanceErrorLogged(object sender, MessageLoggedEventArgs e) - { - lock (LogLock) - { - this.ProcessLogMessage(e.Message); - } - } - - /// <summary> - /// Log a message - /// </summary> - /// <param name="sender"> - /// The sender. - /// </param> - /// <param name="e"> - /// The MessageLoggedEventArgs. - /// </param> - private void HandBrakeInstanceMessageLogged(object sender, MessageLoggedEventArgs e) - { - lock (LogLock) - { - this.ProcessLogMessage(e.Message); - } - } - - /// <summary> /// Encode Progress Event Handler /// </summary> /// <param name="sender"> @@ -194,7 +161,7 @@ namespace HandBrakeWPF.Services.Encode /// </param> private void InstanceEncodeProgress(object sender, EncodeProgressEventArgs e) { - HandBrakeWPF.Services.Encode.EventArgs.EncodeProgressEventArgs args = new HandBrakeWPF.Services.Encode.EventArgs.EncodeProgressEventArgs + EventArgs.EncodeProgressEventArgs args = new EventArgs.EncodeProgressEventArgs { AverageFrameRate = e.AverageFrameRate, CurrentFrameRate = e.CurrentFrameRate, @@ -221,22 +188,24 @@ namespace HandBrakeWPF.Services.Encode { this.IsEncoding = false; this.ServiceLogMessage("Encode Completed ..."); - - // Stop Logging. - HandBrakeUtils.MessageLogged -= this.HandBrakeInstanceMessageLogged; - HandBrakeUtils.ErrorLogged -= this.HandBrakeInstanceErrorLogged; - + // Handling Log Data this.ProcessLogs(this.currentTask.Destination, this.isPreviewInstance, this.currentConfiguration); - // Cleanup - this.ShutdownFileWriter(); - // Raise the Encode Completed EVent. this.InvokeEncodeCompleted( e.Error - ? new HandBrakeWPF.Services.Encode.EventArgs.EncodeCompletedEventArgs(false, null, string.Empty, this.currentTask.Destination) - : new HandBrakeWPF.Services.Encode.EventArgs.EncodeCompletedEventArgs(true, null, string.Empty, this.currentTask.Destination)); + ? new EventArgs.EncodeCompletedEventArgs(false, null, string.Empty, this.currentTask.Destination) + : new EventArgs.EncodeCompletedEventArgs(true, null, string.Empty, this.currentTask.Destination)); + } + + /// <summary> + /// Service Log Message. + /// </summary> + /// <param name="message">Log message content</param> + protected void ServiceLogMessage(string message) + { + this.log.LogMessage(string.Format("# {0}", message), LogMessageType.ScanOrEncode, LogLevel.Info); } #endregion } diff --git a/win/CS/HandBrakeWPF/Services/Scan/Interfaces/IScan.cs b/win/CS/HandBrakeWPF/Services/Scan/Interfaces/IScan.cs index 0af5f30ec..4336574aa 100644 --- a/win/CS/HandBrakeWPF/Services/Scan/Interfaces/IScan.cs +++ b/win/CS/HandBrakeWPF/Services/Scan/Interfaces/IScan.cs @@ -66,11 +66,6 @@ namespace HandBrakeWPF.Services.Scan.Interfaces bool IsScanning { get; } /// <summary> - /// Gets ActivityLog. - /// </summary> - string ActivityLog { get; } - - /// <summary> /// Scan a Source Path. /// Title 0: scan all /// </summary> diff --git a/win/CS/HandBrakeWPF/Services/Scan/LibScan.cs b/win/CS/HandBrakeWPF/Services/Scan/LibScan.cs index 3d9d475a1..d72593cff 100644 --- a/win/CS/HandBrakeWPF/Services/Scan/LibScan.cs +++ b/win/CS/HandBrakeWPF/Services/Scan/LibScan.cs @@ -12,19 +12,18 @@ namespace HandBrakeWPF.Services.Scan using System; using System.Collections.Generic; using System.Diagnostics; - using System.IO; - using System.Text; using System.Windows.Media.Imaging; using HandBrake.ApplicationServices.Interop; - using HandBrake.ApplicationServices.Interop.EventArgs; using HandBrake.ApplicationServices.Interop.HbLib; using HandBrake.ApplicationServices.Interop.Interfaces; using HandBrake.ApplicationServices.Interop.Json.Scan; using HandBrake.ApplicationServices.Interop.Model; using HandBrake.ApplicationServices.Interop.Model.Preview; using HandBrake.ApplicationServices.Model; - using HandBrake.ApplicationServices.Utilities; + using HandBrake.ApplicationServices.Services.Logging; + using HandBrake.ApplicationServices.Services.Logging.Interfaces; + using HandBrake.ApplicationServices.Services.Logging.Model; using HandBrakeWPF.Properties; using HandBrakeWPF.Services.Encode.Model; @@ -32,7 +31,6 @@ namespace HandBrakeWPF.Services.Scan using HandBrakeWPF.Services.Scan.EventArgs; using HandBrakeWPF.Services.Scan.Interfaces; using HandBrakeWPF.Services.Scan.Model; - using HandBrakeWPF.Utilities; using Chapter = HandBrakeWPF.Services.Scan.Model.Chapter; using ScanProgressEventArgs = HandBrake.ApplicationServices.Interop.EventArgs.ScanProgressEventArgs; @@ -46,54 +44,10 @@ namespace HandBrakeWPF.Services.Scan { #region Private Variables - /// <summary> - /// Lock for the log file - /// </summary> - static readonly object LogLock = new object(); - - /// <summary> - /// Log data from HandBrakeInstance - /// </summary> - private readonly StringBuilder logging; - - /// <summary> - /// The Log File Header - /// </summary> - private readonly StringBuilder header; - - /// <summary> - /// The Current source scan path. - /// </summary> + private readonly ILog log = LogService.GetLogger(); private string currentSourceScanPath; - - /// <summary> - /// The log dir. - /// </summary> - private static string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs"; - - /// <summary> - /// The dvd info path. - /// </summary> - private string dvdInfoPath = Path.Combine(logDir, string.Format("last_scan_log{0}.txt", GeneralUtilities.ProcessId)); - - /// <summary> - /// The scan log. - /// </summary> - private StreamWriter scanLog; - - /// <summary> - /// LibHB Instance - /// </summary> private IHandBrakeInstance instance; - - /// <summary> - /// The post scan operation. - /// </summary> private Action<bool, Source> postScanOperation; - - /// <summary> - /// Global to handle cancelled scans. - /// </summary> private bool isCancelled = false; #endregion @@ -103,8 +57,6 @@ namespace HandBrakeWPF.Services.Scan /// </summary> public LibScan() { - this.logging = new StringBuilder(); - this.header = GeneralUtilities.CreateLogHeader(); this.IsScanning = false; } @@ -134,21 +86,6 @@ namespace HandBrakeWPF.Services.Scan /// </summary> public bool IsScanning { get; private set; } - /// <summary> - /// Gets ActivityLog. - /// </summary> - public string ActivityLog - { - get - { - string noLog = "There is no log information to display." + Environment.NewLine + Environment.NewLine - + "This window will only display logging information after you have scanned a source." + Environment.NewLine - + Environment.NewLine + "You can find previous log files in the log directory or by clicking the 'Open Log Directory' button above."; - - return string.IsNullOrEmpty(this.logging.ToString()) ? noLog : this.header + this.logging.ToString(); - } - } - #endregion #region Public Methods @@ -176,12 +113,6 @@ namespace HandBrakeWPF.Services.Scan { try { - lock (LogLock) - { - this.scanLog.Close(); - this.scanLog.Dispose(); - this.scanLog = null; - } this.instance.Dispose(); } catch (Exception) @@ -193,33 +124,7 @@ namespace HandBrakeWPF.Services.Scan // Handle the post scan operation. this.postScanOperation = postAction; - // Clear down the logging - this.logging.Clear(); - - try - { - // Make we don't pick up a stale last_scan_log_xyz.txt (and that we have rights to the file) - if (File.Exists(this.dvdInfoPath)) - { - File.Delete(this.dvdInfoPath); - } - } - catch (Exception exc) - { - Debug.WriteLine(exc); - } - - if (!Directory.Exists(Path.GetDirectoryName(this.dvdInfoPath))) - { - Directory.CreateDirectory(Path.GetDirectoryName(this.dvdInfoPath)); - } - - // Create a new scan log. - this.scanLog = new StreamWriter(this.dvdInfoPath); - // Create a new HandBrake Instance. - HandBrakeUtils.MessageLogged += this.HandBrakeInstanceMessageLogged; - HandBrakeUtils.ErrorLogged += this.HandBrakeInstanceErrorLogged; this.instance = HandBrakeInstanceManager.GetScanInstance(configuraiton.Verbosity); this.instance.ScanProgress += this.InstanceScanProgress; this.instance.ScanCompleted += this.InstanceScanCompleted; @@ -238,16 +143,6 @@ namespace HandBrakeWPF.Services.Scan this.ServiceLogMessage("Stopping Scan."); this.IsScanning = false; this.instance.StopScan(); - - lock (LogLock) - { - if (this.scanLog != null) - { - this.scanLog.Close(); - this.scanLog.Dispose(); - this.scanLog = null; - } - } } catch (Exception exc) { @@ -339,8 +234,6 @@ namespace HandBrakeWPF.Services.Scan { try { - this.logging.Clear(); - string source = sourcePath.ToString().EndsWith("\\") ? string.Format("\"{0}\\\\\"", sourcePath.ToString().TrimEnd('\\')) : "\"" + sourcePath + "\""; this.currentSourceScanPath = source; @@ -362,8 +255,7 @@ namespace HandBrakeWPF.Services.Scan this.ServiceLogMessage("Scan Failed ..." + Environment.NewLine + exc); this.Stop(); - if (this.ScanCompleted != null) - this.ScanCompleted(this, new ScanCompletedEventArgs(false, exc, "An Error has occured in ScanService.ScanSource()", null)); + this.ScanCompleted?.Invoke(this, new ScanCompletedEventArgs(false, exc, "An Error has occured in ScanService.ScanSource()", null)); } } @@ -385,22 +277,6 @@ namespace HandBrakeWPF.Services.Scan bool cancelled = this.isCancelled; this.isCancelled = false; - // Write the log file out before we start processing incase we crash. - try - { - if (this.scanLog != null) - { - this.scanLog.Flush(); - } - } - catch (Exception exc) - { - Debug.WriteLine(exc); - } - - HandBrakeUtils.MessageLogged -= this.HandBrakeInstanceMessageLogged; - HandBrakeUtils.ErrorLogged -= this.HandBrakeInstanceErrorLogged; - // TODO -> Might be a better place to fix this. string path = this.currentSourceScanPath; if (this.currentSourceScanPath.Contains("\"")) @@ -449,8 +325,8 @@ namespace HandBrakeWPF.Services.Scan { if (this.ScanStatusChanged != null) { - HandBrakeWPF.Services.Scan.EventArgs.ScanProgressEventArgs eventArgs = - new HandBrakeWPF.Services.Scan.EventArgs.ScanProgressEventArgs + EventArgs.ScanProgressEventArgs eventArgs = + new EventArgs.ScanProgressEventArgs { CurrentTitle = e.CurrentTitle, Titles = e.Titles, @@ -462,34 +338,6 @@ namespace HandBrakeWPF.Services.Scan } /// <summary> - /// Log a message - /// </summary> - /// <param name="sender"> - /// The sender. - /// </param> - /// <param name="e"> - /// The MessageLoggedEventArgs. - /// </param> - private void HandBrakeInstanceErrorLogged(object sender, MessageLoggedEventArgs e) - { - this.LogMessage(e.Message); - } - - /// <summary> - /// Log a message - /// </summary> - /// <param name="sender"> - /// The sender. - /// </param> - /// <param name="e"> - /// The MessageLoggedEventArgs. - /// </param> - private void HandBrakeInstanceMessageLogged(object sender, MessageLoggedEventArgs e) - { - this.LogMessage(e.Message); - } - - /// <summary> /// Convert Interop Title objects to App Services Title object /// </summary> /// <param name="titles"> @@ -587,25 +435,6 @@ namespace HandBrakeWPF.Services.Scan } /// <summary> - /// The log message. - /// </summary> - /// <param name="message"> - /// The message. - /// </param> - private void LogMessage(string message) - { - lock (LogLock) - { - if (this.scanLog != null) - { - this.scanLog.WriteLine(message); - } - - this.logging.AppendLine(message); - } - } - - /// <summary> /// The service log message. /// </summary> /// <param name="message"> @@ -613,7 +442,7 @@ namespace HandBrakeWPF.Services.Scan /// </param> protected void ServiceLogMessage(string message) { - this.LogMessage(string.Format("# {0}", message)); + this.log.LogMessage(string.Format("{0} # {1}{0}", Environment.NewLine, message), LogMessageType.ScanOrEncode, LogLevel.Info); } #endregion } diff --git a/win/CS/HandBrakeWPF/ViewModels/Interfaces/ILogViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/Interfaces/ILogViewModel.cs index 6c7a7a2c8..6aa1020d4 100644 --- a/win/CS/HandBrakeWPF/ViewModels/Interfaces/ILogViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/Interfaces/ILogViewModel.cs @@ -14,9 +14,5 @@ namespace HandBrakeWPF.ViewModels.Interfaces /// </summary>
public interface ILogViewModel
{
- /// <summary>
- /// Gets or sets the selected tab.
- /// </summary>
- int SelectedTab { get; set; }
}
}
\ No newline at end of file diff --git a/win/CS/HandBrakeWPF/ViewModels/LogViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/LogViewModel.cs index f9a26c1ed..572d8a440 100644 --- a/win/CS/HandBrakeWPF/ViewModels/LogViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/LogViewModel.cs @@ -11,15 +11,18 @@ namespace HandBrakeWPF.ViewModels {
using System;
using System.Diagnostics;
+ using System.Text;
using System.Windows;
- using HandBrakeWPF.Services.Scan.EventArgs;
- using HandBrakeWPF.Services.Scan.Interfaces;
+ using Caliburn.Micro;
+
+ using HandBrake.ApplicationServices.Services.Logging;
+ using HandBrake.ApplicationServices.Services.Logging.EventArgs;
+ using HandBrake.ApplicationServices.Services.Logging.Model;
+
using HandBrakeWPF.ViewModels.Interfaces;
- using EncodeCompletedEventArgs = HandBrakeWPF.Services.Encode.EventArgs.EncodeCompletedEventArgs;
- using EncodeProgressEventArgs = HandBrakeWPF.Services.Encode.EventArgs.EncodeProgressEventArgs;
- using IEncode = HandBrakeWPF.Services.Encode.Interfaces.IEncode;
+ using ILog = HandBrake.ApplicationServices.Services.Logging.Interfaces.ILog;
/// <summary>
/// The Log View Model
@@ -28,83 +31,37 @@ namespace HandBrakeWPF.ViewModels {
#region Private Fields
- /// <summary>
- /// Backing field for the encodeService service
- /// </summary>
- private readonly IEncode encodeService;
-
- /// <summary>
- /// Backing field for the Scan Service
- /// </summary>
- private readonly IScan scanService;
-
- /// <summary>
- /// The selected tab.
- /// </summary>
- private int selectedTab;
-
- /// <summary>
- /// The encode log index.
- /// </summary>
- private int encodeLogIndex;
+ private readonly ILog logService;
+ private StringBuilder log = new StringBuilder();
+ private long lastReadIndex;
#endregion
/// <summary>
/// Initializes a new instance of the <see cref="LogViewModel"/> class.
/// </summary>
- /// <param name="encodeService">
- /// The encode service.
- /// </param>
- /// <param name="scanService">
- /// The scan service.
- /// </param>
- public LogViewModel(IEncode encodeService, IScan scanService)
+ public LogViewModel()
{
- this.encodeService = encodeService;
- this.scanService = scanService;
+ this.logService = LogService.GetLogger();
this.Title = "Log Viewer";
- this.encodeLogIndex = 0;
- }
-
- /// <summary>
- /// Gets or sets the selected tab.
- /// </summary>
- public int SelectedTab
- {
- get
- {
- return this.selectedTab;
- }
- set
- {
- this.selectedTab = value;
- this.NotifyOfPropertyChange(() => this.SelectedTab);
- }
}
/// <summary>
/// Gets Log.
/// </summary>
- public string ScanLog
+ public string ActivityLog
{
get
{
- return this.scanService.ActivityLog;
+ return this.log.ToString();
}
}
/// <summary>
- /// Gets the encodelog.
+ /// The log message received.
/// </summary>
- public string EncodeLog
- {
- get
- {
- return this.encodeService.ActivityLog;
- }
- }
-
+ public event EventHandler<LogEventArgs> LogMessageReceived;
+
/// <summary>
/// Open the Log file directory
/// </summary>
@@ -121,7 +78,7 @@ namespace HandBrakeWPF.ViewModels /// </summary>
public void CopyLog()
{
- Clipboard.SetDataObject(this.SelectedTab == 1 ? this.ScanLog : this.EncodeLog, true);
+ Clipboard.SetDataObject(this.ActivityLog, true);
}
/// <summary>
@@ -129,49 +86,26 @@ namespace HandBrakeWPF.ViewModels /// </summary>
protected override void OnActivate()
{
- this.scanService.ScanCompleted += ScanServiceScanCompleted;
- this.encodeService.EncodeCompleted += EncodeServiceEncodeCompleted;
- this.encodeService.EncodeStatusChanged += this.EncodeServiceEncodeStatusChanged;
- this.scanService.ScanStatusChanged += this.ScanServiceScanStatusChanged;
- this.scanService.ScanStarted += this.scanService_ScanStared;
- this.encodeService.EncodeStarted += this.encodeService_EncodeStarted;
- base.OnActivate();
-
- this.NotifyOfPropertyChange(() => this.ScanLog);
- this.NotifyOfPropertyChange(() => this.EncodeLog);
- }
-
- /// <summary>
- /// Scan Status has changed, update log window.
- /// </summary>
- /// <param name="sender">
- /// The sender.
- /// </param>
- /// <param name="e">
- /// The e.
- /// </param>
- private void ScanServiceScanStatusChanged(object sender, ScanProgressEventArgs e)
- {
- this.NotifyOfPropertyChange(() => this.ScanLog);
- }
+ this.logService.MessageLogged += this.LogService_MessageLogged;
+ this.logService.LogReset += LogService_LogReset;
- /// <summary>
- /// Encode Status has changed, update log window
- /// </summary>
- /// <param name="sender">
- /// The sender.
- /// </param>
- /// <param name="e">
- /// The e.
- /// </param>
- private void EncodeServiceEncodeStatusChanged(object sender, EncodeProgressEventArgs e)
- {
- if (encodeLogIndex != this.encodeService.LogIndex || this.encodeService.LogIndex == -1)
+ // Refresh the Log Display
+ this.log.Clear();
+ foreach (LogMessage logMessage in this.logService.LogMessages)
{
- this.NotifyOfPropertyChange(() => this.EncodeLog);
+ this.log.AppendLine(logMessage.Content);
+ this.lastReadIndex = logMessage.MessageIndex;
+
+ if (this.lastReadIndex > logMessage.MessageIndex)
+ {
+ throw new Exception("Log Message Index Error");
+ }
}
- encodeLogIndex = this.encodeService.LogIndex;
+ this.OnLogMessageReceived(null);
+ this.NotifyOfPropertyChange("ActivityLog");
+
+ base.OnActivate();
}
/// <summary>
@@ -182,18 +116,14 @@ namespace HandBrakeWPF.ViewModels /// </param>
protected override void OnDeactivate(bool close)
{
- this.scanService.ScanCompleted -= ScanServiceScanCompleted;
- this.encodeService.EncodeCompleted -= EncodeServiceEncodeCompleted;
- this.encodeService.EncodeStatusChanged -= this.EncodeServiceEncodeStatusChanged;
- this.scanService.ScanStatusChanged -= this.ScanServiceScanStatusChanged;
- this.scanService.ScanStarted -= this.scanService_ScanStared;
- this.encodeService.EncodeStarted -= this.encodeService_EncodeStarted;
+ this.logService.MessageLogged -= this.LogService_MessageLogged;
+ this.logService.LogReset -= this.LogService_LogReset;
base.OnDeactivate(close);
}
/// <summary>
- /// Scan Completed Event Handler.
+ /// The log service_ log reset.
/// </summary>
/// <param name="sender">
/// The sender.
@@ -201,27 +131,28 @@ namespace HandBrakeWPF.ViewModels /// <param name="e">
/// The e.
/// </param>
- private void ScanServiceScanCompleted(object sender, ScanCompletedEventArgs e)
+ private void LogService_LogReset(object sender, EventArgs e)
{
- this.NotifyOfPropertyChange(() => this.ScanLog);
- }
+ this.log.Clear();
+ this.lastReadIndex = 0;
- /// <summary>
- /// Encode Completed Event Handler.
- /// </summary>
- /// <param name="sender">
- /// The sender.
- /// </param>
- /// <param name="e">
- /// The e.
- /// </param>
- private void EncodeServiceEncodeCompleted(object sender, EncodeCompletedEventArgs e)
- {
- this.NotifyOfPropertyChange(() => this.EncodeLog);
+ foreach (LogMessage logMessage in this.logService.LogMessages)
+ {
+ this.log.AppendLine(logMessage.Content);
+ this.lastReadIndex = logMessage.MessageIndex;
+
+ if (this.lastReadIndex > logMessage.MessageIndex)
+ {
+ throw new Exception("Log Message Index Error");
+ }
+ }
+
+ this.NotifyOfPropertyChange("ActivityLog");
+ this.OnLogMessageReceived(null);
}
/// <summary>
- /// The encode service encode started.
+ /// The log service_ message logged.
/// </summary>
/// <param name="sender">
/// The sender.
@@ -229,24 +160,34 @@ namespace HandBrakeWPF.ViewModels /// <param name="e">
/// The e.
/// </param>
- private void encodeService_EncodeStarted(object sender, EventArgs e)
+ private void LogService_MessageLogged(object sender, LogEventArgs e)
{
- this.encodeLogIndex = -1; // Reset the log index.
- this.SelectedTab = 0;
+ if (this.lastReadIndex < e.Log.MessageIndex)
+ {
+ Execute.OnUIThreadAsync(
+ () =>
+ {
+ this.lastReadIndex = e.Log.MessageIndex;
+ this.log.AppendLine(e.Log.Content);
+ this.OnLogMessageReceived(e);
+ this.NotifyOfPropertyChange("ActivityLog");
+ });
+ }
}
/// <summary>
- /// The scan service scan stared.
+ /// Trigger a faster / smoother way of updating the log window.
/// </summary>
- /// <param name="sender">
- /// The sender.
- /// </param>
/// <param name="e">
/// The e.
/// </param>
- private void scanService_ScanStared(object sender, EventArgs e)
+ protected virtual void OnLogMessageReceived(LogEventArgs e)
{
- this.SelectedTab = 1;
+ var onLogMessageReceived = this.LogMessageReceived;
+ if (onLogMessageReceived != null)
+ {
+ onLogMessageReceived.Invoke(this, e);
+ }
}
}
}
\ No newline at end of file diff --git a/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs index 0886768e7..3f9bc7201 100644 --- a/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs @@ -23,6 +23,8 @@ namespace HandBrakeWPF.ViewModels using Caliburn.Micro;
using HandBrake.ApplicationServices.Interop;
+ using HandBrake.ApplicationServices.Interop.HbLib;
+ using HandBrake.ApplicationServices.Services.Logging;
using HandBrake.ApplicationServices.Utilities;
using HandBrakeWPF.Commands;
@@ -56,6 +58,8 @@ namespace HandBrakeWPF.ViewModels using Action = System.Action;
using Execute = Caliburn.Micro.Execute;
+ using ILog = HandBrake.ApplicationServices.Services.Logging.Interfaces.ILog;
+ using LogManager = HandBrakeWPF.Helpers.LogManager;
/// <summary>
/// HandBrakes Main Window
@@ -226,6 +230,7 @@ namespace HandBrakeWPF.ViewModels // Setup Commands
this.QueueCommand = new QueueCommands(this.QueueViewModel);
+ LogManager.Init();
HandBrakeInstanceManager.Init();
}
@@ -1277,14 +1282,11 @@ namespace HandBrakeWPF.ViewModels if (window != null)
{
- ILogViewModel logvm = (ILogViewModel)window.DataContext;
- logvm.SelectedTab = this.IsEncoding ? 0 : 1;
window.Activate();
}
else
{
ILogViewModel logvm = IoC.Get<ILogViewModel>();
- logvm.SelectedTab = this.IsEncoding ? 0 : 1;
this.windowManager.ShowWindow(logvm);
}
}
diff --git a/win/CS/HandBrakeWPF/Views/LogView.xaml b/win/CS/HandBrakeWPF/Views/LogView.xaml index 64ca9da2d..878fd430a 100644 --- a/win/CS/HandBrakeWPF/Views/LogView.xaml +++ b/win/CS/HandBrakeWPF/Views/LogView.xaml @@ -38,51 +38,8 @@ </ToolBar>
+ <TextBox Grid.Row="2" ScrollViewer.VerticalScrollBarVisibility="Visible" TextWrapping="Wrap" x:Name="logText" />
- <TabControl Grid.Row="2" SelectedIndex="{Binding SelectedTab}" Margin="0,3,0,0">
- <TabItem>
- <TabItem.Header>
- <TextBlock Text="{x:Static Properties:ResourcesUI.LogView_EncodeLog}" Padding="4">
- <TextBlock.Style>
- <Style TargetType="TextBlock">
- <Style.Triggers>
- <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=TabItem}}" Value="True">
- <Setter Property="FontWeight" Value="Bold"/>
- </DataTrigger>
- </Style.Triggers>
- </Style>
- </TextBlock.Style>
- </TextBlock>
- </TabItem.Header>
-
- <TextBox
- AcceptsReturn="True"
- IsReadOnly="True"
- ScrollViewer.VerticalScrollBarVisibility="Visible"
- Text="{Binding EncodeLog, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
- TextWrapping="Wrap" />
- </TabItem>
-
- <TabItem>
- <TabItem.Header>
- <TextBlock Text="{x:Static Properties:ResourcesUI.LogView_ScanLog}" Padding="4">
- <TextBlock.Style>
- <Style TargetType="TextBlock">
- <Style.Triggers>
- <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=TabItem}}" Value="True">
- <Setter Property="FontWeight" Value="Bold"/>
- </DataTrigger>
- </Style.Triggers>
- </Style>
- </TextBlock.Style>
- </TextBlock>
- </TabItem.Header>
- <TextBox AcceptsReturn="True" IsReadOnly="True" ScrollViewer.VerticalScrollBarVisibility="Visible"
- Text="{Binding ScanLog, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
- TextWrapping="Wrap" />
- </TabItem>
-
- </TabControl>
</Grid>
</Grid>
diff --git a/win/CS/HandBrakeWPF/Views/LogView.xaml.cs b/win/CS/HandBrakeWPF/Views/LogView.xaml.cs index d0bdaf0ee..af07ae509 100644 --- a/win/CS/HandBrakeWPF/Views/LogView.xaml.cs +++ b/win/CS/HandBrakeWPF/Views/LogView.xaml.cs @@ -9,9 +9,13 @@ namespace HandBrakeWPF.Views
{
+ using System;
+ using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
+ using HandBrakeWPF.ViewModels;
+
/// <summary>
/// Interaction logic for LogView.xaml
/// </summary>
@@ -22,7 +26,59 @@ namespace HandBrakeWPF.Views /// </summary>
public LogView()
{
- InitializeComponent();
+ this.InitializeComponent();
+ this.DataContextChanged += this.LogView_DataContextChanged;
+ }
+
+ /// <summary>
+ /// The log view_ data context changed.
+ /// </summary>
+ /// <param name="sender">
+ /// The sender.
+ /// </param>
+ /// <param name="e">
+ /// The e.
+ /// </param>
+ private void LogView_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
+ {
+ LogViewModel vm = e.NewValue as LogViewModel;
+ if (vm != null)
+ {
+ this.logText.AppendText(vm.ActivityLog);
+ vm.LogMessageReceived += this.Vm_LogMessageReceived;
+ }
+ }
+
+ /// <summary>
+ /// The vm_ log message received.
+ /// </summary>
+ /// <param name="sender">
+ /// The sender.
+ /// </param>
+ /// <param name="e">
+ /// The e.
+ /// </param>
+ private void Vm_LogMessageReceived(object sender, HandBrake.ApplicationServices.Services.Logging.EventArgs.LogEventArgs e)
+ {
+ if (e == null)
+ {
+ LogViewModel vm = this.DataContext as LogViewModel;
+ if (vm != null)
+ {
+ this.logText.Clear();
+ this.logText.AppendText(vm.ActivityLog);
+ }
+ else
+ {
+ Debug.WriteLine("Failed to Reset Log correctly.");
+ }
+ }
+ else
+ {
+ // This works better than Data Binding because of the scroll.
+ this.logText.AppendText(Environment.NewLine + e.Log.Content);
+ this.logText.ScrollToEnd();
+ }
}
/// <summary>
|