// Copyright (C) 2024, The Duplicati Team // https://duplicati.com, hello@duplicati.com // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; using System.Linq; namespace Duplicati.Library.Logging { /// /// Instance of a log entry /// public class LogEntry { /// /// The time when the entry was logged /// public DateTime When; /// /// The message that was logged /// public readonly string Message; /// /// The string format arguments, if any /// public readonly object[] Arguments; /// /// The message level /// public readonly LogMessageType Level; /// /// The filter tag for the message /// public readonly string FilterTag; /// /// The filter tag for the message /// public readonly string Tag; /// /// The message help-id /// public readonly string Id; /// /// An optional exception /// public readonly Exception Exception; /// /// The log context data, if any /// private Dictionary m_logContext; /// /// Gets or sets the with the specified value. /// /// The key to use. public string this[string key] { get { if (m_logContext == null) return null; m_logContext.TryGetValue(key, out var s); return s; } set { if (m_logContext == null) m_logContext = new Dictionary(); m_logContext[key] = value; } } /// /// Gets the keys in this log context /// /// The context keys. public IEnumerable ContextKeys { get { if (m_logContext == null) return new string[0]; return m_logContext.Keys; } } /// /// Gets the message, formatted with arguments /// /// The formatted message. public string FormattedMessage { get { if (Arguments == null || Arguments.Length == 0) return Message; try { return string.Format(Message, Arguments); } catch { // Try no to crash ... return string.Format("Error while formating: \"{0}\" with arguments: [{1}]", Message, string.Join(", ", Arguments.Select(x => x == null ? "(null)" : x.ToString()))); } } } /// /// Initializes a new instance of the class. /// /// The message to use. /// An optional set of arguments. /// The log level. /// The tag to use. /// The message ID. /// An optional exception. public LogEntry(string message, object[] arguments, LogMessageType level, string tag, string id, Exception exception) { When = DateTime.Now; Message = message; Arguments = arguments; Level = level; Tag = tag; Id = id; Exception = exception; FilterTag = level + "-" + tag + "-" + id; } /// /// Returns a that represents the current . /// /// A that represents the current . public override string ToString() { return string.Format("{0:yyyy-MM-dd HH:mm:ss zz} - [{1}]: {2}", When.ToLocalTime(), FilterTag, FormattedMessage); } /// /// Returns the item as a string optionally with exception details /// /// A that represents the current . /// If set to true the result has expanded exception details. public string AsString(bool withExceptionDetails) { if (Exception == null) { return ToString(); } else { return this + Environment.NewLine + (withExceptionDetails ? Exception.ToString() : (Exception.GetType().Name + ": " + Exception.Message)); } } } }