diff --git a/EonaCat.Logger/EonaCat.Logger.csproj b/EonaCat.Logger/EonaCat.Logger.csproj index 8f17c31..fbb483c 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.3.5 + 1.3.6 EonaCat (Jeroen Saey) true EonaCat (Jeroen Saey) @@ -24,7 +24,7 @@ - 1.3.5+{chash:10}.{c:ymd} + 1.3.6+{chash:10}.{c:ymd} true true v[0-9]* @@ -52,10 +52,11 @@ - - runtime; build; native; contentfiles; analyzers; buildtransitive; compile + + runtime; build; native; contentfiles; analyzers; buildtransitive + all - + diff --git a/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLoggerProvider.cs b/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLoggerProvider.cs index 4364cab..ff16ab4 100644 --- a/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLoggerProvider.cs +++ b/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLoggerProvider.cs @@ -310,12 +310,6 @@ public abstract class BatchingLoggerProvider : ILoggerProvider, IDisposable return message; } - private async Task WriteStopMessage() - { - var message = LogHelper.GetStopMessage(); - await WriteMessagesAsync(new List { CreateLoggerMessage(message, CurrentDateTimeOffset) }, _cancellationTokenSource.Token).ConfigureAwait(false); - } - internal string AddMessage(DateTimeOffset timestamp, string message) { var result = CreateLoggerMessage(message, timestamp); diff --git a/EonaCat.Logger/Managers/ILogManager.cs b/EonaCat.Logger/Managers/ILogManager.cs index b3576d9..0260478 100644 --- a/EonaCat.Logger/Managers/ILogManager.cs +++ b/EonaCat.Logger/Managers/ILogManager.cs @@ -8,12 +8,10 @@ namespace EonaCat.Logger.Managers; public interface ILogManager { Task WriteAsync(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 customSplunkSourceType = null, string grayLogFacility = null, string grayLogSource = null, string grayLogVersion = "1.1"); Task WriteAsync(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, + bool? writeToConsole = null, string customSplunkSourceType = 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 fa23b5d..8d8e374 100644 --- a/EonaCat.Logger/Managers/LogHelper.cs +++ b/EonaCat.Logger/Managers/LogHelper.cs @@ -2,14 +2,12 @@ using System.Collections.Generic; using System.Linq; using System.Net; -using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using EonaCat.Json; using EonaCat.Logger.Extensions; -using EonaCat.Logger.GrayLog; -using EonaCat.Logger.Splunk.Models; -using EonaCat.Logger.Syslog; +using EonaCat.Logger.Servers.GrayLog; +using EonaCat.Logger.Servers.Splunk.Models; using Microsoft.Extensions.Logging; // This file is part of the EonaCat project(s) which is released under the Apache License. @@ -35,7 +33,10 @@ internal static class LogHelper internal static string FormatMessageWithHeader(LoggerSettings settings, ELogType logType, string currentMessage, DateTime dateTime, string category = null) { - if (string.IsNullOrWhiteSpace(currentMessage)) return currentMessage; + if (string.IsNullOrWhiteSpace(currentMessage)) + { + return currentMessage; + } category ??= "General"; var sb = new StringBuilder(settings?.HeaderFormat ?? "[EonaCatLogger]"); @@ -143,9 +144,9 @@ internal static class LogHelper logger.Log(logLevel, message); } - public static async Task SendToSplunkServersAsync(LoggerSettings settings, SplunkPayload splunkPayload, bool sendToSplunkServer) + public static async Task SendToSplunkServersAsync(LoggerSettings settings, SplunkPayload splunkPayload) { - if (settings == null || !sendToSplunkServer || splunkPayload == null) + if (settings == null || splunkPayload == null) { return; } @@ -174,9 +175,14 @@ internal static class LogHelper /// /// Overload for sending a simple log message to Splunk. /// - public static async Task SendToSplunkServersAsync(LoggerSettings settings, string logType, string message, bool sendToSplunkServer) + public static async Task SendToSplunkServersAsync(LoggerSettings settings, string logType, string message) { - if (settings == null || !sendToSplunkServer || string.IsNullOrWhiteSpace(message)) + if (settings == null || string.IsNullOrWhiteSpace(message)) + { + return; + } + + if (settings.SplunkServers == null || settings.SplunkServers.Count() == 0) { return; } @@ -188,7 +194,7 @@ internal static class LogHelper SourceType = logType }; - await SendToSplunkServersAsync(settings, splunkPayload, sendToSplunkServer); + await SendToSplunkServersAsync(settings, splunkPayload); } /// @@ -201,9 +207,14 @@ internal static class LogHelper internal static async Task SendToGrayLogServersAsync(LoggerSettings settings, string message, ELogType logLevel, - string facility, string source, bool sendToGrayLogServer, string version = "1.1") + string facility, string source, string version = "1.1") { - if (settings == null || !sendToGrayLogServer || string.IsNullOrWhiteSpace(message)) + if (settings == null || string.IsNullOrWhiteSpace(message)) + { + return; + } + + if (settings.GrayLogServers == null || settings.GrayLogServers.Count() == 0) { return; } @@ -258,13 +269,12 @@ internal static class LogHelper await Task.WhenAll(tasks); } - /// /// Sends a message via TCP to a GrayLog server. /// - private static async Task SendViaTcpAsync(GrayLogServer server, byte[] data) + private static async Task SendViaTcpAsync(Graylog server, byte[] data) { - using var tcpClient = new TcpClient(); + using var tcpClient = new System.Net.Sockets.TcpClient(); await tcpClient.ConnectAsync(server.Hostname, server.Port); using var stream = tcpClient.GetStream(); await stream.WriteAsync(data, 0, data.Length); @@ -274,7 +284,7 @@ internal static class LogHelper /// /// Sends large messages in chunks over UDP. /// - private static async Task SendUdpInChunksAsync(GrayLogServer server, byte[] data, int chunkSize) + private static async Task SendUdpInChunksAsync(Graylog server, byte[] data, int chunkSize) { for (int i = 0; i < data.Length; i += chunkSize) { @@ -283,9 +293,14 @@ internal static class LogHelper } } - internal static async Task SendToSysLogServersAsync(LoggerSettings settings, string message, bool sendToSyslogServers) + internal static async Task SendToSysLogServersAsync(LoggerSettings settings, string message) { - if (settings == null || !sendToSyslogServers || string.IsNullOrWhiteSpace(message)) + if (settings == null || string.IsNullOrWhiteSpace(message)) + { + return; + } + + if (settings.SysLogServers == null || settings.SysLogServers.Count() == 0) { return; } @@ -329,12 +344,84 @@ internal static class LogHelper await Task.WhenAll(tasks); } + internal static async Task SendToTcpLogServersAsync(LoggerSettings settings, string message) + { + if (settings == null || string.IsNullOrWhiteSpace(message)) + { + return; + } + + if (settings.TcpServers == null || settings.TcpServers.Count() == 0) + { + return; + } + + var tasks = settings.TcpServers? + .Where(server => !string.IsNullOrWhiteSpace(server.Hostname) && server.Port >= 0) + .Select(async server => + { + try + { + var data = Encoding.UTF8.GetBytes(message); + server.DisposeTcp(); + server.SetTcp(); + await server.WriteAsync(data).ConfigureAwait(false); + } + catch (Exception ex) + { + OnException?.Invoke(null, new ErrorMessage + { + Exception = ex, + Message = $"Error logging to Tcp Server '{server.Hostname}': {ex.Message}" + }); + } + }) ?? new List(); + + await Task.WhenAll(tasks); + } + + internal static async Task SendToUdpLogServersAsync(LoggerSettings settings, string message) + { + if (settings == null || string.IsNullOrWhiteSpace(message)) + { + return; + } + + if (settings.UdpServers == null || settings.UdpServers.Count() == 0) + { + return; + } + + var tasks = settings.UdpServers? + .Where(server => !string.IsNullOrWhiteSpace(server.Hostname) && server.Port >= 0) + .Select(async server => + { + try + { + var data = Encoding.UTF8.GetBytes(message); + server.DisposeUdp(); + server.SetUdp(); + await server.WriteAsync(data).ConfigureAwait(false); + } + catch (Exception ex) + { + OnException?.Invoke(null, new ErrorMessage + { + Exception = ex, + Message = $"Error logging to Udp Server '{server.Hostname}': {ex.Message}" + }); + } + }) ?? new List(); + + await Task.WhenAll(tasks); + } + /// /// Sends a message via TCP to a syslog server. /// - private static async Task SendViaTcpAsync(SyslogServer server, byte[] data) + private static async Task SendViaTcpAsync(Servers.Syslog.Syslog server, byte[] data) { - using var tcpClient = new TcpClient(); + using var tcpClient = new System.Net.Sockets.TcpClient(); await tcpClient.ConnectAsync(server.Hostname, server.Port); using var stream = tcpClient.GetStream(); await stream.WriteAsync(data, 0, data.Length); @@ -344,7 +431,7 @@ internal static class LogHelper /// /// Sends large messages in chunks over UDP. /// - private static async Task SendUdpInChunksAsync(SyslogServer server, byte[] data, int chunkSize) + private static async Task SendUdpInChunksAsync(Servers.Syslog.Syslog server, byte[] data, int chunkSize) { for (int i = 0; i < data.Length; i += chunkSize) { diff --git a/EonaCat.Logger/Managers/LogManager.cs b/EonaCat.Logger/Managers/LogManager.cs index b953922..e59f418 100644 --- a/EonaCat.Logger/Managers/LogManager.cs +++ b/EonaCat.Logger/Managers/LogManager.cs @@ -1,13 +1,19 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using EonaCat.Logger.EonaCatCoreLogger; using EonaCat.Logger.EonaCatCoreLogger.Extensions; using EonaCat.Logger.EonaCatCoreLogger.Models; using EonaCat.Logger.Extensions; -using EonaCat.Logger.Syslog; +using EonaCat.Logger.Servers.GrayLog; +using EonaCat.Logger.Servers.Splunk; +using EonaCat.Logger.Servers.Syslog; +using EonaCat.Logger.Servers.Tcp; +using EonaCat.Logger.Servers.Udp; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -24,23 +30,8 @@ namespace EonaCat.Logger.Managers private bool _isDisposing; private string _category; - public LogManager(LoggerSettings settings, string serverIp, int serverPort) + public LogManager(LoggerSettings settings) { - if (string.IsNullOrEmpty(serverIp)) - { - throw new ArgumentNullException(nameof(serverIp)); - } - - if (serverPort < 0) - { - throw new ArgumentException("Server port must be zero or greater."); - } - - settings.SysLogServers = new List - { - new(serverIp, serverPort) - }; - Settings = settings; SetupLogManager(); } @@ -87,8 +78,7 @@ namespace EonaCat.Logger.Managers public async Task WriteAsync(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, + bool? writeToConsole = null, string customSplunkSourceType = null, string grayLogFacility = null, string grayLogSource = null, string grayLogVersion = "1.1") { if (exception == null) @@ -97,14 +87,14 @@ namespace EonaCat.Logger.Managers } await WriteAsync(exception.FormatExceptionToMessage(module, method), - criticalException ? ELogType.CRITICAL : ELogType.ERROR, writeToConsole, sendToSysLogServers, - sendToSplunkServers, customSplunkSourceType, sendToGrayLogServers, grayLogFacility, grayLogSource, + criticalException ? ELogType.CRITICAL : ELogType.ERROR, writeToConsole, + customSplunkSourceType, grayLogFacility, grayLogSource, grayLogVersion); } public async Task WriteAsync(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 customSplunkSourceType = null, + string grayLogFacility = null, string grayLogSource = null, string grayLogVersion = "1.1") { if (logType == ELogType.NONE) @@ -112,8 +102,8 @@ namespace EonaCat.Logger.Managers return; } - await InternalWriteAsync(CurrentDateTime, message, logType, writeToConsole, sendToSysLogServers, sendToSplunkServers, - customSplunkSourceType, sendToGrayLogServers, grayLogFacility, grayLogSource, grayLogVersion); + await InternalWriteAsync(CurrentDateTime, message, logType, writeToConsole, + customSplunkSourceType, grayLogFacility, grayLogSource, grayLogVersion); } /// @@ -202,8 +192,7 @@ namespace EonaCat.Logger.Managers } private async Task 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, + bool? writeToConsole = null, string customSplunkSourceType = null, string grayLogFacility = null, string grayLogSource = null, string grayLogVersion = "1.1") { if (string.IsNullOrWhiteSpace(message) || logType == ELogType.NONE || !IsLogLevelEnabled(logType) || _isDisposing) @@ -218,9 +207,6 @@ namespace EonaCat.Logger.Managers var messageWithHeader = LogHelper.FormatMessageWithHeader(Settings, logType, message, dateTime, _category); var writeToConsoleValue = writeToConsole.GetValueOrDefault(Settings.EnableConsole); - var sendToSyslogServersValue = sendToSyslogServers.GetValueOrDefault(Settings.SendToSyslogServers); - var sendToSplunkServersValue = sendToSplunkServers.GetValueOrDefault(Settings.SendToSplunkServers); - var sendToGrayLogServersValue = sendToGrayLogServers.GetValueOrDefault(Settings.SendToGrayLogServers); LogHelper.SendToFile(Logger, Settings, logType, message); @@ -229,21 +215,14 @@ namespace EonaCat.Logger.Managers LogHelper.SendToConsole(Settings, logType, messageWithHeader, true); } - var tasks = new List(3); - if (sendToSyslogServersValue) + var tasks = new List(5) { - tasks.Add(LogHelper.SendToSysLogServersAsync(Settings, messageWithHeader, true)); - } - if (sendToSplunkServersValue) - { - tasks.Add(LogHelper.SendToSplunkServersAsync(Settings, customSplunkSourceType ?? logType.ToString(), - messageWithHeader, true)); - } - if (sendToGrayLogServersValue) - { - tasks.Add(LogHelper.SendToGrayLogServersAsync(Settings, messageWithHeader, logType, grayLogFacility, - grayLogSource, true, grayLogVersion)); - } + LogHelper.SendToSysLogServersAsync(Settings, messageWithHeader), + LogHelper.SendToSplunkServersAsync(Settings, customSplunkSourceType ?? logType.ToString(), messageWithHeader), + LogHelper.SendToGrayLogServersAsync(Settings, messageWithHeader, logType, grayLogFacility, grayLogSource, grayLogVersion), + LogHelper.SendToTcpLogServersAsync(Settings, messageWithHeader), + LogHelper.SendToUdpLogServersAsync(Settings, messageWithHeader), + }; if (tasks.Count > 0) { @@ -340,5 +319,326 @@ namespace EonaCat.Logger.Managers File.Delete(CurrentLogFile); } } + + /// + /// Add sysLog server + /// + /// + /// + /// + /// + public bool AddSyslogServer(string address, int port, string nickName = null) + { + if (Settings.SysLogServers == null) + { + Settings.SysLogServers = new List(); + } + + if (Settings.SysLogServers.Any(x => (nickName != null && x.Nickname == nickName) || nickName == null && x.Hostname == address && x.Port == port)) + { + return false; + } + + Settings.SysLogServers.Add(new Syslog(address, port)); + return true; + } + + /// + /// Remove the sysLog server + /// + /// + /// + /// + public bool RemoveSyslogServer(string address, int port) + { + if (Settings.SysLogServers == null) + { + return false; + } + + var delete = Settings.SysLogServers.FirstOrDefault(x => x.Hostname == address && x.Port == port); + if (delete != null) + { + Settings.SysLogServers.Remove(delete); + } + return true; + } + + /// + /// Remove the sysLog server + /// + /// + /// + public bool RemoveSyslogServer(string nickName) + { + if (Settings.SysLogServers == null) + { + return false; + } + + var delete = Settings.SysLogServers.FirstOrDefault(x => x.Nickname == nickName); + if (delete != null) + { + Settings.SysLogServers.Remove(delete); + } + return true; + } + + /// + /// Add Splunk server + /// + /// + /// + /// (optional) + /// (optional) + /// + public bool AddSplunkServer(string splunkHecUrl, string splunkHecToken, HttpClientHandler httpClientHandler = null, string nickName = null) + { + if (Settings.SplunkServers == null) + { + Settings.SplunkServers = new List(); + } + + if (Settings.SplunkServers.Any(x => (nickName != null && x.Nickname == nickName) || nickName == null && x.SplunkHecUrl == splunkHecUrl && x.SplunkHecToken == splunkHecToken)) + { + return false; + } + + Settings.SplunkServers.Add(new Splunk(splunkHecUrl, splunkHecToken, httpClientHandler, nickName)); + return true; + } + + /// + /// Remove the Splunk server + /// + /// + /// + /// + public bool RemoveSplunkServer(string splunkHecUrl, string splunkHecToken) + { + if (Settings.SplunkServers == null) + { + return false; + } + + var delete = Settings.SplunkServers.FirstOrDefault(x => x.SplunkHecUrl == splunkHecUrl && x.SplunkHecToken == splunkHecToken); + if (delete != null) + { + Settings.SplunkServers.Remove(delete); + } + return true; + } + + /// + /// Remove the Splunk server + /// + /// + /// + public bool RemoveSplunkServer(string nickName) + { + if (Settings.SplunkServers == null) + { + return false; + } + + var delete = Settings.SplunkServers.FirstOrDefault(x => x.Nickname == nickName); + if (delete != null) + { + Settings.SplunkServers.Remove(delete); + } + return true; + } + + /// + /// Add GrayLog server + /// + /// + /// + /// + /// + public bool AddGrayLogServer(string address, int port, string nickName = null) + { + if (Settings.GrayLogServers == null) + { + Settings.GrayLogServers = new List(); + } + + if (Settings.GrayLogServers.Any(x => (nickName != null && x.Nickname == nickName) || nickName == null && x.Hostname == address && x.Port == port)) + { + return false; + } + + Settings.GrayLogServers.Add(new Graylog(address, port)); + return true; + } + + /// + /// Remove the GrayLog server + /// + /// + /// + /// + public bool RemoveGrayLogServer(string address, int port) + { + if (Settings.GrayLogServers == null) + { + return false; + } + + var delete = Settings.GrayLogServers.FirstOrDefault(x => x.Hostname == address && x.Port == port); + if (delete != null) + { + Settings.GrayLogServers.Remove(delete); + } + return true; + } + + /// + /// Remove the GrayLog server + /// + /// + /// + public bool RemoveGrayLogServer(string nickName) + { + if (Settings.GrayLogServers == null) + { + return false; + } + + var delete = Settings.GrayLogServers.FirstOrDefault(x => x.Nickname == nickName); + if (delete != null) + { + Settings.GrayLogServers.Remove(delete); + } + return true; + } + + /// + /// Add Tcp server + /// + /// + /// + /// + /// + public bool AddTcpLogServer(string address, int port, string nickName = null) + { + if (Settings.TcpServers == null) + { + Settings.TcpServers = new List(); + } + + if (Settings.TcpServers.Any(x => (nickName != null && x.Nickname == nickName) || (nickName == null && x.Hostname == address && x.Port == port))) + { + return false; + } + + Settings.TcpServers.Add(new Tcp(address, port)); + return true; + } + + /// + /// Remove the Tcp server + /// + /// + /// + /// + public bool RemoveTcpLogServer(string address, int port) + { + if (Settings.TcpServers == null) + { + return false; + } + + var delete = Settings.TcpServers.FirstOrDefault(x => x.Hostname == address && x.Port == port); + if (delete != null) + { + Settings.TcpServers.Remove(delete); + } + return true; + } + + /// + /// Remove the Tcp server + /// + /// + /// + public bool RemoveTcpLogServer(string nickName) + { + if (Settings.TcpServers == null) + { + return false; + } + + var delete = Settings.TcpServers.FirstOrDefault(x => x.Nickname == nickName); + if (delete != null) + { + Settings.TcpServers.Remove(delete); + } + return true; + } + + /// + /// Add Udp server + /// + /// + /// + /// + /// + public bool AddUdpLogServer(string address, int port, string nickName = null) + { + if (Settings.UdpServers == null) + { + Settings.UdpServers = new List(); + } + + if (Settings.UdpServers.Any(x => (nickName != null && x.Nickname == nickName) || nickName == null && x.Hostname == address && x.Port == port)) + { + return false; + } + + Settings.UdpServers.Add(new Udp(address, port)); + return true; + } + + /// + /// Remove the Udp server + /// + /// + /// + /// + public bool RemoveUdpLogServer(string address, int port) + { + if (Settings.UdpServers == null) + { + return false; + } + + var delete = Settings.UdpServers.FirstOrDefault(x => x.Hostname == address && x.Port == port); + if (delete != null) + { + Settings.UdpServers.Remove(delete); + } + return true; + } + + /// + /// Remove the Udp server + /// + /// + /// + public bool RemoveUdpLogServer(string nickName) + { + if (Settings.UdpServers == null) + { + return false; + } + + var delete = Settings.UdpServers.FirstOrDefault(x => x.Nickname == nickName); + if (delete != null) + { + Settings.UdpServers.Remove(delete); + } + return true; + } } } \ No newline at end of file diff --git a/EonaCat.Logger/Managers/LoggerSettings.cs b/EonaCat.Logger/Managers/LoggerSettings.cs index 3b2a8cc..e500570 100644 --- a/EonaCat.Logger/Managers/LoggerSettings.cs +++ b/EonaCat.Logger/Managers/LoggerSettings.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; +using System.Net.Sockets; using System.Text.RegularExpressions; using EonaCat.Logger.EonaCatCoreLogger; using EonaCat.Logger.EonaCatCoreLogger.Models; -using EonaCat.Logger.GrayLog; -using EonaCat.Logger.Syslog; +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. @@ -127,18 +127,13 @@ public class LoggerSettings } public ELogType MaxLogType { get; set; } = ELogType.INFO; + public List SysLogServers { get; internal set; } + public List SplunkServers { get; internal set; } - public bool SendToSyslogServers { get; set; } + public List GrayLogServers { get; internal set; } + public List TcpServers { get; internal set; } - 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; } + public List UdpServers { get; internal set; } /// /// Determines if the fileLogging is enabled diff --git a/EonaCat.Logger/GrayLog/GrayLogServer.cs b/EonaCat.Logger/Servers/GrayLog/Graylog.cs similarity index 58% rename from EonaCat.Logger/GrayLog/GrayLogServer.cs rename to EonaCat.Logger/Servers/GrayLog/Graylog.cs index 3f134ce..c08a103 100644 --- a/EonaCat.Logger/GrayLog/GrayLogServer.cs +++ b/EonaCat.Logger/Servers/GrayLog/Graylog.cs @@ -1,87 +1,84 @@ using System; using System.Net.Sockets; -namespace EonaCat.Logger.GrayLog; +namespace EonaCat.Logger.Servers.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. +/// GrayLog client /// -public class GrayLogServer +public class Graylog : IDisposable { internal readonly object SendLock = new(); private string _Hostname = "127.0.0.1"; private int _Port = 12201; internal UdpClient Udp; - /// - /// Instantiate the object. - /// - public GrayLogServer() + public bool SupportsTcp { get; set; } + public string Nickname { get; set; } + public string IpPort => _Hostname + ":" + _Port; + + public Graylog() { } + + public Graylog(string hostname = "127.0.0.1", int port = 12201, string nickName = null) { + _Hostname = hostname ?? throw new ArgumentNullException(nameof(hostname)); + _Port = port >= 0 ? port : throw new ArgumentException("Port must be zero or greater."); + + Nickname = nickName ?? IpPort; + SetUdp(); } - /// - /// Instantiate the object. - /// - /// Hostname. - /// Port. - public GrayLogServer(string hostname = "127.0.0.1", int port = 12201) - { - Hostname = hostname; - Port = port; - } - - /// - /// Hostname. - /// public string Hostname { get => _Hostname; - set { if (string.IsNullOrEmpty(value)) - { throw new ArgumentNullException(nameof(Hostname)); - } _Hostname = value; - SetUdp(); } } - /// - /// UDP port. - /// public int Port { get => _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 => _Hostname + ":" + _Port; - - public bool SupportsTcp { get; set; } - private void SetUdp() { - Udp = null; + DisposeUdp(); Udp = new UdpClient(_Hostname, _Port); } + + private void DisposeUdp() + { + if (Udp != null) + { + Udp.Dispose(); + Udp = null; + } + } + + public void Dispose() + { + DisposeUdp(); + GC.SuppressFinalize(this); + } + + ~Graylog() + { + Dispose(); + } } \ No newline at end of file diff --git a/EonaCat.Logger/Splunk/Models/SplunkPayload.cs b/EonaCat.Logger/Servers/Splunk/Models/SplunkPayload.cs similarity index 87% rename from EonaCat.Logger/Splunk/Models/SplunkPayload.cs rename to EonaCat.Logger/Servers/Splunk/Models/SplunkPayload.cs index 73a2db9..4fa59d9 100644 --- a/EonaCat.Logger/Splunk/Models/SplunkPayload.cs +++ b/EonaCat.Logger/Servers/Splunk/Models/SplunkPayload.cs @@ -1,4 +1,4 @@ -namespace EonaCat.Logger.Splunk.Models; +namespace EonaCat.Logger.Servers.Splunk.Models; public class SplunkPayload { diff --git a/EonaCat.Logger/Servers/Splunk/Splunk.cs b/EonaCat.Logger/Servers/Splunk/Splunk.cs new file mode 100644 index 0000000..2308fe3 --- /dev/null +++ b/EonaCat.Logger/Servers/Splunk/Splunk.cs @@ -0,0 +1,130 @@ +using System; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using EonaCat.Json; + +namespace EonaCat.Logger.Servers.Splunk; + +using EonaCat.Logger.Servers.Splunk.Models; +// 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. +/// +using System; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +public class Splunk : IDisposable +{ + internal readonly object SendLock = new(); + private string _splunkHecUrl = "https://127.0.0.1:8088/services/collector/event"; + + public string SplunkHecToken { get; set; } = "splunk-hec-token"; + public HttpClientHandler SplunkClientHandler { get; private set; } + public HttpClient HttpClient { get; private set; } + public string Nickname { get; set; } + + public bool HasHecToken => !string.IsNullOrWhiteSpace(SplunkHecToken) && SplunkHecToken != "splunk-hec-token"; + public bool HasHecUrl => !string.IsNullOrWhiteSpace(SplunkHecUrl); + public bool IsHttpsHecUrl => HasHecUrl && _splunkHecUrl.ToLower().StartsWith("https"); + public bool IsLocalHost => HasHecUrl && (_splunkHecUrl.ToLower().Contains("127.0.0.1") || _splunkHecUrl.ToLower().Contains("localhost")); + + public Splunk(string splunkHecUrl, string splunkHecToken, HttpClientHandler httpClientHandler = null, string nickName = null) + { + SplunkHecUrl = splunkHecUrl ?? throw new ArgumentNullException(nameof(splunkHecUrl)); + SplunkHecToken = splunkHecToken ?? throw new ArgumentNullException(nameof(splunkHecToken)); + + Nickname = nickName ?? $"{splunkHecUrl}_{splunkHecToken}"; + SplunkClientHandler = httpClientHandler ?? new HttpClientHandler(); + + CreateHttpClient(); + } + + public string SplunkHecUrl + { + get => _splunkHecUrl; + set + { + if (!string.IsNullOrWhiteSpace(value) && !value.ToLower().Contains("http")) + { + value = $"http://{value}"; + } + + _splunkHecUrl = value; + CreateHttpClient(); + } + } + + private void CreateHttpClient() + { + DisposeHttpClient(); + + SplunkClientHandler ??= new HttpClientHandler(); + HttpClient = new HttpClient(SplunkClientHandler) + { + BaseAddress = new Uri(SplunkHecUrl) + }; + + HttpClient.DefaultRequestHeaders.Add("Authorization", $"Splunk {SplunkHecToken}"); + } + + public void DisableSSLValidation() + { + DisposeHttpClient(); + + SplunkClientHandler = new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true + }; + + CreateHttpClient(); + } + + public async Task SendAsync(SplunkPayload splunkPayload) + { + if (splunkPayload == null) return null; + + var eventObject = new + { + @event = splunkPayload.EventData, + sourcetype = splunkPayload.SourceType, + host = splunkPayload.Host + }; + + var eventJson = JsonHelper.ToJson(eventObject); + if (!HasHecToken) CreateHttpClient(); + + using var content = new StringContent(eventJson, Encoding.UTF8, "application/json"); + return await HttpClient.PostAsync("/services/collector/event", content); + } + + private void DisposeHttpClient() + { + if (HttpClient != null) + { + HttpClient.Dispose(); + HttpClient = null; + } + + if (SplunkClientHandler != null) + { + SplunkClientHandler.Dispose(); + SplunkClientHandler = null; + } + } + + public void Dispose() + { + DisposeHttpClient(); + GC.SuppressFinalize(this); + } + + ~Splunk() + { + Dispose(); + } +} \ No newline at end of file diff --git a/EonaCat.Logger/Syslog/SyslogServer.cs b/EonaCat.Logger/Servers/Syslog/Syslog.cs similarity index 63% rename from EonaCat.Logger/Syslog/SyslogServer.cs rename to EonaCat.Logger/Servers/Syslog/Syslog.cs index 824ff1b..c54a9ca 100644 --- a/EonaCat.Logger/Syslog/SyslogServer.cs +++ b/EonaCat.Logger/Servers/Syslog/Syslog.cs @@ -1,87 +1,82 @@ using System; using System.Net.Sockets; -namespace EonaCat.Logger.Syslog; +namespace EonaCat.Logger.Servers.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. /// -public class SyslogServer +public class Syslog : IDisposable { private string _Hostname = "127.0.0.1"; private int _Port = 514; internal UdpClient Udp; - /// - /// Instantiate the object. - /// - public SyslogServer() - { - } + public Syslog() { } - /// - /// Instantiate the object. - /// - /// Hostname. - /// Port. - public SyslogServer(string hostname = "127.0.0.1", int port = 514) + public Syslog(string hostname = "127.0.0.1", int port = 514, string nickName = null) { Hostname = hostname; Port = port; + Nickname = nickName ?? IpPort; } - /// - /// Hostname. - /// public string Hostname { get => _Hostname; - set { if (string.IsNullOrEmpty(value)) - { throw new ArgumentNullException(nameof(Hostname)); - } _Hostname = value; - SetUdp(); } } - /// - /// UDP port. - /// public int Port { get => _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 => _Hostname + ":" + _Port; - - public bool SupportsTcp { get; set; } - + public string IpPort => _Hostname + ":" + _Port; + public bool SupportsTcp { get; set; } + public string Nickname { get; set; } + private void SetUdp() { - Udp = null; + DisposeUdp(); Udp = new UdpClient(_Hostname, _Port); } + + private void DisposeUdp() + { + if (Udp != null) + { + Udp.Dispose(); + Udp = null; + } + } + + public void Dispose() + { + DisposeUdp(); + GC.SuppressFinalize(this); + } + + ~Syslog() + { + Dispose(); + } } \ No newline at end of file diff --git a/EonaCat.Logger/Servers/Tcp/Tcp.cs b/EonaCat.Logger/Servers/Tcp/Tcp.cs new file mode 100644 index 0000000..07f30e4 --- /dev/null +++ b/EonaCat.Logger/Servers/Tcp/Tcp.cs @@ -0,0 +1,115 @@ +using System; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; +namespace EonaCat.Logger.Servers.Tcp +{ + // 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 class Tcp : IDisposable + { + private string _Hostname = "127.0.0.1"; + private int _Port = 514; + internal TcpClient _tcp; + + public string Nickname { get; set; } + public string IpPort => _Hostname + ":" + _Port; + + public Tcp(string hostname, int port, string nickname = null) + { + _Hostname = hostname ?? throw new ArgumentNullException(nameof(hostname)); + _Port = port >= 0 ? port : throw new ArgumentException("Port must be zero or greater."); + + Nickname = nickname ?? IpPort; + SetTcp(); + } + + public string Hostname + { + get => _Hostname; + set + { + if (string.IsNullOrEmpty(value)) + throw new ArgumentNullException(nameof(Hostname)); + + _Hostname = value; + SetTcp(); + } + } + + public int Port + { + get => _Port; + set + { + if (value < 0) + throw new ArgumentException("Port must be zero or greater."); + + _Port = value; + SetTcp(); + } + } + + internal void SetTcp() + { + DisposeTcp(); + _tcp = new TcpClient(_Hostname, _Port); + } + + internal void DisposeTcp() + { + if (_tcp != null) + { + _tcp.Close(); + _tcp.Dispose(); + _tcp = null; + } + } + + public void Dispose() + { + DisposeTcp(); + GC.SuppressFinalize(this); + } + + internal async Task WriteAsync(byte[] data) + { + if (_tcp == null) + { + return; + } + + if (data == null) + { + return; + } + + using var stream = _tcp.GetStream(); + await stream.WriteAsync(data, 0, data.Length); + await stream.FlushAsync(); + } + + internal async Task WriteAsync(string data) + { + if (_tcp == null) + { + return; + } + + if (string.IsNullOrEmpty(data)) + { + return; + } + + var sendData = Encoding.UTF8.GetBytes(data); + using var stream = _tcp.GetStream(); + await stream.WriteAsync(sendData, 0, sendData.Length); + await stream.FlushAsync(); + } + + ~Tcp() + { + Dispose(); + } + } +} diff --git a/EonaCat.Logger/Servers/Udp/Udp.cs b/EonaCat.Logger/Servers/Udp/Udp.cs new file mode 100644 index 0000000..c99dc12 --- /dev/null +++ b/EonaCat.Logger/Servers/Udp/Udp.cs @@ -0,0 +1,127 @@ +using System; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; +namespace EonaCat.Logger.Servers.Udp +{ + // 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 class Udp : IDisposable + { + const int MaxUdpPacketSize = 4096; + private string _Hostname = "127.0.0.1"; + private int _Port = 514; + internal UdpClient _udp; + + public string Nickname { get; set; } + public string IpPort => _Hostname + ":" + _Port; + + public Udp(string hostname, int port, string nickname = null) + { + _Hostname = hostname ?? throw new ArgumentNullException(nameof(hostname)); + _Port = port >= 0 ? port : throw new ArgumentException("Port must be zero or greater."); + + Nickname = nickname ?? IpPort; + SetUdp(); + } + + public string Hostname + { + get => _Hostname; + set + { + if (string.IsNullOrEmpty(value)) + throw new ArgumentNullException(nameof(Hostname)); + + _Hostname = value; + SetUdp(); + } + } + + public int Port + { + get => _Port; + set + { + if (value < 0) + throw new ArgumentException("Port must be zero or greater."); + + _Port = value; + SetUdp(); + } + } + + internal void SetUdp() + { + DisposeUdp(); + _udp = new UdpClient(_Hostname, _Port); + } + + internal void DisposeUdp() + { + if (_udp != null) + { + _udp.Dispose(); + _udp = null; + } + } + + public void Dispose() + { + DisposeUdp(); + GC.SuppressFinalize(this); + } + + internal async Task WriteAsync(byte[] data, bool dontFragment = false) + { + if (_udp == null || data == null) + { + return; + } + + _udp.DontFragment = dontFragment; + + int maxChunkSize = MaxUdpPacketSize; + int offset = 0; + + while (offset < data.Length) + { + int chunkSize = Math.Min(maxChunkSize, data.Length - offset); + byte[] chunk = new byte[chunkSize]; + Array.Copy(data, offset, chunk, 0, chunkSize); + + await _udp.SendAsync(chunk, chunk.Length); + offset += chunkSize; + } + } + + internal async Task WriteAsync(string data, bool dontFragment = false) + { + if (_udp == null || string.IsNullOrEmpty(data)) + { + return; + } + + var sendData = Encoding.UTF8.GetBytes(data); + _udp.DontFragment = dontFragment; + + int maxChunkSize = MaxUdpPacketSize; + int offset = 0; + + while (offset < sendData.Length) + { + int chunkSize = Math.Min(maxChunkSize, sendData.Length - offset); + byte[] chunk = new byte[chunkSize]; + Array.Copy(sendData, offset, chunk, 0, chunkSize); + + await _udp.SendAsync(chunk, chunk.Length); + offset += chunkSize; + } + } + + ~Udp() + { + Dispose(); + } + } +} diff --git a/EonaCat.Logger/Zabbix/API/ZabbixApi.cs b/EonaCat.Logger/Servers/Zabbix/API/ZabbixApi.cs similarity index 98% rename from EonaCat.Logger/Zabbix/API/ZabbixApi.cs rename to EonaCat.Logger/Servers/Zabbix/API/ZabbixApi.cs index 1ff6966..fdb64e3 100644 --- a/EonaCat.Logger/Zabbix/API/ZabbixApi.cs +++ b/EonaCat.Logger/Servers/Zabbix/API/ZabbixApi.cs @@ -5,7 +5,7 @@ using System.IO; using System.Net; using System.Text; -namespace EonaCat.Logger.Zabbix.API; +namespace EonaCat.Logger.Servers.Zabbix.API; // 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. @@ -26,8 +26,8 @@ public class ZabbixApi } public ZabbixApi(string user, string password, string zabbixURL) : this(user, password, zabbixURL, false) - { - + { + } private readonly string _user; @@ -112,7 +112,7 @@ public class ZabbixApi private string SendRequest(string jsonParams) { WebRequest request = WebRequest.Create(_zabbixURL); - + if (_basicAuth != null) { request.Headers.Add("Authorization", "Basic " + _basicAuth); diff --git a/EonaCat.Logger/Zabbix/API/ZabbixApiRequest.cs b/EonaCat.Logger/Servers/Zabbix/API/ZabbixApiRequest.cs similarity index 95% rename from EonaCat.Logger/Zabbix/API/ZabbixApiRequest.cs rename to EonaCat.Logger/Servers/Zabbix/API/ZabbixApiRequest.cs index 650d832..ac40e98 100644 --- a/EonaCat.Logger/Zabbix/API/ZabbixApiRequest.cs +++ b/EonaCat.Logger/Servers/Zabbix/API/ZabbixApiRequest.cs @@ -1,4 +1,4 @@ -namespace EonaCat.Logger.Zabbix.API +namespace EonaCat.Logger.Servers.Zabbix.API { // 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. diff --git a/EonaCat.Logger/Zabbix/API/ZabbixApiResponse.cs b/EonaCat.Logger/Servers/Zabbix/API/ZabbixApiResponse.cs similarity index 93% rename from EonaCat.Logger/Zabbix/API/ZabbixApiResponse.cs rename to EonaCat.Logger/Servers/Zabbix/API/ZabbixApiResponse.cs index 6a838a7..14a01c5 100644 --- a/EonaCat.Logger/Zabbix/API/ZabbixApiResponse.cs +++ b/EonaCat.Logger/Servers/Zabbix/API/ZabbixApiResponse.cs @@ -1,6 +1,6 @@ using System.Dynamic; -namespace EonaCat.Logger.Zabbix.API +namespace EonaCat.Logger.Servers.Zabbix.API { // 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. diff --git a/EonaCat.Logger/Servers/Zabbix/ZabbixData.cs b/EonaCat.Logger/Servers/Zabbix/ZabbixData.cs new file mode 100644 index 0000000..5e4c715 --- /dev/null +++ b/EonaCat.Logger/Servers/Zabbix/ZabbixData.cs @@ -0,0 +1,22 @@ + +namespace EonaCat.Logger.Servers.Zabbix +{ + // 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. + /// + /// Zabbix server. + /// + public class ZabbixData + { + public string Host { get; set; } + public string Key { get; set; } + public string Value { get; set; } + + public ZabbixData(string host, string key, string value) + { + Host = host; + Key = key; + Value = value; + } + } +} diff --git a/EonaCat.Logger/Servers/Zabbix/ZabbixRequest.cs b/EonaCat.Logger/Servers/Zabbix/ZabbixRequest.cs new file mode 100644 index 0000000..0b13e48 --- /dev/null +++ b/EonaCat.Logger/Servers/Zabbix/ZabbixRequest.cs @@ -0,0 +1,79 @@ +using EonaCat.Json; +using System; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; + +namespace EonaCat.Logger.Servers.Zabbix +{ + // 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 class ZabbixRequest + { + private const int BUFFER_SIZE = 1024; + + /// + /// The request to send to the Zabbix server + /// + public string Request { get; set; } + + /// + /// The data to send to the Zabbix server + /// + public ZabbixData[] Data { get; set; } + + public ZabbixRequest(string host, string key, string value) + { + Request = "sender data"; + Data = [new ZabbixData(host, key, value)]; + } + + /// + /// Sends the request to the Zabbix server + /// + /// + /// + /// + /// + /// + public async Task SendAsync(string server, int port = 10051, int timeout = 500) + { + string json = JsonHelper.ToJson(new ZabbixRequest(Data[0].Host, Data[0].Key, Data[0].Value)); + using (TcpClient tcpClient = new TcpClient(server, port)) + using (NetworkStream stream = tcpClient.GetStream()) + { + byte[] header = Encoding.ASCII.GetBytes("ZBXD\x01"); + byte[] dataLength = BitConverter.GetBytes((long)json.Length); + byte[] content = Encoding.ASCII.GetBytes(json); + byte[] message = new byte[header.Length + dataLength.Length + content.Length]; + + Buffer.BlockCopy(header, 0, message, 0, header.Length); + Buffer.BlockCopy(dataLength, 0, message, header.Length, dataLength.Length); + Buffer.BlockCopy(content, 0, message, header.Length + dataLength.Length, content.Length); + + stream.Write(message, 0, message.Length); + stream.Flush(); + + int counter = 0; + while (!stream.DataAvailable) + { + if (counter < timeout / 50) + { + counter++; + await Task.Delay(50).ConfigureAwait(false); + } + else + { + throw new TimeoutException(); + } + } + + byte[] responseBytes = new byte[BUFFER_SIZE]; + stream.Read(responseBytes, 0, responseBytes.Length); + string responseAsString = Encoding.UTF8.GetString(responseBytes); + string jsonResult = responseAsString.Substring(responseAsString.IndexOf('{')); + return JsonHelper.ToObject(jsonResult); + } + } + } +} \ No newline at end of file diff --git a/EonaCat.Logger/Servers/Zabbix/ZabbixResponse.cs b/EonaCat.Logger/Servers/Zabbix/ZabbixResponse.cs new file mode 100644 index 0000000..ce56f9e --- /dev/null +++ b/EonaCat.Logger/Servers/Zabbix/ZabbixResponse.cs @@ -0,0 +1,11 @@ +namespace EonaCat.Logger.Servers.Zabbix +{ + // 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 class ZabbixResponse + { + public string Response { get; set; } + public string Info { get; set; } + + } +} diff --git a/EonaCat.Logger/Splunk/SplunkServer.cs b/EonaCat.Logger/Splunk/SplunkServer.cs deleted file mode 100644 index dbc4cad..0000000 --- a/EonaCat.Logger/Splunk/SplunkServer.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using EonaCat.Json; -using EonaCat.Logger.Splunk.Models; - -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 -{ - internal readonly object SendLock = new(); - private string _splunkHecUrl = "https://127.0.0.1:8088/services/collector/event"; - - - /// - /// Instantiate the object. - /// - /// splunkHecUrl. - /// splunkHecToken. - /// httpClientHandler. (optional) - public SplunkServer(string splunkHecUrl, string splunkHecToken, HttpClientHandler httpClientHandler = null) - { - SplunkHecUrl = splunkHecUrl; - SplunkHecToken = splunkHecToken; - - if (httpClientHandler == null) - { - httpClientHandler = new HttpClientHandler(); - } - - SplunkClientHandler = httpClientHandler; - CreateHttpClient(); - } - - /// - /// SplunkHecUrl - /// - public string SplunkHecUrl - { - get => _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; set; } = "splunk-hec-token"; - - public HttpClientHandler SplunkClientHandler { get; internal set; } - public HttpClient HttpClient { get; private set; } - - /// - /// Determines if a HEC token is available - /// - public bool HasHecToken => !string.IsNullOrWhiteSpace(SplunkHecToken) && SplunkHecToken != "splunk-hec-token"; - - /// - /// Determines if a HEC url is available - /// - public bool HasHecUrl => !string.IsNullOrWhiteSpace(SplunkHecUrl); - - /// - /// Determines if the splunk URL is local - /// - public bool IsLocalHost => HasHecUrl && - (SplunkHecUrl.ToLower().Contains("127.0.0.1") || - SplunkHecUrl.ToLower().Contains("localhost")); - - private void CreateHttpClient() - { - HttpClient = new HttpClient(SplunkClientHandler); - HttpClient.BaseAddress = new Uri(SplunkHecUrl); - - // Add the HEC token to the request headers for authorization - HttpClient.DefaultRequestHeaders.Add("Authorization", $"Splunk {SplunkHecToken}"); - } - - /// - /// Disables SSL validation (can be used for insecure https urls) - /// This overwrites your own httpClientHandler - /// - public void DisableSSLValidation() - { - var clientHandler = new HttpClientHandler - { - ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true - }; - - SplunkClientHandler = clientHandler; - CreateHttpClient(); - } - - public async Task SendAsync(SplunkPayload splunkPayload) - { - if (splunkPayload == null) - { - return null; - } - - // Create an event object with the required fields - var eventObject = new - { - @event = splunkPayload.EventData, - sourcetype = splunkPayload.SourceType, - host = splunkPayload.Host - }; - - // Serialize the event object to JSON - var eventJson = JsonHelper.ToJson(eventObject); - - if (!HasHecToken) - { - CreateHttpClient(); - } - - // Create an HTTP content with the event data - var content = new StringContent(eventJson, Encoding.UTF8, "application/json"); - - // Send the event to Splunk - var response = await HttpClient.PostAsync("/services/collector/event", content); - - return response; - } -} \ No newline at end of file diff --git a/EonaCat.Logger/Zabbix/ZabbixData.cs b/EonaCat.Logger/Zabbix/ZabbixData.cs deleted file mode 100644 index 0bfcead..0000000 --- a/EonaCat.Logger/Zabbix/ZabbixData.cs +++ /dev/null @@ -1,17 +0,0 @@ - -/// -/// Zabbix server. -/// -public class ZabbixData -{ - public string Host { get; set; } - public string Key { get; set; } - public string Value { get; set; } - - public ZabbixData(string host, string key, string value) - { - Host = host; - Key = key; - Value = value; - } -} diff --git a/EonaCat.Logger/Zabbix/ZabbixRequest.cs b/EonaCat.Logger/Zabbix/ZabbixRequest.cs deleted file mode 100644 index 5c376eb..0000000 --- a/EonaCat.Logger/Zabbix/ZabbixRequest.cs +++ /dev/null @@ -1,74 +0,0 @@ -using EonaCat.Json; -using System; -using System.Net.Sockets; -using System.Text; -using System.Threading.Tasks; - -public class ZabbixRequest -{ - private const int BUFFER_SIZE = 1024; - - /// - /// The request to send to the Zabbix server - /// - public string Request { get; set; } - - /// - /// The data to send to the Zabbix server - /// - public ZabbixData[] Data { get; set; } - - public ZabbixRequest(string host, string key, string value) - { - Request = "sender data"; - Data = [new ZabbixData(host, key, value)]; - } - - /// - /// Sends the request to the Zabbix server - /// - /// - /// - /// - /// - /// - public async Task SendAsync(string server, int port = 10051, int timeout = 500) - { - string json = JsonHelper.ToJson(new ZabbixRequest(Data[0].Host, Data[0].Key, Data[0].Value)); - using (TcpClient tcpClient = new TcpClient(server, port)) - using (NetworkStream stream = tcpClient.GetStream()) - { - byte[] header = Encoding.ASCII.GetBytes("ZBXD\x01"); - byte[] dataLength = BitConverter.GetBytes((long)json.Length); - byte[] content = Encoding.ASCII.GetBytes(json); - byte[] message = new byte[header.Length + dataLength.Length + content.Length]; - - Buffer.BlockCopy(header, 0, message, 0, header.Length); - Buffer.BlockCopy(dataLength, 0, message, header.Length, dataLength.Length); - Buffer.BlockCopy(content, 0, message, header.Length + dataLength.Length, content.Length); - - stream.Write(message, 0, message.Length); - stream.Flush(); - - int counter = 0; - while (!stream.DataAvailable) - { - if (counter < timeout / 50) - { - counter++; - await Task.Delay(50).ConfigureAwait(false); - } - else - { - throw new TimeoutException(); - } - } - - byte[] responseBytes = new byte[BUFFER_SIZE]; - stream.Read(responseBytes, 0, responseBytes.Length); - string responseAsString = Encoding.UTF8.GetString(responseBytes); - string jsonResult = responseAsString.Substring(responseAsString.IndexOf('{')); - return JsonHelper.ToObject(jsonResult); - } - } -} \ No newline at end of file diff --git a/EonaCat.Logger/Zabbix/ZabbixResponse.cs b/EonaCat.Logger/Zabbix/ZabbixResponse.cs deleted file mode 100644 index 2f46c16..0000000 --- a/EonaCat.Logger/Zabbix/ZabbixResponse.cs +++ /dev/null @@ -1,6 +0,0 @@ -public class ZabbixResponse -{ - public string Response { get; set; } - public string Info { get; set; } - -} diff --git a/Testers/EonaCat.Logger.Test.Web/Program.cs b/Testers/EonaCat.Logger.Test.Web/Program.cs index 5d8129b..ba8b999 100644 --- a/Testers/EonaCat.Logger.Test.Web/Program.cs +++ b/Testers/EonaCat.Logger.Test.Web/Program.cs @@ -183,7 +183,7 @@ async void RunWebLoggingTests() await file.WriteAsync($"WebLogged: {i}{Environment.NewLine}").ConfigureAwait(false); } Console.WriteLine($"WebLogged: {i}"); - Task.Delay(1); + await Task.Delay(1); } } @@ -203,10 +203,10 @@ async void RunMaskTest() using (var file = new StreamWriter(Path.Combine(logger.LogFolder, "testmask.log"), true)) { - file.WriteAsync(message); + await file.WriteAsync(message); } Console.WriteLine($"Masked: {i}"); - Task.Delay(1); + await Task.Delay(1); } }