501 lines
18 KiB
Markdown
501 lines
18 KiB
Markdown
# 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
|