renamed control to action to reflect its purpose and be more consistent with asp.net conventions
This commit is contained in:
36
Oqtane.Server/Logging/DBLoggerExtensions.cs
Normal file
36
Oqtane.Server/Logging/DBLoggerExtensions.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace Oqtane.Logging
|
||||
{
|
||||
static public class DBLoggerExtensions
|
||||
{
|
||||
static public ILoggingBuilder AddDBLogger(this ILoggingBuilder builder)
|
||||
{
|
||||
builder.AddConfiguration();
|
||||
|
||||
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, DBLoggerProvider>());
|
||||
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<DBLoggerOptions>, DBLoggerOptionsSetup>());
|
||||
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IOptionsChangeTokenSource<DBLoggerOptions>, LoggerProviderOptionsChangeTokenSource<DBLoggerOptions, DBLoggerProvider>>());
|
||||
return builder;
|
||||
}
|
||||
|
||||
static public ILoggingBuilder AddDBLogger(this ILoggingBuilder builder, Action<DBLoggerOptions> configure)
|
||||
{
|
||||
if (configure == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configure));
|
||||
}
|
||||
|
||||
builder.AddDBLogger();
|
||||
builder.Services.Configure(configure);
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
13
Oqtane.Server/Logging/DBLoggerOptions.cs
Normal file
13
Oqtane.Server/Logging/DBLoggerOptions.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Oqtane.Logging
|
||||
{
|
||||
public class DBLoggerOptions
|
||||
{
|
||||
public DBLoggerOptions()
|
||||
{
|
||||
}
|
||||
|
||||
public LogLevel LogLevel { get; set; } = LogLevel.Information;
|
||||
}
|
||||
}
|
11
Oqtane.Server/Logging/DBLoggerOptionsSetup.cs
Normal file
11
Oqtane.Server/Logging/DBLoggerOptionsSetup.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.Logging.Configuration;
|
||||
|
||||
namespace Oqtane.Logging
|
||||
{
|
||||
internal class DBLoggerOptionsSetup : ConfigureFromConfigurationOptions<DBLoggerOptions>
|
||||
{
|
||||
public DBLoggerOptionsSetup(ILoggerProviderConfiguration<DBLoggerProvider> providerConfiguration)
|
||||
: base(providerConfiguration.Configuration) {}
|
||||
}
|
||||
}
|
94
Oqtane.Server/Logging/DBLoggerProvider.cs
Normal file
94
Oqtane.Server/Logging/DBLoggerProvider.cs
Normal file
@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Concurrent;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Logging
|
||||
{
|
||||
[Microsoft.Extensions.Logging.ProviderAlias("DB")]
|
||||
public class DBLoggerProvider : LoggerProvider
|
||||
{
|
||||
bool Terminated;
|
||||
ConcurrentQueue<LogEntry> LogQueue = new ConcurrentQueue<LogEntry>();
|
||||
private Tenant tenant;
|
||||
internal DBLoggerOptions Settings { get; private set; }
|
||||
|
||||
public DBLoggerProvider(ITenantResolver TenantResolver)
|
||||
{
|
||||
tenant = TenantResolver.GetTenant();
|
||||
}
|
||||
|
||||
public override void WriteLog(LogEntry LogEntry)
|
||||
{
|
||||
// enrich with tenant information
|
||||
LogQueue.Enqueue(LogEntry);
|
||||
}
|
||||
|
||||
void ThreadProc()
|
||||
{
|
||||
Task.Run(() => {
|
||||
|
||||
while (!Terminated)
|
||||
{
|
||||
try
|
||||
{
|
||||
AddLogEntry();
|
||||
System.Threading.Thread.Sleep(100);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
void AddLogEntry()
|
||||
{
|
||||
// check the LogQueue.Count to determine if a threshold has been reached
|
||||
// then dequeue the items into temp storage based on TenantId and bulk insert them into the database
|
||||
LogEntry logentry = null;
|
||||
if (LogQueue.TryDequeue(out logentry))
|
||||
{
|
||||
// convert logentry object to object which can be stored in database
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected override void Dispose(bool Disposing)
|
||||
{
|
||||
Terminated = true;
|
||||
base.Dispose(Disposing);
|
||||
}
|
||||
|
||||
public DBLoggerProvider(IOptionsMonitor<DBLoggerOptions> Settings)
|
||||
: this(Settings.CurrentValue)
|
||||
{
|
||||
SettingsChangeToken = Settings.OnChange(settings => {
|
||||
this.Settings = settings;
|
||||
});
|
||||
}
|
||||
|
||||
public DBLoggerProvider(DBLoggerOptions Settings)
|
||||
{
|
||||
this.Settings = Settings;
|
||||
ThreadProc();
|
||||
}
|
||||
|
||||
public override bool IsEnabled(LogLevel LogLevel)
|
||||
{
|
||||
bool Result = LogLevel != LogLevel.None
|
||||
&& this.Settings.LogLevel != LogLevel.None
|
||||
&& Convert.ToInt32(LogLevel) >= Convert.ToInt32(this.Settings.LogLevel);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
32
Oqtane.Server/Logging/LogEntry.cs
Normal file
32
Oqtane.Server/Logging/LogEntry.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Oqtane.Logging
|
||||
{
|
||||
public class LogEntry
|
||||
{
|
||||
public LogEntry()
|
||||
{
|
||||
TimeStampUtc = DateTime.UtcNow;
|
||||
UserName = Environment.UserName;
|
||||
}
|
||||
|
||||
static public readonly string StaticHostName = System.Net.Dns.GetHostName();
|
||||
|
||||
public string UserName { get; private set; }
|
||||
public string HostName { get { return StaticHostName; } }
|
||||
public DateTime TimeStampUtc { get; private set; }
|
||||
public string Category { get; set; }
|
||||
public LogLevel Level { get; set; }
|
||||
public string Text { get; set; }
|
||||
public Exception Exception { get; set; }
|
||||
public EventId EventId { get; set; }
|
||||
public object State { get; set; }
|
||||
public string StateText { get; set; }
|
||||
public Dictionary<string, object> StateProperties { get; set; }
|
||||
public List<LogScope> Scopes { get; set; }
|
||||
}
|
||||
}
|
10
Oqtane.Server/Logging/LogScope.cs
Normal file
10
Oqtane.Server/Logging/LogScope.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Oqtane.Logging
|
||||
{
|
||||
public class LogScope
|
||||
{
|
||||
public string Text { get; set; }
|
||||
public Dictionary<string, object> Properties { get; set; }
|
||||
}
|
||||
}
|
91
Oqtane.Server/Logging/Logger.cs
Normal file
91
Oqtane.Server/Logging/Logger.cs
Normal file
@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Oqtane.Logging
|
||||
{
|
||||
internal class Logger : ILogger
|
||||
{
|
||||
public LoggerProvider Provider { get; private set; }
|
||||
public string Category { get; private set; }
|
||||
|
||||
public Logger(LoggerProvider Provider, string Category)
|
||||
{
|
||||
this.Provider = Provider;
|
||||
this.Category = Category;
|
||||
}
|
||||
|
||||
IDisposable ILogger.BeginScope<TState>(TState State)
|
||||
{
|
||||
return Provider.ScopeProvider.Push(State);
|
||||
}
|
||||
|
||||
bool ILogger.IsEnabled(LogLevel LogLevel)
|
||||
{
|
||||
return Provider.IsEnabled(LogLevel);
|
||||
}
|
||||
|
||||
void ILogger.Log<TState>(LogLevel LogLevel, EventId EventId, TState State, Exception Exception, Func<TState, Exception, string> Formatter)
|
||||
{
|
||||
if ((this as ILogger).IsEnabled(LogLevel))
|
||||
{
|
||||
|
||||
LogEntry logentry = new LogEntry();
|
||||
// we need the TenantId and SiteId
|
||||
logentry.Category = this.Category;
|
||||
logentry.Level = LogLevel;
|
||||
logentry.Text = Exception?.Message ?? State.ToString();
|
||||
logentry.Exception = Exception;
|
||||
logentry.EventId = EventId;
|
||||
logentry.State = State;
|
||||
|
||||
if (State is string)
|
||||
{
|
||||
logentry.StateText = State.ToString();
|
||||
}
|
||||
else if (State is IEnumerable<KeyValuePair<string, object>> Properties)
|
||||
{
|
||||
logentry.StateProperties = new Dictionary<string, object>();
|
||||
|
||||
foreach (KeyValuePair<string, object> item in Properties)
|
||||
{
|
||||
logentry.StateProperties[item.Key] = item.Value;
|
||||
}
|
||||
}
|
||||
|
||||
if (Provider.ScopeProvider != null)
|
||||
{
|
||||
Provider.ScopeProvider.ForEachScope((value, loggingProps) =>
|
||||
{
|
||||
if (logentry.Scopes == null)
|
||||
{
|
||||
logentry.Scopes = new List<LogScope>();
|
||||
}
|
||||
|
||||
LogScope Scope = new LogScope();
|
||||
logentry.Scopes.Add(Scope);
|
||||
|
||||
if (value is string)
|
||||
{
|
||||
Scope.Text = value.ToString();
|
||||
}
|
||||
else if (value is IEnumerable<KeyValuePair<string, object>> props)
|
||||
{
|
||||
if (Scope.Properties == null)
|
||||
Scope.Properties = new Dictionary<string, object>();
|
||||
|
||||
foreach (var pair in props)
|
||||
{
|
||||
Scope.Properties[pair.Key] = pair.Value;
|
||||
}
|
||||
}
|
||||
}, State);
|
||||
|
||||
}
|
||||
|
||||
Provider.WriteLog(logentry);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
80
Oqtane.Server/Logging/LoggerProvider.cs
Normal file
80
Oqtane.Server/Logging/LoggerProvider.cs
Normal file
@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Oqtane.Logging
|
||||
{
|
||||
public abstract class LoggerProvider : IDisposable, ILoggerProvider, ISupportExternalScope
|
||||
{
|
||||
ConcurrentDictionary<string, Logger> loggers = new ConcurrentDictionary<string, Logger>();
|
||||
IExternalScopeProvider fScopeProvider;
|
||||
protected IDisposable SettingsChangeToken;
|
||||
|
||||
void ISupportExternalScope.SetScopeProvider(IExternalScopeProvider ScopeProvider)
|
||||
{
|
||||
fScopeProvider = ScopeProvider;
|
||||
}
|
||||
|
||||
ILogger ILoggerProvider.CreateLogger(string Category)
|
||||
{
|
||||
return loggers.GetOrAdd(Category,
|
||||
(category) => {
|
||||
return new Logger(this, category);
|
||||
});
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
if (!this.IsDisposed)
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
this.IsDisposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool Disposing)
|
||||
{
|
||||
if (SettingsChangeToken != null)
|
||||
{
|
||||
SettingsChangeToken.Dispose();
|
||||
SettingsChangeToken = null;
|
||||
}
|
||||
}
|
||||
|
||||
public LoggerProvider()
|
||||
{
|
||||
}
|
||||
|
||||
~LoggerProvider()
|
||||
{
|
||||
if (!this.IsDisposed)
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract bool IsEnabled(LogLevel LogLevel);
|
||||
|
||||
public abstract void WriteLog(LogEntry LogEntry);
|
||||
|
||||
internal IExternalScopeProvider ScopeProvider
|
||||
{
|
||||
get
|
||||
{
|
||||
if (fScopeProvider == null)
|
||||
fScopeProvider = new LoggerExternalScopeProvider();
|
||||
return fScopeProvider;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDisposed { get; protected set; }
|
||||
}
|
||||
}
|
@ -43,6 +43,7 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.0-preview1.19506.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0-rc3" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -6,6 +6,7 @@ using System.Reflection;
|
||||
using System;
|
||||
using Oqtane.Modules;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Repository
|
||||
{
|
||||
@ -120,7 +121,7 @@ namespace Oqtane.Repository
|
||||
Dependencies = GetProperty(properties, "Dependencies"),
|
||||
PermissionNames = GetProperty(properties, "PermissionNames"),
|
||||
ServerAssemblyName = GetProperty(properties, "ServerAssemblyName"),
|
||||
ControlTypeTemplate = ModuleType + ".{Control}" + ", " + typename[1],
|
||||
ControlTypeTemplate = ModuleType + "." + Constants.ActionToken + ", " + typename[1],
|
||||
ControlTypeRoutes = "",
|
||||
AssemblyName = assembly.FullName.Split(",")[0]
|
||||
};
|
||||
@ -141,7 +142,7 @@ namespace Oqtane.Repository
|
||||
Dependencies = "",
|
||||
PermissionNames = "",
|
||||
ServerAssemblyName = "",
|
||||
ControlTypeTemplate = ModuleType + ".{Control}" + ", " + typename[1],
|
||||
ControlTypeTemplate = ModuleType + "." + Constants.ActionToken + ", " + typename[1],
|
||||
ControlTypeRoutes = "",
|
||||
AssemblyName = assembly.FullName.Split(",")[0]
|
||||
};
|
||||
|
Reference in New Issue
Block a user