# EonaCat.Logger

Log application information to log files.

Be sure the following dependencies are added:

> Microsoft.Extensions.Logging.Abstractions
Microsoft.Extensions.DependencyInjection.Abstractions
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.Logging

**Easy way of logging without configuring anything:**
```csharp
LogManager.Instance.WriteAsync("INFO", ELogType.INFO, true);
LogManager.Instance.WriteAsync("WARNING", ELogType.WARNING, true);
LogManager.Instance.WriteAsync("ERROR", ELogType.ERROR, true);
LogManager.Instance.WriteAsync("DEBUG", ELogType.DEBUG, true);
LogManager.Instance.WriteAsync("CRITICAL", ELogType.CRITICAL, true);
LogManager.Instance.WriteAsync("TRACE", ELogType.TRACE, true);
LogManager.Instance.WriteAsync("TRAFFIC", ELogType.TRAFFIC, true);
LogManager.Instance.WriteAsync("NONE", ELogType.NONE, true);
```

**Logging in .NET 4.8 or higher: **

```csharp
public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args)
        {
            // Add services to the container.
            FileLoggerOptions options = new FileLoggerOptions();
            options.MaxRolloverFiles = 20;
            options.FileSizeLimit = 1 * 1024 * 1024 / 4;
            options.UseLocalTime = true;

            var builder = Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                }).ConfigureLogging(x => x.AddEonaCatFileLogger(fileLoggerOptions: options, filenamePrefix: "web"));
            return builder;
        }
    }    
```

**Example of *advanced* logging class:**

```csharp
// Import necessary namespaces.
using EonaCat.Logger;
using EonaCat.Logger.Managers;
using EonaCat.Logger.Syslog;
using EonaCat.Logger.SplunkServer;
using EonaCat.Logger.GrayLog;

namespace EonaCat.Logger.Advanced
{
    // The GrayLogSettings class represents settings for GrayLog servers.
    internal class GrayLogSettings
    {
        // Constructor for GrayLogSettings class.
        public GrayLogSettings(string facility, string source, string version = "1.1")
        {
            Facility = facility;
            Source = source;
            Version = version;
        }

        // Facility represents the facility for GrayLog logs.
        public string Facility { get; }
        // Source represents the source for GrayLog logs.
        public string Source { get; }
        // Version represents the version for GrayLog logs (default is "1.1").
        public string Version { get; }
    }

    // The Logger class provides advanced logging functionality.
    internal class Logger
    {
        private static readonly LogManager _logManager;
        private static ConsoleLogTextWriter _consoleLogTextWriter;

        // Exposes a TextWriter property to allow for logging to the console.
        public static TextWriter ConsoleLog { get; internal set; }

        // Static constructor for the Logger class.
        static Logger()
        {
            // Create and configure a LogManager for logging.
            _logManager = new LogManager(new LoggerSettings());
            _logManager.OnException += _logManager_OnException;
            _logManager.OnLogLevelDisabled += _logManager_OnLogLevelDisabled;
            _logManager.Settings.FileLoggerOptions.FileNamePrefix = "advanced";
            _logManager.Settings.UseLocalTime = true;
            _logManager.Settings.FileLoggerOptions.UseLocalTime = true;
            _logManager.Settings.SysLogServers = new List<SyslogServer>();
            _logManager.Settings.SplunkServers = new List<SplunkServer>();
            _logManager.Settings.GrayLogServers = new List<GrayLogServer>();
            _logManager.StartNewLogAsync();
        }

        // Event handler for LogManager exceptions, writes messages to the console.
        private static void _logManager_OnException(object? sender, ErrorMessage e)
        {
            Console.WriteLine(e.Message);
            if (e.Exception != null)
            {
                Console.WriteLine(e.Exception);
            }
        }

         // Event handler for LogManager loglevel disabled notifications, writes messages to the console.
        private static void _logManager_OnLogLevelDisabled(object? sender, ErrorMessage e)
        {
            Console.WriteLine(e.Message);
            if (e.Exception != null)
            {
                Console.WriteLine(e.Exception);
            }
        }

        // Redirects console output to the log.
        public static void RedirectConsoleToLog()
        {
            // Create the callback function to capture console output and log it.
            static void callback(string line) => Info(line, writeToConsole: false);

            _consoleLogTextWriter = new ConsoleLogTextWriter(callback);
            Console.SetOut(_consoleLogTextWriter);
        }

        // Adds a GrayLog server with the specified hostname and port.
        public static void AddGrayLogServer(string hostname, int port)
        {
            _logManager.Settings.GrayLogServers.Add(new GrayLogServer(hostname, port));
        }

        // Removes a GrayLog server from the configuration.
        public static bool RemoveGrayLogServer(GrayLogServer grayLogServer)
        {
            return _logManager.Settings.GrayLogServers.Remove(grayLogServer);
        }

        // Adds a Splunk server with the specified HEC URL and token.
        public static void AddSplunkServer(string splunkHecUrl, string splunkHecToken, bool disableSSL = false)
        {
            var splunkServer = new SplunkServer(splunkHecUrl, splunkHecToken);
            if (disableSSL)
            {
                splunkServer.DisableSSLValidation();
            }
            _logManager.Settings.SplunkServers.Add(splunkServer);
        }

        // Removes a Splunk server from the configuration.
        public static bool RemoveSplunkServer(SplunkServer splunkServer)
        {
            return _logManager.Settings.SplunkServers.Remove(splunkServer);
        }

        // Adds a Syslog server with the specified IP address and port.
        public static void AddSyslogServer(string ipAddress, int port)
        {
            _logManager.Settings.SysLogServers.Add(new SyslogServer(ipAddress, port));
        }

        // Removes a Syslog server from the configuration.
        public static bool RemoveSyslogServer(SyslogServer syslogServer)
        {
            return _logManager.Settings.SysLogServers.Remove(syslogServer);
        }

        // Logs an informational message.
        public static void Info(string message, bool? writeToConsole = null, string? customSplunkSourceType = null, GrayLogSettings grayLogSettings = null)
        {
            WriteAsync(message, ELogType.INFO, writeToConsole, customSplunkSourceType, grayLogSettings);
        }

        // Internal method to write logs.
        private static void WriteAsync(string message, ELogType logType, bool? writeToConsole = null, string? customSplunkSourceType = null, GrayLogSettings grayLogSettings = null)
        {
            if (grayLogSettings != null)
            {
                // Log the message with specified settings.
                _logManager.WriteAsync(message, logType, writeToConsole, customSplunkSourceType, grayLogSettings.Facility, grayLogSettings.Source, grayLogSettings.Version);
            }
            else
            {
                // Log the message with default settings.
                _logManager.WriteAsync(message, logType, writeToConsole, customSplunkSourceType);
            }
        }

        // Logs a debug message.
        public static void Debug(string message, bool? writeToConsole = null, string? customSplunkSourceType = null, GrayLogSettings grayLogSettings = null)
        {
            WriteAsync(message, ELogType.DEBUG, writeToConsole, customSplunkSourceType, grayLogSettings);
        }

        // Logs an error message along with an exception.
        public static void Error(Exception exception, string message = null, bool isCriticalException = false, bool? writeToConsole = null, string? customSplunkSourceType = null, GrayLogSettings grayLogSettings = null)
        {
            if (grayLogSettings != null)
            {
                // Log the exception and message with specified settings.
                _logManager.WriteAsync(exception, message, criticalException: isCriticalException, writeToConsole: writeToConsole, customSplunkSourceType: customSplunkSourceType, grayLogFacility: grayLogSettings.Facility, grayLogSource: grayLogSettings.Source, grayLogVersion: grayLogSettings.Version);
            }
            else
            {
                // Log the exception and message with default settings.
                _logManager.WriteAsync(exception, message, criticalException: isCriticalException, writeToConsole: writeToConsole, customSplunkSourceType: customSplunkSourceType);
            }
        }

        // Logs an error message.
        public static void Error(string message = null, bool? writeToConsole = null, string? customSplunkSourceType = null, string grayLogFacility = null, string grayLogSource = null, string grayLogVersion = "1.1", bool isCriticalException = false)
        {
            if (isCriticalException)
            {
                // Log a critical error message.
                _logManager.WriteAsync(message, ELogType.CRITICAL, writeToConsole);
            }
            else
            {
                // Log a regular error message.
                _logManager.WriteAsync(message, ELogType.ERROR, writeToConsole);
            }
        }

        // Logs a warning message.
        public static void Warning(string message, bool? writeToConsole = null, string? customSplunkSourceType = null, GrayLogSettings grayLogSettings = null)
        {
            WriteAsync(message, ELogType.WARNING, writeToConsole, customSplunkSourceType, grayLogSettings);
        }

        // Logs a critical message.
        public static void Critical(string message, bool? writeToConsole = null, bool? string? customSplunkSourceType = null, bool? GrayLogSettings grayLogSettings = null)
        {
            WriteAsync(message, ELogType.CRITICAL, writeToConsole, customSplunkSourceType, grayLogSettings);
        }

        // Logs a traffic message.
        public static void Traffic(string message, bool? writeToConsole = null, string? customSplunkSourceType = null, GrayLogSettings grayLogSettings = null)
        {
            WriteAsync(message, ELogType.TRAFFIC, writeToConsole, customSplunkSourceType, grayLogSettings);
        }

        // Logs a trace message.
        public static void Trace(string message, bool? writeToConsole = null, string? customSplunkSourceType = null, GrayLogSettings grayLogSettings = null)
        {
            WriteAsync(message, ELogType.TRACE, writeToConsole, customSplunkSourceType, grayLogSettings);
        }
    }
}
```

**Code for enabling keyword masking (default: false):**

```csharp
Logger.LoggerSettings.UseMask = true;
```

Sensitive information will be replaced with ****MASKED****
You can add additional masking keywords using the MaskedKeywords property on the LoggerSettings object

You can also override the MaskSensitiveInformation method of the batchLoggingProvider to add your own masking


Default maskings (when the masking is enabled):
IP addresses
MAC addresses
Emails
Passwords
Credit card numbers
Social security numbers (SSN) and BSN (Dutch Citizen Service Number)
API keys/tokens
Phone numbers (generic and Dutch specific)
Dates of birth (DOB) or other date formats
IBAN/Bank account numbers (generic and Dutch specific)
JWT tokens
URLs with sensitive query strings
License keys
Public and private keys (e.g., PEM format)
Dutch KVK number (8 or 12 digits)
Dutch BTW-nummer (VAT number)
Dutch driving license number (10-12 characters)
Dutch health insurance number (Zorgnummer)
Other Dutch Bank Account numbers (9-10 digits)
Dutch Passport Numbers (9 alphanumeric characters
Dutch Identification Document Numbers (varying formats)
Custom keywords specified in LoggerSettings

Header tokens:

{date} {time} {ts} {tz} {unix} {ticks}{newline}
{sev} {category} {env}{newline}
{host} {machine}{newline}
{process} {pid} {procstart} {uptime}{newline}
{thread} {threadname} {task}{newline}
{user}{newline}
{app} {appbase} {domain}{newline}
{framework} {os} {arch}{newline}
{mem} {gc}{newline}
{cwd}

Example of custom header:
```csharp
[Date: 2026-01-30] [Time: 14:22:11.384] [2026-01-30 14:22:11.384] [UTC] [Unix: 1738246931] [Ticks: 638422525313840000]
[Severity: Info] [Category: Startup] [Env: Production]
[Host: api-01] [Machine: API-SERVER-01]
[Process: MyService] [PID: 4216] [ProcStart: 2026-01-30T14:20:03.5123456Z] [Uptime: 128s]
[Thread: 9] [ThreadName: worker-1] [TaskId: 42]
[User: svc-api]
[App: MyService.exe] [AppBase: C:\apps\myservice\] [Domain: 1]
[Runtime: .NET 8.0.1] [OS: Linux 6.6.9] [Arch: X64]
[Memory: 128MB] [GC: 12/4/1]
[CWD: /app]
```

Add Custom tokens:

```csharp
Logger.LoggerSettings.HeaderTokens.AddCustomToken("spaceShuttleId", context => $"[Shuttle: {context.SpaceShuttleId}]");
```


**Code for enabling GrayLog in the above *advanced* logger class:**

```csharp
 // Set grayLog information
 var ipAddress = "192.168.10.50"
 var port = 9000;

Logger.AddGrayLogServer(ipAddress, port);
```
**Code for enabling Splunk in the above *advanced* logger class:**

```csharp
// Set Splunk information
var splunkHecUrl = "https://192.168.10.51:8088/services/collector";
var splunkHecToken = "cf0c7e68-e14b-48c1-949f-efdf5d388254";

Logger.AddSplunkServer(splunkHecUrl, splunkHecToken, true);
```

**Code for enabling SysLog in the above *advanced* logger class:**

```csharp
 // Set sysLog information
 var ipAddress = "192.168.10.53";
 var port = 514;

Logger.AddSyslogServer(ipAddress, port);
```


**Logging Test with *default* LogManager:**

```csharp
Task.Run(() => 
{
    var loggerSettings = new LoggerSettings();
    loggerSettings.UseLocalTime = true;
    loggerSettings.FileLoggerOptions.UseLocalTime = true;
    loggerSettings.MaxLogType = ELogType.TRACE;
    loggerSettings.FileLoggerOptions.FileSizeLimit = 1024 * 1024 * 1;
    loggerSettings.FileLoggerOptions.FileNamePrefix = "AllTypes";
    loggerSettings.FileLoggerOptions.MaxRolloverFiles = 5;
	
	// Create an instance of the logManager with the specified loggerSettings
    var logger = new LogManager(loggerSettings);

    // 10.000.000 lines to go :) 
    for (int i = 0; i < 10000000; i++)
    {
        logger.WriteAsync($"test to file {i} INFO", ELogType.INFO);
        logger.WriteAsync($"test to file {i} CRITICAL", ELogType.CRITICAL);
        logger.WriteAsync($"test to file {i} DEBUG", ELogType.DEBUG);
        logger.WriteAsync($"test to file {i} ERROR", ELogType.ERROR);
        logger.WriteAsync($"test to file {i} TRACE", ELogType.TRACE);
        logger.WriteAsync($"test to file {i} TRAFFIC", ELogType.TRAFFIC);
        logger.WriteAsync($"test to file {i} WARNING", ELogType.WARNING);
        logger.WriteAsync($"test to file {i} NONE", ELogType.NONE);
        Console.WriteLine($"Logged: {i}");
        Task.Delay(1);
    }
});
```

How to retrieve exceptions thrown by the library (from splunk, syslog and grayLog)

```csharp
LogManager logManager = new LogManager();
logManager.OnException += LogManager_OnException;

private void LogHelper_OnException(object sender, ErrorMessage e)
{
    if (e.Exception != null)
	{
       Console.WriteLine(e.Exception);
	}
	
	if (e.Message != null)
	{
	    Console.WriteLine("Error message from logger: " + e.Message)
	}
}
```

Example of Discord Logging:
```csharp
loggingBuilder.AddEonaCatDiscordLogger(options =>
{
    options.WebhookUrl = "https://discord.com/api/webhooks/your_webhook_here";
});
```

Example of Slack Logging:
```csharp
loggingBuilder.AddEonaCatSlackLogger(options =>
{
    options.WebhookUrl = "https://hooks.slack.com/services/your_webhook_here";
});

```

Example of DatabaseLogging:

Create the table:
```csharp
CREATE TABLE Logs (
    Id INT IDENTITY(1,1) PRIMARY KEY, -- SERIAL for PostgreSQL, AUTO_INCREMENT for MySQL
    Timestamp DATETIME NOT NULL,
    LogLevel NVARCHAR(50),
    Category NVARCHAR(255),
    Message NVARCHAR(MAX),
    Exception NVARCHAR(MAX),
    CorrelationId NVARCHAR(255)
);
```

MySQL:
```csharp
using MySql.Data.MySqlClient;

loggingBuilder.AddEonaCatDatabaseLogger(options =>
{
    options.DbProviderFactory = MySqlClientFactory.Instance;
    options.ConnectionString = "Server=localhost;Database=EonaCatLogs;User=root;Password=yourpassword;";
});
```

SQL Server:
```csharp
using Microsoft.Data.SqlClient;

loggingBuilder.AddEonaCatDatabaseLogger(options =>
{
    options.DbProviderFactory = SqlClientFactory.Instance;
    options.ConnectionString = "Server=localhost;Database=EonaCatLogs;User Id=sa;Password=yourpassword;";
});
```

PostgreSQL:
```csharp
using Npgsql;

loggingBuilder.AddEonaCatDatabaseLogger(options =>
{
    options.DbProviderFactory = NpgsqlFactory.Instance;
    options.ConnectionString = "Host=localhost;Database=EonaCatLogs;Username=postgres;Password=yourpassword;";
});
```

Example of batching database logging:
```csharp
loggingBuilder.AddEonaCatBatchingDatabaseLogger(options =>
{
    options.DbProviderFactory = MySql.Data.MySqlClient.MySqlClientFactory.Instance;
    options.ConnectionString = "Server=localhost;Database=EonaCatLogs;User=root;Password=yourpassword;";
    options.BatchInterval = TimeSpan.FromSeconds(10); // Flush every 10 seconds
});
```

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
