2021-11-17 08:36:23 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
using System ;
2022-11-14 10:12:52 -05:00
using System.Diagnostics ;
2021-11-17 08:36:23 -05:00
using System.IO ;
2023-03-03 07:44:02 -05:00
using EpicGames.Core ;
2021-11-17 08:36:23 -05:00
using Microsoft.AspNetCore.Hosting ;
2023-03-03 07:44:02 -05:00
using Microsoft.AspNetCore.Server.Kestrel.Core ;
2021-11-17 08:36:23 -05:00
using Microsoft.Extensions.Configuration ;
using Microsoft.Extensions.Hosting ;
using Serilog ;
2022-11-14 10:12:52 -05:00
using Serilog.Core ;
2023-03-03 07:44:02 -05:00
using Log = Serilog . Log ;
2021-11-17 08:36:23 -05:00
namespace Jupiter
{
2023-07-27 11:20:47 -04:00
// ReSharper disable once UnusedMember.Global
public static class BaseProgram < T > where T : BaseStartup
{
private static IConfiguration Configuration { get ; } = GetConfigurationBuilder ( ) ;
2021-11-17 08:36:23 -05:00
2023-07-27 11:20:47 -04:00
private static IConfiguration GetConfigurationBuilder ( )
{
string env = Environment . GetEnvironmentVariable ( "ASPNETCORE_ENVIRONMENT" ) ? ? "Production" ;
string mode = Environment . GetEnvironmentVariable ( "JUPITER_MODE" ) ? ? "DefaultMode" ;
string configRoot = "/config" ;
// set the config root to config under the current directory for windows
if ( OperatingSystem . IsWindows ( ) )
{
configRoot = Path . Combine ( Directory . GetCurrentDirectory ( ) , "config" ) ;
}
return new ConfigurationBuilder ( )
. SetBasePath ( Directory . GetCurrentDirectory ( ) )
. AddJsonFile ( "appsettings.json" , false , false )
. AddJsonFile (
path :
$"appsettings.{env}.json" ,
true )
. AddYamlFile (
path :
$"appsettings.{mode}.yaml" ,
true )
. AddYamlFile ( Path . Combine ( configRoot , "appsettings.Local.yaml" ) , optional : true , reloadOnChange : true )
. AddEnvironmentVariables ( )
. Build ( ) ;
2021-11-17 08:36:23 -05:00
2023-07-27 11:20:47 -04:00
}
2021-11-17 08:36:23 -05:00
2023-07-27 11:20:47 -04:00
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1000:Do not declare static members on generic types", Justification = "Keep logic for the base program together")]
public static int BaseMain ( string [ ] args )
{
Log . Logger = new LoggerConfiguration ( )
. ReadFrom . Configuration ( Configuration )
. Enrich . With < DatadogLogEnricher > ( )
2024-06-13 02:54:39 -04:00
. Enrich . WithRequestHeader ( "x-ue-session" , "ue-session" )
2024-06-03 04:21:28 -04:00
. Enrich . WithRequestHeader ( "ue-session" , "ue-session" )
2023-07-27 11:20:47 -04:00
. CreateLogger ( ) ;
2021-11-17 08:36:23 -05:00
2023-07-27 11:20:47 -04:00
try
{
JupiterSettings settings = new JupiterSettings ( ) ;
Configuration . GetSection ( "Jupiter" ) . Bind ( settings ) ;
string socketsRoot = settings . DomainSocketsRoot ;
2023-03-03 07:44:02 -05:00
2023-07-27 11:20:47 -04:00
if ( settings . UseDomainSockets )
{
File . Delete ( Path . Combine ( socketsRoot , "jupiter-http.sock" ) ) ;
File . Delete ( Path . Combine ( socketsRoot , "jupiter-http2.sock" ) ) ;
}
2023-03-10 06:58:44 -05:00
2023-07-27 11:20:47 -04:00
Log . Information ( "Creating ASPNET Host" ) ;
IHost host = CreateHostBuilder ( args ) . Build ( ) ;
host . Start ( ) ;
2023-03-10 06:58:44 -05:00
2023-07-27 11:20:47 -04:00
if ( settings . ChmodDomainSockets )
{
FileUtils . SetFileMode_Linux ( Path . Combine ( socketsRoot , "jupiter-http.sock" ) , 766 ) ;
FileUtils . SetFileMode_Linux ( Path . Combine ( socketsRoot , "jupiter-http2.sock" ) , 766 ) ;
}
2023-03-03 07:44:02 -05:00
2023-07-27 11:20:47 -04:00
host . WaitForShutdown ( ) ;
return 0 ;
}
catch ( Exception ex )
{
Log . Fatal ( ex , "Host terminated unexpectedly" ) ;
return 1 ;
}
finally
{
Log . CloseAndFlush ( ) ;
}
}
2021-11-17 08:36:23 -05:00
2023-07-27 11:20:47 -04:00
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1000:Do not declare static members on generic types", Justification = "Keep logic for the base program together")]
public static IHostBuilder CreateHostBuilder ( string [ ] args )
{
return Host . CreateDefaultBuilder ( args )
. ConfigureWebHostDefaults ( webBuilder = >
{
webBuilder . UseStartup < T > ( ) ;
webBuilder . UseConfiguration ( Configuration ) ;
// configure microsoft.extensions.logging to configure log4net to allow us to set it in our appsettings
// Disabled forwarding of log4net logs into serilog, as the AWS sdk is very spammy with its output producing multiple errors for a 404 (which isn't even an error in the first place)
// This can be enabled if you need to investigate some more complicated AWS sdk issue
/ * webBuilder . ConfigureLogging ( ( hostingContext , logging ) = >
{
// configure log4net (used by aws sdk) to write to serilog so we get the logs in the system we want it in
Log4net . Appender . Serilog . Configuration . Configure ( ) ;
} ) ; * /
// remove the server header from kestrel
2023-11-30 06:17:47 -05:00
JupiterSettings settings = new JupiterSettings ( ) ;
Configuration . GetSection ( "Jupiter" ) . Bind ( settings ) ;
if ( settings . PendingConnectionMax . HasValue )
{
webBuilder . UseSockets ( options = >
{
options . Backlog = settings . PendingConnectionMax . Value ;
} ) ;
}
2023-07-27 11:20:47 -04:00
webBuilder . ConfigureKestrel ( options = >
{
options . AddServerHeader = false ;
2023-03-03 07:44:02 -05:00
2024-06-03 08:07:14 -04:00
// Decrease min request body rate to be more forgiving for clients that are going wide and not sending as much data per connection
options . Limits . MinRequestBodyDataRate = new MinDataRate ( 10 , TimeSpan . FromSeconds ( 60 ) ) ;
2023-07-27 11:20:47 -04:00
string socketsRoot = settings . DomainSocketsRoot ;
2023-03-03 07:44:02 -05:00
2023-07-27 11:20:47 -04:00
if ( settings . UseDomainSockets )
{
Log . Logger . Information ( "Using unix domain sockets at {SocketsRoot}" , socketsRoot ) ;
options . ListenUnixSocket ( Path . Combine ( socketsRoot , "jupiter-http.sock" ) , listenOptions = >
{
listenOptions . Protocols = HttpProtocols . Http1AndHttp2 ;
} ) ;
options . ListenUnixSocket ( Path . Combine ( socketsRoot , "jupiter-http2.sock" ) , listenOptions = >
{
listenOptions . Protocols = HttpProtocols . Http2 ;
} ) ;
}
} ) ;
2024-01-30 07:04:44 -05:00
} ) . UseSerilog ( ) ;
2023-07-27 11:20:47 -04:00
}
}
2022-11-14 10:12:52 -05:00
2023-07-27 11:20:47 -04:00
class DatadogLogEnricher : ILogEventEnricher
{
public void Enrich ( Serilog . Events . LogEvent logEvent , ILogEventPropertyFactory propertyFactory )
{
string? ddAgentHost = System . Environment . GetEnvironmentVariable ( "DD_AGENT_HOST" ) ;
if ( string . IsNullOrEmpty ( ddAgentHost ) )
{
return ;
}
2022-11-14 10:12:52 -05:00
2023-07-27 11:20:47 -04:00
if ( Activity . Current = = null )
{
return ;
}
2022-11-14 10:12:52 -05:00
2023-07-27 11:20:47 -04:00
// convert open telemetry trace ids to dd traces
string stringTraceId = Activity . Current . TraceId . ToString ( ) ;
string stringSpanId = Activity . Current . SpanId . ToString ( ) ;
2022-11-14 10:12:52 -05:00
2023-07-27 11:20:47 -04:00
string ddTraceId = Convert . ToUInt64 ( stringTraceId . Substring ( 16 ) , 16 ) . ToString ( ) ;
string ddSpanId = Convert . ToUInt64 ( stringSpanId , 16 ) . ToString ( ) ;
2022-11-14 10:12:52 -05:00
2023-07-27 11:20:47 -04:00
logEvent . AddPropertyIfAbsent ( propertyFactory . CreateProperty ( "dd.trace_id" , ddTraceId ) ) ;
logEvent . AddPropertyIfAbsent ( propertyFactory . CreateProperty ( "dd.span_id" , ddSpanId ) ) ;
}
}
2021-11-17 08:36:23 -05:00
}