diff --git a/EonaCat.Logger/Enums.cs b/EonaCat.Logger/Enums.cs
index cfe343a..2c159ab 100644
--- a/EonaCat.Logger/Enums.cs
+++ b/EonaCat.Logger/Enums.cs
@@ -67,6 +67,31 @@ namespace EonaCat.Logger
}
}
+ public static string ToString(this ELogType logLevel)
+ {
+ switch (logLevel)
+ {
+ case ELogType.NONE:
+ return "NONE";
+ case ELogType.ERROR:
+ return "ERROR";
+ case ELogType.DEBUG:
+ return "DEBUG";
+ case ELogType.CRITICAL:
+ return "CRITICAL";
+ case ELogType.WARNING:
+ return "WARNING";
+ case ELogType.TRACE:
+ return "TRACE";
+ case ELogType.TRAFFIC:
+ return "TRAFFIC";
+ case ELogType.INFO:
+ return "INFO";
+ default:
+ return "INFO";
+ }
+ }
+
public static ELogType FromSeverity(this ESeverity logLevel)
{
switch (logLevel)
@@ -88,6 +113,22 @@ namespace EonaCat.Logger
}
}
+ public static int ToGrayLogLevel(this ELogType logLevel)
+ {
+ // Loglevel to GELF format
+ switch (logLevel.ToString())
+ {
+ case "TRAFFIC": return 7;
+ case "TRACE": return 7;
+ case "DEBUG": return 7;
+ case "INFO": return 6;
+ case "WARNING": return 4;
+ case "ERROR": return 3;
+ case "CRITICAL": return 2;
+ default: return 6; // Default to INFO
+ }
+ }
+
public static ESeverity ToSeverity(this ELogType logLevel)
{
switch (logLevel)
diff --git a/EonaCat.Logger/EonaCat.Logger.csproj b/EonaCat.Logger/EonaCat.Logger.csproj
index e0a6d53..41da821 100644
--- a/EonaCat.Logger/EonaCat.Logger.csproj
+++ b/EonaCat.Logger/EonaCat.Logger.csproj
@@ -7,7 +7,7 @@
net7.0;
icon.ico
- 1.2.0
+ 1.2.1
EonaCat (Jeroen Saey)
true
EonaCat (Jeroen Saey)
@@ -43,6 +43,7 @@
+
diff --git a/EonaCat.Logger/Extensions/DateTimeExtensions.cs b/EonaCat.Logger/Extensions/DateTimeExtensions.cs
new file mode 100644
index 0000000..f23fcfe
--- /dev/null
+++ b/EonaCat.Logger/Extensions/DateTimeExtensions.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace EonaCat.Logger.Extensions
+{
+ public static class DateTimeExtensions
+ {
+ public static long ToUnixTimestamp(this DateTime dateTime)
+ {
+ return (long)(dateTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
+ }
+ }
+}
diff --git a/EonaCat.Logger/GrayLog/GrayLogServer.cs b/EonaCat.Logger/GrayLog/GrayLogServer.cs
new file mode 100644
index 0000000..6f63a74
--- /dev/null
+++ b/EonaCat.Logger/GrayLog/GrayLogServer.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Net.Sockets;
+
+namespace EonaCat.Logger.GrayLog
+{
+ // 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.
+
+ ///
+ /// Syslog server.
+ ///
+ public class GrayLogServer
+ {
+ ///
+ /// Hostname.
+ ///
+ public string Hostname
+ {
+ get
+ {
+ return _Hostname;
+ }
+
+ set
+ {
+ if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(Hostname));
+ _Hostname = value;
+
+ SetUdp();
+ }
+ }
+
+ ///
+ /// UDP port.
+ ///
+ public int Port
+ {
+ get
+ {
+ return _Port;
+ }
+ set
+ {
+ if (value < 0) throw new ArgumentException("Port must be zero or greater.");
+ _Port = value;
+
+ SetUdp();
+ }
+ }
+
+ ///
+ /// IP:port of the server.
+ ///
+ public string IpPort
+ {
+ get
+ {
+ return _Hostname + ":" + _Port;
+ }
+ }
+
+ internal readonly object SendLock = new object();
+ internal UdpClient Udp = null;
+ private string _Hostname = "127.0.0.1";
+ private int _Port = 12201;
+
+ ///
+ /// Instantiate the object.
+ ///
+ public GrayLogServer()
+ {
+ }
+
+ ///
+ /// Instantiate the object.
+ ///
+ /// Hostname.
+ /// Port.
+ public GrayLogServer(string hostname = "127.0.0.1", int port = 12201)
+ {
+ Hostname = hostname;
+ Port = port;
+ }
+
+ private void SetUdp()
+ {
+ Udp = null;
+ Udp = new UdpClient(_Hostname, _Port);
+ }
+ }
+}
diff --git a/EonaCat.Logger/Managers/ColorSchema.cs b/EonaCat.Logger/Managers/ColorSchema.cs
index f40c19e..9e7b1b0 100644
--- a/EonaCat.Logger/Managers/ColorSchema.cs
+++ b/EonaCat.Logger/Managers/ColorSchema.cs
@@ -2,6 +2,9 @@
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.
+
///
/// Colors to use when writing to the console.
///
diff --git a/EonaCat.Logger/Managers/ILogManager.cs b/EonaCat.Logger/Managers/ILogManager.cs
index 6427feb..bff79b7 100644
--- a/EonaCat.Logger/Managers/ILogManager.cs
+++ b/EonaCat.Logger/Managers/ILogManager.cs
@@ -3,11 +3,14 @@ using System.Threading.Tasks;
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.
+
public interface ILogManager
{
- void Write(string message, ELogType logType = ELogType.INFO, bool? writeToConsole = null);
+ void Write(string message, ELogType logType = ELogType.INFO, bool? writeToConsole = null, bool? sendToSysLogServers = null, bool? sendToSplunkServers = null, string? customSplunkSourceType = null, bool? sendToGrayLogServers = null, string grayLogFacility = null, string grayLogSource = null, string grayLogVersion = "1.1");
void Write(Exception exception, string module = null, string method = null, bool criticalException = false,
- bool? writeToConsole = null);
+ bool? writeToConsole = null, bool? sendToSysLogServers = null, bool? sendToSplunkServers = null, string? customSplunkSourceType = null, bool? sendToGrayLogServers = null, string grayLogFacility = null, string grayLogSource = null, string grayLogVersion = "1.1");
}
}
\ No newline at end of file
diff --git a/EonaCat.Logger/Managers/LogHelper.cs b/EonaCat.Logger/Managers/LogHelper.cs
index 59f60c9..3fd3901 100644
--- a/EonaCat.Logger/Managers/LogHelper.cs
+++ b/EonaCat.Logger/Managers/LogHelper.cs
@@ -2,10 +2,18 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
+using System.Net.Http;
using System.Text;
+using System.Threading.Tasks;
+using EonaCat.Json;
+using EonaCat.Logger.Extensions;
+using EonaCat.Logger.GrayLog;
using EonaCat.Logger.Syslog;
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.Managers
{
internal static class LogHelper
@@ -43,7 +51,7 @@ namespace EonaCat.Logger.Managers
return sb.ToString();
}
-
+
internal static void SendToConsole(LoggerSettings settings, ELogType logType, string message, bool writeToConsole)
{
@@ -119,9 +127,104 @@ namespace EonaCat.Logger.Managers
logger.Log(logLevel, message);
}
- internal static void SendToSysLogServers(LoggerSettings settings, string message)
+ public static async Task SendToSplunkServersAsync(LoggerSettings settings, string logType, string message, bool sendToSplunkServer)
{
- if (settings == null || !settings.SendToSyslogServers || string.IsNullOrWhiteSpace(message))
+ if (settings == null || !sendToSplunkServer || string.IsNullOrWhiteSpace(message))
+ return;
+
+ if (settings.SplunkServers == null)
+ {
+ settings.SplunkServers = new List();
+ }
+
+ foreach (var splunkServer in settings.SplunkServers)
+ {
+ if (!splunkServer.HasHecUrl)
+ {
+ Console.WriteLine("Splunk server HecUrl not specified, skipping splunkServer");
+ continue;
+ }
+
+ if (!splunkServer.HasHecToken)
+ {
+ Console.WriteLine($"Splunk server HecToken not specified, skipping splunkServer '{splunkServer.SplunkHecUrl}'");
+ continue;
+ }
+
+ await Task.Run(async () =>
+ {
+ try
+ {
+ using (var httpClient = new HttpClient())
+ {
+ var payload = new
+ {
+ log_message = message,
+ sourcetype = logType
+ };
+
+ var jsonPayload = JsonHelper.ToJson(payload);
+ var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
+
+ httpClient.DefaultRequestHeaders.Add("Authorization", $"Splunk {splunkServer.SplunkHecToken}");
+
+ var response = await httpClient.PostAsync(splunkServer.SplunkHecUrl, content);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ Console.WriteLine($"Failed to send log to Splunk '{splunkServer.SplunkHecUrl}'. Status code: {response.StatusCode}");
+ }
+ }
+ }
+ catch (Exception exception)
+ {
+ Console.WriteLine($"Error while logging to Splunk server '{splunkServer.SplunkHecUrl}': {exception.Message}");
+ }
+ });
+ }
+ }
+
+ internal static async Task SendToGrayLogServersAsync(LoggerSettings settings, string message, ELogType logLevel, string facility, string source, bool sendToGrayLogServer, string version = "1.1")
+ {
+ if (settings == null || !sendToGrayLogServer || string.IsNullOrWhiteSpace(message))
+ return;
+
+ if (settings.GrayLogServers == null || !settings.GrayLogServers.Any())
+ {
+ settings.GrayLogServers = new List { new GrayLogServer("127.0.0.1", 12201) };
+ }
+
+ foreach (var grayLogServer in settings.GrayLogServers)
+ {
+ await Task.Run(async () =>
+ {
+ try
+ {
+ var gelfMessage = new
+ {
+ version,
+ host = Environment.MachineName,
+ short_message = message,
+ level = logLevel.ToGrayLogLevel(),
+ facility,
+ source,
+ timestamp = DateTime.UtcNow.ToUnixTimestamp(),
+ };
+
+ var messageBytes = Encoding.UTF8.GetBytes(JsonHelper.ToJson(gelfMessage));
+ await grayLogServer.Udp.SendAsync(messageBytes, messageBytes.Length, new IPEndPoint(IPAddress.Parse(grayLogServer.Hostname), grayLogServer.Port));
+ }
+ catch (Exception exception)
+ {
+ Console.WriteLine($"Error while logging to GrayLog server '{grayLogServer.Hostname}': {exception.Message}");
+ }
+ });
+ }
+ }
+
+ internal static async Task SendToSysLogServersAsync(LoggerSettings settings, string message, bool sendToSyslogServers)
+ {
+ if (settings == null || !sendToSyslogServers || string.IsNullOrWhiteSpace(message))
return;
if (settings.SysLogServers == null || !settings.SysLogServers.Any())
@@ -133,28 +236,36 @@ namespace EonaCat.Logger.Managers
foreach (SyslogServer server in settings.SysLogServers)
{
- if (string.IsNullOrWhiteSpace(server.Hostname))
- {
- Console.WriteLine("Server hostname not specified, skipping syslog server");
- continue;
- }
- if (server.Port < 0)
- {
- Console.WriteLine("Server port must be zero or greater, skipping syslog server");
- continue;
- }
-
- lock (server.SendLock)
+ await Task.Run(() =>
{
try
{
- server.Udp.Send(data, data.Length);
+ if (string.IsNullOrWhiteSpace(server.Hostname))
+ {
+ Console.WriteLine("Server hostname not specified, skipping SysLog Server");
+ return;
+ }
+
+ if (server.Port < 0)
+ {
+ Console.WriteLine("Server port must be zero or greater, skipping SysLog Server");
+ return;
+ }
+
+ try
+ {
+ server.Udp.Send(data, data.Length);
+ }
+ catch (Exception exception)
+ {
+ Console.WriteLine($"Error while logging to SysLog Server '{server.Hostname}': {exception.Message}");
+ }
}
- catch
+ catch (Exception exception)
{
- // Do nothing
+ Console.WriteLine($"Error while logging to SysLog Server '{server.Hostname}': {exception.Message}");
}
- }
+ });
}
}
}
diff --git a/EonaCat.Logger/Managers/LogManager.cs b/EonaCat.Logger/Managers/LogManager.cs
index c614b95..be506ac 100644
--- a/EonaCat.Logger/Managers/LogManager.cs
+++ b/EonaCat.Logger/Managers/LogManager.cs
@@ -13,6 +13,9 @@ using EonaCat.Logger.Extensions;
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.
+
public partial class LogManager : ILogManager, IDisposable
{
private DateTime CurrentDateTme => Settings.UseLocalTime ? DateTime.Now : DateTime.UtcNow;
@@ -98,7 +101,7 @@ namespace EonaCat.Logger.Managers
Logger = LoggerFactory.CreateLogger(Settings.Id);
}
- private void InternalWriteAsync(DateTime dateTime, string message, ELogType logType = ELogType.INFO, bool? writeToConsole = null)
+ private void InternalWriteAsync(DateTime dateTime, string message, ELogType logType = ELogType.INFO, bool? writeToConsole = null, bool? sendToSyslogServers = null, bool? sendToSplunkServers = null, string customSplunkSourceType = null, bool? sendToGrayLogServers = null, string grayLogFacility = null, string grayLogSource = null, string grayLogVersion = "1.1")
{
if (string.IsNullOrEmpty(message) || logType == ELogType.NONE || (int)logType >= (int)Settings.MaxLogType)
return;
@@ -113,7 +116,32 @@ namespace EonaCat.Logger.Managers
Task.Run(() => { LogHelper.SendToFile(Logger, Settings, logType, message); });
- Task.Run(() => { LogHelper.SendToSysLogServers(Settings, messageWithHeader); });
+ sendToSyslogServers ??= Settings.SendToSyslogServers;
+ if (sendToSyslogServers.Value)
+ {
+ Task.Run(async () =>
+ {
+ await LogHelper.SendToSysLogServersAsync(Settings, messageWithHeader, true);
+ });
+ }
+
+ sendToSplunkServers ??= Settings.SendToSplunkServers;
+ if (sendToSplunkServers.Value)
+ {
+ Task.Run(async () =>
+ {
+ await LogHelper.SendToSplunkServersAsync(Settings, customSplunkSourceType ?? logType.ToString(), messageWithHeader, true);
+ });
+ }
+
+ sendToGrayLogServers ??= Settings.SendToGrayLogServers;
+ if (sendToGrayLogServers.Value)
+ {
+ Task.Run(async () =>
+ {
+ await LogHelper.SendToGrayLogServersAsync(Settings, messageWithHeader, logType, grayLogFacility, grayLogSource, true, grayLogVersion);
+ });
+ }
var logMessage = new EonaCatLogMessage
{
@@ -203,15 +231,15 @@ namespace EonaCat.Logger.Managers
GC.SuppressFinalize(this);
}
- public void Write(Exception exception, string module = null, string method = null, bool criticalException = false, bool? writeToConsole = null)
+ public void Write(Exception exception, string module = null, string method = null, bool criticalException = false, bool? writeToConsole = null, bool? sendToSysLogServers = null, bool? sendToSplunkServers = null, string? customSplunkSourceType = null, bool? sendToGrayLogServers = null, string grayLogFacility = null, string grayLogSource = null, string grayLogVersion = "1.1")
{
if (exception == null)
return;
- Write(exception.FormatExceptionToMessage(module, method), criticalException ? ELogType.CRITICAL : ELogType.ERROR, writeToConsole);
+ Write(exception.FormatExceptionToMessage(module, method), criticalException ? ELogType.CRITICAL : ELogType.ERROR, writeToConsole, sendToSysLogServers, sendToSplunkServers, customSplunkSourceType, sendToGrayLogServers, grayLogFacility, grayLogSource, grayLogVersion);
}
- public void Write(string message, ELogType logType = ELogType.INFO, bool? writeToConsole = null)
+ public void Write(string message, ELogType logType = ELogType.INFO, bool? writeToConsole = null, bool? sendToSysLogServers = null, bool? sendToSplunkServers = null, string? customSplunkSourceType = null, bool? sendToGrayLogServers = null, string grayLogFacility = null, string grayLogSource = null, string grayLogVersion = "1.1")
{
if (logType == ELogType.NONE)
return;
@@ -219,7 +247,7 @@ namespace EonaCat.Logger.Managers
if (!IsRunning)
StartNewLogAsync().ConfigureAwait(false);
- InternalWriteAsync(CurrentDateTme, message, logType, writeToConsole);
+ InternalWriteAsync(CurrentDateTme, message, logType, writeToConsole, sendToSysLogServers, sendToSplunkServers, customSplunkSourceType, sendToGrayLogServers, grayLogFacility, grayLogSource, grayLogVersion);
}
}
}
diff --git a/EonaCat.Logger/Managers/LoggerSettings.cs b/EonaCat.Logger/Managers/LoggerSettings.cs
index ce36a74..12e3ff7 100644
--- a/EonaCat.Logger/Managers/LoggerSettings.cs
+++ b/EonaCat.Logger/Managers/LoggerSettings.cs
@@ -2,10 +2,14 @@
using System.Collections.Generic;
using EonaCat.Logger.EonaCatCoreLogger;
using EonaCat.Logger.EonaCatCoreLogger.Models;
+using EonaCat.Logger.GrayLog;
using EonaCat.Logger.Syslog;
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.
+
///
/// Logger settings.
///
@@ -113,6 +117,14 @@ namespace EonaCat.Logger.Managers
public List SysLogServers { get; set; }
+ public bool SendToSplunkServers { get; set; }
+
+ public bool SendToGrayLogServers { get; set; }
+
+ public List SplunkServers { get; set; }
+
+ public List GrayLogServers { get; set; }
+
///
/// Determines if the fileLogging is enabled
///
diff --git a/EonaCat.Logger/Splunk/SplunkServer.cs b/EonaCat.Logger/Splunk/SplunkServer.cs
new file mode 100644
index 0000000..6be8765
--- /dev/null
+++ b/EonaCat.Logger/Splunk/SplunkServer.cs
@@ -0,0 +1,79 @@
+using System;
+
+namespace EonaCat.Logger.SplunkServer
+{
+ // 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.
+
+ ///
+ /// Splunk Server.
+ ///
+ public class SplunkServer
+ {
+ ///
+ /// SplunkHecUrl
+ ///
+ public string SplunkHecUrl
+ {
+ get
+ {
+ return _splunkHecUrl;
+ }
+
+ set
+ {
+ if (!string.IsNullOrWhiteSpace(_splunkHecUrl) && !_splunkHecUrl.ToLower().Contains("http"))
+ {
+ value = $"http://{value}";
+ }
+ _splunkHecUrl = value;
+ }
+ }
+
+ public bool IsHttpsHecUrl => HasHecUrl && _splunkHecUrl.ToLower().StartsWith("https");
+
+ ///
+ /// SplunkHecToken
+ ///
+ public string SplunkHecToken
+ {
+ get
+ {
+ return _splunkHecToken;
+ }
+ set
+ {
+ _splunkHecToken = value;
+ }
+ }
+
+ internal readonly object SendLock = new object();
+ private string _splunkHecUrl = "https://127.0.0.1:8088";
+ private string _splunkHecToken = "splunk-hec-token";
+ private string _hostName;
+
+ public bool HasHecToken => !string.IsNullOrWhiteSpace(SplunkHecToken) && SplunkHecToken != "splunk-hec-token";
+
+ public bool HasHecUrl => !string.IsNullOrWhiteSpace(SplunkHecUrl);
+
+ public bool IsLocalHost => HasHecUrl && (SplunkHecUrl.ToLower().Contains("127.0.0.1") || SplunkHecUrl.ToLower().Contains("localhost"));
+
+ ///
+ /// Instantiate the object.
+ ///
+ public SplunkServer()
+ {
+ }
+
+ ///
+ /// Instantiate the object.
+ ///
+ /// splunkHecUrl.
+ /// splunkHecToken.
+ public SplunkServer(string splunkHecUrl, string splunkHecToken)
+ {
+ SplunkHecUrl = splunkHecUrl;
+ SplunkHecToken = splunkHecToken;
+ }
+ }
+}
diff --git a/EonaCat.Logger/Syslog/SyslogServer.cs b/EonaCat.Logger/Syslog/SyslogServer.cs
index f682932..cf15696 100644
--- a/EonaCat.Logger/Syslog/SyslogServer.cs
+++ b/EonaCat.Logger/Syslog/SyslogServer.cs
@@ -5,6 +5,9 @@ using System.Text;
namespace EonaCat.Logger.Syslog
{
+ // 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.
+
///
/// Syslog server.
///
@@ -58,7 +61,6 @@ namespace EonaCat.Logger.Syslog
}
}
- internal readonly object SendLock = new object();
internal UdpClient Udp = null;
private string _Hostname = "127.0.0.1";
private int _Port = 514;