diff --git a/EonaCat.Logger/EonaCat.Logger.csproj b/EonaCat.Logger/EonaCat.Logger.csproj
index ed3d15e..e22a245 100644
--- a/EonaCat.Logger/EonaCat.Logger.csproj
+++ b/EonaCat.Logger/EonaCat.Logger.csproj
@@ -3,7 +3,7 @@
.netstandard2.1; net6.0; net7.0; net8.0; net4.8;
icon.ico
latest
- 1.4.5
+ 1.4.6
EonaCat (Jeroen Saey)
true
EonaCat (Jeroen Saey)
@@ -24,7 +24,7 @@
- 1.4.5+{chash:10}.{c:ymd}
+ 1.4.6+{chash:10}.{c:ymd}
true
true
v[0-9]*
@@ -51,15 +51,16 @@
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
-
+
+
+
diff --git a/EonaCat.Logger/EonaCatCoreLogger/ElasticSearchLogger.cs b/EonaCat.Logger/EonaCatCoreLogger/ElasticSearchLogger.cs
new file mode 100644
index 0000000..5ba6d1b
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/ElasticSearchLogger.cs
@@ -0,0 +1,182 @@
+using System.Linq;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ using Microsoft.Extensions.Logging;
+ using System;
+ using System.Collections.Generic;
+ using System.Net.Http;
+ using System.Text;
+ using System.Text.Json;
+ using System.Threading.Tasks;
+
+ public class ElasticSearchLogger : ILogger
+ {
+ private readonly string _categoryName;
+ private readonly ElasticSearchLoggerOptions _options;
+ private static readonly HttpClient _httpClient = new HttpClient();
+ private static readonly List _buffer = new List();
+ private static readonly object _lock = new object();
+ private static bool _flushLoopStarted = false;
+ public event EventHandler OnException;
+ public event EventHandler OnInvalidStatusCode;
+ private readonly LoggerScopedContext _context = new();
+ public bool IncludeCorrelationId { get; set; }
+
+ public ElasticSearchLogger(string categoryName, ElasticSearchLoggerOptions options)
+ {
+ _categoryName = categoryName;
+ _options = options;
+ IncludeCorrelationId = options.IncludeCorrelationId;
+
+ if (!_flushLoopStarted)
+ {
+ _flushLoopStarted = true;
+ Task.Run(FlushLoopAsync);
+ }
+ }
+
+ public void SetContext(string key, string value) => _context.Set(key, value);
+ public void ClearContext() => _context.Clear();
+ public string GetContext(string key) => _context.Get(key);
+
+ public IDisposable BeginScope(TState state) => null;
+ public bool IsEnabled(LogLevel logLevel) => _options.IsEnabled;
+
+ public void Log(LogLevel logLevel, EventId eventId, TState state,
+ Exception exception, Func formatter)
+ {
+ if (!_options.IsEnabled || formatter == null)
+ {
+ return;
+ }
+
+ // Get correlation ID from context or generate new one
+ if (IncludeCorrelationId)
+ {
+ var correlationId = _context.Get("CorrelationId") ?? Guid.NewGuid().ToString();
+ _context.Set("CorrelationId", correlationId);
+ }
+
+ // Prepare the log entry
+ var logDoc = new
+ {
+ timestamp = DateTime.UtcNow,
+ level = logLevel.ToString(),
+ category = _categoryName,
+ message = formatter(state, exception),
+ exception = exception?.ToString(),
+ eventId = eventId.Id,
+ customContext = _context.GetAll()
+ };
+
+ // Serialize log to JSON
+ string json = JsonSerializer.Serialize(logDoc);
+
+ // Add to the buffer
+ lock (_lock)
+ {
+ _buffer.Add(json);
+ if (_buffer.Count >= _options.RetryBufferSize)
+ {
+ _ = FlushBufferAsync();
+ }
+ }
+ }
+
+ private async Task FlushLoopAsync()
+ {
+ while (true)
+ {
+ await Task.Delay(TimeSpan.FromSeconds(_options.FlushIntervalSeconds));
+ await FlushBufferAsync();
+ }
+ }
+
+ private async Task FlushBufferAsync()
+ {
+ List toSend;
+ lock (_lock)
+ {
+ if (_buffer.Count == 0) return;
+ toSend = new List(_buffer);
+ _buffer.Clear();
+ }
+
+ // Elasticsearch URL with dynamic index
+ string indexName = $"{_options.IndexName}-{DateTime.UtcNow:yyyy.MM.dd}";
+ string url = $"{_options.Uri.TrimEnd('/')}/{(_options.UseBulkInsert ? "_bulk" : indexName + "/_doc")}";
+
+ var request = new HttpRequestMessage(HttpMethod.Post, url);
+ request.Headers.Accept.ParseAdd("application/json");
+
+ // Add authentication headers if configured
+ if (!string.IsNullOrWhiteSpace(_options.Username))
+ {
+ var authToken = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{_options.Username}:{_options.Password}"));
+ request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authToken);
+ }
+
+ // Add custom headers (static ones)
+ foreach (var header in _options.CustomHeaders)
+ {
+ request.Headers.TryAddWithoutValidation(header.Key, header.Value);
+ }
+
+ // Add template headers (dynamic ones based on log data)
+ var dynamicHeaders = new Dictionary
+ {
+ { "index", _options.IndexName },
+ { "date", DateTime.UtcNow.ToString("yyyy-MM-dd") },
+ { "timestamp", DateTime.UtcNow.ToString("o") },
+ };
+
+ foreach (var header in _options.TemplateHeaders)
+ {
+ var value = ReplaceTemplate(header.Value, dynamicHeaders);
+ request.Headers.TryAddWithoutValidation(header.Key, value);
+ }
+
+ // Add context headers (correlationId, custom context)
+ foreach (var kv in _context.GetAll())
+ {
+ request.Headers.TryAddWithoutValidation($"X-Context-{kv.Key}", kv.Value);
+ }
+
+ // Prepare the content for the request
+ request.Content = new StringContent(
+ _options.UseBulkInsert
+ ? string.Join("\n", toSend.Select(d => $"{{\"index\":{{}}}}\n{d}")) + "\n"
+ : string.Join("\n", toSend),
+ Encoding.UTF8,
+ "application/json"
+ );
+
+ try
+ {
+ var response = await _httpClient.SendAsync(request);
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync();
+ OnInvalidStatusCode?.Invoke(this, $"ElasticSearch request failed: {response.StatusCode}, {errorContent}");
+ }
+ }
+ catch (Exception exception)
+ {
+ OnException?.Invoke(this, exception);
+ }
+ }
+
+ private static string ReplaceTemplate(string template, Dictionary values)
+ {
+ foreach (var kv in values)
+ {
+ template = template.Replace($"{{{kv.Key}}}", kv.Value);
+ }
+ return template;
+ }
+ }
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/ElasticSearchLoggerOptions.cs b/EonaCat.Logger/EonaCatCoreLogger/ElasticSearchLoggerOptions.cs
new file mode 100644
index 0000000..7f35120
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/ElasticSearchLoggerOptions.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class ElasticSearchLoggerOptions
+ {
+ public string Uri { get; set; } = "http://localhost:9200";
+ public string IndexName { get; set; } = "eonacat-logs";
+ public bool IsEnabled { get; set; } = true;
+ public string Username { get; set; }
+ public string Password { get; set; }
+ public Dictionary CustomHeaders { get; set; } = new();
+ public Dictionary TemplateHeaders { get; set; } = new();
+ public int RetryBufferSize { get; set; } = 100;
+ public int FlushIntervalSeconds { get; set; } = 5;
+ public bool UseBulkInsert { get; set; } = true;
+ public bool IncludeCorrelationId { get; set; } = true;
+ }
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/ElasticSearchLoggerProvider.cs b/EonaCat.Logger/EonaCatCoreLogger/ElasticSearchLoggerProvider.cs
new file mode 100644
index 0000000..0798f91
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/ElasticSearchLoggerProvider.cs
@@ -0,0 +1,32 @@
+using Microsoft.Extensions.Logging;
+using System.Collections.Generic;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class ElasticSearchLoggerProvider : ILoggerProvider
+ {
+ private readonly ElasticSearchLoggerOptions _options;
+
+ public ElasticSearchLoggerProvider(ElasticSearchLoggerOptions options = null)
+ {
+ if (options == null)
+ {
+ options = new ElasticSearchLoggerOptions();
+ }
+ _options = options;
+ }
+
+ public ILogger CreateLogger(string categoryName)
+ {
+ return new ElasticSearchLogger(categoryName, _options);
+ }
+
+ public void Dispose()
+ {
+ // No unmanaged resources, nothing to dispose here
+ }
+ }
+}
\ No newline at end of file
diff --git a/EonaCat.Logger/EonaCatCoreLogger/Extensions/ConsoleLoggerFactoryExtensions.cs b/EonaCat.Logger/EonaCatCoreLogger/Extensions/ConsoleLoggerFactoryExtensions.cs
new file mode 100644
index 0000000..81a5866
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/Extensions/ConsoleLoggerFactoryExtensions.cs
@@ -0,0 +1,34 @@
+using System;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Console;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger.Extensions
+{
+ ///
+ /// Extensions for adding the built-in Console Logger to the
+ ///
+ public static class ConsoleLoggerFactoryExtensions
+ {
+ ///
+ /// Adds the built-in Console Logger to the logging builder.
+ ///
+ /// The to use.
+ /// Optional configuration for
+ public static ILoggingBuilder AddEonaCatConsoleLogger(this ILoggingBuilder builder, Action configure = null)
+ {
+ if (configure != null)
+ {
+ builder.AddConsole(configure);
+ }
+ else
+ {
+ builder.AddConsole();
+ }
+
+ return builder;
+ }
+ }
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/Extensions/ElasticSearchLoggerFactoryExtensions.cs b/EonaCat.Logger/EonaCatCoreLogger/Extensions/ElasticSearchLoggerFactoryExtensions.cs
new file mode 100644
index 0000000..90d2094
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/Extensions/ElasticSearchLoggerFactoryExtensions.cs
@@ -0,0 +1,20 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using System;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger.Extensions
+{
+ public static class ElasticSearchLoggerFactoryExtensions
+ {
+ public static ILoggingBuilder AddEonaCatElasticSearchLogger(this ILoggingBuilder builder, Action configure)
+ {
+ var options = new ElasticSearchLoggerOptions();
+ configure?.Invoke(options);
+ builder.Services.AddSingleton(new ElasticSearchLoggerProvider(options));
+ return builder;
+ }
+ }
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/Extensions/HttpLoggerFactoryExtensions.cs b/EonaCat.Logger/EonaCatCoreLogger/Extensions/HttpLoggerFactoryExtensions.cs
new file mode 100644
index 0000000..d5929ca
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/Extensions/HttpLoggerFactoryExtensions.cs
@@ -0,0 +1,21 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using System;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger.Extensions
+{
+ public static class HttpLoggerFactoryExtensions
+ {
+ public static ILoggingBuilder AddEonaCatHttpLogger(this ILoggingBuilder builder, Action configure)
+ {
+ var options = new HttpLoggerOptions();
+ configure?.Invoke(options);
+ builder.Services.AddSingleton(new HttpLoggerProvider(options));
+ return builder;
+ }
+ }
+
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/Extensions/JsonFIleLoggerFactoryExtensions.cs b/EonaCat.Logger/EonaCatCoreLogger/Extensions/JsonFIleLoggerFactoryExtensions.cs
new file mode 100644
index 0000000..4c0d9b6
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/Extensions/JsonFIleLoggerFactoryExtensions.cs
@@ -0,0 +1,21 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using System;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger.Extensions
+{
+ public static class JsonFileLoggerFactoryExtensions
+ {
+ public static ILoggingBuilder AddEonaCatJsonFileLogger(this ILoggingBuilder builder, Action configure)
+ {
+ var options = new JsonFileLoggerOptions();
+ configure?.Invoke(options);
+
+ builder.Services.AddSingleton(new JsonFileLoggerProvider(options));
+ return builder;
+ }
+ }
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/Extensions/TcpLoggerFactoryExtensions.cs b/EonaCat.Logger/EonaCatCoreLogger/Extensions/TcpLoggerFactoryExtensions.cs
new file mode 100644
index 0000000..172856e
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/Extensions/TcpLoggerFactoryExtensions.cs
@@ -0,0 +1,22 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using System;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger.Extensions
+{
+ public static class TcpLoggerFactoryExtensions
+ {
+ public static ILoggingBuilder AddEonaCatTcpLogger(this ILoggingBuilder builder, Action configure)
+ {
+ var options = new TcpLoggerOptions();
+ configure?.Invoke(options);
+
+ builder.Services.AddSingleton(new TcpLoggerProvider(options));
+ return builder;
+ }
+ }
+
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/Extensions/UdpLoggerFactoryExtensions.cs b/EonaCat.Logger/EonaCatCoreLogger/Extensions/UdpLoggerFactoryExtensions.cs
new file mode 100644
index 0000000..4bd783d
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/Extensions/UdpLoggerFactoryExtensions.cs
@@ -0,0 +1,21 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using System;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger.Extensions
+{
+ public static class UdpLoggerFactoryExtensions
+ {
+ public static ILoggingBuilder AddEonaCatUdpLogger(this ILoggingBuilder builder, Action configure)
+ {
+ var options = new UdpLoggerOptions();
+ configure?.Invoke(options);
+
+ builder.Services.AddSingleton(new UdpLoggerProvider(options));
+ return builder;
+ }
+ }
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/FileLoggerOptions.cs b/EonaCat.Logger/EonaCatCoreLogger/FileLoggerOptions.cs
index a156261..04bac3c 100644
--- a/EonaCat.Logger/EonaCatCoreLogger/FileLoggerOptions.cs
+++ b/EonaCat.Logger/EonaCatCoreLogger/FileLoggerOptions.cs
@@ -139,4 +139,9 @@ public class FileLoggerOptions : BatchingLoggerOptions
/// Custom keywords specified in LoggerSettings
///
public bool UseDefaultMasking { get; set; } = true;
+
+ ///
+ /// Determines if we need to include the correlation ID in the log
+ ///
+ public bool IncludeCorrelationId { get; set; } = true;
}
\ No newline at end of file
diff --git a/EonaCat.Logger/EonaCatCoreLogger/FileLoggerProvider.cs b/EonaCat.Logger/EonaCatCoreLogger/FileLoggerProvider.cs
index cfa66a7..225e2f2 100644
--- a/EonaCat.Logger/EonaCatCoreLogger/FileLoggerProvider.cs
+++ b/EonaCat.Logger/EonaCatCoreLogger/FileLoggerProvider.cs
@@ -30,6 +30,7 @@ public class FileLoggerProvider : BatchingLoggerProvider
private bool _rollingOver;
private int _rollOverCount;
private ConcurrentDictionary _buffer = new ConcurrentDictionary();
+ private readonly LoggerScopedContext _context = new();
public event EventHandler OnError;
@@ -46,6 +47,7 @@ public class FileLoggerProvider : BatchingLoggerProvider
_maxRetainedFiles = loggerOptions.RetainedFileCountLimit;
_maxRolloverFiles = loggerOptions.MaxRolloverFiles;
_maxTries = loggerOptions.MaxWriteTries;
+ IncludeCorrelationId = loggerOptions.IncludeCorrelationId;
}
///
@@ -72,6 +74,10 @@ public class FileLoggerProvider : BatchingLoggerProvider
}
}
+ public void SetContext(string key, string value) => _context.Set(key, value);
+ public void ClearContext() => _context.Clear();
+ public string GetContext(string key) => _context.Get(key);
+
///
protected override async Task WriteMessagesAsync(IEnumerable messages,
CancellationToken cancellationToken)
@@ -90,7 +96,22 @@ public class FileLoggerProvider : BatchingLoggerProvider
foreach (var group in messages.GroupBy(GetGrouping))
{
LogFile = GetFullName(group.Key);
- var currentMessages = string.Join(string.Empty, group.Select(item => item.Message));
+
+ var currentMessages = string.Join(string.Empty, group.Select(item =>
+ {
+ if (IncludeCorrelationId)
+ {
+ var correlationId = _context.Get("CorrelationId") ?? Guid.NewGuid().ToString();
+ _context.Set("CorrelationId", correlationId);
+ }
+
+ var contextData = _context.GetAll();
+ var contextInfo = contextData.Count > 0
+ ? string.Join(" ", contextData.Select(kvp => $"{kvp.Key}={kvp.Value}"))
+ : string.Empty;
+ return $"[Timestamp: {item.Timestamp:u}] {item.Message} {contextInfo}{Environment.NewLine}";
+ }));
+
if (!_buffer.TryAdd(LogFile, currentMessages))
{
_buffer[LogFile] += currentMessages;
@@ -128,6 +149,7 @@ public class FileLoggerProvider : BatchingLoggerProvider
}
public bool IsWriting { get; set; }
+ public bool IncludeCorrelationId { get; set; }
private async Task TryWriteToFileAsync(CancellationToken cancellationToken)
{
diff --git a/EonaCat.Logger/EonaCatCoreLogger/HttpLogger.cs b/EonaCat.Logger/EonaCatCoreLogger/HttpLogger.cs
new file mode 100644
index 0000000..27f84f0
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/HttpLogger.cs
@@ -0,0 +1,132 @@
+using EonaCat.Json;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Net.Http;
+using System.Text;
+using System.Collections.Generic;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class HttpLogger : ILogger
+ {
+ private readonly string _categoryName;
+ private readonly HttpLoggerOptions _options;
+ private readonly LoggerScopedContext _context = new();
+
+ public bool IncludeCorrelationId { get; set; }
+
+ private static readonly HttpClient _client = new();
+ public event EventHandler OnException;
+ public event EventHandler OnInvalidStatusCode;
+
+ public HttpLogger(string categoryName, HttpLoggerOptions options)
+ {
+ _categoryName = categoryName;
+ _options = options;
+ IncludeCorrelationId = options.IncludeCorrelationId;
+ }
+
+ public void SetContext(string key, string value) => _context.Set(key, value);
+ public void ClearContext() => _context.Clear();
+ public string GetContext(string key) => _context.Get(key);
+
+ public IDisposable BeginScope(TState state) => null;
+ public bool IsEnabled(LogLevel logLevel) => _options.IsEnabled;
+
+ public void Log(LogLevel logLevel, EventId eventId, TState state,
+ Exception exception, Func formatter)
+ {
+ if (!IsEnabled(logLevel))
+ {
+ return;
+ }
+
+ string message = formatter(state, exception);
+
+ if (IncludeCorrelationId)
+ {
+ var correlationId = _context.Get("CorrelationId") ?? Guid.NewGuid().ToString();
+ _context.Set("CorrelationId", correlationId);
+ }
+
+ var payload = new Dictionary
+ {
+ { "timestamp", DateTime.UtcNow },
+ { "level", logLevel.ToString() },
+ { "category", _categoryName },
+ { "message", message },
+ { "eventId", eventId.Id }
+ };
+
+ // Add full log context as a nested dictionary
+ var contextData = _context.GetAll();
+ if (contextData.Count > 0)
+ {
+ payload["context"] = contextData;
+ }
+
+ try
+ {
+ var content = _options.SendAsJson
+ ? new StringContent(JsonHelper.ToJson(payload), Encoding.UTF8, "application/json")
+ : new StringContent(message);
+
+ var result = _client.PostAsync(_options.Endpoint, content);
+ if (result.Result.IsSuccessStatusCode)
+ {
+ return;
+ }
+
+ // Handle non-success status codes
+ var statusCode = result.Result.StatusCode;
+ var statusCodeMessage = statusCode switch
+ {
+ System.Net.HttpStatusCode.BadRequest => "400 Bad Request",
+ System.Net.HttpStatusCode.Unauthorized => "401 Unauthorized",
+ System.Net.HttpStatusCode.Forbidden => "403 Forbidden",
+ System.Net.HttpStatusCode.NotFound => "404 Not Found",
+ System.Net.HttpStatusCode.MethodNotAllowed => "405 Method Not Allowed",
+ System.Net.HttpStatusCode.NotAcceptable => "406 Not Acceptable",
+ System.Net.HttpStatusCode.ProxyAuthenticationRequired => "407 Proxy Authentication Required",
+ System.Net.HttpStatusCode.RequestTimeout => "408 Request Timeout",
+ System.Net.HttpStatusCode.Conflict => "409 Conflict",
+ System.Net.HttpStatusCode.Gone => "410 Gone",
+ System.Net.HttpStatusCode.LengthRequired => "411 Length Required",
+ System.Net.HttpStatusCode.PreconditionFailed => "412 Precondition Failed",
+ System.Net.HttpStatusCode.RequestEntityTooLarge => "413 Request Entity Too Large",
+ System.Net.HttpStatusCode.RequestUriTooLong => "414 Request URI Too Long",
+ System.Net.HttpStatusCode.UnsupportedMediaType => "415 Unsupported Media Type",
+ System.Net.HttpStatusCode.RequestedRangeNotSatisfiable => "416 Requested Range Not Satisfiable",
+ System.Net.HttpStatusCode.ExpectationFailed => "417 Expectation Failed",
+ (System.Net.HttpStatusCode)418 => "418 I'm a teapot",
+ (System.Net.HttpStatusCode)421 => "421 Misdirected Request",
+ (System.Net.HttpStatusCode)422 => "422 Unprocessable Entity",
+ (System.Net.HttpStatusCode)423 => "423 Locked",
+ (System.Net.HttpStatusCode)424 => "424 Failed Dependency",
+ (System.Net.HttpStatusCode)425 => "425 Too Early",
+ (System.Net.HttpStatusCode)426 => "426 Upgrade Required",
+ (System.Net.HttpStatusCode)428 => "428 Precondition Required",
+ (System.Net.HttpStatusCode)429 => "429 Too Many Requests",
+ (System.Net.HttpStatusCode)431 => "431 Request Header Fields Too Large",
+ (System.Net.HttpStatusCode)451 => "451 Unavailable For Legal Reasons",
+ System.Net.HttpStatusCode.InternalServerError => "500 Internal Server Error",
+ System.Net.HttpStatusCode.NotImplemented => "501 Not Implemented",
+ System.Net.HttpStatusCode.BadGateway => "502 Bad Gateway",
+ System.Net.HttpStatusCode.ServiceUnavailable => "503 Service Unavailable",
+ System.Net.HttpStatusCode.GatewayTimeout => "504 Gateway Timeout",
+ System.Net.HttpStatusCode.HttpVersionNotSupported => "505 HTTP Version Not Supported",
+ _ => statusCode.ToString()
+ };
+
+ OnInvalidStatusCode?.Invoke(this, statusCodeMessage);
+ }
+ catch (Exception e)
+ {
+ OnException?.Invoke(this, e);
+ }
+ }
+ }
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/HttpLoggerOptions.cs b/EonaCat.Logger/EonaCatCoreLogger/HttpLoggerOptions.cs
new file mode 100644
index 0000000..d505b00
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/HttpLoggerOptions.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class HttpLoggerOptions
+ {
+ public string Endpoint { get; set; } = "http://localhost:5000/logs";
+ public bool IsEnabled { get; set; } = true;
+ public bool SendAsJson { get; set; } = true;
+ public bool IncludeCorrelationId { get; set; } = true;
+ }
+
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/HttpLoggerProvider.cs b/EonaCat.Logger/EonaCatCoreLogger/HttpLoggerProvider.cs
new file mode 100644
index 0000000..18f1f9c
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/HttpLoggerProvider.cs
@@ -0,0 +1,31 @@
+using Microsoft.Extensions.Logging;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class HttpLoggerProvider : ILoggerProvider
+ {
+ private readonly HttpLoggerOptions _options;
+
+ public HttpLoggerProvider(HttpLoggerOptions options = null)
+ {
+ if (options == null)
+ {
+ options = new HttpLoggerOptions();
+ }
+ _options = options;
+ }
+
+ public ILogger CreateLogger(string categoryName)
+ {
+ return new HttpLogger(categoryName, _options);
+ }
+
+ public void Dispose()
+ {
+ // No unmanaged resources, nothing to dispose here
+ }
+ }
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/JsonFIleLoggerProvider.cs b/EonaCat.Logger/EonaCatCoreLogger/JsonFIleLoggerProvider.cs
new file mode 100644
index 0000000..5a2788f
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/JsonFIleLoggerProvider.cs
@@ -0,0 +1,35 @@
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class JsonFileLoggerProvider : ILoggerProvider
+ {
+ private readonly JsonFileLoggerOptions _options;
+
+ public JsonFileLoggerProvider(JsonFileLoggerOptions options = null)
+ {
+ if (options == null)
+ {
+ options = new JsonFileLoggerOptions();
+ }
+ _options = options;
+ }
+
+ public ILogger CreateLogger(string categoryName)
+ {
+ return new JsonFileLogger(categoryName, _options);
+ }
+
+ public void Dispose()
+ {
+
+ }
+ }
+
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/JsonFileLogger.cs b/EonaCat.Logger/EonaCatCoreLogger/JsonFileLogger.cs
new file mode 100644
index 0000000..b39b3cf
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/JsonFileLogger.cs
@@ -0,0 +1,80 @@
+using EonaCat.Json;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class JsonFileLogger : ILogger
+ {
+ private readonly string _categoryName;
+ private readonly JsonFileLoggerOptions _options;
+ private readonly string _filePath;
+ private readonly LoggerScopedContext _context = new();
+ public bool IncludeCorrelationId { get; set; }
+ public event EventHandler OnException;
+
+ public JsonFileLogger(string categoryName, JsonFileLoggerOptions options)
+ {
+ _categoryName = categoryName;
+ _options = options;
+ _filePath = Path.Combine(_options.LogDirectory, _options.FileName);
+ Directory.CreateDirectory(_options.LogDirectory);
+ IncludeCorrelationId = options.IncludeCorrelationId;
+ }
+
+ public void SetContext(string key, string value) => _context.Set(key, value);
+ public void ClearContext() => _context.Clear();
+ public string GetContext(string key) => _context.Get(key);
+
+ public IDisposable BeginScope(TState state) => null;
+ public bool IsEnabled(LogLevel logLevel) => _options.IsEnabled;
+
+ public void Log(LogLevel logLevel, EventId eventId, TState state,
+ Exception exception, Func formatter)
+ {
+ if (!IsEnabled(logLevel))
+ {
+ return;
+ }
+
+ string message = formatter(state, exception);
+ if (IncludeCorrelationId)
+ {
+ var correlationId = _context.Get("CorrelationId") ?? Guid.NewGuid().ToString();
+ _context.Set("CorrelationId", correlationId);
+ }
+
+ var logObject = new Dictionary
+ {
+ { "timestamp", DateTime.UtcNow },
+ { "level", logLevel.ToString() },
+ { "category", _categoryName },
+ { "message", message },
+ { "exception", exception?.ToString() },
+ { "eventId", eventId.Id }
+ };
+
+ var contextData = _context.GetAll();
+ if (contextData.Count > 0)
+ {
+ logObject["context"] = contextData;
+ }
+
+ try
+ {
+ string json = JsonHelper.ToJson(logObject);
+ File.AppendAllText(_filePath, json + Environment.NewLine, Encoding.UTF8);
+ }
+ catch (Exception e)
+ {
+ OnException?.Invoke(this, e);
+ }
+ }
+ }
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/JsonFileLoggerOptions.cs b/EonaCat.Logger/EonaCatCoreLogger/JsonFileLoggerOptions.cs
new file mode 100644
index 0000000..a162304
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/JsonFileLoggerOptions.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class JsonFileLoggerOptions
+ {
+ public string LogDirectory { get; set; } = "Logs";
+ public string FileName { get; set; } = "log.json";
+ public bool IsEnabled { get; set; } = true;
+ public bool IncludeCorrelationId { get; set; } = true;
+ }
+
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/LogContext.cs b/EonaCat.Logger/EonaCatCoreLogger/LogContext.cs
new file mode 100644
index 0000000..3acf2c1
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/LogContext.cs
@@ -0,0 +1,30 @@
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class LoggerScopedContext
+ {
+ private readonly ConcurrentDictionary _context = new();
+
+ public void Set(string key, string value)
+ {
+ _context[key] = value;
+ }
+
+ public string Get(string key)
+ {
+ return _context.TryGetValue(key, out var value) ? value : null;
+ }
+
+ public IReadOnlyDictionary GetAll()
+ {
+ return new Dictionary(_context);
+ }
+
+ public void Clear()
+ {
+ _context.Clear();
+ }
+ }
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/TcpLogger.cs b/EonaCat.Logger/EonaCatCoreLogger/TcpLogger.cs
new file mode 100644
index 0000000..326108f
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/TcpLogger.cs
@@ -0,0 +1,90 @@
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net.Sockets;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class TcpLogger : ILogger
+ {
+ private readonly string _categoryName;
+ private readonly TcpLoggerOptions _options;
+ private readonly LoggerScopedContext _context = new();
+ public bool IncludeCorrelationId { get; set; }
+ public event EventHandler OnException;
+
+ public TcpLogger(string categoryName, TcpLoggerOptions options)
+ {
+ _categoryName = categoryName;
+ _options = options;
+ IncludeCorrelationId = options.IncludeCorrelationId;
+ }
+
+ public void SetContext(string key, string value) => _context.Set(key, value);
+ public void ClearContext() => _context.Clear();
+ public string GetContext(string key) => _context.Get(key);
+
+ public IDisposable BeginScope(TState state) => null;
+ public bool IsEnabled(LogLevel logLevel) => _options.IsEnabled;
+
+ public void Log(LogLevel logLevel, EventId eventId, TState state,
+ Exception exception, Func formatter)
+ {
+ if (!IsEnabled(logLevel))
+ {
+ return;
+ }
+
+ try
+ {
+ string message = formatter(state, exception);
+ if (IncludeCorrelationId)
+ {
+ var correlationId = _context.Get("CorrelationId") ?? Guid.NewGuid().ToString();
+ _context.Set("CorrelationId", correlationId);
+ }
+
+ var logParts = new List
+ {
+ $"[{DateTime.UtcNow:u}]",
+ $"[{logLevel}]",
+ $"[{_categoryName}]",
+ $"Message: {message}",
+ };
+
+ var contextData = _context.GetAll();
+ if (contextData.Count > 0)
+ {
+ foreach (var kvp in contextData)
+ {
+ logParts.Add($"{kvp.Key}: {kvp.Value}");
+ }
+ }
+
+ if (exception != null)
+ {
+ logParts.Add($"Exception: {exception}");
+ }
+
+ string fullLog = string.Join(" | ", logParts);
+
+ using var client = new TcpClient();
+ client.Connect(_options.Host, _options.Port);
+ using var stream = client.GetStream();
+ using var writer = new StreamWriter(stream, System.Text.Encoding.UTF8)
+ {
+ AutoFlush = true
+ };
+ writer.WriteLine(fullLog);
+ }
+ catch (Exception e)
+ {
+ OnException?.Invoke(this, e);
+ }
+ }
+ }
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/TcpLoggerOptions.cs b/EonaCat.Logger/EonaCatCoreLogger/TcpLoggerOptions.cs
new file mode 100644
index 0000000..bc436ee
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/TcpLoggerOptions.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class TcpLoggerOptions
+ {
+ public string Host { get; set; }
+ public int Port { get; set; }
+ public bool IsEnabled { get; set; } = true;
+ public bool IncludeCorrelationId { get; set; } = true;
+ }
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/TcpLoggerProvider.cs b/EonaCat.Logger/EonaCatCoreLogger/TcpLoggerProvider.cs
new file mode 100644
index 0000000..bad5c80
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/TcpLoggerProvider.cs
@@ -0,0 +1,31 @@
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class TcpLoggerProvider : ILoggerProvider
+ {
+ private readonly TcpLoggerOptions _options;
+
+ public TcpLoggerProvider(TcpLoggerOptions options)
+ {
+ _options = options;
+ }
+
+ public ILogger CreateLogger(string categoryName)
+ {
+ return new TcpLogger(categoryName, _options);
+ }
+
+ public void Dispose()
+ {
+
+ }
+ }
+
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/UdpLogger.cs b/EonaCat.Logger/EonaCatCoreLogger/UdpLogger.cs
new file mode 100644
index 0000000..8d12b2c
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/UdpLogger.cs
@@ -0,0 +1,88 @@
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Net.Sockets;
+using System.Text;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class UdpLogger : ILogger
+ {
+ private readonly string _categoryName;
+ private readonly UdpLoggerOptions _options;
+ private readonly LoggerScopedContext _context = new();
+ public bool IncludeCorrelationId { get; set; }
+ public event EventHandler OnException;
+
+ public UdpLogger(string categoryName, UdpLoggerOptions options)
+ {
+ _categoryName = categoryName;
+ _options = options;
+ IncludeCorrelationId = options.IncludeCorrelationId;
+ }
+
+ public void SetContext(string key, string value) => _context.Set(key, value);
+ public void ClearContext() => _context.Clear();
+ public string GetContext(string key) => _context.Get(key);
+
+ public IDisposable BeginScope(TState state) => null;
+
+ public bool IsEnabled(LogLevel logLevel) => _options.IsEnabled;
+
+ public void Log(LogLevel logLevel, EventId eventId, TState state,
+ Exception exception, Func formatter)
+ {
+ if (!IsEnabled(logLevel) || formatter == null)
+ {
+ return;
+ }
+
+ string message = formatter(state, exception);
+
+ // Get correlation ID from context or generate new one
+ if (IncludeCorrelationId)
+ {
+ var correlationId = _context.Get("CorrelationId") ?? Guid.NewGuid().ToString();
+ _context.Set("CorrelationId", correlationId);
+ }
+
+ var logParts = new List
+ {
+ $"[{DateTime.UtcNow:u}]",
+ $"[{logLevel}]",
+ $"[{_categoryName}]",
+ $"Message: {message}",
+ };
+
+ var contextData = _context.GetAll();
+ if (contextData.Count > 0)
+ {
+ foreach (var kvp in contextData)
+ {
+ logParts.Add($"{kvp.Key}: {kvp.Value}");
+ }
+ }
+
+ if (exception != null)
+ {
+ logParts.Add($"Exception: {exception}");
+ }
+
+ string fullMessage = string.Join(" | ", logParts);
+
+ try
+ {
+ using var client = new UdpClient();
+ byte[] bytes = Encoding.UTF8.GetBytes(fullMessage);
+ client.Send(bytes, bytes.Length, _options.Host, _options.Port);
+ }
+ catch (Exception e)
+ {
+ OnException?.Invoke(this, e);
+ }
+ }
+ }
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/UdpLoggerOptions.cs b/EonaCat.Logger/EonaCatCoreLogger/UdpLoggerOptions.cs
new file mode 100644
index 0000000..29491fb
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/UdpLoggerOptions.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class UdpLoggerOptions
+ {
+ public string Host { get; set; } = "127.0.0.1";
+
+ public int Port { get; set; } = 514;
+
+ public bool IsEnabled { get; set; } = true;
+ public bool IncludeCorrelationId { get; set; } = true;
+ }
+
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/UdpLoggerProvider.cs b/EonaCat.Logger/EonaCatCoreLogger/UdpLoggerProvider.cs
new file mode 100644
index 0000000..5b0006c
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/UdpLoggerProvider.cs
@@ -0,0 +1,32 @@
+using Microsoft.Extensions.Logging;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class UdpLoggerProvider : ILoggerProvider
+ {
+ private readonly UdpLoggerOptions _options;
+
+ public UdpLoggerProvider(UdpLoggerOptions options = null)
+ {
+ if (options == null)
+ {
+ options = new UdpLoggerOptions();
+ }
+ _options = options;
+ }
+
+ public ILogger CreateLogger(string categoryName)
+ {
+ return new UdpLogger(categoryName, _options);
+ }
+
+ public void Dispose()
+ {
+ // No unmanaged resources, nothing to dispose here
+ }
+ }
+
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/XmlFIleLoggerProvider.cs b/EonaCat.Logger/EonaCatCoreLogger/XmlFIleLoggerProvider.cs
new file mode 100644
index 0000000..8e1575e
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/XmlFIleLoggerProvider.cs
@@ -0,0 +1,35 @@
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class XmlFileLoggerProvider : ILoggerProvider
+ {
+ private readonly XmlFileLoggerOptions _options;
+
+ public XmlFileLoggerProvider(XmlFileLoggerOptions options = null)
+ {
+ if (options == null)
+ {
+ options = new XmlFileLoggerOptions();
+ }
+ _options = options;
+ }
+
+ public ILogger CreateLogger(string categoryName)
+ {
+ return new XmlFileLogger(categoryName, _options);
+ }
+
+ public void Dispose()
+ {
+
+ }
+ }
+
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/XmlFileLogger.cs b/EonaCat.Logger/EonaCatCoreLogger/XmlFileLogger.cs
new file mode 100644
index 0000000..0af6283
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/XmlFileLogger.cs
@@ -0,0 +1,87 @@
+using Microsoft.Extensions.Logging;
+using System;
+using System.IO;
+using System.Xml.Linq;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class XmlFileLogger : ILogger
+ {
+ private readonly string _categoryName;
+ private readonly XmlFileLoggerOptions _options;
+ private readonly string _filePath;
+ private readonly LoggerScopedContext _context = new();
+
+ public bool IncludeCorrelationId { get; set; }
+
+ public event EventHandler OnException;
+
+
+ public XmlFileLogger(string categoryName, XmlFileLoggerOptions options)
+ {
+ _categoryName = categoryName;
+ _options = options;
+ _filePath = Path.Combine(_options.LogDirectory, _options.FileName);
+ Directory.CreateDirectory(_options.LogDirectory);
+ IncludeCorrelationId = options.IncludeCorrelationId;
+ }
+
+ public void SetContext(string key, string value) => _context.Set(key, value);
+ public void ClearContext() => _context.Clear();
+ public string GetContext(string key) => _context.Get(key);
+
+ public IDisposable BeginScope(TState state) => null;
+
+ public bool IsEnabled(LogLevel logLevel) => _options.IsEnabled;
+
+ public void Log(LogLevel logLevel, EventId eventId, TState state,
+ Exception exception, Func formatter)
+ {
+ if (!IsEnabled(logLevel) || formatter == null)
+ {
+ return;
+ }
+
+ try
+ {
+ if (IncludeCorrelationId)
+ {
+ var correlationId = _context.Get("CorrelationId") ?? Guid.NewGuid().ToString();
+ _context.Set("CorrelationId", correlationId);
+ }
+
+ var logElement = new XElement("log",
+ new XElement("timestamp", DateTime.UtcNow.ToString("o")),
+ new XElement("level", logLevel.ToString()),
+ new XElement("category", _categoryName),
+ new XElement("message", formatter(state, exception))
+ );
+
+ var context = _context.GetAll();
+ if (context.Count > 0)
+ {
+ var contextElement = new XElement("context");
+ foreach (var item in context)
+ {
+ contextElement.Add(new XElement(item.Key, item.Value));
+ }
+ logElement.Add(contextElement);
+ }
+
+ if (exception != null)
+ {
+ logElement.Add(new XElement("exception", exception.ToString()));
+ }
+
+ File.AppendAllText(_filePath, logElement.ToString() + Environment.NewLine);
+ }
+ catch (Exception e)
+ {
+ OnException?.Invoke(this, e);
+ }
+ }
+ }
+}
diff --git a/EonaCat.Logger/EonaCatCoreLogger/XmlFileLoggerOptions.cs b/EonaCat.Logger/EonaCatCoreLogger/XmlFileLoggerOptions.cs
new file mode 100644
index 0000000..6cb2940
--- /dev/null
+++ b/EonaCat.Logger/EonaCatCoreLogger/XmlFileLoggerOptions.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+// 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.
+
+namespace EonaCat.Logger.EonaCatCoreLogger
+{
+ public class XmlFileLoggerOptions
+ {
+ public string LogDirectory { get; set; } = "Logs";
+ public string FileName { get; set; } = "log.xml";
+ public bool IsEnabled { get; set; } = true;
+ public bool IncludeCorrelationId { get; set; } = true;
+ }
+
+}
diff --git a/README.md b/README.md
index 6e58a1a..dcf8584 100644
--- a/README.md
+++ b/README.md
@@ -378,4 +378,15 @@ private void LogHelper_OnException(object sender, ErrorMessage e)
Console.WriteLine("Error message from logger: " + e.Message)
}
}
-```
\ No newline at end of file
+```
+
+Example of adding custom context to the log messages:
+
+```csharp
+var jsonLogger = new JsonFileLoggerProvider().CreateLogger("MyCategory") as JsonFileLogger;
+jsonLogger?.SetContext("CorrelationId", "abc-123");
+jsonLogger?.SetContext("UserId", "john.doe");
+jsonLogger?.LogInformation("User logged in");
+````
+// Output:
+// [2025-04-25 17:01:00Z] [Information] MyCategory: User logged in | CorrelationId=abc-123 UserId=john.doe
diff --git a/Testers/EonaCat.Logger.Test.Web/Logger.cs b/Testers/EonaCat.Logger.Test.Web/Logger.cs
index 58788c0..702209b 100644
--- a/Testers/EonaCat.Logger.Test.Web/Logger.cs
+++ b/Testers/EonaCat.Logger.Test.Web/Logger.cs
@@ -37,9 +37,11 @@ public class Logger
UseLocalTime = UseLocalTime,
},
};
+
_logManager = new LogManager(LoggerSettings);
_logManager.Settings.TypesToLog.Clear();
_logManager.Settings.LogInfo();
+
while (true)
{
_logManager.WriteAsync("2222", ELogType.INFO, writeToConsole: false);
diff --git a/Testers/EonaCat.Logger.Test.Web/Program.cs b/Testers/EonaCat.Logger.Test.Web/Program.cs
index 2f2127a..78a062f 100644
--- a/Testers/EonaCat.Logger.Test.Web/Program.cs
+++ b/Testers/EonaCat.Logger.Test.Web/Program.cs
@@ -9,6 +9,7 @@ using EonaCat.Web.RateLimiter;
using EonaCat.Web.RateLimiter.Endpoints.Extensions;
using EonaCat.Web.Tracer.Extensions;
using EonaCat.Web.Tracer.Models;
+using Microsoft.Extensions.Logging;
using System.Runtime.Versioning;
var builder = WebApplication.CreateBuilder(args);
@@ -32,6 +33,11 @@ logger.LoggerSettings.UseMask = true;
Console.WriteLine(DllInfo.EonaCatVersion);
Console.WriteLine(VersionHelper.GetInformationalVersion());
+var jsonLogger = new JsonFileLoggerProvider().CreateLogger("MyCategory") as JsonFileLogger;
+jsonLogger?.SetContext("CorrelationId", "abc-123");
+jsonLogger?.SetContext("UserId", "john.doe");
+jsonLogger?.LogInformation("User logged in");
+
void LoggerSettings_OnLog(EonaCatLogMessage message)
{
Console.ForegroundColor = ConsoleColor.Yellow;
@@ -45,6 +51,7 @@ options.MaxRolloverFiles = 5;
options.UseLocalTime = true;
options.UseMask = true;
builder.Logging.AddEonaCatFileLogger(fileLoggerOptions: options, filenamePrefix: "web");
+builder.Logging.AddEonaCatConsoleLogger();
builder.Services.AddRazorPages();