This commit is contained in:
246
server/AyaNova/Program.cs
Normal file
246
server/AyaNova/Program.cs
Normal file
@@ -0,0 +1,246 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using NLog.Web;
|
||||
using NLog.Targets;
|
||||
using NLog.Config;
|
||||
|
||||
using App.Metrics;
|
||||
using App.Metrics.AspNetCore;
|
||||
|
||||
using AyaNova.Util;
|
||||
using AyaNova.Api.ControllerHelpers;
|
||||
|
||||
namespace AyaNova
|
||||
{
|
||||
|
||||
public class Program
|
||||
{
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
|
||||
//Get config
|
||||
var config = new ConfigurationBuilder().AddEnvironmentVariables().AddCommandLine(args).Build();
|
||||
ServerBootConfig.SetConfiguration(config);
|
||||
|
||||
#region Initialize Logging
|
||||
|
||||
//default log level
|
||||
NLog.LogLevel NLogLevel = NLog.LogLevel.Info;
|
||||
bool logLevelIsInfoOrHigher = true;
|
||||
|
||||
switch (ServerBootConfig.AYANOVA_LOG_LEVEL.ToLowerInvariant())
|
||||
{
|
||||
case "fatal":
|
||||
NLogLevel = NLog.LogLevel.Fatal;
|
||||
break;
|
||||
case "error":
|
||||
NLogLevel = NLog.LogLevel.Error;
|
||||
break;
|
||||
case "warn":
|
||||
NLogLevel = NLog.LogLevel.Warn;
|
||||
break;
|
||||
case "info":
|
||||
NLogLevel = NLog.LogLevel.Info;
|
||||
break;
|
||||
case "debug":
|
||||
NLogLevel = NLog.LogLevel.Debug;
|
||||
logLevelIsInfoOrHigher = false;
|
||||
break;
|
||||
case "trace":
|
||||
NLogLevel = NLog.LogLevel.Trace;
|
||||
logLevelIsInfoOrHigher = false;
|
||||
break;
|
||||
default:
|
||||
NLogLevel = NLog.LogLevel.Info;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// Step 1. Create configuration object
|
||||
var logConfig = new LoggingConfiguration();
|
||||
|
||||
// Step 2. Create targets and add them to the configuration
|
||||
var fileTarget = new FileTarget();
|
||||
logConfig.AddTarget("file", fileTarget);
|
||||
|
||||
//console target for really serious errors only
|
||||
var consoleTarget = new ConsoleTarget();
|
||||
logConfig.AddTarget("console", consoleTarget);
|
||||
|
||||
var nullTarget = new NLog.Targets.NullTarget();
|
||||
logConfig.AddTarget("blackhole", nullTarget);
|
||||
|
||||
// Step 3. Set target properties
|
||||
|
||||
fileTarget.FileName = Path.Combine(ServerBootConfig.AYANOVA_LOG_PATH, "log-ayanova.txt");
|
||||
fileTarget.Layout = "${longdate}|${uppercase:${level}}|${logger}|${message:exceptionSeparator==>:withException=true}";
|
||||
fileTarget.ArchiveFileName = Path.Combine(ServerBootConfig.AYANOVA_LOG_PATH, "log-ayanova-{#}.txt");
|
||||
fileTarget.ArchiveEvery = FileArchivePeriod.Wednesday;
|
||||
fileTarget.MaxArchiveFiles = 3;
|
||||
|
||||
// Step 4. Define rules
|
||||
|
||||
//filter out all Microsoft INFO level logs as they are too much
|
||||
var logRuleFilterOutMicrosoft = new LoggingRule("Microsoft.*", NLog.LogLevel.Trace, NLog.LogLevel.Info, nullTarget);
|
||||
logRuleFilterOutMicrosoft.Final = true;
|
||||
|
||||
//filter out all Microsoft EF CORE concurrency exceptions, it's a nuisance unless debugging or something
|
||||
//This is what I have to filter because it's the top exception: Microsoft.EntityFrameworkCore.Update
|
||||
//But this is what I'm actually trying to filter: Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException
|
||||
//however there doesn't appear to be a way to filter out based on content so...
|
||||
|
||||
var logRuleFilterOutMicrosoftEfCoreConcurrencyExceptions = new LoggingRule("Microsoft.EntityFrameworkCore.Update", NLog.LogLevel.Trace, NLog.LogLevel.Error, nullTarget);
|
||||
logRuleFilterOutMicrosoftEfCoreConcurrencyExceptions.Final = true;
|
||||
|
||||
//Log all other regular items at selected level
|
||||
var logRuleAyaNovaItems = new LoggingRule("*", NLogLevel, fileTarget);
|
||||
|
||||
//Log error or above to console
|
||||
var logRuleForConsole = new LoggingRule("*", NLog.LogLevel.Error, consoleTarget);
|
||||
|
||||
//add console serious error only log rule
|
||||
logConfig.LoggingRules.Add(logRuleForConsole);
|
||||
|
||||
//only log microsoft stuff it log is debug level or lower
|
||||
if (logLevelIsInfoOrHigher)
|
||||
{
|
||||
//filter OUT microsoft stuff
|
||||
logConfig.LoggingRules.Add(logRuleFilterOutMicrosoft);
|
||||
logConfig.LoggingRules.Add(logRuleFilterOutMicrosoftEfCoreConcurrencyExceptions);
|
||||
}
|
||||
|
||||
logConfig.LoggingRules.Add(logRuleAyaNovaItems);
|
||||
|
||||
|
||||
//Turn on internal logging:
|
||||
if (ServerBootConfig.AYANOVA_LOG_ENABLE_LOGGER_DIAGNOSTIC_LOG)
|
||||
{
|
||||
NLog.Common.InternalLogger.LogFile = "log-ayanova-logger.txt";
|
||||
NLog.Common.InternalLogger.LogLevel = NLog.LogLevel.Debug;
|
||||
}
|
||||
|
||||
// NLog: setup the logger first to catch all errors
|
||||
var logger = NLogBuilder.ConfigureNLog(logConfig).GetCurrentClassLogger();
|
||||
|
||||
//This is the first log entry
|
||||
logger.Info("AYANOVA SERVER BOOTING (log level: \"{0}\")", ServerBootConfig.AYANOVA_LOG_LEVEL);
|
||||
logger.Info(AyaNovaVersion.FullNameAndVersion);
|
||||
logger.Debug("BOOT: Log path is \"{0}\" ", ServerBootConfig.AYANOVA_LOG_PATH);
|
||||
|
||||
if (ServerBootConfig.AYANOVA_LOG_ENABLE_LOGGER_DIAGNOSTIC_LOG)
|
||||
{
|
||||
logger.Warn("BOOT: AYANOVA_LOG_ENABLE_LOGGER_DIAGNOSTIC_LOG is enabled! Disable as soon as no longer required.");
|
||||
}
|
||||
|
||||
//Log environmental settings
|
||||
logger.Info("BOOT: OS - {0}", Environment.OSVersion.ToString());
|
||||
logger.Debug("BOOT: Machine - {0}", Environment.MachineName);
|
||||
logger.Debug("BOOT: User - {0}", Environment.UserName);
|
||||
logger.Debug("BOOT: .Net Version - {0}", Environment.Version.ToString());
|
||||
logger.Debug("BOOT: CPU count - {0}", Environment.ProcessorCount);
|
||||
logger.Debug("BOOT: Default language - \"{0}\"", ServerBootConfig.AYANOVA_DEFAULT_LANGUAGE);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
//Ensure we are in the correct folder
|
||||
string startFolder = Directory.GetCurrentDirectory();
|
||||
var wwwRootFolder = Path.Combine(startFolder, "wwwroot");
|
||||
|
||||
|
||||
//Test for web root path
|
||||
//If user starts AyaNova from folder that is not the contentRoot then
|
||||
//AyaNova won't be able to serve static files
|
||||
if (!Directory.Exists(wwwRootFolder))
|
||||
{
|
||||
var err = string.Format("BOOT: E1010 - AyaNova was not started in the correct folder. AyaNova must be started from the folder that contains the \"wwwroot\" folder but was started instead from this folder: \"{0}\" which does not contain the wwwroot folder.", startFolder);
|
||||
logger.Fatal(err);
|
||||
throw new System.ApplicationException(err);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
BuildWebHost(args, logger).Run();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Fatal(e, "BOOT: E1090 - AyaNova server can't start due to unexpected exception during initialization");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static IWebHost BuildWebHost(string[] args, NLog.Logger logger)
|
||||
{
|
||||
logger.Debug("BOOT: building web host");
|
||||
var configuration = new ConfigurationBuilder().AddCommandLine(args).Build();
|
||||
|
||||
return WebHost.CreateDefaultBuilder(args)
|
||||
.CaptureStartupErrors(true)
|
||||
.UseSetting("detailedErrors", "true")
|
||||
.UseUrls(ServerBootConfig.AYANOVA_USE_URLS)//default port and urls, set first can be overridden by any later setting here
|
||||
.UseConfiguration(configuration)//support command line override of port (dotnet run urls=http://*:8081)
|
||||
.UseIISIntegration()//support IIS integration just in case, it appears here to override prior settings if necessary (port)
|
||||
.ConfigureMetricsWithDefaults(builder =>
|
||||
{
|
||||
if (ServerBootConfig.AYANOVA_METRICS_USE_INFLUXDB)
|
||||
{
|
||||
builder.Report.ToInfluxDb(
|
||||
options =>
|
||||
{
|
||||
|
||||
options.InfluxDb.BaseUri = new Uri(ServerBootConfig.AYANOVA_METRICS_INFLUXDB_BASEURL);
|
||||
options.InfluxDb.Database = ServerBootConfig.AYANOVA_METRICS_INFLUXDB_DBNAME;
|
||||
if (!string.IsNullOrWhiteSpace(ServerBootConfig.AYANOVA_METRICS_INFLUXDB_CONSISTENCY))
|
||||
{
|
||||
options.InfluxDb.Consistenency = ServerBootConfig.AYANOVA_METRICS_INFLUXDB_CONSISTENCY;
|
||||
}
|
||||
options.InfluxDb.UserName = ServerBootConfig.AYANOVA_METRICS_INFLUXDB_USERNAME;
|
||||
options.InfluxDb.Password = ServerBootConfig.AYANOVA_METRICS_INFLUXDB_PASSWORD;
|
||||
if (!string.IsNullOrWhiteSpace(ServerBootConfig.AYANOVA_METRICS_INFLUXDB_RETENSION_POLICY))
|
||||
{
|
||||
options.InfluxDb.RetensionPolicy = ServerBootConfig.AYANOVA_METRICS_INFLUXDB_RETENSION_POLICY;
|
||||
}
|
||||
|
||||
options.InfluxDb.CreateDataBaseIfNotExists = true;
|
||||
options.HttpPolicy.BackoffPeriod = TimeSpan.FromSeconds(30);
|
||||
options.HttpPolicy.FailuresBeforeBackoff = 5;
|
||||
options.HttpPolicy.Timeout = TimeSpan.FromSeconds(10);
|
||||
//options.MetricsOutputFormatter = new App.Metrics.Formatters.Json.MetricsJsonOutputFormatter();
|
||||
//options.Filter = filter;
|
||||
options.FlushInterval = TimeSpan.FromSeconds(20);
|
||||
});
|
||||
}
|
||||
|
||||
})
|
||||
.UseMetricsEndpoints(opt =>
|
||||
{
|
||||
opt.EnvironmentInfoEndpointEnabled = false;
|
||||
opt.MetricsEndpointEnabled = false;
|
||||
opt.MetricsTextEndpointEnabled = false;
|
||||
})
|
||||
.UseMetrics()
|
||||
.UseStartup<Startup>()
|
||||
.ConfigureLogging((context, logging) =>
|
||||
{
|
||||
// clear all previously registered providers
|
||||
//https://stackoverflow.com/a/46336988/8939
|
||||
logging.ClearProviders();
|
||||
})
|
||||
.UseNLog() // NLog: setup NLog for Dependency injection
|
||||
.Build();
|
||||
}
|
||||
|
||||
}//eoc
|
||||
|
||||
}//eons
|
||||
Reference in New Issue
Block a user