Changed the Logging screen to a single panel in the WinGui. This will change back to separate Scan/Encode logs when we get libhb it's own processes.
Added Auto-Scroll to the log window.
<Compile Include="Interop\Model\VideoQualityLimits.cs" />\r
<Compile Include="Model\HBConfiguration.cs" />\r
<Compile Include="Model\VideoScaler.cs" />\r
- <Compile Include="Services\Logging\LogHelper.cs" />\r
+ <Compile Include="Services\Logging\EventArgs\LogEventArgs.cs" />\r
+ <Compile Include="Services\Logging\Interfaces\ILog.cs" />\r
+ <Compile Include="Services\Logging\LogService.cs" />\r
<Compile Include="Services\Logging\Model\LogLevel.cs" />\r
<Compile Include="Services\Logging\Model\LogMessage.cs" />\r
<Compile Include="Services\Logging\Model\LogMessageType.cs" />\r
using HandBrake.ApplicationServices.Interop.Model.Encoding;\r
using HandBrake.ApplicationServices.Interop.Model.Preview;\r
using HandBrake.ApplicationServices.Services.Logging;\r
+ using HandBrake.ApplicationServices.Services.Logging.Interfaces;\r
using HandBrake.ApplicationServices.Services.Logging.Model;\r
\r
using Newtonsoft.Json;\r
/// </summary>\r
private const double EncodePollIntervalMs = 250;\r
\r
+ private readonly ILog log = LogService.GetLogger();\r
+\r
/// <summary>\r
/// The native handle to the HandBrake instance.\r
/// </summary>\r
{\r
IntPtr json = HBFunctions.hb_get_state_json(this.hbHandle);\r
string statusJson = Marshal.PtrToStringAnsi(json);\r
- LogHelper.LogMessage(new LogMessage(statusJson, LogMessageType.progressJson, LogLevel.debug));\r
+ this.log.LogMessage(statusJson, LogMessageType.Progress, LogLevel.Trace);\r
JsonState state = JsonConvert.DeserializeObject<JsonState>(statusJson);\r
\r
if (state != null && state.State == NativeConstants.HB_STATE_SCANNING)\r
{\r
var jsonMsg = HBFunctions.hb_get_title_set_json(this.hbHandle);\r
string scanJson = InteropUtilities.ToStringFromUtf8Ptr(jsonMsg);\r
- LogHelper.LogMessage(new LogMessage(scanJson, LogMessageType.scanJson, LogLevel.debug));\r
+ this.log.LogMessage(scanJson, LogMessageType.Progress, LogLevel.Trace);\r
this.titles = JsonConvert.DeserializeObject<JsonScanObject>(scanJson);\r
this.featureTitle = this.titles.MainFeature;\r
\r
IntPtr json = HBFunctions.hb_get_state_json(this.hbHandle);\r
string statusJson = Marshal.PtrToStringAnsi(json);\r
\r
- LogHelper.LogMessage(new LogMessage(statusJson, LogMessageType.progressJson, LogLevel.debug));\r
+ this.log.LogMessage(statusJson, LogMessageType.Progress, LogLevel.Trace);\r
\r
JsonState state = JsonConvert.DeserializeObject<JsonState>(statusJson);\r
\r
using HandBrake.ApplicationServices.Interop.Helpers;\r
using HandBrake.ApplicationServices.Interop.Json.Presets;\r
using HandBrake.ApplicationServices.Services.Logging;\r
+ using HandBrake.ApplicationServices.Services.Logging.Interfaces;\r
using HandBrake.ApplicationServices.Services.Logging.Model;\r
\r
using Newtonsoft.Json;\r
/// </summary>\r
public class HandBrakePresetService\r
{\r
+ private static readonly ILog log = LogService.GetLogger();\r
+\r
/// <summary>\r
/// The get built in presets.\r
/// Requires an hb_init to have been invoked.\r
IntPtr presets = HBFunctions.hb_presets_builtin_get_json();\r
string presetJson = Marshal.PtrToStringAnsi(presets);\r
\r
- LogHelper.LogMessage(new LogMessage(presetJson, LogMessageType.progressJson, LogLevel.debug));\r
+ log.LogMessage(presetJson, LogMessageType.API, LogLevel.Debug);\r
\r
IList<PresetCategory> presetList = JsonConvert.DeserializeObject<IList<PresetCategory>>(presetJson);\r
\r
IntPtr presetStringPointer = HBFunctions.hb_presets_read_file_json(InteropUtilities.ToUtf8PtrFromString(filename));\r
string presetJson = Marshal.PtrToStringAnsi(presetStringPointer);\r
\r
- LogHelper.LogMessage(new LogMessage(presetJson, LogMessageType.libhb, LogLevel.debug));\r
+ log.LogMessage(presetJson, LogMessageType.API, LogLevel.Debug);\r
\r
PresetTransportContainer preset = JsonConvert.DeserializeObject<PresetTransportContainer>(presetJson);\r
\r
{\r
using System;\r
using System.Collections.Generic;\r
- using System.Diagnostics;\r
using System.Runtime.InteropServices;\r
\r
using HandBrake.ApplicationServices.Interop.EventArgs;\r
using HandBrake.ApplicationServices.Interop.Json.Anamorphic;\r
using HandBrake.ApplicationServices.Interop.Json.Shared;\r
using HandBrake.ApplicationServices.Services.Logging;\r
+ using HandBrake.ApplicationServices.Services.Logging.Interfaces;\r
using HandBrake.ApplicationServices.Services.Logging.Model;\r
\r
using Newtonsoft.Json;\r
/// </summary>\r
public static class HandBrakeUtils\r
{\r
+ private static readonly ILog log = LogService.GetLogger();\r
+\r
/// <summary>\r
/// The callback for log messages from HandBrake.\r
/// </summary>\r
public static Geometry GetAnamorphicSize(AnamorphicGeometry anamorphicGeometry)\r
{\r
string encode = JsonConvert.SerializeObject(anamorphicGeometry, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });\r
- LogHelper.LogMessage(new LogMessage(encode, LogMessageType.encodeJson, LogLevel.debug));\r
+ log.LogMessage(encode, LogMessageType.API, LogLevel.Debug);\r
IntPtr json = HBFunctions.hb_set_anamorphic_size_json(Marshal.StringToHGlobalAnsi(encode));\r
string result = Marshal.PtrToStringAnsi(json);\r
return JsonConvert.DeserializeObject<Geometry>(result);\r
{\r
if (MessageLogged != null)\r
{\r
+ log.LogMessage(message, LogMessageType.ScanOrEncode, LogLevel.Info);\r
MessageLogged(null, new MessageLoggedEventArgs(message));\r
}\r
-\r
- Debug.WriteLine(message);\r
}\r
\r
/// <summary>\r
{\r
if (ErrorLogged != null)\r
{\r
+ log.LogMessage(message, LogMessageType.ScanOrEncode, LogLevel.Error);\r
ErrorLogged(null, new MessageLoggedEventArgs(message));\r
}\r
-\r
- Debug.WriteLine("ERROR: " + message);\r
}\r
}\r
}\r
--- /dev/null
+// --------------------------------------------------------------------------------------------------------------------
+// <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; }
+ }
+}
--- /dev/null
+// --------------------------------------------------------------------------------------------------------------------
+// <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
+++ /dev/null
-// --------------------------------------------------------------------------------------------------------------------\r
-// <copyright file="LogHelper.cs" company="HandBrake Project (http://handbrake.fr)">\r
-// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.\r
-// </copyright>\r
-// <summary>\r
-// The log service.\r
-// For now, this is just a simple logging service but we could provide support for a formal logging library later.\r
-// Also, we can consider providing the UI layer with more functional logging. (i.e levels, time/date, highlighting etc)\r
-// The Interop Classes are not very OO friendly, so this is going to be a static class.\r
-// </summary>\r
-// --------------------------------------------------------------------------------------------------------------------\r
-\r
-namespace HandBrake.ApplicationServices.Services.Logging\r
-{\r
- using System.Diagnostics;\r
-\r
- using HandBrake.ApplicationServices.Services.Logging.Model;\r
-\r
- /// <summary>\r
- /// The log helper.\r
- /// </summary>\r
- public static class LogHelper\r
- {\r
- private static LogLevel currentLogLevel = LogLevel.debug; // TODO default to Info when this class is implimented. \r
-\r
- /// <summary>\r
- /// Log message.\r
- /// </summary>\r
- /// <param name="message">\r
- /// The message.\r
- /// </param>\r
- public static void LogMessage(LogMessage message)\r
- {\r
- if (message.LogLevel <= currentLogLevel)\r
- {\r
- //Debug.WriteLine(message.Content);\r
- }\r
-\r
- // TODO cache logging. \r
- }\r
-\r
- /// <summary>\r
- /// The set log level. Default: Info.\r
- /// </summary>\r
- /// <param name="level">\r
- /// The level.\r
- /// </param>\r
- public static void SetLogLevel(LogLevel level)\r
- {\r
- currentLogLevel = level;\r
- }\r
- }\r
-}\r
--- /dev/null
+// --------------------------------------------------------------------------------------------------------------------
+// <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);
+ }
+ }
+}
/// <summary>\r
/// The info.\r
/// </summary>\r
- info,\r
+ Info,\r
\r
/// <summary>\r
/// The warning.\r
/// </summary>\r
- warning, \r
+ Warning, \r
\r
/// <summary>\r
/// The error.\r
/// </summary>\r
- error, \r
+ Error, \r
\r
/// <summary>\r
/// The debug.\r
/// </summary>\r
- debug, \r
+ Debug,\r
+ \r
+ /// <summary>\r
+ /// Trace Level Logging.\r
+ /// </summary>\r
+ Trace, \r
}\r
}\r
namespace HandBrake.ApplicationServices.Services.Logging.Model\r
{\r
/// <summary>\r
- /// The json message.\r
+ /// An Immutable Log Entry.\r
/// </summary>\r
public class LogMessage\r
{\r
/// <param name="logLevel">\r
/// The log level.\r
/// </param>\r
- public LogMessage(string content, LogMessageType messageType, LogLevel logLevel)\r
+ /// <param name="messageIndex">\r
+ /// The message Index.\r
+ /// </param>\r
+ public LogMessage(string content, LogMessageType messageType, LogLevel logLevel, long messageIndex)\r
{\r
this.Content = content;\r
this.MessageType = messageType;\r
this.LogLevel = logLevel;\r
+ this.MessageIndex = messageIndex;\r
}\r
\r
/// <summary>\r
/// Gets the log level.\r
/// </summary>\r
public LogLevel LogLevel { get; private set; }\r
+\r
+ /// <summary>\r
+ /// Gets the message index.\r
+ /// </summary>\r
+ public long MessageIndex { get; private set; }\r
}\r
}\r
/// </summary>\r
public enum LogMessageType\r
{\r
- scanJson,\r
- encodeJson,\r
- anamorphicJson,\r
- progressJson,\r
- libhb,\r
+ ScanOrEncode,\r
+ API,\r
+ Progress,\r
+ Vital,\r
}\r
}\r
return iso6392Codes;\r
}\r
\r
+ /// <summary>\r
+ /// The get language names.\r
+ /// </summary>\r
+ /// <param name="languageCodes">\r
+ /// The language codes.\r
+ /// </param>\r
+ /// <returns>\r
+ /// The <see cref="List"/>.\r
+ /// </returns>\r
public static List<string> GetLanguageNames(IList<string> languageCodes)\r
{\r
// Translate to Iso Codes\r
<Compile Include="EventArgs\SettingChangedEventArgs.cs" />\r
<Compile Include="Exceptions\GeneralApplicationException.cs" />\r
<Compile Include="Extensions\StringExtensions.cs" />\r
+ <Compile Include="Helpers\LogManager.cs" />\r
<Compile Include="Helpers\MP4Helper.cs" />\r
<Compile Include="Helpers\TimeSpanHelper.cs" />\r
<Compile Include="Helpers\Validate.cs" />\r
--- /dev/null
+// --------------------------------------------------------------------------------------------------------------------
+// <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
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;
/// </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
/// </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
{
handler(this, e);
}
-
- this.LogIndex = 0; // Reset
}
/// <summary>
/// <param name="destination">
/// The Destination File Path
/// </param>
+ /// <param name="isPreview">
+ /// The is Preview.
+ /// </param>
/// <param name="configuration">
/// The configuration.
/// </param>
{
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))
}
// 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)
}
/// <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);
}
}
/// </summary>
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>
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;
{
#region Private Variables
- private static readonly object LogLock = new object();
+ private ILog log = LogService.GetLogger();
private IHandBrakeInstance instance;
private DateTime startTime;
private EncodeTask currentTask;
// 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;
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
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));
}
}
#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>
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,
{
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
}
/// </summary>
bool IsScanning { get; }
- /// <summary>
- /// Gets ActivityLog.
- /// </summary>
- string ActivityLog { get; }
-
/// <summary>
/// Scan a Source Path.
/// Title 0: scan all
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;
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;
{
#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
/// </summary>
public LibScan()
{
- this.logging = new StringBuilder();
- this.header = GeneralUtilities.CreateLogHeader();
this.IsScanning = false;
}
/// </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
{
try
{
- lock (LogLock)
- {
- this.scanLog.Close();
- this.scanLog.Dispose();
- this.scanLog = null;
- }
this.instance.Dispose();
}
catch (Exception)
// 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;
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)
{
{
try
{
- this.logging.Clear();
-
string source = sourcePath.ToString().EndsWith("\\") ? string.Format("\"{0}\\\\\"", sourcePath.ToString().TrimEnd('\\'))
: "\"" + sourcePath + "\"";
this.currentSourceScanPath = source;
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));
}
}
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("\""))
{
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,
}
}
- /// <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>
return titleList;
}
- /// <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>
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
}
/// </summary>\r
public interface ILogViewModel\r
{\r
- /// <summary>\r
- /// Gets or sets the selected tab.\r
- /// </summary>\r
- int SelectedTab { get; set; }\r
}\r
}
\ No newline at end of file
{\r
using System;\r
using System.Diagnostics;\r
+ using System.Text;\r
using System.Windows;\r
\r
- using HandBrakeWPF.Services.Scan.EventArgs;\r
- using HandBrakeWPF.Services.Scan.Interfaces;\r
+ using Caliburn.Micro;\r
+\r
+ using HandBrake.ApplicationServices.Services.Logging;\r
+ using HandBrake.ApplicationServices.Services.Logging.EventArgs;\r
+ using HandBrake.ApplicationServices.Services.Logging.Model;\r
+\r
using HandBrakeWPF.ViewModels.Interfaces;\r
\r
- using EncodeCompletedEventArgs = HandBrakeWPF.Services.Encode.EventArgs.EncodeCompletedEventArgs;\r
- using EncodeProgressEventArgs = HandBrakeWPF.Services.Encode.EventArgs.EncodeProgressEventArgs;\r
- using IEncode = HandBrakeWPF.Services.Encode.Interfaces.IEncode;\r
+ using ILog = HandBrake.ApplicationServices.Services.Logging.Interfaces.ILog;\r
\r
/// <summary>\r
/// The Log View Model\r
{\r
#region Private Fields\r
\r
- /// <summary>\r
- /// Backing field for the encodeService service\r
- /// </summary>\r
- private readonly IEncode encodeService;\r
-\r
- /// <summary>\r
- /// Backing field for the Scan Service\r
- /// </summary>\r
- private readonly IScan scanService;\r
-\r
- /// <summary>\r
- /// The selected tab.\r
- /// </summary>\r
- private int selectedTab;\r
-\r
- /// <summary>\r
- /// The encode log index.\r
- /// </summary>\r
- private int encodeLogIndex;\r
+ private readonly ILog logService;\r
+ private StringBuilder log = new StringBuilder();\r
+ private long lastReadIndex;\r
\r
#endregion\r
\r
/// <summary>\r
/// Initializes a new instance of the <see cref="LogViewModel"/> class.\r
/// </summary>\r
- /// <param name="encodeService">\r
- /// The encode service.\r
- /// </param>\r
- /// <param name="scanService">\r
- /// The scan service.\r
- /// </param>\r
- public LogViewModel(IEncode encodeService, IScan scanService)\r
+ public LogViewModel()\r
{\r
- this.encodeService = encodeService;\r
- this.scanService = scanService;\r
+ this.logService = LogService.GetLogger();\r
this.Title = "Log Viewer";\r
- this.encodeLogIndex = 0;\r
- }\r
-\r
- /// <summary>\r
- /// Gets or sets the selected tab.\r
- /// </summary>\r
- public int SelectedTab\r
- {\r
- get\r
- {\r
- return this.selectedTab;\r
- }\r
- set\r
- {\r
- this.selectedTab = value;\r
- this.NotifyOfPropertyChange(() => this.SelectedTab);\r
- }\r
}\r
\r
/// <summary>\r
/// Gets Log.\r
/// </summary>\r
- public string ScanLog\r
+ public string ActivityLog\r
{\r
get\r
{\r
- return this.scanService.ActivityLog;\r
+ return this.log.ToString();\r
}\r
}\r
\r
/// <summary>\r
- /// Gets the encodelog.\r
+ /// The log message received.\r
/// </summary>\r
- public string EncodeLog\r
- {\r
- get\r
- {\r
- return this.encodeService.ActivityLog;\r
- }\r
- }\r
-\r
+ public event EventHandler<LogEventArgs> LogMessageReceived;\r
+ \r
/// <summary>\r
/// Open the Log file directory\r
/// </summary>\r
/// </summary>\r
public void CopyLog()\r
{\r
- Clipboard.SetDataObject(this.SelectedTab == 1 ? this.ScanLog : this.EncodeLog, true);\r
+ Clipboard.SetDataObject(this.ActivityLog, true);\r
}\r
\r
/// <summary>\r
/// </summary>\r
protected override void OnActivate()\r
{\r
- this.scanService.ScanCompleted += ScanServiceScanCompleted;\r
- this.encodeService.EncodeCompleted += EncodeServiceEncodeCompleted;\r
- this.encodeService.EncodeStatusChanged += this.EncodeServiceEncodeStatusChanged;\r
- this.scanService.ScanStatusChanged += this.ScanServiceScanStatusChanged;\r
- this.scanService.ScanStarted += this.scanService_ScanStared;\r
- this.encodeService.EncodeStarted += this.encodeService_EncodeStarted;\r
- base.OnActivate();\r
-\r
- this.NotifyOfPropertyChange(() => this.ScanLog);\r
- this.NotifyOfPropertyChange(() => this.EncodeLog);\r
- }\r
-\r
- /// <summary>\r
- /// Scan Status has changed, update log window.\r
- /// </summary>\r
- /// <param name="sender">\r
- /// The sender.\r
- /// </param>\r
- /// <param name="e">\r
- /// The e.\r
- /// </param>\r
- private void ScanServiceScanStatusChanged(object sender, ScanProgressEventArgs e)\r
- {\r
- this.NotifyOfPropertyChange(() => this.ScanLog);\r
- }\r
+ this.logService.MessageLogged += this.LogService_MessageLogged;\r
+ this.logService.LogReset += LogService_LogReset;\r
\r
- /// <summary>\r
- /// Encode Status has changed, update log window\r
- /// </summary>\r
- /// <param name="sender">\r
- /// The sender.\r
- /// </param>\r
- /// <param name="e">\r
- /// The e.\r
- /// </param>\r
- private void EncodeServiceEncodeStatusChanged(object sender, EncodeProgressEventArgs e)\r
- {\r
- if (encodeLogIndex != this.encodeService.LogIndex || this.encodeService.LogIndex == -1)\r
+ // Refresh the Log Display\r
+ this.log.Clear();\r
+ foreach (LogMessage logMessage in this.logService.LogMessages)\r
{\r
- this.NotifyOfPropertyChange(() => this.EncodeLog);\r
+ this.log.AppendLine(logMessage.Content);\r
+ this.lastReadIndex = logMessage.MessageIndex;\r
+\r
+ if (this.lastReadIndex > logMessage.MessageIndex)\r
+ {\r
+ throw new Exception("Log Message Index Error");\r
+ }\r
}\r
\r
- encodeLogIndex = this.encodeService.LogIndex;\r
+ this.OnLogMessageReceived(null);\r
+ this.NotifyOfPropertyChange("ActivityLog");\r
+\r
+ base.OnActivate();\r
}\r
\r
/// <summary>\r
/// </param>\r
protected override void OnDeactivate(bool close)\r
{\r
- this.scanService.ScanCompleted -= ScanServiceScanCompleted;\r
- this.encodeService.EncodeCompleted -= EncodeServiceEncodeCompleted;\r
- this.encodeService.EncodeStatusChanged -= this.EncodeServiceEncodeStatusChanged;\r
- this.scanService.ScanStatusChanged -= this.ScanServiceScanStatusChanged;\r
- this.scanService.ScanStarted -= this.scanService_ScanStared;\r
- this.encodeService.EncodeStarted -= this.encodeService_EncodeStarted;\r
+ this.logService.MessageLogged -= this.LogService_MessageLogged;\r
+ this.logService.LogReset -= this.LogService_LogReset;\r
\r
base.OnDeactivate(close);\r
}\r
\r
/// <summary>\r
- /// Scan Completed Event Handler.\r
+ /// The log service_ log reset.\r
/// </summary>\r
/// <param name="sender">\r
/// The sender.\r
/// <param name="e">\r
/// The e.\r
/// </param>\r
- private void ScanServiceScanCompleted(object sender, ScanCompletedEventArgs e)\r
+ private void LogService_LogReset(object sender, EventArgs e)\r
{\r
- this.NotifyOfPropertyChange(() => this.ScanLog);\r
- }\r
+ this.log.Clear();\r
+ this.lastReadIndex = 0;\r
\r
- /// <summary>\r
- /// Encode Completed Event Handler.\r
- /// </summary>\r
- /// <param name="sender">\r
- /// The sender.\r
- /// </param>\r
- /// <param name="e">\r
- /// The e.\r
- /// </param>\r
- private void EncodeServiceEncodeCompleted(object sender, EncodeCompletedEventArgs e)\r
- {\r
- this.NotifyOfPropertyChange(() => this.EncodeLog);\r
+ foreach (LogMessage logMessage in this.logService.LogMessages)\r
+ {\r
+ this.log.AppendLine(logMessage.Content);\r
+ this.lastReadIndex = logMessage.MessageIndex;\r
+\r
+ if (this.lastReadIndex > logMessage.MessageIndex)\r
+ {\r
+ throw new Exception("Log Message Index Error");\r
+ }\r
+ }\r
+\r
+ this.NotifyOfPropertyChange("ActivityLog");\r
+ this.OnLogMessageReceived(null);\r
}\r
\r
/// <summary>\r
- /// The encode service encode started.\r
+ /// The log service_ message logged.\r
/// </summary>\r
/// <param name="sender">\r
/// The sender.\r
/// <param name="e">\r
/// The e.\r
/// </param>\r
- private void encodeService_EncodeStarted(object sender, EventArgs e)\r
+ private void LogService_MessageLogged(object sender, LogEventArgs e)\r
{\r
- this.encodeLogIndex = -1; // Reset the log index.\r
- this.SelectedTab = 0;\r
+ if (this.lastReadIndex < e.Log.MessageIndex)\r
+ {\r
+ Execute.OnUIThreadAsync(\r
+ () =>\r
+ {\r
+ this.lastReadIndex = e.Log.MessageIndex;\r
+ this.log.AppendLine(e.Log.Content);\r
+ this.OnLogMessageReceived(e);\r
+ this.NotifyOfPropertyChange("ActivityLog");\r
+ });\r
+ }\r
}\r
\r
/// <summary>\r
- /// The scan service scan stared.\r
+ /// Trigger a faster / smoother way of updating the log window.\r
/// </summary>\r
- /// <param name="sender">\r
- /// The sender.\r
- /// </param>\r
/// <param name="e">\r
/// The e.\r
/// </param>\r
- private void scanService_ScanStared(object sender, EventArgs e)\r
+ protected virtual void OnLogMessageReceived(LogEventArgs e)\r
{\r
- this.SelectedTab = 1;\r
+ var onLogMessageReceived = this.LogMessageReceived;\r
+ if (onLogMessageReceived != null)\r
+ {\r
+ onLogMessageReceived.Invoke(this, e);\r
+ }\r
}\r
}\r
}
\ No newline at end of file
using Caliburn.Micro;\r
\r
using HandBrake.ApplicationServices.Interop;\r
+ using HandBrake.ApplicationServices.Interop.HbLib;\r
+ using HandBrake.ApplicationServices.Services.Logging;\r
using HandBrake.ApplicationServices.Utilities;\r
\r
using HandBrakeWPF.Commands;\r
\r
using Action = System.Action;\r
using Execute = Caliburn.Micro.Execute;\r
+ using ILog = HandBrake.ApplicationServices.Services.Logging.Interfaces.ILog;\r
+ using LogManager = HandBrakeWPF.Helpers.LogManager;\r
\r
/// <summary>\r
/// HandBrakes Main Window\r
// Setup Commands\r
this.QueueCommand = new QueueCommands(this.QueueViewModel);\r
\r
+ LogManager.Init();\r
HandBrakeInstanceManager.Init();\r
}\r
\r
\r
if (window != null)\r
{\r
- ILogViewModel logvm = (ILogViewModel)window.DataContext;\r
- logvm.SelectedTab = this.IsEncoding ? 0 : 1;\r
window.Activate();\r
}\r
else\r
{\r
ILogViewModel logvm = IoC.Get<ILogViewModel>();\r
- logvm.SelectedTab = this.IsEncoding ? 0 : 1;\r
this.windowManager.ShowWindow(logvm);\r
}\r
}\r
\r
</ToolBar>\r
\r
+ <TextBox Grid.Row="2" ScrollViewer.VerticalScrollBarVisibility="Visible" TextWrapping="Wrap" x:Name="logText" />\r
\r
- <TabControl Grid.Row="2" SelectedIndex="{Binding SelectedTab}" Margin="0,3,0,0">\r
- <TabItem>\r
- <TabItem.Header>\r
- <TextBlock Text="{x:Static Properties:ResourcesUI.LogView_EncodeLog}" Padding="4">\r
- <TextBlock.Style>\r
- <Style TargetType="TextBlock">\r
- <Style.Triggers>\r
- <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=TabItem}}" Value="True">\r
- <Setter Property="FontWeight" Value="Bold"/>\r
- </DataTrigger>\r
- </Style.Triggers>\r
- </Style>\r
- </TextBlock.Style>\r
- </TextBlock>\r
- </TabItem.Header>\r
-\r
- <TextBox\r
- AcceptsReturn="True"\r
- IsReadOnly="True"\r
- ScrollViewer.VerticalScrollBarVisibility="Visible"\r
- Text="{Binding EncodeLog, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"\r
- TextWrapping="Wrap" />\r
- </TabItem>\r
-\r
- <TabItem>\r
- <TabItem.Header>\r
- <TextBlock Text="{x:Static Properties:ResourcesUI.LogView_ScanLog}" Padding="4">\r
- <TextBlock.Style>\r
- <Style TargetType="TextBlock">\r
- <Style.Triggers>\r
- <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=TabItem}}" Value="True">\r
- <Setter Property="FontWeight" Value="Bold"/>\r
- </DataTrigger>\r
- </Style.Triggers>\r
- </Style>\r
- </TextBlock.Style>\r
- </TextBlock>\r
- </TabItem.Header>\r
- <TextBox AcceptsReturn="True" IsReadOnly="True" ScrollViewer.VerticalScrollBarVisibility="Visible" \r
- Text="{Binding ScanLog, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"\r
- TextWrapping="Wrap" />\r
- </TabItem>\r
-\r
- </TabControl>\r
</Grid>\r
\r
</Grid>\r
\r
namespace HandBrakeWPF.Views\r
{\r
+ using System;\r
+ using System.Diagnostics;\r
using System.Windows;\r
using System.Windows.Controls;\r
\r
+ using HandBrakeWPF.ViewModels;\r
+\r
/// <summary>\r
/// Interaction logic for LogView.xaml\r
/// </summary>\r
/// </summary>\r
public LogView()\r
{\r
- InitializeComponent();\r
+ this.InitializeComponent();\r
+ this.DataContextChanged += this.LogView_DataContextChanged;\r
+ }\r
+\r
+ /// <summary>\r
+ /// The log view_ data context changed.\r
+ /// </summary>\r
+ /// <param name="sender">\r
+ /// The sender.\r
+ /// </param>\r
+ /// <param name="e">\r
+ /// The e.\r
+ /// </param>\r
+ private void LogView_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)\r
+ {\r
+ LogViewModel vm = e.NewValue as LogViewModel;\r
+ if (vm != null)\r
+ {\r
+ this.logText.AppendText(vm.ActivityLog);\r
+ vm.LogMessageReceived += this.Vm_LogMessageReceived;\r
+ }\r
+ }\r
+\r
+ /// <summary>\r
+ /// The vm_ log message received.\r
+ /// </summary>\r
+ /// <param name="sender">\r
+ /// The sender.\r
+ /// </param>\r
+ /// <param name="e">\r
+ /// The e.\r
+ /// </param>\r
+ private void Vm_LogMessageReceived(object sender, HandBrake.ApplicationServices.Services.Logging.EventArgs.LogEventArgs e)\r
+ {\r
+ if (e == null)\r
+ {\r
+ LogViewModel vm = this.DataContext as LogViewModel;\r
+ if (vm != null)\r
+ {\r
+ this.logText.Clear();\r
+ this.logText.AppendText(vm.ActivityLog);\r
+ }\r
+ else\r
+ {\r
+ Debug.WriteLine("Failed to Reset Log correctly.");\r
+ }\r
+ }\r
+ else\r
+ {\r
+ // This works better than Data Binding because of the scroll.\r
+ this.logText.AppendText(Environment.NewLine + e.Log.Content);\r
+ this.logText.ScrollToEnd();\r
+ }\r
}\r
\r
/// <summary>\r