Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
warning-explosive committed Mar 23, 2023
1 parent ba5aabf commit 4f34ea1
Show file tree
Hide file tree
Showing 43 changed files with 522 additions and 205 deletions.
7 changes: 7 additions & 0 deletions Benchmarks/GenericHost.Benchmark/Benchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ internal void MessageHandlerMiddlewareBenchmark()
Measure.Mean,
Output.WriteLine);

var tracingMiddleware = summary.MillisecondMeasure(
nameof(MessageHandlerMiddlewareBenchmarkSource.RunTracingMiddleware),
Measure.Mean,
Output.WriteLine);

var errorHandlingMiddleware = summary.MillisecondMeasure(
nameof(MessageHandlerMiddlewareBenchmarkSource.RunErrorHandlingMiddleware),
Measure.Mean,
Expand All @@ -109,6 +114,7 @@ internal void MessageHandlerMiddlewareBenchmark()
Output.WriteLine);

Assert.True(compositeMiddleware < 50m);
Assert.True(tracingMiddleware < 1m);
Assert.True(errorHandlingMiddleware < 1m);
Assert.True(authorizationMiddleware < 1m);
Assert.True(unitOfWorkMiddleware < 25m);
Expand All @@ -129,6 +135,7 @@ internal static async Task MessageHandlerMiddlewareBenchmarkTest()
{
source.IterationSetup();

await source.RunTracingMiddleware().ConfigureAwait(false);
await source.RunErrorHandlingMiddleware().ConfigureAwait(false);
await source.RunAuthorizationMiddleware().ConfigureAwait(false);
await source.RunUnitOfWorkMiddleware().ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace SpaceEngineers.Core.GenericHost.Benchmark.Sources
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Basics;
Expand Down Expand Up @@ -75,7 +76,8 @@ public void GlobalSetup()
.WithInMemoryIntegrationTransport(hostBuilder)
.BuildOptions())
.UseEndpoint(
new EndpointIdentity(nameof(DatabaseConnectionProviderBenchmarkSource), Guid.NewGuid().ToString()),
new EndpointIdentity(nameof(DatabaseConnectionProviderBenchmarkSource)),
Assembly.GetEntryAssembly() !,
(_, builder) => builder
.WithPostgreSqlDataAccess(options => options
.ExecuteMigrations())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace SpaceEngineers.Core.GenericHost.Benchmark.Sources
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Basics;
Expand Down Expand Up @@ -40,6 +41,7 @@ public class MessageHandlerMiddlewareBenchmarkSource
private Func<IAdvancedIntegrationContext, CancellationToken, Task>? _messageHandler;
private IDependencyContainer? _dependencyContainer;
private IMessageHandlerMiddlewareComposite? _messageHandlerMiddleware;
private IMessageHandlerMiddleware? _tracingMiddleware;
private IMessageHandlerMiddleware? _errorHandlingMiddleware;
private IMessageHandlerMiddleware? _authorizationMiddleware;
private IMessageHandlerMiddleware? _unitOfWorkMiddleware;
Expand Down Expand Up @@ -71,7 +73,8 @@ public void GlobalSetup()
.WithAuthorization(context.Configuration)
.BuildOptions())
.UseEndpoint(
new EndpointIdentity(nameof(MessageHandlerMiddlewareBenchmarkSource), Guid.NewGuid().ToString()),
new EndpointIdentity(nameof(MessageHandlerMiddlewareBenchmarkSource)),
Assembly.GetEntryAssembly() !,
(context, builder) => builder
.WithPostgreSqlDataAccess(options => options
.ExecuteMigrations())
Expand Down Expand Up @@ -114,6 +117,7 @@ public void GlobalSetup()

var middlewares = _dependencyContainer.ResolveCollection<IMessageHandlerMiddleware>().ToList();

_tracingMiddleware = middlewares.Single(middleware => middleware.GetType() == typeof(TracingMiddleware));
_errorHandlingMiddleware = middlewares.Single(middleware => middleware.GetType() == typeof(ErrorHandlingMiddleware));
_authorizationMiddleware = middlewares.Single(middleware => middleware.GetType() == typeof(AuthorizationMiddleware));
_unitOfWorkMiddleware = middlewares.Single(middleware => middleware.GetType() == typeof(UnitOfWorkMiddleware));
Expand Down Expand Up @@ -170,6 +174,21 @@ await _messageHandlerMiddleware
}
}

/// <summary> RunTracingMiddleware </summary>
/// <returns>Ongoing operation</returns>
[Benchmark(Description = nameof(RunTracingMiddleware))]
public async Task RunTracingMiddleware()
{
await using (_dependencyContainer.OpenScopeAsync().ConfigureAwait(false))
{
var exclusiveContext = _dependencyContainer.Resolve<IAdvancedIntegrationContext, IntegrationMessage>(_request!);

await _tracingMiddleware
.Handle(exclusiveContext, _messageHandler!, _cts.Token)
.ConfigureAwait(false);
}
}

/// <summary> RunErrorHandlingMiddleware </summary>
/// <returns>Ongoing operation</returns>
[Benchmark(Description = nameof(RunErrorHandlingMiddleware))]
Expand Down
12 changes: 12 additions & 0 deletions Endpoints/AuthEndpoint.Contract/Identity.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
namespace SpaceEngineers.Core.AuthEndpoint.Contract
{
using System.Reflection;
using Basics;

/// <summary>
/// Identity
/// </summary>
Expand All @@ -9,5 +12,14 @@ public static class Identity
/// AuthEndpoint logical name
/// </summary>
public const string LogicalName = nameof(AuthEndpoint);

/// <summary>
/// AuthEndpoint assembly
/// </summary>
public static readonly Assembly Assembly = AssembliesExtensions.FindRequiredAssembly(
AssembliesExtensions.BuildName(
nameof(SpaceEngineers),
nameof(Core),
nameof(AuthEndpoint)));
}
}
3 changes: 2 additions & 1 deletion Endpoints/AuthEndpoint.Host/HostExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public static IHostBuilder UseAuthEndpoint(
};

return hostBuilder.UseEndpoint(
new EndpointIdentity(Identity.LogicalName, Guid.NewGuid().ToString()),
new EndpointIdentity(Identity.LogicalName),
Identity.Assembly,
(context, endpointBuilder) => optionsFactory(endpointBuilder
.WithEndpointPluginAssemblies(assemblies)
.WithAuthorization(context.Configuration)));
Expand Down
4 changes: 2 additions & 2 deletions Endpoints/GenericEndpoint.Authorization/Authorization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ public Authorization(string value)
public string Value { get; }

/// <inheritdoc />
object IIntegrationMessageHeader.Value => Value;
public string StringValue => Value;

/// <inheritdoc />
public override string ToString()
{
return $"[{nameof(Authorization)}] - [{Value}]";
return $"[{nameof(Authorization)}:{StringValue}]";
}
}
}
11 changes: 5 additions & 6 deletions Endpoints/GenericEndpoint.Contract/EndpointIdentity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,21 @@ public class EndpointIdentity : IEquatable<EndpointIdentity>,
{
/// <summary> .cctor </summary>
/// <param name="logicalName">Endpoint logical name</param>
/// <param name="instanceName">Endpoint instance name</param>
public EndpointIdentity(string logicalName, string instanceName)
public EndpointIdentity(string logicalName)
{
LogicalName = logicalName;
InstanceName = instanceName;
InstanceName = Guid.NewGuid().ToString();
}

/// <summary>
/// Endpoint logical name
/// </summary>
public string LogicalName { get; }
public string LogicalName { get; init; }

/// <summary>
/// Endpoint instance name
/// </summary>
public string InstanceName { get; }
public string InstanceName { get; init; }

#region IEquatable

Expand Down Expand Up @@ -86,7 +85,7 @@ public override int GetHashCode()
/// <inheritdoc />
public override string ToString()
{
return $"{LogicalName} - {InstanceName}";
return $"{LogicalName}:{InstanceName}";
}
}
}
5 changes: 5 additions & 0 deletions Endpoints/GenericEndpoint.Host/GenericEndpoint.Host.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="OpenTelemetry" Version="1.4.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.4.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.0.0-rc9.14" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.0.0-rc9.14" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.1.0-rc.2" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
90 changes: 72 additions & 18 deletions Endpoints/GenericEndpoint.Host/HostExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@ namespace SpaceEngineers.Core.GenericEndpoint.Host
{
using System;
using System.Collections.Generic;
using System.Diagnostics.Metrics;
using System.Linq;
using System.Reflection;
using Basics;
using Builder;
using CompositionRoot;
using CompositionRoot.Registration;
using Contract;
using Endpoint;
using GenericHost;
using IntegrationTransport.Api.Abstractions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using Registrations;

/// <summary>
Expand Down Expand Up @@ -90,18 +96,20 @@ static bool IsEndpointContainerUnsafe(IDependencyContainer dependencyContainer,
/// </summary>
/// <param name="hostBuilder">IHostBuilder</param>
/// <param name="endpointIdentity">Endpoint identity</param>
/// <param name="assembly">Endpoint assembly (composition root or executable)</param>
/// <param name="optionsFactory">Endpoint options factory</param>
/// <returns>Configured IHostBuilder</returns>
public static IHostBuilder UseEndpoint(
this IHostBuilder hostBuilder,
EndpointIdentity endpointIdentity,
Assembly assembly,
Func<HostBuilderContext, IEndpointBuilder, EndpointOptions> optionsFactory)
{
hostBuilder.ApplyOptions(endpointIdentity);
hostBuilder.CheckDuplicates(endpointIdentity);

return hostBuilder.ConfigureServices((context, serviceCollection) =>
{
var builder = ConfigureBuilder(hostBuilder, endpointIdentity);
var builder = ConfigureBuilder(hostBuilder, endpointIdentity, assembly);
var options = optionsFactory(context, builder);
Expand All @@ -111,28 +119,65 @@ public static IHostBuilder UseEndpoint(
});
}

internal static void ApplyOptions(this IHostBuilder hostBuilder, EndpointIdentity endpointIdentity)
internal static void CheckDuplicates(this IHostBuilder hostBuilder, EndpointIdentity endpointIdentity)
{
if (!hostBuilder.Properties.TryGetValue(nameof(EndpointIdentity), out var value)
|| value is not ICollection<EndpointIdentity> identities)
|| value is not Dictionary<string, EndpointIdentity> endpointIdentities)
{
hostBuilder.Properties[nameof(EndpointIdentity)] = new List<EndpointIdentity> { endpointIdentity };
return;
endpointIdentities = new Dictionary<string, EndpointIdentity>(StringComparer.OrdinalIgnoreCase);
hostBuilder.Properties[nameof(EndpointIdentity)] = endpointIdentities;
}

var duplicates = identities
.Concat(new[] { endpointIdentity })
.GroupBy(identity => identity.LogicalName)
.Where(grp => grp.Count() > 1)
.Select(grp => grp.Key.ToString())
.ToList();

if (duplicates.Any())
if (!endpointIdentities.TryAdd(endpointIdentity.LogicalName, endpointIdentity))
{
throw new InvalidOperationException(EndpointDuplicatesWasFound.Format(string.Join(", ", duplicates)));
throw new InvalidOperationException(EndpointDuplicatesWasFound.Format(endpointIdentity.LogicalName));
}
}

identities.Add(endpointIdentity);
internal static ITelemetry SetupTelemetry(
this IHostBuilder hostBuilder,
EndpointIdentity endpointIdentity,
Assembly assembly)
{
var serviceName = endpointIdentity.LogicalName;

var version = assembly.GetCustomAttribute<AssemblyVersionAttribute>()?.Version
?? assembly.GetCustomAttribute<AssemblyFileVersionAttribute>()?.Version
?? assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion
?? "1.0.0.0";

var resourceBuilder = ResourceBuilder
.CreateDefault()
.AddService(
serviceVersion: version,
serviceName: endpointIdentity.LogicalName,
serviceInstanceId: endpointIdentity.InstanceName,
autoGenerateServiceInstanceId: false);

var tracerProvider = OpenTelemetry.Sdk
.CreateTracerProviderBuilder()
.SetResourceBuilder(resourceBuilder)
.AddSource(serviceName)
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddOtlpExporter()
.Build();

var meterProvider = OpenTelemetry.Sdk
.CreateMeterProviderBuilder()
.SetResourceBuilder(resourceBuilder)
.AddMeter(serviceName)
.AddRuntimeInstrumentation()
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddOtlpExporter()
.Build();

return new Telemetry(
tracerProvider!,
tracerProvider.GetTracer(serviceName, version),
meterProvider!,
new Meter(serviceName, version));
}

private static IDependencyContainer BuildDependencyContainer(EndpointOptions options)
Expand All @@ -142,13 +187,21 @@ private static IDependencyContainer BuildDependencyContainer(EndpointOptions opt
options.AboveAssemblies.ToArray());
}

private static IEndpointBuilder ConfigureBuilder(IHostBuilder hostBuilder, EndpointIdentity endpointIdentity)
private static IEndpointBuilder ConfigureBuilder(
IHostBuilder hostBuilder,
EndpointIdentity endpointIdentity,
Assembly assembly)
{
var crossCuttingConcernsAssembly = AssembliesExtensions.FindRequiredAssembly(AssembliesExtensions.BuildName(nameof(SpaceEngineers), nameof(Core), nameof(CrossCuttingConcerns)));
var crossCuttingConcernsAssembly = AssembliesExtensions.FindRequiredAssembly(
AssembliesExtensions.BuildName(
nameof(SpaceEngineers),
nameof(Core),
nameof(CrossCuttingConcerns)));

var integrationTransportInjection = hostBuilder.GetIntegrationTransportInjection();
var settingsDirectoryProvider = hostBuilder.GetSettingsDirectoryProvider();
var frameworkDependenciesProvider = hostBuilder.GetFrameworkDependenciesProvider();
var telemetry = hostBuilder.SetupTelemetry(endpointIdentity, assembly);

return new EndpointBuilder(endpointIdentity)
.WithEndpointPluginAssemblies(crossCuttingConcernsAssembly)
Expand All @@ -158,6 +211,7 @@ private static IEndpointBuilder ConfigureBuilder(IHostBuilder hostBuilder, Endpo
new GenericEndpointIdentityManualRegistration(endpointIdentity),
new SettingsProviderManualRegistration(settingsDirectoryProvider),
new LoggerFactoryManualRegistration(endpointIdentity, frameworkDependenciesProvider),
new TelemetryManualRegistration(telemetry),
new HostStartupActionsRegistryManualRegistration(frameworkDependenciesProvider),
new GenericEndpointHostStartupActionManualRegistration())
.WithManualVerification(true));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace SpaceEngineers.Core.GenericEndpoint.Host.Registrations
{
using CompositionRoot.Registration;
using Endpoint;

internal class TelemetryManualRegistration : IManualRegistration
{
private readonly ITelemetry _telemetry;

public TelemetryManualRegistration(ITelemetry telemetry)
{
_telemetry = telemetry;
}

public void Register(IManualRegistrationsContainer container)
{
container.RegisterInstance(_telemetry);
}
}
}
Loading

0 comments on commit 4f34ea1

Please sign in to comment.