mirror of https://github.com/abpframework/abp.git
59 changed files with 519 additions and 55 deletions
@ -0,0 +1,13 @@ |
|||
using Volo.Abp.AspNetCore.Serilog; |
|||
|
|||
namespace Microsoft.AspNetCore.Builder |
|||
{ |
|||
public static class AbpAspNetCoreSerilogApplicationBuilderExtensions |
|||
{ |
|||
public static IApplicationBuilder UseSerilogEnrichers(this IApplicationBuilder app) |
|||
{ |
|||
return app |
|||
.UseMiddleware<SerilogMiddleware>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk.Web"> |
|||
|
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netcoreapp3.1</TargetFramework> |
|||
<AssemblyName>Volo.Abp.AspNetCore.Serilog</AssemblyName> |
|||
<PackageId>Volo.Abp.AspNetCore.Serilog</PackageId> |
|||
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<IsPackable>true</IsPackable> |
|||
<OutputType>Library</OutputType> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Volo.Abp.AspNetCore\Volo.Abp.AspNetCore.csproj" /> |
|||
<ProjectReference Include="..\Volo.Abp.MultiTenancy\Volo.Abp.MultiTenancy.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Serilog" Version="2.8.0" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,21 @@ |
|||
namespace Volo.Abp.AspNetCore.Serilog |
|||
{ |
|||
public class AbpAspNetCoreSerilogEnrichersOptions |
|||
{ |
|||
public string TenantIdEnricherPropertyName { get; set; } |
|||
|
|||
public string UserIdEnricherPropertyName { get; set; } |
|||
|
|||
public string ClientIdEnricherPropertyName { get; set; } |
|||
|
|||
public string CorrelationIdPropertyName { get; set; } |
|||
|
|||
public AbpAspNetCoreSerilogEnrichersOptions() |
|||
{ |
|||
TenantIdEnricherPropertyName = AbpSerilogEnrichersConsts.TenantIdEnricherPropertyName; |
|||
UserIdEnricherPropertyName = AbpSerilogEnrichersConsts.UserIdEnricherPropertyName; |
|||
ClientIdEnricherPropertyName = AbpSerilogEnrichersConsts.ClientIdEnricherPropertyName; |
|||
CorrelationIdPropertyName = AbpSerilogEnrichersConsts.CorrelationIdPropertyName; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
namespace Volo.Abp.AspNetCore.Serilog |
|||
{ |
|||
public class AbpSerilogEnrichersConsts |
|||
{ |
|||
public const string TenantIdEnricherPropertyName = "TenantId"; |
|||
public const string UserIdEnricherPropertyName = "UserId"; |
|||
public const string ClientIdEnricherPropertyName = "ClientId"; |
|||
public const string CorrelationIdPropertyName = "CorrelationId"; |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using Volo.Abp.AspNetCore; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Serilog |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpMultiTenancyModule), |
|||
typeof(AbpAspNetCoreModule) |
|||
)] |
|||
public class AbpSerilogModule : AbpModule |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,69 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Http; |
|||
using Microsoft.Extensions.Options; |
|||
using Serilog.Context; |
|||
using Serilog.Core; |
|||
using Serilog.Core.Enrichers; |
|||
using Volo.Abp.Clients; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.Tracing; |
|||
using Volo.Abp.Users; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Serilog |
|||
{ |
|||
public class SerilogMiddleware : IMiddleware, ITransientDependency |
|||
{ |
|||
private readonly ICurrentClient _currentClient; |
|||
private readonly ICurrentTenant _currentTenant; |
|||
private readonly ICurrentUser _currentUser; |
|||
private readonly ICorrelationIdProvider _correlationIdProvider; |
|||
private readonly AbpAspNetCoreSerilogEnrichersOptions _options; |
|||
|
|||
public SerilogMiddleware( |
|||
ICurrentTenant currentTenant, |
|||
ICurrentUser currentUser, |
|||
ICurrentClient currentClient, |
|||
ICorrelationIdProvider correlationIdProvider, |
|||
IOptions<AbpAspNetCoreSerilogEnrichersOptions> options) |
|||
{ |
|||
_currentTenant = currentTenant; |
|||
_currentUser = currentUser; |
|||
_currentClient = currentClient; |
|||
_correlationIdProvider = correlationIdProvider; |
|||
_options = options.Value; |
|||
} |
|||
|
|||
public async Task InvokeAsync(HttpContext context, RequestDelegate next) |
|||
{ |
|||
var enrichers = new List<ILogEventEnricher>(); |
|||
|
|||
if (_currentTenant?.Id != null) |
|||
{ |
|||
enrichers.Add(new PropertyEnricher(_options.TenantIdEnricherPropertyName, _currentTenant.Id)); |
|||
} |
|||
|
|||
if (_currentUser?.Id != null) |
|||
{ |
|||
enrichers.Add(new PropertyEnricher(_options.UserIdEnricherPropertyName, _currentUser.Id)); |
|||
} |
|||
|
|||
if (_currentClient?.Id != null) |
|||
{ |
|||
enrichers.Add(new PropertyEnricher(_options.ClientIdEnricherPropertyName, _currentClient.Id)); |
|||
} |
|||
|
|||
var correlationId = _correlationIdProvider.Get(); |
|||
if (!string.IsNullOrEmpty(correlationId)) |
|||
{ |
|||
enrichers.Add(new PropertyEnricher(_options.CorrelationIdPropertyName, correlationId)); |
|||
} |
|||
|
|||
using (LogContext.Push(enrichers.ToArray())) |
|||
{ |
|||
await next(context).ConfigureAwait(false); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\common.test.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netcoreapp3.1</TargetFramework> |
|||
<AssemblyName>Volo.Abp.AspNetCore.Serilog.Tests</AssemblyName> |
|||
<PackageId>Volo.Abp.AspNetCore.Serilog.Tests</PackageId> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" /> |
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\src\Volo.Abp.AspNetCore.MultiTenancy\Volo.Abp.AspNetCore.MultiTenancy.csproj" /> |
|||
<ProjectReference Include="..\..\src\Volo.Abp.AspNetCore.Mvc\Volo.Abp.AspNetCore.Mvc.csproj" /> |
|||
<ProjectReference Include="..\..\src\Volo.Abp.AspNetCore.Serilog\Volo.Abp.AspNetCore.Serilog.csproj" /> |
|||
<ProjectReference Include="..\Volo.Abp.AspNetCore.Tests\Volo.Abp.AspNetCore.Tests.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,39 @@ |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Volo.Abp.AspNetCore.MultiTenancy; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Serilog; |
|||
using Volo.Abp.AspNetCore.TestBase; |
|||
using Volo.Abp.Autofac; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace Volo.Abp.AspNetCore.App |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpAspNetCoreTestBaseModule), |
|||
typeof(AbpAspNetCoreMvcModule), |
|||
typeof(AbpAspNetCoreMultiTenancyModule), |
|||
typeof(AbpSerilogModule), |
|||
typeof(AbpAutofacModule) |
|||
)] |
|||
public class AbpSerilogTestModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpMultiTenancyOptions>(options => { options.IsEnabled = true; }); |
|||
} |
|||
|
|||
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
|||
{ |
|||
var app = context.GetApplicationBuilder(); |
|||
|
|||
app.UseCorrelationId(); |
|||
app.UseRouting(); |
|||
app.UseAuthorization(); |
|||
app.UseMultiTenancy(); |
|||
app.UseAuditing(); |
|||
app.UseSerilogEnrichers(); |
|||
app.UseMvcWithDefaultRouteAndArea(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Serilog.Core; |
|||
using Serilog.Events; |
|||
|
|||
namespace Volo.Abp.AspNetCore.App |
|||
{ |
|||
public class CollectingSink : ILogEventSink |
|||
{ |
|||
public List<LogEvent> Events { get; } = new List<LogEvent>(); |
|||
|
|||
public LogEvent SingleEvent => Events.Single(); |
|||
|
|||
public void Emit(LogEvent logEvent) |
|||
{ |
|||
Events.Add(logEvent); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.Extensions.Logging; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.Tracing; |
|||
|
|||
namespace Volo.Abp.AspNetCore.App |
|||
{ |
|||
public class SerilogTestController : AbpController |
|||
{ |
|||
private readonly ICorrelationIdProvider _correlationIdProvider; |
|||
|
|||
public SerilogTestController(ICorrelationIdProvider correlationIdProvider) |
|||
{ |
|||
_correlationIdProvider = correlationIdProvider; |
|||
} |
|||
|
|||
public ActionResult Index() |
|||
{ |
|||
return Content("Index-Result"); |
|||
} |
|||
|
|||
public ActionResult CorrelationId() |
|||
{ |
|||
return Content(_correlationIdProvider.Get()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.AspNetCore.Hosting; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Logging; |
|||
|
|||
namespace Volo.Abp.AspNetCore.App |
|||
{ |
|||
public class Startup |
|||
{ |
|||
public void ConfigureServices(IServiceCollection services) |
|||
{ |
|||
services.AddApplication<AbpSerilogTestModule>(); |
|||
} |
|||
|
|||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env,ILoggerFactory loggerFactory) |
|||
{ |
|||
app.InitializeApplication(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
using System.Linq; |
|||
using Microsoft.Extensions.Hosting; |
|||
using Serilog; |
|||
using Serilog.Events; |
|||
using Volo.Abp.AspNetCore.App; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Serilog |
|||
{ |
|||
public class AbpSerilogTestBase : AbpAspNetCoreTestBase<App.Startup> |
|||
{ |
|||
protected readonly CollectingSink CollectingSink = new CollectingSink(); |
|||
|
|||
protected override IHostBuilder CreateHostBuilder() |
|||
{ |
|||
Log.Logger = new LoggerConfiguration() |
|||
.MinimumLevel.Information() |
|||
.MinimumLevel.Override("Microsoft", LogEventLevel.Information) |
|||
.Enrich.FromLogContext() |
|||
.WriteTo.Sink(CollectingSink) |
|||
.CreateLogger(); |
|||
|
|||
return base.CreateHostBuilder() |
|||
.UseSerilog(); |
|||
} |
|||
|
|||
protected LogEvent GetLogEvent(string text) |
|||
{ |
|||
return CollectingSink.Events.FirstOrDefault(m => m.MessageTemplate.Text == text); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,97 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Hosting; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Options; |
|||
using Serilog.Events; |
|||
using Shouldly; |
|||
using Volo.Abp.AspNetCore.App; |
|||
using Volo.Abp.AspNetCore.MultiTenancy; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.MultiTenancy.ConfigurationStore; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Serilog |
|||
{ |
|||
public class Serilog_Enrichers_Tests : AbpSerilogTestBase |
|||
{ |
|||
private const string ExecutedEndpointLogEventText = "Executed endpoint '{EndpointName}'"; |
|||
|
|||
private readonly Guid _testTenantId = Guid.NewGuid(); |
|||
private readonly string _testTenantName = "acme"; |
|||
|
|||
private readonly AbpAspNetCoreMultiTenancyOptions _tenancyOptions; |
|||
private readonly AbpAspNetCoreSerilogEnrichersOptions _serilogEnrichersOptions; |
|||
private readonly ILogger<Serilog_Enrichers_Tests> _logger; |
|||
|
|||
public Serilog_Enrichers_Tests() |
|||
{ |
|||
_tenancyOptions = ServiceProvider.GetRequiredService<IOptions<AbpAspNetCoreMultiTenancyOptions>>().Value; |
|||
_serilogEnrichersOptions = |
|||
ServiceProvider.GetRequiredService<IOptions<AbpAspNetCoreSerilogEnrichersOptions>>().Value; |
|||
_logger = ServiceProvider.GetRequiredService<ILogger<Serilog_Enrichers_Tests>>(); |
|||
} |
|||
|
|||
protected override IHostBuilder CreateHostBuilder() |
|||
{ |
|||
return base.CreateHostBuilder().ConfigureServices(services => |
|||
{ |
|||
services.Configure<AbpDefaultTenantStoreOptions>(options => |
|||
{ |
|||
options.Tenants = new[] |
|||
{ |
|||
new TenantConfiguration(_testTenantId, _testTenantName) |
|||
}; |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task TenantId_Not_Set_Test() |
|||
{ |
|||
var url = GetUrl<SerilogTestController>(nameof(SerilogTestController.Index)); |
|||
var result = await GetResponseAsStringAsync(url).ConfigureAwait(false); |
|||
|
|||
var executedLogEvent = GetLogEvent(ExecutedEndpointLogEventText); |
|||
|
|||
executedLogEvent.ShouldNotBeNull(); |
|||
executedLogEvent.Properties.ContainsKey(_serilogEnrichersOptions.TenantIdEnricherPropertyName) |
|||
.ShouldBe(false); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task TenantId_Set_Test() |
|||
{ |
|||
var url = |
|||
GetUrl<SerilogTestController>(nameof(SerilogTestController.Index)) + |
|||
$"?{_tenancyOptions.TenantKey}={_testTenantName}"; |
|||
var result = await GetResponseAsStringAsync(url).ConfigureAwait(false); |
|||
|
|||
var executedLogEvent = GetLogEvent(ExecutedEndpointLogEventText); |
|||
|
|||
executedLogEvent.ShouldNotBeNull(); |
|||
executedLogEvent.Properties.ContainsKey(_serilogEnrichersOptions.TenantIdEnricherPropertyName) |
|||
.ShouldBe(true); |
|||
((ScalarValue) executedLogEvent.Properties[_serilogEnrichersOptions.TenantIdEnricherPropertyName]).Value |
|||
.ShouldBe(_testTenantId); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task CorrelationId_Enrichers_Test() |
|||
{ |
|||
var url = GetUrl<SerilogTestController>(nameof(SerilogTestController.CorrelationId)); |
|||
var result = await GetResponseAsStringAsync(url).ConfigureAwait(false); |
|||
|
|||
var executedLogEvent = GetLogEvent(ExecutedEndpointLogEventText); |
|||
|
|||
executedLogEvent.ShouldNotBeNull(); |
|||
|
|||
executedLogEvent.Properties.ContainsKey(_serilogEnrichersOptions.CorrelationIdPropertyName) |
|||
.ShouldNotBeNull(); |
|||
|
|||
((ScalarValue) executedLogEvent.Properties[_serilogEnrichersOptions.CorrelationIdPropertyName]).Value |
|||
.ShouldBe(result); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue