diff --git a/Duplicati/Library/Main/Options.cs b/Duplicati/Library/Main/Options.cs index d28ac6161..4d3196733 100644 --- a/Duplicati/Library/Main/Options.cs +++ b/Duplicati/Library/Main/Options.cs @@ -1248,37 +1248,7 @@ namespace Duplicati.Library.Main } } - /// - /// Helper method to support filters with either a + or - prefix - /// - /// The IFilter instance. - /// The filter string to parse. - private static IFilter StringToIFilter(string msg) - { - if (string.IsNullOrWhiteSpace(msg)) - return new FilterExpression(); - if (msg[0] == '+') - return new FilterExpression(msg.Substring(1), true); - if (msg[0] == '-') - return new FilterExpression(msg.Substring(1), false); - return new FilterExpression(msg, true); - } - /// - /// Parses a log filter string, and returns the filter instance - /// - /// The log filter. - /// The filter string to parse. - public static IFilter ParseLogFilter(string value) - { - if (string.IsNullOrWhiteSpace(value)) - return new FilterExpression(); - - return value - .Split(new char[] { System.IO.Path.PathSeparator, ':', ';', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) - .Select(StringToIFilter) - .Aggregate(FilterExpression.Combine); - } /// /// Parses a log level string @@ -1305,7 +1275,7 @@ namespace Duplicati.Library.Main get { m_options.TryGetValue("log-file-log-filter", out var value); - return ParseLogFilter(value); + return Library.Utility.FilterExpression.ParseLogFilter(value); } } @@ -1318,7 +1288,7 @@ namespace Duplicati.Library.Main get { m_options.TryGetValue("console-log-filter", out var value); - return ParseLogFilter(value); + return Library.Utility.FilterExpression.ParseLogFilter(value); } } diff --git a/Duplicati/Library/Modules/Builtin/SendMail.cs b/Duplicati/Library/Modules/Builtin/SendMail.cs index bc5ca49da..efe831583 100644 --- a/Duplicati/Library/Modules/Builtin/SendMail.cs +++ b/Duplicati/Library/Modules/Builtin/SendMail.cs @@ -62,6 +62,14 @@ namespace Duplicati.Library.Modules.Builtin /// Option used to specify if reports are sent for other operations than backups /// private const string OPTION_SENDALL = "send-mail-any-operation"; + /// + /// Option used to set the log level for mail reports + /// + private const string OPTION_LOG_LEVEL = "send-mail-log-level"; + /// + /// Option used to set the log filters for mail reports + /// + private const string OPTION_LOG_FILTER = "send-mail-log-filter"; #endregion @@ -142,6 +150,14 @@ namespace Duplicati.Library.Modules.Builtin /// True to send all operations /// private bool m_sendAll; + /// + /// The log scope that should be disposed + /// + private IDisposable m_logscope; + /// + /// The log storage + /// + private Utility.FileBackedStringList m_logstorage; #endregion @@ -187,6 +203,10 @@ namespace Duplicati.Library.Modules.Builtin new CommandLineArgument(OPTION_PASSWORD, CommandLineArgument.ArgumentType.String, Strings.SendMail.OptionPasswordShort, Strings.SendMail.OptionPasswordLong), new CommandLineArgument(OPTION_SENDLEVEL, CommandLineArgument.ArgumentType.String, Strings.SendMail.OptionSendlevelShort, Strings.SendMail.OptionSendlevelLong(ParsedResultType.Success.ToString(), ParsedResultType.Warning.ToString(), ParsedResultType.Error.ToString(), ParsedResultType.Fatal.ToString(), "All"), DEFAULT_LEVEL, null, Enum.GetNames(typeof(ParsedResultType)).Union(new string [] { "All" }).ToArray()), new CommandLineArgument(OPTION_SENDALL, CommandLineArgument.ArgumentType.Boolean, Strings.SendMail.OptionSendallShort, Strings.SendMail.OptionSendallLong), + + new CommandLineArgument(OPTION_LOG_LEVEL, CommandLineArgument.ArgumentType.Enumeration, Strings.SendMail.OptionLoglevellShort, Strings.SendMail.OptionLoglevelLong, Logging.LogMessageType.Warning.ToString(), null, Enum.GetNames(typeof(Logging.LogMessageType))), + new CommandLineArgument(OPTION_LOG_FILTER, CommandLineArgument.ArgumentType.String, Strings.SendMail.OptionLogfilterShort, Strings.SendMail.OptionLogfilterLong), + }); } } @@ -236,6 +256,21 @@ namespace Duplicati.Library.Modules.Builtin m_body = DEFAULT_BODY; if (string.IsNullOrEmpty(m_from)) m_from = DEFAULT_SENDER; + + m_options.TryGetValue(OPTION_LOG_FILTER, out var logfilterstring); + var filter = Utility.FilterExpression.ParseLogFilter(logfilterstring); + var logLevel = + + m_logstorage = new FileBackedStringList(); + m_logscope = Logging.Log.StartScope(m => m_logstorage.Add(m.AsString(true)), m => { + + if (filter.Matches(m.Tag, out var result, out var match)) + return result; + else if (m.Level < loglevel) + return false; + + return true; + }); } #endregion @@ -261,6 +296,14 @@ namespace Duplicati.Library.Modules.Builtin /// The result object, if this derives from an exception, the operation failed public void OnFinish(object result) { + // Dispose the current log scope + if (m_logscope != null) + { + try { m_logscope.Dispose(); } + catch { } + m_logscope = null; + } + //If no email is supplied, then skip if (string.IsNullOrEmpty(m_to)) return; diff --git a/Duplicati/Library/Utility/FilterExpression.cs b/Duplicati/Library/Utility/FilterExpression.cs index e03139b93..e16fd8a92 100644 --- a/Duplicati/Library/Utility/FilterExpression.cs +++ b/Duplicati/Library/Utility/FilterExpression.cs @@ -613,6 +613,38 @@ namespace Duplicati.Library.Utility return res; } + + /// + /// Parses a log filter string, and returns the filter instance + /// + /// The log filter. + /// The filter string to parse. + public static IFilter ParseLogFilter(string value) + { + if (string.IsNullOrWhiteSpace(value)) + return new FilterExpression(); + + return value + .Split(new char[] { System.IO.Path.PathSeparator, ':', ';', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) + .Select(StringToIFilter) + .Aggregate(FilterExpression.Combine); + } + + /// + /// Helper method to support filters with either a + or - prefix + /// + /// The IFilter instance. + /// The filter string to parse. + public static IFilter StringToIFilter(string msg) + { + if (string.IsNullOrWhiteSpace(msg)) + return new FilterExpression(); + if (msg[0] == '+') + return new FilterExpression(msg.Substring(1), true); + if (msg[0] == '-') + return new FilterExpression(msg.Substring(1), false); + return new FilterExpression(msg, true); + } } } diff --git a/Duplicati/Library/Utility/Utility.cs b/Duplicati/Library/Utility/Utility.cs index 8e840d0aa..28c42f3c2 100644 --- a/Duplicati/Library/Utility/Utility.cs +++ b/Duplicati/Library/Utility/Utility.cs @@ -687,7 +687,15 @@ namespace Duplicati.Library.Utility return ParseBool(opt, true); else return false; + } + public static T ParseEnum(string value, T @default) + { + foreach (string s in Enum.GetNames(typeof(T))) + if (s.Equals(value, StringComparison.OrdinalIgnoreCase)) + return (T)Enum.Parse(typeof(T), s); + + return @default; } ///