mirror of
https://github.com/hmaxnl/DotBased.git
synced 2025-01-18 10:04:20 +01:00
[REFACTOR] Refactored logging & added support for Microsoft.Extensions.Logging. Added test WebApi project
This commit is contained in:
parent
58739c2aea
commit
737cbcfd11
|
@ -7,14 +7,23 @@
|
||||||
|
|
||||||
using DotBased.Logging.Serilog;
|
using DotBased.Logging.Serilog;
|
||||||
using DotBased.Logging;
|
using DotBased.Logging;
|
||||||
|
using DotBased.Utilities;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using ILogger = Serilog.ILogger;
|
using ILogger = Serilog.ILogger;
|
||||||
|
|
||||||
|
LogService.Initialize(options =>
|
||||||
|
{
|
||||||
|
options
|
||||||
|
.AddSeverityFilter("Program", LogSeverity.Verbose)
|
||||||
|
.AddSeverityFilter("DotBased.dll", LogSeverity.Verbose);
|
||||||
|
});
|
||||||
|
|
||||||
var serilogLogger = SetupSerilog();
|
var serilogLogger = SetupSerilog();
|
||||||
LogService.AddLogAdapter(new BasedSerilogAdapter(serilogLogger));
|
LogService.AddLogAdapter(new BasedSerilogAdapter(serilogLogger));
|
||||||
var logger = LogService.RegisterLogger(typeof(Program));
|
var logger = LogService.RegisterLogger<Program>();
|
||||||
|
|
||||||
logger.Information("Whoah... Hi!");
|
logger.Information("Whoah... Hi!, {Param}", "Test!");
|
||||||
|
var cult = Culture.GetSystemCultures();
|
||||||
|
|
||||||
Console.ReadKey(); // Hold console app open.
|
Console.ReadKey(); // Hold console app open.
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -18,21 +18,23 @@ public class BasedServerAuthenticationStateProvider : ServerAuthenticationStateP
|
||||||
_config = configuration;
|
_config = configuration;
|
||||||
_localStorage = localStorage;
|
_localStorage = localStorage;
|
||||||
_securityService = securityService;
|
_securityService = securityService;
|
||||||
_logger = LogService.RegisterLogger(typeof(BasedServerAuthenticationStateProvider));
|
_logger = LogService.RegisterLogger<BasedServerAuthenticationStateProvider>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private BasedAuthConfiguration _config;
|
private BasedAuthConfiguration _config;
|
||||||
private readonly ProtectedLocalStorage _localStorage;
|
private readonly ProtectedLocalStorage _localStorage;
|
||||||
private readonly SecurityService _securityService;
|
private readonly SecurityService _securityService;
|
||||||
private ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly AuthenticationState _anonState = new(new ClaimsPrincipal());
|
private readonly AuthenticationState _anonState = new(new ClaimsPrincipal());
|
||||||
|
|
||||||
|
|
||||||
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
|
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
|
||||||
{
|
{
|
||||||
|
_logger.Debug("Getting authentication state...");
|
||||||
var sessionIdResult = await _localStorage.GetAsync<string>(BasedAuthDefaults.StorageKey);
|
var sessionIdResult = await _localStorage.GetAsync<string>(BasedAuthDefaults.StorageKey);
|
||||||
if (!sessionIdResult.Success || sessionIdResult.Value == null)
|
if (!sessionIdResult.Success || sessionIdResult.Value == null)
|
||||||
return _anonState;
|
return _anonState;
|
||||||
|
_logger.Debug("Found state [{State}], getting session from {Service}", sessionIdResult.Value, nameof(SecurityService));
|
||||||
var stateResult = await _securityService.GetAuthenticationStateFromSessionAsync(sessionIdResult.Value);
|
var stateResult = await _securityService.GetAuthenticationStateFromSessionAsync(sessionIdResult.Value);
|
||||||
return stateResult is { Success: true, Value: not null } ? stateResult.Value : _anonState;
|
return stateResult is { Success: true, Value: not null } ? stateResult.Value : _anonState;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ public static class DotBasedAuthDependencyInjection
|
||||||
var Configuration = new BasedAuthConfiguration();
|
var Configuration = new BasedAuthConfiguration();
|
||||||
configurationAction?.Invoke(Configuration);
|
configurationAction?.Invoke(Configuration);
|
||||||
|
|
||||||
|
|
||||||
services.AddSingleton<BasedAuthConfiguration>(Configuration);
|
services.AddSingleton<BasedAuthConfiguration>(Configuration);
|
||||||
if (Configuration.AuthDataRepositoryType == null)
|
if (Configuration.AuthDataRepositoryType == null)
|
||||||
throw new ArgumentNullException(nameof(Configuration.AuthDataRepositoryType), $"No '{nameof(IAuthDataRepository)}' configured!");
|
throw new ArgumentNullException(nameof(Configuration.AuthDataRepositoryType), $"No '{nameof(IAuthDataRepository)}' configured!");
|
||||||
|
|
|
@ -34,11 +34,11 @@ public class MemoryAuthDataRepository : IAuthDataRepository
|
||||||
public async Task<Result<UserModel>> GetUserAsync(string id, string email, string username)
|
public async Task<Result<UserModel>> GetUserAsync(string id, string email, string username)
|
||||||
{
|
{
|
||||||
UserModel? userModel = null;
|
UserModel? userModel = null;
|
||||||
if (!id.IsNullOrWhiteSpace())
|
if (!id.IsNullOrEmpty())
|
||||||
userModel = MemoryData.users.FirstOrDefault(u => u.Id.Equals(id, StringComparison.OrdinalIgnoreCase));
|
userModel = MemoryData.users.FirstOrDefault(u => u.Id.Equals(id, StringComparison.OrdinalIgnoreCase));
|
||||||
if (!email.IsNullOrWhiteSpace())
|
if (!email.IsNullOrEmpty())
|
||||||
userModel = MemoryData.users.FirstOrDefault(u => u.Email.Equals(email, StringComparison.OrdinalIgnoreCase));
|
userModel = MemoryData.users.FirstOrDefault(u => u.Email.Equals(email, StringComparison.OrdinalIgnoreCase));
|
||||||
if (!username.IsNullOrWhiteSpace())
|
if (!username.IsNullOrEmpty())
|
||||||
userModel = MemoryData.users.FirstOrDefault(u => u.UserName.Equals(username, StringComparison.OrdinalIgnoreCase));
|
userModel = MemoryData.users.FirstOrDefault(u => u.UserName.Equals(username, StringComparison.OrdinalIgnoreCase));
|
||||||
return userModel != null ? Result<UserModel>.Ok(userModel) : Result<UserModel>.Failed("No user found!");
|
return userModel != null ? Result<UserModel>.Ok(userModel) : Result<UserModel>.Failed("No user found!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ public class SecurityService
|
||||||
_authDataRepository = authDataRepository;
|
_authDataRepository = authDataRepository;
|
||||||
_dataCache = dataCache;
|
_dataCache = dataCache;
|
||||||
_localStorage = localStorage;
|
_localStorage = localStorage;
|
||||||
_logger = LogService.RegisterLogger(typeof(SecurityService));
|
_logger = LogService.RegisterLogger<SecurityService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly IAuthDataRepository _authDataRepository;
|
private readonly IAuthDataRepository _authDataRepository;
|
||||||
|
@ -26,7 +26,7 @@ public class SecurityService
|
||||||
|
|
||||||
public async Task<Result<AuthenticationState>> GetAuthenticationStateFromSessionAsync(string id)
|
public async Task<Result<AuthenticationState>> GetAuthenticationStateFromSessionAsync(string id)
|
||||||
{
|
{
|
||||||
if (id.IsNullOrWhiteSpace())
|
if (id.IsNullOrEmpty())
|
||||||
return Result<AuthenticationState>.Failed("No valid id!");
|
return Result<AuthenticationState>.Failed("No valid id!");
|
||||||
AuthenticationStateModel? authStateModel = null;
|
AuthenticationStateModel? authStateModel = null;
|
||||||
var stateCache = _dataCache.RequestSessionState(id);
|
var stateCache = _dataCache.RequestSessionState(id);
|
||||||
|
@ -75,13 +75,13 @@ public class SecurityService
|
||||||
{
|
{
|
||||||
UserModel? user = null;
|
UserModel? user = null;
|
||||||
Result<UserModel> usrResult;
|
Result<UserModel> usrResult;
|
||||||
if (!login.UserName.IsNullOrWhiteSpace())
|
if (!login.UserName.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
usrResult = await _authDataRepository.GetUserAsync(string.Empty, string.Empty, login.UserName);
|
usrResult = await _authDataRepository.GetUserAsync(string.Empty, string.Empty, login.UserName);
|
||||||
if (usrResult is { Success: true, Value: not null })
|
if (usrResult is { Success: true, Value: not null })
|
||||||
user = usrResult.Value;
|
user = usrResult.Value;
|
||||||
}
|
}
|
||||||
else if (!login.Email.IsNullOrWhiteSpace())
|
else if (!login.Email.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
usrResult = await _authDataRepository.GetUserAsync(string.Empty, login.Email, string.Empty);
|
usrResult = await _authDataRepository.GetUserAsync(string.Empty, login.Email, string.Empty);
|
||||||
if (usrResult is { Success: true, Value: not null })
|
if (usrResult is { Success: true, Value: not null })
|
||||||
|
@ -114,7 +114,7 @@ public class SecurityService
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (state.IsNullOrWhiteSpace())
|
if (state.IsNullOrEmpty())
|
||||||
return Result.Failed($"Argument {nameof(state)} is empty!");
|
return Result.Failed($"Argument {nameof(state)} is empty!");
|
||||||
|
|
||||||
var stateResult = await _authDataRepository.GetAuthenticationStateAsync(state);
|
var stateResult = await _authDataRepository.GetAuthenticationStateAsync(state);
|
||||||
|
|
63
DotBased.Logging.MEL/BasedLogger.cs
Normal file
63
DotBased.Logging.MEL/BasedLogger.cs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace DotBased.Logging.MEL;
|
||||||
|
|
||||||
|
public class BasedLogger : Microsoft.Extensions.Logging.ILogger
|
||||||
|
{
|
||||||
|
public BasedLogger(ILogger logger)
|
||||||
|
{
|
||||||
|
basedLogger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly ILogger basedLogger;
|
||||||
|
|
||||||
|
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
|
||||||
|
{
|
||||||
|
if (!IsEnabled(logLevel))
|
||||||
|
return;
|
||||||
|
var severity = ConvertLogLevelToSeverity(logLevel);
|
||||||
|
var capsule = ConstructCapsule(severity, eventId, state, exception, formatter);
|
||||||
|
basedLogger.Log(capsule);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LogCapsule ConstructCapsule<TState>(LogSeverity severity, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
|
||||||
|
{
|
||||||
|
//TODO: Extract parameters & format
|
||||||
|
if (state is IEnumerable<KeyValuePair<string, object>> stateEnum)
|
||||||
|
{
|
||||||
|
foreach (var prop in stateEnum)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LogCapsule()
|
||||||
|
{
|
||||||
|
Exception = exception,
|
||||||
|
Message = formatter.Invoke(state, exception),
|
||||||
|
Parameters = [],
|
||||||
|
Severity = severity,
|
||||||
|
TimeStamp = DateTime.Now,
|
||||||
|
Logger = basedLogger as LoggerBase ?? throw new NullReferenceException(nameof(basedLogger))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private LogSeverity ConvertLogLevelToSeverity(LogLevel level)
|
||||||
|
{
|
||||||
|
return level switch
|
||||||
|
{
|
||||||
|
LogLevel.Trace => LogSeverity.Trace,
|
||||||
|
LogLevel.Debug => LogSeverity.Debug,
|
||||||
|
LogLevel.Information => LogSeverity.Info,
|
||||||
|
LogLevel.Warning => LogSeverity.Warning,
|
||||||
|
LogLevel.Error => LogSeverity.Error,
|
||||||
|
LogLevel.Critical => LogSeverity.Fatal,
|
||||||
|
LogLevel.None => LogSeverity.Ignore,
|
||||||
|
_ => LogSeverity.Verbose
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None;
|
||||||
|
|
||||||
|
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => default;
|
||||||
|
}
|
23
DotBased.Logging.MEL/BasedLoggerProvider.cs
Normal file
23
DotBased.Logging.MEL/BasedLoggerProvider.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace DotBased.Logging.MEL;
|
||||||
|
|
||||||
|
public class BasedLoggerProvider : ILoggerProvider
|
||||||
|
{
|
||||||
|
public BasedLoggerProvider(LogOptions options)
|
||||||
|
{
|
||||||
|
Options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly LogOptions Options;
|
||||||
|
|
||||||
|
public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName)
|
||||||
|
{
|
||||||
|
return new BasedLogger(Options.LoggerBuilder.Invoke(new LoggerInformation(typeof(BasedLoggerProvider)), categoryName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
18
DotBased.Logging.MEL/DotBased.Logging.MEL.csproj
Normal file
18
DotBased.Logging.MEL/DotBased.Logging.MEL.csproj
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<LangVersion>12</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\DotBased\DotBased.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
14
DotBased.Logging.MEL/LoggerBuilderExtensions.cs
Normal file
14
DotBased.Logging.MEL/LoggerBuilderExtensions.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace DotBased.Logging.MEL;
|
||||||
|
|
||||||
|
public static class LoggerBuilderExtensions
|
||||||
|
{
|
||||||
|
public static ILoggingBuilder AddDotBased(this ILoggingBuilder builder, LogOptions options)
|
||||||
|
{
|
||||||
|
if (builder == null)
|
||||||
|
throw new ArgumentNullException(nameof(builder));
|
||||||
|
builder.AddProvider(new BasedLoggerProvider(options));
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ public static class BasedSerilog
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default output template with the extra properties that can be used for serilog sinks.
|
/// Default output template with the extra properties that can be used for serilog sinks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string OutputTemplate = "[{Timestamp:HH:mm:ss} - {Caller}->{Assembly}] | {Level:u3}] {Message:lj}{NewLine}{Exception}";
|
public const string OutputTemplate = "[{Timestamp:HH:mm:ss} {Level:u3} - {LoggerName}]{NewLine} {Message:lj}{NewLine}{Exception}";
|
||||||
|
|
||||||
public static LoggerConfiguration UseBasedExtension(this LoggerConfiguration loggerConfiguration)
|
public static LoggerConfiguration UseBasedExtension(this LoggerConfiguration loggerConfiguration)
|
||||||
{
|
{
|
||||||
|
@ -20,8 +20,10 @@ public static class BasedSerilog
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ExtraProperties
|
public static class ExtraProperties
|
||||||
{
|
{
|
||||||
|
public const string LoggerName = "LoggerName";
|
||||||
public const string AssemblyProp = "Assembly";
|
public const string AssemblyProp = "Assembly";
|
||||||
public const string SourceProp = "Source";
|
public const string FullNameProp = "FullName";
|
||||||
|
public const string NamespaceProp = "Namespace";
|
||||||
public const string CallerProp = "Caller";
|
public const string CallerProp = "Caller";
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,9 +16,11 @@ public class BasedSerilogAdapter(global::Serilog.ILogger serilogLogger) : LogAda
|
||||||
if (capsule == null)
|
if (capsule == null)
|
||||||
return;
|
return;
|
||||||
var logger = serilogLogger
|
var logger = serilogLogger
|
||||||
.ForContext(BasedSerilog.ExtraProperties.AssemblyProp, capsule.Logger.Caller.AssemblyName)
|
.ForContext(BasedSerilog.ExtraProperties.LoggerName, capsule.Logger.Name)
|
||||||
.ForContext(BasedSerilog.ExtraProperties.SourceProp, capsule.Logger.Caller.Source)
|
.ForContext(BasedSerilog.ExtraProperties.AssemblyProp, capsule.Logger.LoggerInformation.AssemblyName)
|
||||||
.ForContext(BasedSerilog.ExtraProperties.CallerProp, capsule.Logger.Caller.Name);
|
.ForContext(BasedSerilog.ExtraProperties.FullNameProp, capsule.Logger.LoggerInformation.TypeFullName)
|
||||||
|
.ForContext(BasedSerilog.ExtraProperties.NamespaceProp, capsule.Logger.LoggerInformation.TypeNamespace)
|
||||||
|
.ForContext(BasedSerilog.ExtraProperties.CallerProp, capsule.Logger.LoggerInformation.TypeName);
|
||||||
|
|
||||||
var template = _messageTemplateParser.Parse(capsule.Message);
|
var template = _messageTemplateParser.Parse(capsule.Message);
|
||||||
IEnumerable<LogEventProperty>? properties = null;
|
IEnumerable<LogEventProperty>? properties = null;
|
||||||
|
|
|
@ -15,7 +15,7 @@ public class BasedSerilogEnricher : ILogEventEnricher
|
||||||
sourcePropValue = appValue.ToString().Replace("\"", "");
|
sourcePropValue = appValue.ToString().Replace("\"", "");
|
||||||
|
|
||||||
var assemblyProperty = propertyFactory.CreateProperty(BasedSerilog.ExtraProperties.AssemblyProp, asmPropValue);
|
var assemblyProperty = propertyFactory.CreateProperty(BasedSerilog.ExtraProperties.AssemblyProp, asmPropValue);
|
||||||
var sourceProperty = propertyFactory.CreateProperty(BasedSerilog.ExtraProperties.SourceProp, sourcePropValue);
|
var sourceProperty = propertyFactory.CreateProperty(BasedSerilog.ExtraProperties.FullNameProp, sourcePropValue);
|
||||||
var callerProperty = propertyFactory.CreateProperty(BasedSerilog.ExtraProperties.CallerProp, sourcePropValue);
|
var callerProperty = propertyFactory.CreateProperty(BasedSerilog.ExtraProperties.CallerProp, sourcePropValue);
|
||||||
|
|
||||||
logEvent.AddPropertyIfAbsent(assemblyProperty);
|
logEvent.AddPropertyIfAbsent(assemblyProperty);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>default</LangVersion>
|
<LangVersion>default</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
16
DotBased.sln
16
DotBased.sln
|
@ -10,6 +10,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{2156
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotBased.ASP.Auth", "DotBased.ASP.Auth\DotBased.ASP.Auth.csproj", "{CBD4111D-F1CA-466A-AC73-9EAB7F235B3D}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotBased.ASP.Auth", "DotBased.ASP.Auth\DotBased.ASP.Auth.csproj", "{CBD4111D-F1CA-466A-AC73-9EAB7F235B3D}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotBased.Logging.MEL", "DotBased.Logging.MEL\DotBased.Logging.MEL.csproj", "{D4D9B584-A524-4CBB-9B61-9CD65ED4AF0D}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{DBDB4538-85D4-45AC-9E0A-A684467AEABA}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestWebApi", "TestWebApi\TestWebApi.csproj", "{BADA4BAF-142B-47A8-95FC-B25E1D3D0020}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -32,9 +38,19 @@ Global
|
||||||
{CBD4111D-F1CA-466A-AC73-9EAB7F235B3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{CBD4111D-F1CA-466A-AC73-9EAB7F235B3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{CBD4111D-F1CA-466A-AC73-9EAB7F235B3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{CBD4111D-F1CA-466A-AC73-9EAB7F235B3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{CBD4111D-F1CA-466A-AC73-9EAB7F235B3D}.Release|Any CPU.Build.0 = Release|Any CPU
|
{CBD4111D-F1CA-466A-AC73-9EAB7F235B3D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D4D9B584-A524-4CBB-9B61-9CD65ED4AF0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D4D9B584-A524-4CBB-9B61-9CD65ED4AF0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D4D9B584-A524-4CBB-9B61-9CD65ED4AF0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D4D9B584-A524-4CBB-9B61-9CD65ED4AF0D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{BADA4BAF-142B-47A8-95FC-B25E1D3D0020}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{BADA4BAF-142B-47A8-95FC-B25E1D3D0020}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{BADA4BAF-142B-47A8-95FC-B25E1D3D0020}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{BADA4BAF-142B-47A8-95FC-B25E1D3D0020}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{EBBDAF9A-BFC7-4BDC-8C51-0501B59A1DDC} = {2156FB93-C252-4B33-8A0C-73C82FABB163}
|
{EBBDAF9A-BFC7-4BDC-8C51-0501B59A1DDC} = {2156FB93-C252-4B33-8A0C-73C82FABB163}
|
||||||
{CBD4111D-F1CA-466A-AC73-9EAB7F235B3D} = {2156FB93-C252-4B33-8A0C-73C82FABB163}
|
{CBD4111D-F1CA-466A-AC73-9EAB7F235B3D} = {2156FB93-C252-4B33-8A0C-73C82FABB163}
|
||||||
|
{D4D9B584-A524-4CBB-9B61-9CD65ED4AF0D} = {2156FB93-C252-4B33-8A0C-73C82FABB163}
|
||||||
|
{BADA4BAF-142B-47A8-95FC-B25E1D3D0020} = {DBDB4538-85D4-45AC-9E0A-A684467AEABA}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace DotBased.Collections;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class InstanceContainer : IDisposable
|
public class InstanceContainer : IDisposable
|
||||||
{
|
{
|
||||||
private readonly ILogger _log = LogService.RegisterLogger(typeof(InstanceContainer));
|
private readonly ILogger _log = LogService.RegisterLogger<InstanceContainer>();
|
||||||
private readonly Dictionary<string, InstanceNode> _tCollection = new Dictionary<string, InstanceNode>();
|
private readonly Dictionary<string, InstanceNode> _tCollection = new Dictionary<string, InstanceNode>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -40,7 +40,7 @@ public class InstanceContainer : IDisposable
|
||||||
case null:
|
case null:
|
||||||
break;
|
break;
|
||||||
case IDisposable instance when dispose:
|
case IDisposable instance when dispose:
|
||||||
_log.Debug("Disposing disposable object... (InstanceContainer)");
|
_log.Debug("Disposing disposable object...");
|
||||||
instance.Dispose();
|
instance.Dispose();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>default</LangVersion>
|
<LangVersion>default</LangVersion>
|
||||||
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -5,5 +5,5 @@ namespace DotBased.Extensions;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class StringExtensions
|
public static class StringExtensions
|
||||||
{
|
{
|
||||||
public static bool IsNullOrWhiteSpace(this string s) => string.IsNullOrWhiteSpace(s);
|
public static bool IsNullOrEmpty(this string s) => string.IsNullOrWhiteSpace(s);
|
||||||
}
|
}
|
|
@ -5,6 +5,7 @@ namespace DotBased.Logging;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ILogger
|
public interface ILogger
|
||||||
{
|
{
|
||||||
|
public void Log(LogCapsule capsule);
|
||||||
public void Verbose(string message, params object?[]? parameters);
|
public void Verbose(string message, params object?[]? parameters);
|
||||||
|
|
||||||
public void Trace(string message, params object?[]? parameters);
|
public void Trace(string message, params object?[]? parameters);
|
||||||
|
@ -18,4 +19,6 @@ public interface ILogger
|
||||||
public void Error(Exception exception, string message, params object?[]? parameters);
|
public void Error(Exception exception, string message, params object?[]? parameters);
|
||||||
|
|
||||||
public void Fatal(Exception exception, string message, params object?[]? parameters);
|
public void Fatal(Exception exception, string message, params object?[]? parameters);
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
namespace DotBased.Logging;
|
namespace DotBased.Logging;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The base for creating log adpaters.
|
/// The base for creating log adapters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class LogAdapterBase
|
public abstract class LogAdapterBase
|
||||||
{
|
{
|
||||||
|
@ -19,7 +19,7 @@ public abstract class LogAdapterBase
|
||||||
public string AdapterName { get; }
|
public string AdapterName { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handle the incomming <see cref="LogCapsule"/> that the <see cref="LogProcessor"/> sends.
|
/// Handle the incoming <see cref="LogCapsule"/> that the <see cref="LogProcessor"/> sends.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="processor">The log processor that has processed this log</param>
|
/// <param name="processor">The log processor that has processed this log</param>
|
||||||
/// <param name="capsule">The log capsule, which contains the log information</param>
|
/// <param name="capsule">The log capsule, which contains the log information</param>
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using DotBased.Extensions;
|
||||||
|
|
||||||
namespace DotBased.Logging;
|
namespace DotBased.Logging;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -5,14 +8,35 @@ namespace DotBased.Logging;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LogOptions
|
public class LogOptions
|
||||||
{
|
{
|
||||||
|
public readonly SeverityFilterCollection SeverityFilters = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The severty the logger will log
|
/// The severity the logger will log
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public LogSeverity Severity { get; set; } = LogSeverity.Trace;
|
public LogSeverity Severity { get; set; } = LogSeverity.Trace;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The function that will build and return the <see cref="LoggerBase"/> when calling <see cref="LogService.RegisterLogger"/>, so a custom logger based on the <see cref="LoggerBase"/> can be used.
|
/// The function that will build and return the <see cref="ILogger"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<CallerInformation, Action<LogCapsule>, LoggerBase> LoggerBuilder { get; set; } =
|
public Func<LoggerInformation, string, ILogger> LoggerBuilder { get; set; } =
|
||||||
(identifier, sendEvent) => new Logger(identifier, ref sendEvent);
|
(identifier, loggerName) => new Logger(identifier, loggerName);
|
||||||
|
|
||||||
|
public LogOptions AddSeverityFilter(string filter, LogSeverity logSeverity)
|
||||||
|
{
|
||||||
|
if (filter.IsNullOrEmpty())
|
||||||
|
return this;
|
||||||
|
SeverityFilters.Add(new SeverityFilter() { Filter = filter, Severity = logSeverity });
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct SeverityFilter
|
||||||
|
{
|
||||||
|
public string Filter { get; set; }
|
||||||
|
public LogSeverity Severity { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SeverityFilterCollection : KeyedCollection<string, SeverityFilter>
|
||||||
|
{
|
||||||
|
protected override string GetKeyForItem(SeverityFilter item) => item.Filter;
|
||||||
}
|
}
|
|
@ -8,7 +8,7 @@ public class LogProcessor : IDisposable
|
||||||
public LogProcessor()
|
public LogProcessor()
|
||||||
{
|
{
|
||||||
_processorQueue = new Queue<LogCapsule>();
|
_processorQueue = new Queue<LogCapsule>();
|
||||||
IncommingLogHandlerEvent = IncommingLogHandler;
|
IncomingLogHandlerEvent = IncomingLogHandler;
|
||||||
_processorThread = new Thread(ProcessLog)
|
_processorThread = new Thread(ProcessLog)
|
||||||
{
|
{
|
||||||
IsBackground = true,
|
IsBackground = true,
|
||||||
|
@ -16,7 +16,7 @@ public class LogProcessor : IDisposable
|
||||||
};
|
};
|
||||||
_processorThread.Start();
|
_processorThread.Start();
|
||||||
}
|
}
|
||||||
public readonly Action<LogCapsule> IncommingLogHandlerEvent;
|
public readonly Action<LogCapsule> IncomingLogHandlerEvent;
|
||||||
public event EventHandler<LogCapsule>? LogProcessed;
|
public event EventHandler<LogCapsule>? LogProcessed;
|
||||||
private readonly Queue<LogCapsule> _processorQueue;
|
private readonly Queue<LogCapsule> _processorQueue;
|
||||||
private readonly Thread _processorThread;
|
private readonly Thread _processorThread;
|
||||||
|
@ -41,14 +41,14 @@ public class LogProcessor : IDisposable
|
||||||
Stop();
|
Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void IncommingLogHandler(LogCapsule e)
|
private void IncomingLogHandler(LogCapsule e)
|
||||||
{
|
{
|
||||||
_processorQueue.Enqueue(e);
|
_processorQueue.Enqueue(e);
|
||||||
// Check is the thread is running, if not wake up the thread.
|
// Check if the thread is running, if not wake up the thread.
|
||||||
if (!_threadSuspendEvent.WaitOne(0))
|
if (!_threadSuspendEvent.WaitOne(0))
|
||||||
_threadSuspendEvent.Set();
|
_threadSuspendEvent.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessLog()
|
private void ProcessLog()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -63,7 +63,9 @@ public class LogProcessor : IDisposable
|
||||||
if (_processorQueue.Count != 0)
|
if (_processorQueue.Count != 0)
|
||||||
{
|
{
|
||||||
var capsule = _processorQueue.Dequeue();
|
var capsule = _processorQueue.Dequeue();
|
||||||
if (LogService.ShouldLog(LogService.Options.Severity, capsule.Severity))
|
if (!LogService.CanLog(LogService.Options.Severity, capsule.Severity))
|
||||||
|
continue;
|
||||||
|
if (LogService.FilterSeverityLog(capsule))
|
||||||
LogProcessed?.Invoke(this, capsule);
|
LogProcessed?.Invoke(this, capsule);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using DotBased.Extensions;
|
||||||
|
|
||||||
namespace DotBased.Logging;
|
namespace DotBased.Logging;
|
||||||
|
|
||||||
|
@ -8,52 +9,43 @@ namespace DotBased.Logging;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class LogService
|
public static class LogService
|
||||||
{
|
{
|
||||||
// TODO: Future: add middlewares and changeable log processor
|
|
||||||
static LogService()
|
static LogService()
|
||||||
{
|
{
|
||||||
Options = new LogOptions();
|
Options = new LogOptions();
|
||||||
LoggerSendEvent = LogProcessor.IncommingLogHandlerEvent;
|
LoggerSendEvent = LogProcessor.IncomingLogHandlerEvent;
|
||||||
}
|
}
|
||||||
public static bool ShouldLog(LogSeverity maxSeverity, LogSeverity severity) => maxSeverity <= severity;
|
public static bool CanLog(LogSeverity maxSeverity, LogSeverity severity) => maxSeverity <= severity;
|
||||||
public static LogOptions Options { get; private set; }
|
public static LogOptions Options { get; private set; }
|
||||||
public static LogProcessor LogProcessor { get; private set; } = new LogProcessor();
|
public static LogProcessor LogProcessor { get; private set; } = new LogProcessor();
|
||||||
|
|
||||||
private static HashSet<LogAdapterBase> Adapters { get; } = new HashSet<LogAdapterBase>();
|
private static HashSet<LogAdapterBase> Adapters { get; } = [];
|
||||||
private static HashSet<LoggerBase> Loggers { get; } = new HashSet<LoggerBase>();
|
private static HashSet<ILogger> Loggers { get; } = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Action for internal communication between loggers and processor
|
/// Action for internal communication between loggers and processor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly Action<LogCapsule> LoggerSendEvent;
|
internal static readonly Action<LogCapsule> LoggerSendEvent;
|
||||||
|
|
||||||
/// <summary>
|
public static void Initialize(Action<LogOptions>? options = null)
|
||||||
/// Register a logger that will be used in a class and will live as long as the class.
|
|
||||||
/// This will get the calling assembly and will pass that through ther log adapters.
|
|
||||||
/// </summary>
|
|
||||||
/// <example>
|
|
||||||
/// <code>
|
|
||||||
/// public class Program
|
|
||||||
/// {
|
|
||||||
/// public Program
|
|
||||||
/// {
|
|
||||||
/// logger = LogService.RegisterLogger(nameof(Program));
|
|
||||||
/// }
|
|
||||||
/// private ILogger logger;
|
|
||||||
/// }
|
|
||||||
/// </code>
|
|
||||||
/// </example>
|
|
||||||
/// <param name="callerType">The type that called the function</param>
|
|
||||||
/// <returns>The configured <see cref="ILogger"/> implementation that will be configuered in the <see cref="LogOptions.LoggerBuilder"/> at the <see cref="LogService"/> class</returns>
|
|
||||||
public static ILogger RegisterLogger(Type callerType)
|
|
||||||
{
|
{
|
||||||
var logger = Options.LoggerBuilder.Invoke(new CallerInformation(callerType), LoggerSendEvent);
|
Options = new LogOptions();
|
||||||
|
options?.Invoke(Options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ILogger RegisterLogger(Type? callerType, string name = "")
|
||||||
|
{
|
||||||
|
var logger = Options.LoggerBuilder.Invoke(new LoggerInformation(callerType), name);
|
||||||
Loggers.Add(logger);
|
Loggers.Add(logger);
|
||||||
return logger;
|
return logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool UnregisterLogger(LoggerBase logger) => Loggers.Remove(logger);
|
/// <summary>
|
||||||
|
/// Register a logger.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The configured <see cref="ILogger"/> implementation that will be configured in the <see cref="LogOptions.LoggerBuilder"/> at the <see cref="LogService"/> class</returns>
|
||||||
|
public static ILogger RegisterLogger<T>() => RegisterLogger(typeof(T), string.Empty);
|
||||||
|
|
||||||
public static ReadOnlyCollection<LoggerBase> GetLoggers => new ReadOnlyCollection<LoggerBase>(Loggers.ToList());
|
public static ReadOnlyCollection<ILogger> GetLoggers => new ReadOnlyCollection<ILogger>(Loggers.ToList());
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add a log adapter to the service.
|
/// Add a log adapter to the service.
|
||||||
|
@ -69,7 +61,7 @@ public static class LogService
|
||||||
/// Removes the log adapter from the service.
|
/// Removes the log adapter from the service.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="adapter">The adapter to remove</param>
|
/// <param name="adapter">The adapter to remove</param>
|
||||||
/// <returns>True if the adapter is succesfully removed otherwise false.</returns>
|
/// <returns>True if the adapter is successfully removed otherwise false.</returns>
|
||||||
public static bool RemoveLogAdapter(LogAdapterBase adapter)
|
public static bool RemoveLogAdapter(LogAdapterBase adapter)
|
||||||
{
|
{
|
||||||
if (!Adapters.Contains(adapter)) return false;
|
if (!Adapters.Contains(adapter)) return false;
|
||||||
|
@ -77,28 +69,52 @@ public static class LogService
|
||||||
return Adapters.Remove(adapter);
|
return Adapters.Remove(adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ReadOnlyCollection<LogAdapterBase> GetAdapters =>
|
public static ReadOnlyCollection<LogAdapterBase> GetAdapters => new ReadOnlyCollection<LogAdapterBase>(Adapters.ToList());
|
||||||
new ReadOnlyCollection<LogAdapterBase>(Adapters.ToList());
|
|
||||||
|
internal static bool FilterSeverityLog(LogCapsule capsule)
|
||||||
|
{
|
||||||
|
if (Options.SeverityFilters.TryGetValue(capsule.Logger.Name, out var namespaceFilter))
|
||||||
|
return CanLog(namespaceFilter.Severity, capsule.Severity);
|
||||||
|
var filterCapsuleNamespace = Options.SeverityFilters.Where(kvp => capsule.Logger.Name.Contains(kvp.Filter)).Select(v => v).ToList();
|
||||||
|
if (filterCapsuleNamespace.Count == 0) return true;
|
||||||
|
var filter = filterCapsuleNamespace.FirstOrDefault();
|
||||||
|
return CanLog(filter.Severity, capsule.Severity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public readonly struct CallerInformation
|
public readonly struct LoggerInformation
|
||||||
{
|
{
|
||||||
public CallerInformation(Type type)
|
public LoggerInformation(Type? type)
|
||||||
{
|
{
|
||||||
Name = type.Name;
|
if (type == null)
|
||||||
Source = type.FullName ?? type.GUID.ToString();
|
return;
|
||||||
Namespace = type.Namespace ?? string.Empty;
|
|
||||||
SourceAssembly = type.Assembly;
|
|
||||||
|
|
||||||
var asmName = SourceAssembly.GetName();
|
TypeName = type.Name;
|
||||||
AssemblyName = asmName.Name ?? "Unknown";
|
TypeFullName = type.FullName ?? string.Empty;
|
||||||
AssemblyFullname = asmName.FullName;
|
TypeNamespace = type.Namespace ?? string.Empty;
|
||||||
|
|
||||||
|
var module = type.Module;
|
||||||
|
ModuleName = module.Name;
|
||||||
|
ModuleScopeName = module.ScopeName;
|
||||||
|
ModuleFullyQualifiedName = module.FullyQualifiedName;
|
||||||
|
|
||||||
|
var assemblyName = type.Assembly.GetName();
|
||||||
|
AssemblyName = assemblyName.Name ?? (type.Assembly.GetCustomAttributes(typeof(AssemblyTitleAttribute)).FirstOrDefault() as AssemblyTitleAttribute)?.Title ?? string.Empty;
|
||||||
|
AssemblyFullname = assemblyName.FullName;
|
||||||
|
|
||||||
|
if (TypeFullName.IsNullOrEmpty())
|
||||||
|
TypeFullName = !TypeNamespace.IsNullOrEmpty() ? $"{TypeNamespace}.{TypeName}" : TypeName;
|
||||||
|
if (TypeNamespace.IsNullOrEmpty())
|
||||||
|
TypeNamespace = TypeName;
|
||||||
}
|
}
|
||||||
public string Name { get; }
|
|
||||||
public string Source { get; }
|
public string TypeName { get; } = string.Empty;
|
||||||
public string Namespace { get; }
|
public string TypeFullName { get; } = string.Empty;
|
||||||
public Assembly SourceAssembly { get; }
|
public string TypeNamespace { get; } = string.Empty;
|
||||||
public string AssemblyName { get; }
|
public string AssemblyName { get; } = string.Empty;
|
||||||
public string AssemblyFullname { get; }
|
public string AssemblyFullname { get; } = string.Empty;
|
||||||
|
public string ModuleName { get; } = string.Empty;
|
||||||
|
public string ModuleScopeName { get; } = string.Empty;
|
||||||
|
public string ModuleFullyQualifiedName { get; } = string.Empty;
|
||||||
}
|
}
|
|
@ -8,5 +8,6 @@ public enum LogSeverity
|
||||||
Info = 3,
|
Info = 3,
|
||||||
Warning = 4,
|
Warning = 4,
|
||||||
Error = 5,
|
Error = 5,
|
||||||
Fatal = 6
|
Fatal = 6,
|
||||||
|
Ignore = 99
|
||||||
}
|
}
|
|
@ -3,13 +3,8 @@ namespace DotBased.Logging;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Main logger, this class is the default logger that the <see cref="LogService.RegisterLogger"/> function will return.
|
/// Main logger, this class is the default logger that the <see cref="LogService.RegisterLogger"/> function will return.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Logger(CallerInformation caller, ref Action<LogCapsule> logProcessorHandler) : LoggerBase(caller, ref logProcessorHandler)
|
public class Logger(LoggerInformation loggerInformation, string name) : LoggerBase(loggerInformation, name)
|
||||||
{
|
{
|
||||||
public void Log(LogCapsule capsule)
|
|
||||||
{
|
|
||||||
ProcessLog(capsule);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Verbose(string message, params object?[]? parameters)
|
public override void Verbose(string message, params object?[]? parameters)
|
||||||
{
|
{
|
||||||
Log(new LogCapsule()
|
Log(new LogCapsule()
|
||||||
|
@ -96,5 +91,5 @@ public class Logger(CallerInformation caller, ref Action<LogCapsule> logProcesso
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode() => HashCode.Combine(Caller.Source, Caller.AssemblyFullname);
|
public override int GetHashCode() => HashCode.Combine(LoggerInformation.TypeFullName, LoggerInformation.AssemblyFullname);
|
||||||
}
|
}
|
|
@ -1,15 +1,23 @@
|
||||||
|
using DotBased.Extensions;
|
||||||
|
|
||||||
namespace DotBased.Logging;
|
namespace DotBased.Logging;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base for creating loggers
|
/// Base for creating loggers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="caller">The caller information</param>
|
/// <param name="loggerInformation">The caller information</param>
|
||||||
/// <param name="logProcessorHandler">The handler where the logs can be send to</param>
|
public abstract class LoggerBase(LoggerInformation loggerInformation, string name) : ILogger
|
||||||
public abstract class LoggerBase(CallerInformation caller, ref Action<LogCapsule> logProcessorHandler) : ILogger
|
|
||||||
{
|
{
|
||||||
public CallerInformation Caller { get; } = caller;
|
public LoggerInformation LoggerInformation { get; } = loggerInformation;
|
||||||
|
public string Name { get; } = name.IsNullOrEmpty() ? loggerInformation.TypeNamespace : name;
|
||||||
|
|
||||||
internal readonly Action<LogCapsule> ProcessLog = logProcessorHandler;
|
private readonly Action<LogCapsule> ProcessLog = LogService.LoggerSendEvent;
|
||||||
|
|
||||||
|
public void Log(LogCapsule capsule)
|
||||||
|
{
|
||||||
|
ProcessLog(capsule);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public abstract void Verbose(string message, params object?[]? parameters);
|
public abstract void Verbose(string message, params object?[]? parameters);
|
||||||
public abstract void Trace(string message, params object?[]? parameters);
|
public abstract void Trace(string message, params object?[]? parameters);
|
||||||
|
|
|
@ -2,11 +2,11 @@ using DotBased.Extensions;
|
||||||
|
|
||||||
namespace DotBased.Objects;
|
namespace DotBased.Objects;
|
||||||
|
|
||||||
public class DbObjectAttribute<TValueType> : ObjectAttribute<TValueType>
|
public class DbObjectAttribute<TValueType> : ObjectAttribute<TValueType> where TValueType : IConvertible
|
||||||
{
|
{
|
||||||
public DbObjectAttribute(string key, TValueType value, string owner) : base(key, value)
|
public DbObjectAttribute(string key, TValueType value, string owner) : base(key, value)
|
||||||
{
|
{
|
||||||
if (owner.IsNullOrWhiteSpace())
|
if (owner.IsNullOrEmpty())
|
||||||
throw new ArgumentNullException(nameof(owner), $"The parameter {nameof(owner)} is null or empty! This parameter is required!");
|
throw new ArgumentNullException(nameof(owner), $"The parameter {nameof(owner)} is null or empty! This parameter is required!");
|
||||||
Owner = owner;
|
Owner = owner;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ public class ObjectAttribute<TValueType> : IObjectAttribute<TValueType>
|
||||||
{
|
{
|
||||||
protected ObjectAttribute(string key, TValueType value)
|
protected ObjectAttribute(string key, TValueType value)
|
||||||
{
|
{
|
||||||
if (key.IsNullOrWhiteSpace())
|
if (key.IsNullOrEmpty())
|
||||||
throw new ArgumentNullException(nameof(key), $"The parameter {nameof(key)} is null or empty!");
|
throw new ArgumentNullException(nameof(key), $"The parameter {nameof(key)} is null or empty!");
|
||||||
Key = key;
|
Key = key;
|
||||||
Value = value;
|
Value = value;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using DotBased.Logging;
|
||||||
|
|
||||||
namespace DotBased.Utilities;
|
namespace DotBased.Utilities;
|
||||||
|
|
||||||
|
@ -6,6 +7,7 @@ public static class Culture
|
||||||
{
|
{
|
||||||
private static List<CultureInfo> _sysCultures = new List<CultureInfo>();
|
private static List<CultureInfo> _sysCultures = new List<CultureInfo>();
|
||||||
private static Dictionary<string, RegionInfo> _regions = new Dictionary<string, RegionInfo>();
|
private static Dictionary<string, RegionInfo> _regions = new Dictionary<string, RegionInfo>();
|
||||||
|
private static readonly ILogger _logger = LogService.RegisterLogger(typeof(Culture));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get all system known cultures.
|
/// Get all system known cultures.
|
||||||
|
@ -14,6 +16,7 @@ public static class Culture
|
||||||
/// <returns>The list with <see cref="CultureInfo"/>'s the system knows</returns>
|
/// <returns>The list with <see cref="CultureInfo"/>'s the system knows</returns>
|
||||||
public static IEnumerable<CultureInfo> GetSystemCultures()
|
public static IEnumerable<CultureInfo> GetSystemCultures()
|
||||||
{
|
{
|
||||||
|
_logger.Debug("Getting system cultures...");
|
||||||
if (_sysCultures.Count == 0)
|
if (_sysCultures.Count == 0)
|
||||||
_sysCultures = CultureInfo.GetCultures(CultureTypes.AllCultures).ToList();
|
_sysCultures = CultureInfo.GetCultures(CultureTypes.AllCultures).ToList();
|
||||||
return _sysCultures;
|
return _sysCultures;
|
||||||
|
|
72
TestWebApi/Program.cs
Normal file
72
TestWebApi/Program.cs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
using DotBased.Logging;
|
||||||
|
using DotBased.Logging.MEL;
|
||||||
|
using DotBased.Logging.Serilog;
|
||||||
|
using Serilog;
|
||||||
|
using ILogger = Serilog.ILogger;
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
LogService.Initialize(options =>
|
||||||
|
{
|
||||||
|
options
|
||||||
|
.AddSeverityFilter("Program", LogSeverity.Verbose);
|
||||||
|
});
|
||||||
|
|
||||||
|
var serilogLogger = SetupSerilog();
|
||||||
|
LogService.AddLogAdapter(new BasedSerilogAdapter(serilogLogger));
|
||||||
|
|
||||||
|
builder.Logging.ClearProviders();
|
||||||
|
builder.Logging.AddDotBased(LogService.Options);
|
||||||
|
|
||||||
|
// Add services to the container.
|
||||||
|
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
builder.Services.AddSwaggerGen();
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Configure the HTTP request pipeline.
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseSwagger();
|
||||||
|
app.UseSwaggerUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
|
var summaries = new[]
|
||||||
|
{
|
||||||
|
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||||
|
};
|
||||||
|
|
||||||
|
app.MapGet("/weatherforecast", () =>
|
||||||
|
{
|
||||||
|
var forecast = Enumerable.Range(1, 5).Select(index =>
|
||||||
|
new WeatherForecast
|
||||||
|
(
|
||||||
|
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
|
||||||
|
Random.Shared.Next(-20, 55),
|
||||||
|
summaries[Random.Shared.Next(summaries.Length)]
|
||||||
|
))
|
||||||
|
.ToArray();
|
||||||
|
return forecast;
|
||||||
|
})
|
||||||
|
.WithName("GetWeatherForecast")
|
||||||
|
.WithOpenApi();
|
||||||
|
|
||||||
|
app.Run();
|
||||||
|
|
||||||
|
ILogger SetupSerilog()
|
||||||
|
{
|
||||||
|
var logConfig = new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Verbose()
|
||||||
|
.WriteTo.Console(outputTemplate: BasedSerilog.OutputTemplate);
|
||||||
|
return logConfig.CreateLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
|
||||||
|
{
|
||||||
|
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||||
|
}
|
21
TestWebApi/TestWebApi.csproj
Normal file
21
TestWebApi/TestWebApi.csproj
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.8"/>
|
||||||
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\DotBased.Logging.MEL\DotBased.Logging.MEL.csproj" />
|
||||||
|
<ProjectReference Include="..\DotBased.Logging.Serilog\DotBased.Logging.Serilog.csproj" />
|
||||||
|
<ProjectReference Include="..\DotBased\DotBased.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
6
TestWebApi/TestWebApi.http
Normal file
6
TestWebApi/TestWebApi.http
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
@TestWebApi_HostAddress = http://localhost:5044
|
||||||
|
|
||||||
|
GET {{TestWebApi_HostAddress}}/weatherforecast/
|
||||||
|
Accept: application/json
|
||||||
|
|
||||||
|
###
|
Loading…
Reference in New Issue
Block a user