diff --git a/(Setup) Log 4 Graylog/(Setup) Log 4 Graylog.vdproj b/(Setup) Log 4 Graylog/(Setup) Log 4 Graylog.vdproj index 380c339..3c86a7a 100644 --- a/(Setup) Log 4 Graylog/(Setup) Log 4 Graylog.vdproj +++ b/(Setup) Log 4 Graylog/(Setup) Log 4 Graylog.vdproj @@ -19,6 +19,12 @@ "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } + "Entry" + { + "MsmKey" = "8:_B7C9512C21954D9088AFF74B0D0F682B" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } } "Configurations" { @@ -44,6 +50,14 @@ "PrerequisitesLocation" = "2:1" "Url" = "8:" "ComponentsUrl" = "8:" + "Items" + { + "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.7.2" + { + "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)" + "ProductCode" = "8:.NETFramework,Version=v4.7.2" + } + } } } "Release" @@ -108,6 +122,26 @@ } "File" { + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B7C9512C21954D9088AFF74B0D0F682B" + { + "SourcePath" = "8:E:\\GFX\\Loghi e Icone\\008 - Log 4 Graylog\\log-4-graylog.ico" + "TargetName" = "8:log-4-graylog.ico" + "Tag" = "8:" + "Folder" = "8:_9B600ABCFF494174A956D068E6CF1046" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } } "FileType" { @@ -164,15 +198,15 @@ { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:Log 4 Graylog" - "ProductCode" = "8:{20B40DF7-DE7D-4525-8A5A-70A7553AD142}" - "PackageCode" = "8:{8B5226CE-438C-4CA5-AA45-6B913E396AD8}" + "ProductCode" = "8:{E73F35BF-F750-4609-A786-958CE5C83DE7}" + "PackageCode" = "8:{ACC078E3-F12A-4087-A8AE-D7B8DF393845}" "UpgradeCode" = "8:{7CE09C91-3C26-4C8E-BC66-003536E12481}" "AspNetVersion" = "8:4.0.30319.0" "RestartWWWService" = "11:FALSE" "RemovePreviousVersions" = "11:FALSE" "DetectNewerInstalledVersion" = "11:TRUE" "InstallAllUsers" = "11:TRUE" - "ProductVersion" = "8:1.0.1" + "ProductVersion" = "8:1.0.2" "Manufacturer" = "8:PAL s.r.l." "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:" @@ -285,32 +319,32 @@ } "Shortcut" { - "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_7FC43709505E4AD69D729799E1A9FD55" + "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_0AC95449D7BB49C294086916871E955F" { "Name" = "8:Log 4 Graylog" "Arguments" = "8:" "Description" = "8:" "ShowCmd" = "3:1" - "IconIndex" = "3:32512" + "IconIndex" = "3:0" "Transitive" = "11:FALSE" "Target" = "8:_485C7AAA71924496B4CCA8F2B60EB371" "Folder" = "8:_5CBF406C9E44415E87BBF1E35E297CB9" "WorkingFolder" = "8:_9B600ABCFF494174A956D068E6CF1046" - "Icon" = "8:_485C7AAA71924496B4CCA8F2B60EB371" + "Icon" = "8:_B7C9512C21954D9088AFF74B0D0F682B" "Feature" = "8:" } - "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_80AF6F01831346B88EC66109D1FF16DE" + "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_7D574C8D097B44558FBEBD9AF12F9D46" { "Name" = "8:Log 4 Graylog" "Arguments" = "8:" "Description" = "8:" "ShowCmd" = "3:1" - "IconIndex" = "3:32512" + "IconIndex" = "3:0" "Transitive" = "11:FALSE" "Target" = "8:_485C7AAA71924496B4CCA8F2B60EB371" "Folder" = "8:_1D6B671D343A4228A354CA138B3705BD" "WorkingFolder" = "8:_9B600ABCFF494174A956D068E6CF1046" - "Icon" = "8:_485C7AAA71924496B4CCA8F2B60EB371" + "Icon" = "8:_B7C9512C21954D9088AFF74B0D0F682B" "Feature" = "8:" } } diff --git a/console_log4graylog/Enums/SettingsEnum.cs b/console_log4graylog/Enums/SettingsEnum.cs new file mode 100644 index 0000000..f559c95 --- /dev/null +++ b/console_log4graylog/Enums/SettingsEnum.cs @@ -0,0 +1,8 @@ +namespace console_log4graylog.Enums +{ + public enum LogTypeEnums + { + None, + CyberPlan + } +} diff --git a/console_log4graylog/Models/CyberPlanModel.cs b/console_log4graylog/Models/CyberPlanModel.cs new file mode 100644 index 0000000..a328fd8 --- /dev/null +++ b/console_log4graylog/Models/CyberPlanModel.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace console_log4graylog.Models +{ + public class CyberPlanModel + { + public DateTime DateTime { get; set; } + public string Type { get; set; } + public string Instance { get; set; } + public string Message { get; set; } + public string Content { get; set; } + } +} diff --git a/console_log4graylog/Model/SettingsModel.cs b/console_log4graylog/Models/SettingsModel.cs similarity index 67% rename from console_log4graylog/Model/SettingsModel.cs rename to console_log4graylog/Models/SettingsModel.cs index dd40a39..65f1caa 100644 --- a/console_log4graylog/Model/SettingsModel.cs +++ b/console_log4graylog/Models/SettingsModel.cs @@ -3,8 +3,11 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using console_log4graylog.Enums; +using Microsoft.Extensions.Logging; +using Serilog.Events; -namespace console_log4graylog.Model +namespace console_log4graylog.Models { public class SettingsModel { @@ -15,8 +18,9 @@ namespace console_log4graylog.Model public class GraylogSettings { - public string FQDN { get; set; } + public string HostnameOrAddress { get; set; } public int Port { get; set; } + public LogEventLevel MinimumLogEventLevel { get; set; } public string Facility { get; set; } } @@ -25,5 +29,6 @@ namespace console_log4graylog.Model public string DirPath { get; set; } public string FileNamePattern { get; set; } public string LogPath { get; set; } + public LogTypeEnums LogType { get; set; } } } diff --git a/console_log4graylog/Program.cs b/console_log4graylog/Program.cs index d1204ae..e043030 100644 --- a/console_log4graylog/Program.cs +++ b/console_log4graylog/Program.cs @@ -1,11 +1,12 @@ -using console_log4graylog.Model; -using console_log4graylog.Workers; +using console_log4graylog.Workers; using Microsoft.Extensions.Configuration; using Serilog; using Serilog.Core; using Serilog.Events; using Serilog.Sinks.Graylog; using System.ServiceProcess; +using console_log4graylog.Models; +using System.Net; namespace console_log4graylog { @@ -23,25 +24,19 @@ namespace console_log4graylog var graylogSettings = config.GetSection("GraylogSettings").Get(); Log.Logger = new LoggerConfiguration() - .Enrich.With(new PalLogger()) + .Enrich.FromLogContext() + //.Enrich.WithProperty("HostName", Dns.GetHostName()) .WriteTo.Graylog(new GraylogSinkOptions { - HostnameOrAddress = graylogSettings.FQDN, + HostnameOrAddress = graylogSettings.HostnameOrAddress, Port = graylogSettings.Port, - MinimumLogEventLevel = LogEventLevel.Warning, + MinimumLogEventLevel = graylogSettings.MinimumLogEventLevel, Facility = graylogSettings.Facility - }).CreateLogger(); + }) + .CreateLogger(); ServiceBase.Run(new MainWorker(config)); } } - - public class PalLogger : ILogEventEnricher - { - public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) - { - logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("Username", Environment.UserName, true)); - } - } } diff --git a/console_log4graylog/README.md b/console_log4graylog/README.md new file mode 100644 index 0000000..9fef0cb --- /dev/null +++ b/console_log4graylog/README.md @@ -0,0 +1,92 @@ +# Log4Graylog + +![DotNet](https://img.shields.io/badge/Code-.NET%209.0-purple?style=flat-square&logo=dotnet) +![Graylog](https://img.shields.io/badge/Device-Graylog-red?style=flat-square&logo=graylog) +![Release](https://img.shields.io/badge/Release-v1.0.2-green?style=flat-square) + + +Service for monitoring and sending log files to Graylog + +## AppSettings + +
+GraylogSettings +
+ +>HostnameOrAddress + +logs.pal.it [Default] + +>Port + +12204 [Default] + +>MinimumLogEventLevel + +0. Verbose +1. Debug +2. Information [Default] +3. Warning +4. Error +5. Fatal + +>Facility + +ConsoleApp [Default] + +--- +
+ +
+GeneralSettings +
+ +>LogType + +0. None +1. Cyperplan + +>DirPath + +Path to the folder where the file to be monitored is located + +>FileNamePattern + +"\*.\*" Regex for file search + +--- +
+ +### Already run example and backup + +
+PALCYBERPAN01 +
+ +``` +{ + "GraylogSettings" : { + "HostnameOrAddress" : "logs.pal.local", + "Port" : 12204, + "MinimumLogEventLevel": 2, + "Facility" : "CyberPlan Logs" + }, + "GeneralSettings" : { + "LogType": 1, + "DirPath" : "E:\\CyberPlanWeb_Data\\cybinstance\\PLANNING\\logs", + "FileNamePattern": "debug.*.log*" + } +} +``` +
+ +## Run as Services + +**Powershell** +``` +New-Service -Name "Log4Graylog" ` + -BinaryPathName "C:\Program Files\PAL s.r.l\Log 4 Graylog\console_log4graylog.exe" ` + -DisplayName "Log 4 Graylog" ` + -Description "Servizio per il monitoring ed invio dei file di log a Graylog" ` + -StartupType Automatic +``` \ No newline at end of file diff --git a/console_log4graylog/Utils/Log4Platform.cs b/console_log4graylog/Utils/Log4Platform.cs new file mode 100644 index 0000000..3ccb17f --- /dev/null +++ b/console_log4graylog/Utils/Log4Platform.cs @@ -0,0 +1,48 @@ +using console_log4graylog.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Serilog; +using Serilog.Events; + +namespace console_log4graylog.Utils +{ + public class Log4Platform + { + public static void CyberPlanLogger(string logString, CancellationToken cancellationToken) + { + try + { + cancellationToken.ThrowIfCancellationRequested(); + + var log = logString.Split('\t'); + + var logModel = new CyberPlanModel + { + DateTime = DateTime.Parse(log[0].Trim(new[] { '[', ']' })), + Type = log[1].Trim(':'), + Instance = log[2].Trim(new[] { '[', ']' }), + Message = log[3], + Content = log[4] + }; + + Log.Logger + .ForContext("logts", logModel.DateTime) + .ForContext("instance", logModel.Instance) + .ForContext("event", logModel.Type.FirstCharToUpper()) + .ForContext("content", logModel.Content) + .Write( + SharedUtils.GetLogEventLevel(logModel.Type), + logModel.Message + ); + } + catch (TaskCanceledException) { return; } + catch (Exception ex) + { + SharedUtils.LogError(ex); + } + } + } +} diff --git a/console_log4graylog/Utils/SharedUtils.cs b/console_log4graylog/Utils/SharedUtils.cs new file mode 100644 index 0000000..5279887 --- /dev/null +++ b/console_log4graylog/Utils/SharedUtils.cs @@ -0,0 +1,50 @@ +using Serilog; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using console_log4graylog.Models; +using Serilog.Events; + +namespace console_log4graylog.Utils +{ + public static class SharedUtils + { + public static void LogError(Exception ex) + { + Log.Logger.Fatal(ex, "⚠️ " + ex.Message); + throw new Exception(ex.Message); + } + + public static FileInfo GetLatestLogFile(GeneralSettings gs) + { + DirectoryInfo dir = new DirectoryInfo(gs.DirPath); + return dir.GetFiles(gs.FileNamePattern) + .OrderByDescending(f => f.LastWriteTime) + .FirstOrDefault(); + } + + public static LogEventLevel GetLogEventLevel(string logType) + { + switch (logType) + { + case "error": + return LogEventLevel.Error; + case "info": + case "debug": + return LogEventLevel.Information; + default: + return LogEventLevel.Warning; + } + } + + public static string FirstCharToUpper(this string input) => + input switch + { + null => throw new ArgumentNullException(nameof(input)), + "" => throw new ArgumentException($"{nameof(input)} cannot be empty", nameof(input)), + _ => string.Concat(input[0].ToString().ToUpper(), input.AsSpan(1)) + }; + } +} diff --git a/console_log4graylog/Workers/MainWorker.cs b/console_log4graylog/Workers/MainWorker.cs index 405561d..78f7ca5 100644 --- a/console_log4graylog/Workers/MainWorker.cs +++ b/console_log4graylog/Workers/MainWorker.cs @@ -1,14 +1,16 @@ -using console_log4graylog.Model; +using console_log4graylog.Models; using Microsoft.Extensions.Configuration; using Serilog; using System.Net; using System.ServiceProcess; +using console_log4graylog.Enums; +using console_log4graylog.Utils; namespace console_log4graylog.Workers { internal class MainWorker : ServiceBase { - private SettingsModel Settings { get; set; } + private SettingsModel Settings { get; } private FileSystemWatcher watcher; private Task monitorTask; private CancellationTokenSource cancellationTokenSource; @@ -17,14 +19,14 @@ namespace console_log4graylog.Workers { Settings = new () { - GeneralSettings = _configuration.GetSection("GeneralSettings").Get() + GeneralSettings = _configuration.GetSection("GeneralSettings").Get(), + GraylogSettings = _configuration.GetSection("GraylogSettings").Get() }; } protected override void OnStart(string[] args) { - Log2File("Start Log 4 Graylog"); - Log.Logger.Warning("▶️ Start Log 4 Graylog on " + Dns.GetHostName()); + Log.Logger.Information("▶️ Start Log 4 Graylog on " + Dns.GetHostName()); cancellationTokenSource = new CancellationTokenSource(); monitorTask = Task.Run(() => MonitorFolder(cancellationTokenSource.Token), cancellationTokenSource.Token); @@ -33,8 +35,7 @@ namespace console_log4graylog.Workers protected override void OnStop() { - Log2File("End Log 4 Graylog"); - Log.Logger.Error("⏹️ End Log 4 Graylog on " + Dns.GetHostName()); + Log.Logger.Fatal("⏹️ End Log 4 Graylog on " + Dns.GetHostName()); cancellationTokenSource.Cancel(); watcher?.Dispose(); @@ -47,7 +48,7 @@ namespace console_log4graylog.Workers { try { - var latestFile = GetLatestLogFile(); + var latestFile = SharedUtils.GetLatestLogFile(Settings.GeneralSettings); if (latestFile != null) { await MonitorLogFile(latestFile, cancellationToken); @@ -60,25 +61,16 @@ namespace console_log4graylog.Workers catch (TaskCanceledException) { return; } catch (Exception ex) { - LogError("Service encountered an error: " + ex.Message); + SharedUtils.LogError(ex); } } } - private FileInfo GetLatestLogFile() - { - DirectoryInfo dir = new DirectoryInfo(Settings.GeneralSettings.DirPath); - return dir.GetFiles(Settings.GeneralSettings.FileNamePattern) - .OrderByDescending(f => f.LastWriteTime) - .FirstOrDefault(); - } - private async Task MonitorLogFile(FileInfo file, CancellationToken cancellationToken) { try { - Log2File("Attach to file: " + file.FullName); - Log.Logger.Warning("🗂️ Attach to file: " + file.FullName); + Log.Logger.Information("🗂️ Attach to file: " + file.FullName); using (var fs = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var reader = new StreamReader(fs)) { @@ -90,50 +82,36 @@ namespace console_log4graylog.Workers string line = reader.ReadLine(); while (line != null) { - Log.Logger.Warning(line); + switch (Settings.GeneralSettings.LogType) + { + case LogTypeEnums.CyberPlan: + Log4Platform.CyberPlanLogger(line, cancellationToken); + break; + + default: + Log.Logger.Write( + Settings.GraylogSettings.MinimumLogEventLevel, + line + ); + break; + } + line = reader.ReadLine(); } - if (GetLatestLogFile()?.FullName != file.FullName) - { + + if (SharedUtils.GetLatestLogFile(Settings.GeneralSettings)?.FullName != file.FullName) break; - } - await Task.Delay(1, cancellationToken); + + if (line == null) + await Task.Delay(1, cancellationToken); } } } catch (TaskCanceledException) { return; } catch (Exception ex) { - LogError("Error monitoring file: " + ex.Message); + SharedUtils.LogError(ex); } } - - - private void LogError(string errorMessage) - { - Log2File(errorMessage); - Log.Logger.Error("⚠️ " + errorMessage); - - throw new Exception(errorMessage); - } - - private void Log2File(string message) - { - if (!Directory.Exists(Path.GetDirectoryName(Settings.GeneralSettings.LogPath))) - { - Directory.CreateDirectory(Path.GetDirectoryName(Settings.GeneralSettings.LogPath)); - } - - if (!File.Exists(Settings.GeneralSettings.LogPath)) - { - using (FileStream fs = File.Create(Settings.GeneralSettings.LogPath)) - { - byte[] info = new System.Text.UTF8Encoding(true).GetBytes(""); - fs.Write(info, 0, info.Length); - } - } - - File.AppendAllText(Settings.GeneralSettings.LogPath, DateTime.Now + " - " + message + "\n"); - } } } diff --git a/console_log4graylog/appsettings.json b/console_log4graylog/appsettings.json index ea91ec1..cb3ac7d 100644 --- a/console_log4graylog/appsettings.json +++ b/console_log4graylog/appsettings.json @@ -1,12 +1,13 @@ { - "GraylogSettings" : { - "FQDN" : "graylog.local", - "Port" : 12202, - "Facility" : "ConsoleApp" + "GraylogSettings": { + "HostnameOrAddress": "logs.pal.it", + "Port": 12204, + "MinimumLogEventLevel": 2, + "Facility": "ConsoleApp" }, "GeneralSettings" : { + "LogType": 1, "DirPath" : "C:\\Logs", - "FileNamePattern": "*.log", - "LogPath": "C:\\Logs\\debug.l4g" + "FileNamePattern": "*.log" } } diff --git a/console_log4graylog/console_log4graylog.csproj b/console_log4graylog/console_log4graylog.csproj index 889fded..7205fe6 100644 --- a/console_log4graylog/console_log4graylog.csproj +++ b/console_log4graylog/console_log4graylog.csproj @@ -6,14 +6,15 @@ enable enable Log-4-Graylog.ico + critical - none + full - none + full