From de84650eae85dd42e90b6e87381449f09303300a Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Thu, 12 Apr 2018 11:46:54 +0200 Subject: [PATCH] Rewrote the logic for reporting JSON to avoid reporting JSON inside a text blob, but instead use an extra tag in the JSON. The logic is currently that the template is scanned for potential values, and those that are found are reported in the extra tag for the JSON. A bit clumsy, but allows the user to choose specific fields to include in the reported data. --- .../Library/Modules/Builtin/ReportHelper.cs | 74 +++++++++++++------ .../DuplicatiFormatSerializer.cs | 6 +- .../IResultFormatSerializer.cs | 3 +- .../JsonFormatSerializer.cs | 8 +- .../Library/Modules/Builtin/RunScript.cs | 2 +- .../Modules/Builtin/SendHttpMessage.cs | 1 + 6 files changed, 67 insertions(+), 27 deletions(-) diff --git a/Duplicati/Library/Modules/Builtin/ReportHelper.cs b/Duplicati/Library/Modules/Builtin/ReportHelper.cs index b83c81d3f..4f5f145c3 100644 --- a/Duplicati/Library/Modules/Builtin/ReportHelper.cs +++ b/Duplicati/Library/Modules/Builtin/ReportHelper.cs @@ -294,29 +294,61 @@ namespace Duplicati.Library.Modules.Builtin /// The result object. /// If set to true, the result is intended for a subject or title line. protected virtual string ReplaceTemplate(string input, object result, bool subjectline) - { - input = Regex.Replace(input, "\\%OPERATIONNAME\\%", m_operationname ?? "", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); - input = Regex.Replace(input, "\\%REMOTEURL\\%", m_remoteurl ?? "", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); - input = Regex.Replace(input, "\\%LOCALPATH\\%", m_localpath == null ? "" : string.Join(System.IO.Path.PathSeparator.ToString(), m_localpath), RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); - input = Regex.Replace(input, "\\%PARSEDRESULT\\%", m_parsedresultlevel ?? "", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); - if (subjectline) - { - input = Regex.Replace(input, "\\%RESULT\\%", m_parsedresultlevel ?? "", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); - } - else + { + // For JSON, ignore the template and just use the contents + if (ExportFormat == ResultExportFormat.Json) { - if (input.IndexOf("%RESULT%", StringComparison.OrdinalIgnoreCase) >= 0) - input = Regex.Replace(input, "\\%RESULT\\%", m_resultFormatSerializer.Serialize(result, LogLines), RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + var extra = new Dictionary(); + + if (input.IndexOf("%OPERATIONNAME%", StringComparison.OrdinalIgnoreCase) >= 0) + extra["OperationName"] = m_operationname; + if (input.IndexOf("%REMOTEURL%", StringComparison.OrdinalIgnoreCase) >= 0) + extra["RemoteUrl"] = m_remoteurl; + if (input.IndexOf("%LOCALPATH%", StringComparison.OrdinalIgnoreCase) >= 0 && m_localpath != null) + extra["LocalPath"] = string.Join(System.IO.Path.PathSeparator.ToString(), m_localpath); + if (input.IndexOf("%PARSEDRESULT%", StringComparison.OrdinalIgnoreCase) >= 0) + extra["ParsedResult"] = m_parsedresultlevel; + + if (input.IndexOf("%backup-name%", StringComparison.OrdinalIgnoreCase) >= 0) + { + if (m_options.ContainsKey("backup-name")) + extra["backup-name"] = m_options["backup-name"]; + else + extra["backup-name"] = System.IO.Path.GetFileNameWithoutExtension(Duplicati.Library.Utility.Utility.getEntryAssembly().Location); + } + + foreach (KeyValuePair kv in m_options) + if (input.IndexOf($"%{kv.Key}%", StringComparison.OrdinalIgnoreCase) >= 0) + extra[kv.Key] = kv.Value; + + return m_resultFormatSerializer.Serialize(result, LogLines, extra); + } + else + { + + input = Regex.Replace(input, "\\%OPERATIONNAME\\%", m_operationname ?? "", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + input = Regex.Replace(input, "\\%REMOTEURL\\%", m_remoteurl ?? "", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + input = Regex.Replace(input, "\\%LOCALPATH\\%", m_localpath == null ? "" : string.Join(System.IO.Path.PathSeparator.ToString(), m_localpath), RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + input = Regex.Replace(input, "\\%PARSEDRESULT\\%", m_parsedresultlevel ?? "", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + if (subjectline) + { + input = Regex.Replace(input, "\\%RESULT\\%", m_parsedresultlevel ?? "", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + } + else + { + if (input.IndexOf("%RESULT%", StringComparison.OrdinalIgnoreCase) >= 0) + input = Regex.Replace(input, "\\%RESULT\\%", m_resultFormatSerializer.Serialize(result, LogLines, null), RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + } + + foreach (KeyValuePair kv in m_options) + input = Regex.Replace(input, "\\%" + kv.Key + "\\%", kv.Value ?? "", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + + if (!m_options.ContainsKey("backup-name")) + input = Regex.Replace(input, "\\%backup-name\\%", System.IO.Path.GetFileNameWithoutExtension(Duplicati.Library.Utility.Utility.getEntryAssembly().Location) ?? "", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + + input = Regex.Replace(input, "\\%[^\\%]+\\%", ""); + return input; } - - foreach (KeyValuePair kv in m_options) - input = Regex.Replace(input, "\\%" + kv.Key + "\\%", kv.Value ?? "", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); - - if (!m_options.ContainsKey("backup-name")) - input = Regex.Replace(input, "\\%backup-name\\%", System.IO.Path.GetFileNameWithoutExtension(Duplicati.Library.Utility.Utility.getEntryAssembly().Location) ?? "", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); - - input = Regex.Replace(input, "\\%[^\\%]+\\%", ""); - return input; } /// diff --git a/Duplicati/Library/Modules/Builtin/ResultSerialization/DuplicatiFormatSerializer.cs b/Duplicati/Library/Modules/Builtin/ResultSerialization/DuplicatiFormatSerializer.cs index a066e370f..a88cf21d6 100644 --- a/Duplicati/Library/Modules/Builtin/ResultSerialization/DuplicatiFormatSerializer.cs +++ b/Duplicati/Library/Modules/Builtin/ResultSerialization/DuplicatiFormatSerializer.cs @@ -17,7 +17,8 @@ namespace Duplicati.Library.Modules.Builtin.ResultSerialization /// The serialized result string. /// The result to serialize. /// The log lines to serialize. - public string Serialize(object result, IEnumerable loglines) + /// Additional parameters to include + public string Serialize(object result, IEnumerable loglines, Dictionary additional) { StringBuilder sb = new StringBuilder(); @@ -88,6 +89,9 @@ namespace Duplicati.Library.Modules.Builtin.ResultSerialization Utility.Utility.PrintSerializeObject(result, sb); } + if (additional != null && additional.Count > 0) + sb.AppendLine(Serialize(additional, null, null)); + if (loglines != null && loglines.Any()) { sb.AppendLine(); diff --git a/Duplicati/Library/Modules/Builtin/ResultSerialization/IResultFormatSerializer.cs b/Duplicati/Library/Modules/Builtin/ResultSerialization/IResultFormatSerializer.cs index 4fbfdf3fb..2df6776dc 100644 --- a/Duplicati/Library/Modules/Builtin/ResultSerialization/IResultFormatSerializer.cs +++ b/Duplicati/Library/Modules/Builtin/ResultSerialization/IResultFormatSerializer.cs @@ -13,7 +13,8 @@ namespace Duplicati.Library.Modules.Builtin /// The serialized result string. /// The result to serialize. /// The log lines to serialize. - string Serialize(object result, IEnumerable loglines); + /// Additional parameters to include + string Serialize(object result, IEnumerable loglines, Dictionary additional); /// /// Returns the format that the serializer represents diff --git a/Duplicati/Library/Modules/Builtin/ResultSerialization/JsonFormatSerializer.cs b/Duplicati/Library/Modules/Builtin/ResultSerialization/JsonFormatSerializer.cs index 1d1bdee49..f15516fca 100644 --- a/Duplicati/Library/Modules/Builtin/ResultSerialization/JsonFormatSerializer.cs +++ b/Duplicati/Library/Modules/Builtin/ResultSerialization/JsonFormatSerializer.cs @@ -53,12 +53,14 @@ namespace Duplicati.Library.Modules.Builtin.ResultSerialization /// The serialized result string. /// The result to serialize. /// The log lines to serialize. - public string Serialize(object result, IEnumerable loglines) - { + /// Additional parameters to include + public string Serialize(object result, IEnumerable loglines, Dictionary additional) + { return JsonConvert.SerializeObject( new { - Data = result, + Data = result, + Extra = additional, LogLines = loglines }, diff --git a/Duplicati/Library/Modules/Builtin/RunScript.cs b/Duplicati/Library/Modules/Builtin/RunScript.cs index 4c33a44a1..25db9a530 100644 --- a/Duplicati/Library/Modules/Builtin/RunScript.cs +++ b/Duplicati/Library/Modules/Builtin/RunScript.cs @@ -188,7 +188,7 @@ namespace Duplicati.Library.Modules.Builtin using (TempFile tmpfile = new TempFile()) { using (var streamWriter = new StreamWriter(tmpfile)) - streamWriter.Write(resultFormatSerializer.Serialize(result, m_logstorage)); + streamWriter.Write(resultFormatSerializer.Serialize(result, m_logstorage, null)); Execute(m_finishScript, "AFTER", m_operationName, ref m_remoteurl, ref m_localpath, m_timeout, false, m_options, tmpfile, level); } diff --git a/Duplicati/Library/Modules/Builtin/SendHttpMessage.cs b/Duplicati/Library/Modules/Builtin/SendHttpMessage.cs index e0dc9fdb8..ec1363c1f 100644 --- a/Duplicati/Library/Modules/Builtin/SendHttpMessage.cs +++ b/Duplicati/Library/Modules/Builtin/SendHttpMessage.cs @@ -191,6 +191,7 @@ namespace Duplicati.Library.Modules.Builtin { // No need to do the expansion as we throw away the result if (subjectline) return string.Empty; + return base.ReplaceTemplate(input, result, subjectline); }