Added some ObjectExtensions
This commit is contained in:
@@ -2,9 +2,9 @@
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>.netstandard2.1; net8.0; net4.8;</TargetFrameworks>
|
||||
<ApplicationIcon>icon.ico</ApplicationIcon>
|
||||
<Version>1.4.8</Version>
|
||||
<Version>1.4.9</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<FileVersion>1.4.8</FileVersion>
|
||||
<FileVersion>1.4.9</FileVersion>
|
||||
<Authors>EonaCat (Jeroen Saey)</Authors>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Company>EonaCat (Jeroen Saey)</Company>
|
||||
@@ -25,7 +25,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<EVRevisionFormat>1.4.8+{chash:10}.{c:ymd}</EVRevisionFormat>
|
||||
<EVRevisionFormat>1.4.9+{chash:10}.{c:ymd}</EVRevisionFormat>
|
||||
<EVDefault>true</EVDefault>
|
||||
<EVInfo>true</EVInfo>
|
||||
<EVTagMatch>v[0-9]*</EVTagMatch>
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
namespace EonaCat.Logger.Extensions;
|
||||
|
||||
// This file is part of the EonaCat project(s) which is released under the Apache License.
|
||||
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
|
||||
|
||||
public static class DateTimeExtensions
|
||||
{
|
||||
public static long ToUnixTimestamp(this DateTime dateTime)
|
||||
|
||||
@@ -1,98 +1,101 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
namespace EonaCat.Logger.Extensions;
|
||||
|
||||
public static class ExceptionExtensions
|
||||
{
|
||||
public static string FormatExceptionToMessage(this Exception exception, string module = null, string method = null)
|
||||
{
|
||||
if (exception == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var st = new StackTrace(exception, true);
|
||||
var frame = st.GetFrame(0);
|
||||
int fileLine = -1;
|
||||
string filename = "Unknown";
|
||||
|
||||
if (frame != null)
|
||||
{
|
||||
fileLine = frame.GetFileLineNumber();
|
||||
filename = frame.GetFileName();
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine();
|
||||
sb.AppendLine($"--- Exception details provided by {DllInfo.ApplicationName} ---");
|
||||
if (!string.IsNullOrEmpty(module))
|
||||
{
|
||||
sb.AppendLine(" Module : " + module);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(method))
|
||||
{
|
||||
sb.AppendLine(" Method : " + method);
|
||||
}
|
||||
|
||||
sb.Append(" Type : ").AppendLine(exception.GetType().ToString());
|
||||
sb.Append(" Data : ").AppendLine(exception.Data != null && exception.Data.Count > 0
|
||||
? FormatExceptionData(exception.Data)
|
||||
: "(none)");
|
||||
sb.Append(" Inner : ").AppendLine(exception.InnerException != null
|
||||
? FormatInnerException(exception.InnerException)
|
||||
: "(null)");
|
||||
sb.Append(" Message : ").AppendLine(exception.Message);
|
||||
sb.Append(" Source : ").AppendLine(exception.Source);
|
||||
sb.Append(" StackTrace : ").AppendLine(exception.StackTrace);
|
||||
sb.Append(" Line : ").AppendLine(fileLine.ToString());
|
||||
sb.Append(" File : ").AppendLine(filename);
|
||||
sb.Append(" ToString : ").AppendLine(exception.ToString());
|
||||
sb.AppendLine("---");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string FormatExceptionData(IDictionary data)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
foreach (DictionaryEntry entry in data)
|
||||
{
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
namespace EonaCat.Logger.Extensions;
|
||||
|
||||
// This file is part of the EonaCat project(s) which is released under the Apache License.
|
||||
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
|
||||
|
||||
public static class ExceptionExtensions
|
||||
{
|
||||
public static string FormatExceptionToMessage(this Exception exception, string module = null, string method = null)
|
||||
{
|
||||
if (exception == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var st = new StackTrace(exception, true);
|
||||
var frame = st.GetFrame(0);
|
||||
int fileLine = -1;
|
||||
string filename = "Unknown";
|
||||
|
||||
if (frame != null)
|
||||
{
|
||||
fileLine = frame.GetFileLineNumber();
|
||||
filename = frame.GetFileName();
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine();
|
||||
sb.AppendLine($"--- Exception details provided by {DllInfo.ApplicationName} ---");
|
||||
if (!string.IsNullOrEmpty(module))
|
||||
{
|
||||
sb.AppendLine(" Module : " + module);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(method))
|
||||
{
|
||||
sb.AppendLine(" Method : " + method);
|
||||
}
|
||||
|
||||
sb.Append(" Type : ").AppendLine(exception.GetType().ToString());
|
||||
sb.Append(" Data : ").AppendLine(exception.Data != null && exception.Data.Count > 0
|
||||
? FormatExceptionData(exception.Data)
|
||||
: "(none)");
|
||||
sb.Append(" Inner : ").AppendLine(exception.InnerException != null
|
||||
? FormatInnerException(exception.InnerException)
|
||||
: "(null)");
|
||||
sb.Append(" Message : ").AppendLine(exception.Message);
|
||||
sb.Append(" Source : ").AppendLine(exception.Source);
|
||||
sb.Append(" StackTrace : ").AppendLine(exception.StackTrace);
|
||||
sb.Append(" Line : ").AppendLine(fileLine.ToString());
|
||||
sb.Append(" File : ").AppendLine(filename);
|
||||
sb.Append(" ToString : ").AppendLine(exception.ToString());
|
||||
sb.AppendLine("---");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string FormatExceptionData(IDictionary data)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
foreach (DictionaryEntry entry in data)
|
||||
{
|
||||
if (entry.Key != null)
|
||||
{
|
||||
sb.Append(" | ")
|
||||
sb.Append(" | ")
|
||||
.Append(entry.Key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (entry.Value != null)
|
||||
{
|
||||
sb.Append(": ")
|
||||
sb.Append(": ")
|
||||
.AppendLine(entry.Value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string FormatInnerException(Exception innerException)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine(innerException.GetType().ToString())
|
||||
.AppendLine(" Message : " + innerException.Message)
|
||||
.AppendLine(" Source : " + innerException.Source)
|
||||
.AppendLine(" StackTrace : " + innerException.StackTrace)
|
||||
.AppendLine(" ToString : " + innerException)
|
||||
.Append(" Data : ")
|
||||
.AppendLine(innerException.Data != null && innerException.Data.Count > 0
|
||||
? FormatExceptionData(innerException.Data)
|
||||
: "(none)");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string FormatInnerException(Exception innerException)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine(innerException.GetType().ToString())
|
||||
.AppendLine(" Message : " + innerException.Message)
|
||||
.AppendLine(" Source : " + innerException.Source)
|
||||
.AppendLine(" StackTrace : " + innerException.StackTrace)
|
||||
.AppendLine(" ToString : " + innerException)
|
||||
.Append(" Data : ")
|
||||
.AppendLine(innerException.Data != null && innerException.Data.Count > 0
|
||||
? FormatExceptionData(innerException.Data)
|
||||
: "(none)");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
425
EonaCat.Logger/Extensions/ObjectExtensions.cs
Normal file
425
EonaCat.Logger/Extensions/ObjectExtensions.cs
Normal file
@@ -0,0 +1,425 @@
|
||||
using EonaCat.Json;
|
||||
using EonaCat.Json.Serialization;
|
||||
using EonaCat.Logger.Managers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace EonaCat.Logger.Extensions
|
||||
{
|
||||
// This file is part of the EonaCat project(s) which is released under the Apache License.
|
||||
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
|
||||
|
||||
public enum DumpFormat
|
||||
{
|
||||
Json,
|
||||
Xml,
|
||||
Tree
|
||||
}
|
||||
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Dumps any object to a string in JSON, XML, or detailed tree format.
|
||||
/// </summary>
|
||||
/// <param name="currentObject">Object to dump</param>
|
||||
/// <param name="format">"json" (default), "xml", or "tree"</param>
|
||||
/// <param name="detailed">For JSON: include private/internal fields. Ignored for tree format</param>
|
||||
/// <param name="maxDepth">Optional max depth for tree dump. Null = no limit</param>
|
||||
/// <param name="maxCollectionItems">Optional max items to display in collections. Null = show all</param>
|
||||
/// <returns>String representation of the object</returns>
|
||||
public static string Dump(this object currentObject, DumpFormat format = DumpFormat.Json, bool detailed = false, int? maxDepth = null, int? maxCollectionItems = null)
|
||||
{
|
||||
if (currentObject == null)
|
||||
{
|
||||
return "null";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case DumpFormat.Xml:
|
||||
return DumpXml(currentObject);
|
||||
case DumpFormat.Tree:
|
||||
return DumpTree(currentObject, maxDepth, maxCollectionItems);
|
||||
case DumpFormat.Json:
|
||||
default:
|
||||
return DumpJson(currentObject, detailed);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return $"Error dumping object: {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
private static string DumpJson(object currentObject, bool isDetailed)
|
||||
{
|
||||
var settings = new JsonSerializerSettings
|
||||
{
|
||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
|
||||
Formatting = Formatting.Indented
|
||||
};
|
||||
|
||||
if (isDetailed)
|
||||
{
|
||||
settings.ContractResolver = new DefaultContractResolver
|
||||
{
|
||||
IgnoreSerializableAttribute = false,
|
||||
IgnoreSerializableInterface = false
|
||||
};
|
||||
}
|
||||
|
||||
return JsonHelper.ToJson(currentObject, settings);
|
||||
}
|
||||
|
||||
private static string DumpXml(object currentObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
var xmlSerializer = new XmlSerializer(currentObject.GetType());
|
||||
using (var stringWriter = new StringWriter())
|
||||
{
|
||||
xmlSerializer.Serialize(stringWriter, currentObject);
|
||||
return stringWriter.ToString();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return $"XML serialization failed: {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
private static string DumpTree(object currentObject, int? maxDepth, int? maxCollectionItems)
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
var visitedHashSet = new HashSet<object>(new ReferenceEqualityComparer());
|
||||
DumpTreeInternal(currentObject, stringBuilder, 0, visitedHashSet, maxDepth, maxCollectionItems);
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
private static void DumpTreeInternal(object currentObject, StringBuilder stringBuilder, int indent, HashSet<object> visited, int? maxDepth, int? maxCollectionItems)
|
||||
{
|
||||
string indentation = new string(' ', indent * 2);
|
||||
|
||||
if (currentObject == null)
|
||||
{
|
||||
stringBuilder.AppendLine($"{indentation}null");
|
||||
return;
|
||||
}
|
||||
|
||||
Type type = currentObject.GetType();
|
||||
string typeName = type.FullName;
|
||||
|
||||
if (IsPrimitive(type))
|
||||
{
|
||||
stringBuilder.AppendLine($"{indentation}{currentObject} ({typeName})");
|
||||
return;
|
||||
}
|
||||
|
||||
if (visited.Contains(currentObject))
|
||||
{
|
||||
stringBuilder.AppendLine($"{indentation}<<circular reference to {typeName}>>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (maxDepth.HasValue && indent >= maxDepth.Value)
|
||||
{
|
||||
stringBuilder.AppendLine($"{indentation}<<max depth reached: {typeName}>>");
|
||||
return;
|
||||
}
|
||||
|
||||
visited.Add(currentObject);
|
||||
|
||||
if (currentObject is IEnumerable enumerable && !(currentObject is string))
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
foreach (var _ in enumerable)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
if (maxCollectionItems.HasValue && count > maxCollectionItems.Value)
|
||||
{
|
||||
stringBuilder.AppendLine($"{indentation}{typeName} [<<{count} items, collapsed>>]");
|
||||
return;
|
||||
}
|
||||
|
||||
stringBuilder.AppendLine($"{indentation}{typeName} [");
|
||||
|
||||
foreach (var item in enumerable)
|
||||
{
|
||||
DumpTreeInternal(item, stringBuilder, indent + 1, visited, maxDepth, maxCollectionItems);
|
||||
}
|
||||
stringBuilder.AppendLine($"{indentation}]");
|
||||
}
|
||||
else
|
||||
{
|
||||
stringBuilder.AppendLine($"{indentation}{typeName} {{");
|
||||
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
||||
var members = type.GetFields(flags);
|
||||
|
||||
foreach (var field in members)
|
||||
{
|
||||
object value = null;
|
||||
|
||||
try
|
||||
{
|
||||
value = field.GetValue(currentObject);
|
||||
}
|
||||
catch
|
||||
{
|
||||
value = "<<unavailable>>";
|
||||
}
|
||||
|
||||
stringBuilder.Append($"{indentation} {field.Name} = ");
|
||||
DumpTreeInternal(value, stringBuilder, indent + 1, visited, maxDepth, maxCollectionItems);
|
||||
}
|
||||
|
||||
var properties = type.GetProperties(flags);
|
||||
|
||||
foreach (var current in properties)
|
||||
{
|
||||
if (current.GetIndexParameters().Length > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
object value = null;
|
||||
try { value = current.GetValue(currentObject); } catch { value = "<<unavailable>>"; }
|
||||
stringBuilder.Append($"{indentation} {current.Name} = ");
|
||||
DumpTreeInternal(value, stringBuilder, indent + 1, visited, maxDepth, maxCollectionItems);
|
||||
}
|
||||
|
||||
stringBuilder.AppendLine($"{indentation}}}");
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsPrimitive(Type type)
|
||||
{
|
||||
return type.IsPrimitive
|
||||
|| type.IsEnum
|
||||
|| type == typeof(string)
|
||||
|| type == typeof(decimal)
|
||||
|| type == typeof(DateTime)
|
||||
|| type == typeof(DateTimeOffset)
|
||||
|| type == typeof(Guid)
|
||||
|| type == typeof(TimeSpan);
|
||||
}
|
||||
|
||||
private class ReferenceEqualityComparer : IEqualityComparer<object>
|
||||
{
|
||||
public new bool Equals(object x, object y) => ReferenceEquals(x, y);
|
||||
public int GetHashCode(object obj) => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj);
|
||||
}
|
||||
|
||||
public static void ForEach<T>(this IEnumerable<T> items, Action<T> action)
|
||||
{
|
||||
if (items == null || action == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
action(item);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Check if collection is null or empty</summary>
|
||||
public static bool IsNullOrEmpty<T>(this IEnumerable<T> items) => items == null || !items.Any();
|
||||
|
||||
/// <summary>Check if collection has items</summary>
|
||||
public static bool HasItems<T>(this IEnumerable<T> items) => !items.IsNullOrEmpty();
|
||||
|
||||
/// <summary>Safe get by index</summary>
|
||||
public static T SafeGet<T>(this IList<T> list, int index, T defaultValue = default)
|
||||
{
|
||||
if (list == null || index < 0 || index >= list.Count)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return list[index];
|
||||
}
|
||||
|
||||
/// <summary>Convert collection to delimited string</summary>
|
||||
public static string ToDelimitedString<T>(this IEnumerable<T> items, string delimiter = ", ")
|
||||
{
|
||||
return items == null ? "" : string.Join(delimiter, items);
|
||||
}
|
||||
|
||||
public static bool IsNullOrWhiteSpace(this string s) => string.IsNullOrWhiteSpace(s);
|
||||
|
||||
public static string Truncate(this string s, int maxLength)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s))
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
return s.Length <= maxLength ? s : s.Substring(0, maxLength);
|
||||
}
|
||||
|
||||
public static bool ContainsIgnoreCase(this string s, string value) =>
|
||||
s?.IndexOf(value ?? "", StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
|
||||
public static string OrDefault(this string s, string defaultValue) =>
|
||||
string.IsNullOrEmpty(s) ? defaultValue : s;
|
||||
|
||||
public static bool IsWeekend(this DateTime date) =>
|
||||
date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday;
|
||||
|
||||
public static DateTime StartOfDay(this DateTime date) =>
|
||||
date.Date;
|
||||
|
||||
public static DateTime EndOfDay(this DateTime date) =>
|
||||
date.Date.AddDays(1).AddTicks(-1);
|
||||
|
||||
/// <summary>
|
||||
/// Log an object only if a condition is true.
|
||||
/// </summary>
|
||||
public static async Task LogIfAsync(this LogManager logger, object currentObject, Func<object, bool> condition,
|
||||
ELogType logType = ELogType.INFO, string message = null)
|
||||
{
|
||||
if (logger == null || currentObject == null || condition == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (condition(currentObject))
|
||||
{
|
||||
string output = message ?? currentObject.Dump();
|
||||
await logger.WriteAsync(output, logType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static IDisposable BeginLoggingScope(this ILogger logger, object context)
|
||||
{
|
||||
if (logger == null || context == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return logger.BeginScope(context.ToDictionary());
|
||||
}
|
||||
|
||||
public static void LogExecutionTime(this ILogger logger, Action action, string operationName)
|
||||
{
|
||||
if (logger == null || action == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var sw = System.Diagnostics.Stopwatch.StartNew();
|
||||
action();
|
||||
sw.Stop();
|
||||
logger.LogInformation("{Operation} executed in {ElapsedMilliseconds}ms", operationName, sw.ElapsedMilliseconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Unix timestamp, expressed as the number of seconds since the Unix epoch, to a local DateTime
|
||||
/// value.
|
||||
/// </summary>
|
||||
/// <remarks>The returned DateTime is expressed in the local time zone. To obtain a UTC DateTime,
|
||||
/// use DateTimeOffset.FromUnixTimeSeconds(timestamp).UtcDateTime instead.</remarks>
|
||||
/// <param name="timestamp">The Unix timestamp representing the number of seconds that have elapsed since 00:00:00 UTC on 1 January
|
||||
/// 1970.</param>
|
||||
/// <returns>A DateTime value that represents the local date and time equivalent of the specified Unix timestamp.</returns>
|
||||
public static DateTime FromUnixTimestamp(this long timestamp) =>
|
||||
DateTimeOffset.FromUnixTimeSeconds(timestamp).DateTime;
|
||||
|
||||
/// <summary>
|
||||
/// Executes the specified task without waiting for its completion and handles any exceptions that occur during
|
||||
/// its execution.
|
||||
/// </summary>
|
||||
/// <remarks>Use this method to start a task when you do not need to await its completion but want
|
||||
/// to ensure that exceptions are observed. This method should be used with caution, as exceptions may be
|
||||
/// handled asynchronously and may not be propagated to the calling context. Avoid using this method for tasks
|
||||
/// that must complete before continuing execution.</remarks>
|
||||
/// <param name="task">The task to execute in a fire-and-forget manner. Cannot be null.</param>
|
||||
/// <param name="onError">An optional callback that is invoked if the task throws an exception. If not provided, exceptions are
|
||||
/// written to the console.</param>
|
||||
public static async void FireAndForget(this Task task, Action<Exception> onError = null)
|
||||
{
|
||||
if (task == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try { await task; }
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (onError != null)
|
||||
{
|
||||
onError(ex);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("FireAndForget Exception: " + ex.FormatExceptionToMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Check if object has property</summary>
|
||||
public static bool HasProperty(this object obj, string name) =>
|
||||
obj != null && obj.GetType().GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) != null;
|
||||
|
||||
/// <summary>Get property value safely</summary>
|
||||
public static object GetPropertyValue(this object obj, string name)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var prop = obj.GetType().GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
return prop?.GetValue(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a dictionary containing the public and non-public instance properties and fields of the specified
|
||||
/// object.
|
||||
/// </summary>
|
||||
/// <remarks>Indexed properties are excluded from the resulting dictionary. Both public and
|
||||
/// non-public instance members are included. If multiple members share the same name, property values will
|
||||
/// overwrite field values with the same name.</remarks>
|
||||
/// <param name="obj">The object whose properties and fields are to be included in the dictionary. Can be null.</param>
|
||||
/// <returns>A dictionary with the names and values of the object's properties and fields. If the object is null, returns
|
||||
/// an empty dictionary.</returns>
|
||||
public static Dictionary<string, object> ToDictionary(this object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
var dict = new Dictionary<string, object>();
|
||||
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
||||
foreach (var prop in obj.GetType().GetProperties(flags))
|
||||
{
|
||||
if (prop.GetIndexParameters().Length > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
dict[prop.Name] = prop.GetValue(obj);
|
||||
}
|
||||
foreach (var field in obj.GetType().GetFields(flags))
|
||||
{
|
||||
dict[field.Name] = field.GetValue(obj);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,6 +76,21 @@ namespace EonaCat.Logger.Managers
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public async Task WriteAsync(object currentObject, ELogType logType = ELogType.INFO, bool? writeToConsole = null,
|
||||
string customSplunkSourceType = null,
|
||||
string grayLogFacility = null, string grayLogSource = null,
|
||||
string grayLogVersion = "1.1", bool disableSplunkSSL = false, DumpFormat dumpFormat = DumpFormat.Json, bool isDetailedDump = false, int? dumpDepth = null, int? maxCollectionItems = null)
|
||||
{
|
||||
if (currentObject == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await WriteAsync(currentObject.Dump(dumpFormat, isDetailedDump, dumpDepth, maxCollectionItems), logType, writeToConsole,
|
||||
customSplunkSourceType, grayLogFacility, grayLogSource,
|
||||
grayLogVersion, disableSplunkSSL);
|
||||
}
|
||||
|
||||
public async Task WriteAsync(Exception exception, string module = null, string method = null,
|
||||
bool criticalException = false,
|
||||
bool? writeToConsole = null, string customSplunkSourceType = null, string grayLogFacility = null,
|
||||
|
||||
@@ -1,343 +1,343 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Text.RegularExpressions;
|
||||
using EonaCat.Json.Linq;
|
||||
using EonaCat.Logger.EonaCatCoreLogger;
|
||||
using EonaCat.Logger.EonaCatCoreLogger.Models;
|
||||
using EonaCat.Logger.Servers.GrayLog;
|
||||
|
||||
namespace EonaCat.Logger.Managers;
|
||||
// This file is part of the EonaCat project(s) which is released under the Apache License.
|
||||
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
|
||||
|
||||
/// <summary>
|
||||
/// Logger settings.
|
||||
/// </summary>
|
||||
public class LoggerSettings
|
||||
{
|
||||
public delegate void LogDelegate(EonaCatLogMessage message);
|
||||
|
||||
private ColorSchema _colors = new();
|
||||
private bool _enableConsole = true;
|
||||
|
||||
private FileLoggerOptions _fileLoggerOptions;
|
||||
|
||||
private string _headerFormat = "{ts} {host} {category} {thread} {sev}";
|
||||
private string _timestampFormat = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
/// <summary>
|
||||
/// Determines if we need to use the local time in the logging or UTC (default:false)
|
||||
/// </summary>
|
||||
public bool UseLocalTime { get; set; }
|
||||
|
||||
public string Id { get; set; } = DllInfo.ApplicationName;
|
||||
|
||||
/// <summary>
|
||||
/// Header format. Provide a string that specifies how the preamble of each message should be structured. You can use
|
||||
/// variables including:
|
||||
/// {ts}: UTC timestamp
|
||||
/// {host}: Hostname
|
||||
/// {category}: Category
|
||||
/// {thread}: Thread ID
|
||||
/// {sev}: Severity
|
||||
/// Default: {ts} {host} {category} {thread} {sev}
|
||||
/// A space will be inserted between the header and the message.
|
||||
/// </summary>
|
||||
public string HeaderFormat
|
||||
{
|
||||
get => _headerFormat;
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
_headerFormat = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
_headerFormat = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp format.
|
||||
/// </summary>
|
||||
public string TimestampFormat
|
||||
{
|
||||
get => _timestampFormat;
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(HeaderFormat));
|
||||
}
|
||||
|
||||
_timestampFormat = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable or disable console logging.
|
||||
/// Settings this to true will first validate if a console exists.
|
||||
/// If a console is not available, it will be set to false.
|
||||
/// </summary>
|
||||
public bool EnableConsole
|
||||
{
|
||||
get => _enableConsole;
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
_enableConsole = ConsoleExists();
|
||||
}
|
||||
else
|
||||
{
|
||||
_enableConsole = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable or disable use of color for console messages.
|
||||
/// </summary>
|
||||
public bool EnableColors { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Colors to use for console messages based on message severity.
|
||||
/// </summary>
|
||||
public ColorSchema Colors
|
||||
{
|
||||
get => _colors;
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Colors));
|
||||
}
|
||||
|
||||
_colors = value;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<ELogType> _defaultLogTypes = new List<ELogType> { ELogType.INFO, ELogType.WARNING, ELogType.ERROR, ELogType.TRAFFIC, ELogType.DEBUG, ELogType.CRITICAL, ELogType.TRACE };
|
||||
private List<ELogType> _logTypes = new List<ELogType> { ELogType.INFO, ELogType.WARNING, ELogType.ERROR, ELogType.TRAFFIC, ELogType.DEBUG, ELogType.CRITICAL, ELogType.TRACE };
|
||||
public List<ELogType> TypesToLog
|
||||
{
|
||||
get
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Text.RegularExpressions;
|
||||
using EonaCat.Json.Linq;
|
||||
using EonaCat.Logger.EonaCatCoreLogger;
|
||||
using EonaCat.Logger.EonaCatCoreLogger.Models;
|
||||
using EonaCat.Logger.Servers.GrayLog;
|
||||
|
||||
namespace EonaCat.Logger.Managers;
|
||||
// This file is part of the EonaCat project(s) which is released under the Apache License.
|
||||
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
|
||||
|
||||
/// <summary>
|
||||
/// Logger settings.
|
||||
/// </summary>
|
||||
public class LoggerSettings
|
||||
{
|
||||
public delegate void LogDelegate(EonaCatLogMessage message);
|
||||
|
||||
private ColorSchema _colors = new();
|
||||
private bool _enableConsole = true;
|
||||
|
||||
private FileLoggerOptions _fileLoggerOptions;
|
||||
|
||||
private string _headerFormat = "{ts} {host} {category} {thread} {sev}";
|
||||
private string _timestampFormat = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
/// <summary>
|
||||
/// Determines if we need to use the local time in the logging or UTC (default:false)
|
||||
/// </summary>
|
||||
public bool UseLocalTime { get; set; }
|
||||
|
||||
public string Id { get; set; } = DllInfo.ApplicationName;
|
||||
|
||||
/// <summary>
|
||||
/// Header format. Provide a string that specifies how the preamble of each message should be structured. You can use
|
||||
/// variables including:
|
||||
/// {ts}: UTC timestamp
|
||||
/// {host}: Hostname
|
||||
/// {category}: Category
|
||||
/// {thread}: Thread ID
|
||||
/// {sev}: Severity
|
||||
/// Default: {ts} {host} {category} {thread} {sev}
|
||||
/// A space will be inserted between the header and the message.
|
||||
/// </summary>
|
||||
public string HeaderFormat
|
||||
{
|
||||
get => _headerFormat;
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
_headerFormat = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
_headerFormat = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp format.
|
||||
/// </summary>
|
||||
public string TimestampFormat
|
||||
{
|
||||
get => _timestampFormat;
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(HeaderFormat));
|
||||
}
|
||||
|
||||
_timestampFormat = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable or disable console logging.
|
||||
/// Settings this to true will first validate if a console exists.
|
||||
/// If a console is not available, it will be set to false.
|
||||
/// </summary>
|
||||
public bool EnableConsole
|
||||
{
|
||||
get => _enableConsole;
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
_enableConsole = ConsoleExists();
|
||||
}
|
||||
else
|
||||
{
|
||||
_enableConsole = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable or disable use of color for console messages.
|
||||
/// </summary>
|
||||
public bool EnableColors { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Colors to use for console messages based on message severity.
|
||||
/// </summary>
|
||||
public ColorSchema Colors
|
||||
{
|
||||
get => _colors;
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Colors));
|
||||
}
|
||||
|
||||
_colors = value;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<ELogType> _defaultLogTypes = new List<ELogType> { ELogType.INFO, ELogType.WARNING, ELogType.ERROR, ELogType.TRAFFIC, ELogType.DEBUG, ELogType.CRITICAL, ELogType.TRACE };
|
||||
private List<ELogType> _logTypes = new List<ELogType> { ELogType.INFO, ELogType.WARNING, ELogType.ERROR, ELogType.TRAFFIC, ELogType.DEBUG, ELogType.CRITICAL, ELogType.TRACE };
|
||||
public List<ELogType> TypesToLog
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_logTypes == null)
|
||||
{
|
||||
_logTypes = _defaultLogTypes;
|
||||
}
|
||||
return _logTypes;
|
||||
}
|
||||
|
||||
set
|
||||
}
|
||||
return _logTypes;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_logTypes = value;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Servers.Syslog.Syslog> SysLogServers { get; internal set; }
|
||||
public List<Servers.Splunk.Splunk> SplunkServers { get; internal set; }
|
||||
|
||||
public List<Graylog> GrayLogServers { get; internal set; }
|
||||
public List<Servers.Tcp.Tcp> TcpServers { get; internal set; }
|
||||
|
||||
public List<Servers.Udp.Udp> UdpServers { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the fileLogging is enabled
|
||||
/// </summary>
|
||||
public bool EnableFileLogging { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// FileLogger settings.
|
||||
/// </summary>
|
||||
public FileLoggerOptions FileLoggerOptions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_fileLoggerOptions == null)
|
||||
{
|
||||
_fileLoggerOptions = CreateDefaultFileLoggerOptions();
|
||||
}
|
||||
|
||||
return _fileLoggerOptions;
|
||||
}
|
||||
|
||||
set => _fileLoggerOptions = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the origin of where the OnLog event was initiated
|
||||
/// </summary>
|
||||
public string LogOrigin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if we need to mask certain keywords
|
||||
/// </summary>
|
||||
public bool UseMask { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines the keywords to mask
|
||||
/// </summary>
|
||||
public List<string> MaskedKeywords { get; set; } = new List<string>();
|
||||
public string Mask { get; set; } = "***MASKED***";
|
||||
|
||||
/// <summary>
|
||||
/// Determines that if masking is enabled we also need to use the default masking options:
|
||||
/// IP addresses
|
||||
/// MAC addresses
|
||||
/// Emails
|
||||
/// Passwords
|
||||
/// Credit card numbers
|
||||
/// Social security numbers (SSN) and BSN (Dutch Citizen Service Number)
|
||||
/// API keys/tokens
|
||||
/// Phone numbers (generic and Dutch specific)
|
||||
/// Dates of birth (DOB) or other date formats
|
||||
/// IBAN/Bank account numbers (generic and Dutch specific)
|
||||
/// JWT tokens
|
||||
/// URLs with sensitive query strings
|
||||
/// License keys
|
||||
/// Public and private keys (e.g., PEM format)
|
||||
/// Dutch KVK number (8 or 12 digits)
|
||||
/// Dutch BTW-nummer (VAT number)
|
||||
/// Dutch driving license number (10-12 characters)
|
||||
/// Dutch health insurance number (Zorgnummer)
|
||||
/// Other Dutch Bank Account numbers (9-10 digits)
|
||||
/// Dutch Passport Numbers (9 alphanumeric characters
|
||||
/// Dutch Identification Document Numbers (varying formats)
|
||||
/// Custom keywords specified in LoggerSettings
|
||||
/// </summary>
|
||||
public bool UseDefaultMasking { get; set; } = true;
|
||||
|
||||
public event LogDelegate OnLog;
|
||||
|
||||
private static FileLoggerOptions CreateDefaultFileLoggerOptions()
|
||||
{
|
||||
return new FileLoggerOptions();
|
||||
}
|
||||
|
||||
|
||||
private static bool ConsoleExists()
|
||||
{
|
||||
try
|
||||
{
|
||||
var test1 = Environment.UserInteractive;
|
||||
var test2 = Console.WindowHeight > 0;
|
||||
return test1 && test2;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnLogEvent(EonaCatLogMessage eonaCatLogMessage)
|
||||
{
|
||||
OnLog?.Invoke(eonaCatLogMessage);
|
||||
}
|
||||
|
||||
internal void ResetLogEvent()
|
||||
{
|
||||
OnLog = null;
|
||||
}
|
||||
|
||||
public void AllowAllLogTypes()
|
||||
{
|
||||
TypesToLog.Clear();
|
||||
}
|
||||
|
||||
public void LogInfo()
|
||||
{
|
||||
if (TypesToLog == null)
|
||||
{
|
||||
TypesToLog = new List<ELogType>();
|
||||
}
|
||||
|
||||
if (!TypesToLog.Contains(ELogType.INFO))
|
||||
{
|
||||
TypesToLog.Add(ELogType.INFO);
|
||||
}
|
||||
}
|
||||
|
||||
public void LogWarning()
|
||||
{
|
||||
if (TypesToLog == null)
|
||||
{
|
||||
TypesToLog = new List<ELogType>();
|
||||
}
|
||||
|
||||
if (!TypesToLog.Contains(ELogType.WARNING))
|
||||
{
|
||||
TypesToLog.Add(ELogType.WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
public void LogError()
|
||||
{
|
||||
if (TypesToLog == null)
|
||||
{
|
||||
TypesToLog = new List<ELogType>();
|
||||
}
|
||||
|
||||
if (!TypesToLog.Contains(ELogType.ERROR))
|
||||
{
|
||||
TypesToLog.Add(ELogType.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
public void LogCritical()
|
||||
{
|
||||
if (TypesToLog == null)
|
||||
{
|
||||
TypesToLog = new List<ELogType>();
|
||||
}
|
||||
|
||||
if (!TypesToLog.Contains(ELogType.CRITICAL))
|
||||
{
|
||||
TypesToLog.Add(ELogType.CRITICAL);
|
||||
}
|
||||
}
|
||||
|
||||
public void LogTraffic()
|
||||
{
|
||||
if (TypesToLog == null)
|
||||
{
|
||||
TypesToLog = new List<ELogType>();
|
||||
}
|
||||
|
||||
if (!TypesToLog.Contains(ELogType.TRAFFIC))
|
||||
{
|
||||
TypesToLog.Add(ELogType.TRAFFIC);
|
||||
}
|
||||
}
|
||||
|
||||
public void LogTrace()
|
||||
{
|
||||
if (TypesToLog == null)
|
||||
{
|
||||
TypesToLog = new List<ELogType>();
|
||||
}
|
||||
|
||||
if (!TypesToLog.Contains(ELogType.TRACE))
|
||||
{
|
||||
TypesToLog.Add(ELogType.TRACE);
|
||||
}
|
||||
}
|
||||
|
||||
public void LogDebug()
|
||||
{
|
||||
if (TypesToLog == null)
|
||||
{
|
||||
TypesToLog = new List<ELogType>();
|
||||
}
|
||||
|
||||
if (!TypesToLog.Contains(ELogType.DEBUG))
|
||||
{
|
||||
TypesToLog.Add(ELogType.DEBUG);
|
||||
}
|
||||
}
|
||||
_logTypes = value;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Servers.Syslog.Syslog> SysLogServers { get; internal set; }
|
||||
public List<Servers.Splunk.Splunk> SplunkServers { get; internal set; }
|
||||
|
||||
public List<Graylog> GrayLogServers { get; internal set; }
|
||||
public List<Servers.Tcp.Tcp> TcpServers { get; internal set; }
|
||||
|
||||
public List<Servers.Udp.Udp> UdpServers { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the fileLogging is enabled
|
||||
/// </summary>
|
||||
public bool EnableFileLogging { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// FileLogger settings.
|
||||
/// </summary>
|
||||
public FileLoggerOptions FileLoggerOptions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_fileLoggerOptions == null)
|
||||
{
|
||||
_fileLoggerOptions = CreateDefaultFileLoggerOptions();
|
||||
}
|
||||
|
||||
return _fileLoggerOptions;
|
||||
}
|
||||
|
||||
set => _fileLoggerOptions = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the origin of where the OnLog event was initiated
|
||||
/// </summary>
|
||||
public string LogOrigin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if we need to mask certain keywords
|
||||
/// </summary>
|
||||
public bool UseMask { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines the keywords to mask
|
||||
/// </summary>
|
||||
public List<string> MaskedKeywords { get; set; } = new List<string>();
|
||||
public string Mask { get; set; } = "***MASKED***";
|
||||
|
||||
/// <summary>
|
||||
/// Determines that if masking is enabled we also need to use the default masking options:
|
||||
/// IP addresses
|
||||
/// MAC addresses
|
||||
/// Emails
|
||||
/// Passwords
|
||||
/// Credit card numbers
|
||||
/// Social security numbers (SSN) and BSN (Dutch Citizen Service Number)
|
||||
/// API keys/tokens
|
||||
/// Phone numbers (generic and Dutch specific)
|
||||
/// Dates of birth (DOB) or other date formats
|
||||
/// IBAN/Bank account numbers (generic and Dutch specific)
|
||||
/// JWT tokens
|
||||
/// URLs with sensitive query strings
|
||||
/// License keys
|
||||
/// Public and private keys (e.g., PEM format)
|
||||
/// Dutch KVK number (8 or 12 digits)
|
||||
/// Dutch BTW-nummer (VAT number)
|
||||
/// Dutch driving license number (10-12 characters)
|
||||
/// Dutch health insurance number (Zorgnummer)
|
||||
/// Other Dutch Bank Account numbers (9-10 digits)
|
||||
/// Dutch Passport Numbers (9 alphanumeric characters
|
||||
/// Dutch Identification Document Numbers (varying formats)
|
||||
/// Custom keywords specified in LoggerSettings
|
||||
/// </summary>
|
||||
public bool UseDefaultMasking { get; set; } = true;
|
||||
|
||||
public event LogDelegate OnLog;
|
||||
|
||||
private static FileLoggerOptions CreateDefaultFileLoggerOptions()
|
||||
{
|
||||
return new FileLoggerOptions();
|
||||
}
|
||||
|
||||
|
||||
private static bool ConsoleExists()
|
||||
{
|
||||
try
|
||||
{
|
||||
var test1 = Environment.UserInteractive;
|
||||
var test2 = Console.WindowHeight > 0;
|
||||
return test1 && test2;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnLogEvent(EonaCatLogMessage eonaCatLogMessage)
|
||||
{
|
||||
OnLog?.Invoke(eonaCatLogMessage);
|
||||
}
|
||||
|
||||
internal void ResetLogEvent()
|
||||
{
|
||||
OnLog = null;
|
||||
}
|
||||
|
||||
public void AllowAllLogTypes()
|
||||
{
|
||||
TypesToLog.Clear();
|
||||
}
|
||||
|
||||
public void LogInfo()
|
||||
{
|
||||
if (TypesToLog == null)
|
||||
{
|
||||
TypesToLog = new List<ELogType>();
|
||||
}
|
||||
|
||||
if (!TypesToLog.Contains(ELogType.INFO))
|
||||
{
|
||||
TypesToLog.Add(ELogType.INFO);
|
||||
}
|
||||
}
|
||||
|
||||
public void LogWarning()
|
||||
{
|
||||
if (TypesToLog == null)
|
||||
{
|
||||
TypesToLog = new List<ELogType>();
|
||||
}
|
||||
|
||||
if (!TypesToLog.Contains(ELogType.WARNING))
|
||||
{
|
||||
TypesToLog.Add(ELogType.WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
public void LogError()
|
||||
{
|
||||
if (TypesToLog == null)
|
||||
{
|
||||
TypesToLog = new List<ELogType>();
|
||||
}
|
||||
|
||||
if (!TypesToLog.Contains(ELogType.ERROR))
|
||||
{
|
||||
TypesToLog.Add(ELogType.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
public void LogCritical()
|
||||
{
|
||||
if (TypesToLog == null)
|
||||
{
|
||||
TypesToLog = new List<ELogType>();
|
||||
}
|
||||
|
||||
if (!TypesToLog.Contains(ELogType.CRITICAL))
|
||||
{
|
||||
TypesToLog.Add(ELogType.CRITICAL);
|
||||
}
|
||||
}
|
||||
|
||||
public void LogTraffic()
|
||||
{
|
||||
if (TypesToLog == null)
|
||||
{
|
||||
TypesToLog = new List<ELogType>();
|
||||
}
|
||||
|
||||
if (!TypesToLog.Contains(ELogType.TRAFFIC))
|
||||
{
|
||||
TypesToLog.Add(ELogType.TRAFFIC);
|
||||
}
|
||||
}
|
||||
|
||||
public void LogTrace()
|
||||
{
|
||||
if (TypesToLog == null)
|
||||
{
|
||||
TypesToLog = new List<ELogType>();
|
||||
}
|
||||
|
||||
if (!TypesToLog.Contains(ELogType.TRACE))
|
||||
{
|
||||
TypesToLog.Add(ELogType.TRACE);
|
||||
}
|
||||
}
|
||||
|
||||
public void LogDebug()
|
||||
{
|
||||
if (TypesToLog == null)
|
||||
{
|
||||
TypesToLog = new List<ELogType>();
|
||||
}
|
||||
|
||||
if (!TypesToLog.Contains(ELogType.DEBUG))
|
||||
{
|
||||
TypesToLog.Add(ELogType.DEBUG);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user