renamed control to action to reflect its purpose and be more consistent with asp.net conventions

This commit is contained in:
Shaun Walker
2019-10-19 11:09:10 -04:00
parent f6e70036b1
commit ce25967633
18 changed files with 401 additions and 30 deletions

View 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;
}
}
}

View File

@ -0,0 +1,13 @@
using Microsoft.Extensions.Logging;
namespace Oqtane.Logging
{
public class DBLoggerOptions
{
public DBLoggerOptions()
{
}
public LogLevel LogLevel { get; set; } = LogLevel.Information;
}
}

View 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) {}
}
}

View 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;
}
}
}

View 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; }
}
}

View 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; }
}
}

View 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);
}
}
}
}

View 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; }
}
}

View File

@ -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>

View File

@ -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]
};