This commit is contained in:
2019-10-22 20:33:18 +00:00
parent 4da7fbee0d
commit bcd050c4c9
7 changed files with 100 additions and 56 deletions

View File

@@ -16,7 +16,7 @@ UPDATE all the things before commencing work
- Find and read changes for 3.1 dotnet core and Note that that above is for v2.2 my controllers appear to date from the v1 .net core era and I will need to then move them to the .netcore 3.1 era changes
- This is important and worth doing to make sure everything will work going forward (the swashbuckle [apicontroller] attribute debacle is proof of this)
- Should not process jobs during boot, maybe serverstate=booting would be useful here?
-------------------------------------------------------------------------------------------------------------------------------------
Need a sprint to get to a fully testable client with entry form, list and as much as possible all features from COMMON-* specs list

View File

@@ -22,14 +22,24 @@ namespace AyaNova.Api.ControllerHelpers
{
private readonly ILogger log;
public ApiCustomExceptionFilter(ILoggerFactory logger)
// public ApiCustomExceptionFilter(ILoggerFactory logger)
// {
// if (logger == null)
// {
// throw new ArgumentNullException(nameof(logger));
// }
// this.log = logger.CreateLogger("Server Exception");
// }
public ApiCustomExceptionFilter(ILogger logger)
{
if (logger == null)
{
throw new ArgumentNullException(nameof(logger));
}
this.log = logger.CreateLogger("Server Exception");
this.log = logger;
}
@@ -71,10 +81,10 @@ namespace AyaNova.Api.ControllerHelpers
if (loggableError)
log.LogError(context.Exception, "Error");
//Track this exception
IMetrics metrics = (IMetrics)ServiceProviderProvider.Provider.GetService(typeof(IMetrics));
metrics.Measure.Meter.Mark(MetricsRegistry.UnhandledExceptionsMeter,context.Exception.GetType().ToString());
IMetrics metrics = (IMetrics)ServiceProviderProvider.Provider.GetService(typeof(IMetrics));
metrics.Measure.Meter.Mark(MetricsRegistry.UnhandledExceptionsMeter, context.Exception.GetType().ToString());
HttpResponse response = context.HttpContext.Response;

View File

@@ -376,6 +376,7 @@ namespace AyaNova.Api.Controllers
[HttpGet("exception")]
public ActionResult GetException()
{
log.LogCritical("Widget::getexception->CRITICAL LOG TEST");
if (!serverState.IsOpen)
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
throw new System.NotSupportedException("Test exception from widget controller");

View File

@@ -33,10 +33,10 @@ namespace AyaNova
ServerBootConfig.SetConfiguration(config);
#region Initialize Logging
//NOTE: there is a logging issue that breaks all this with .net 3.1 hostbuilder vs webhostbuilder but webhostbuilder will be deprecated so we need to work around it
//the discussion about that is here: https://github.com/aspnet/AspNetCore/issues/9337
//NOTE: there is a logging issue that breaks all this with .net 3.1 hostbuilder vs webhostbuilder but webhostbuilder will be deprecated so we need to work around it
//the discussion about that is here: https://github.com/aspnet/AspNetCore/issues/9337
//NLOG OFFICIAL GUIDELINES FOR .net core 3.x https://github.com/NLog/NLog/wiki/Getting-started-with-ASP.NET-Core-3
//NLOG OFFICIAL GUIDELINES FOR .net core 3.x https://github.com/NLog/NLog/wiki/Getting-started-with-ASP.NET-Core-3
//default log level
NLog.LogLevel NLogLevel = NLog.LogLevel.Info;
@@ -198,6 +198,12 @@ namespace AyaNova
logger.Fatal(e, "BOOT: E1090 - AyaNova server can't start due to unexpected exception during initialization");
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
logger.Info("AyaNova server shutting down");
NLog.LogManager.Shutdown();
}
}

View File

@@ -22,23 +22,41 @@ using AyaNova.Util;
using AyaNova.Generator;
using AyaNova.Biz;
using NLog.Web;
using NLog.Targets;
using NLog.Config;
using NLog.Extensions.Logging;
namespace AyaNova
{
public class Startup
{
/////////////////////////////////////////////////////////////
//
public Startup(ILogger<Startup> logger, ILoggerFactory logFactory, Microsoft.AspNetCore.Hosting.IWebHostEnvironment hostingEnvironment)
{
_log = logger;
public Startup( Microsoft.AspNetCore.Hosting.IWebHostEnvironment hostingEnvironment)
{//ILogger<Startup> logger, ILoggerFactory logFactory,
// Get the factory for ILogger instances.
var nlogLoggerProvider = new NLogLoggerProvider();
// Create an ILogger.
_newLog = nlogLoggerProvider.CreateLogger(typeof(Startup).FullName);
//x_log = logger;
_hostingEnvironment = hostingEnvironment;
AyaNova.Util.ApplicationLogging.LoggerFactory = logFactory;
//AyaNova.Util.ApplicationLogging.LoggerFactory = logFactory;
//AyaNova.Util.ApplicationLogging.theLogger = _newLog;
AyaNova.Util.ApplicationLogging.LoggerProvider=nlogLoggerProvider;
//this must be set here
ServerBootConfig.AYANOVA_CONTENT_ROOT_PATH = hostingEnvironment.ContentRootPath;
}
private readonly ILogger<Startup> _log;
private readonly ILogger _newLog;
private readonly ILogger<Startup>x_log;
private string _connectionString = "";
private readonly Microsoft.AspNetCore.Hosting.IWebHostEnvironment _hostingEnvironment;
@@ -47,19 +65,20 @@ namespace AyaNova
//
public void ConfigureServices(IServiceCollection services)
{
_log.LogDebug("BOOT: initializing services...");
_newLog.LogDebug("BOOT: initializing services...");
//Server state service for shutting people out of api
_log.LogDebug("BOOT: init ApiServerState service");
_newLog.LogDebug("BOOT: init ApiServerState service");
services.AddSingleton(new AyaNova.Api.ControllerHelpers.ApiServerState());
//Init controllers
_log.LogDebug("BOOT: init controllers");
_newLog.LogDebug("BOOT: init controllers");
var MvcBuilder = services.AddControllers(config =>
{
config.Filters.Add(new AyaNova.Api.ControllerHelpers.ApiCustomExceptionFilter(AyaNova.Util.ApplicationLogging.LoggerFactory));
// config.Filters.Add(new AyaNova.Api.ControllerHelpers.ApiCustomExceptionFilter(AyaNova.Util.ApplicationLogging.LoggerFactory));
config.Filters.Add(new AyaNova.Api.ControllerHelpers.ApiCustomExceptionFilter(_newLog));
});
//Prevent default model binding automatic 400 page so we can consistently show *our* error to our specs
@@ -69,7 +88,7 @@ namespace AyaNova
options.SuppressModelStateInvalidFilter = true;
});
_log.LogDebug("BOOT: init JSON");
_newLog.LogDebug("BOOT: init JSON");
MvcBuilder.AddNewtonsoftJson(options =>
{
options.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
@@ -80,41 +99,41 @@ namespace AyaNova
//2019-10-17 METRICS will not work just yet with .netcore 3.1 see here https://github.com/AppMetrics/AppMetrics/issues/480
//awaiting a new release from them
//_log.LogDebug("BOOT: init Metrics service");
//_newLog.LogDebug("BOOT: init Metrics service");
//MvcBuilder.AddMetrics();
_log.LogDebug("BOOT: ensuring user and backup folders exist and are separate locations...");
_newLog.LogDebug("BOOT: ensuring user and backup folders exist and are separate locations...");
FileUtil.EnsureUserAndUtilityFoldersExistAndAreNotIdentical(_hostingEnvironment.ContentRootPath);
#region DATABASE
_connectionString = ServerBootConfig.AYANOVA_DB_CONNECTION;
//Check DB server exists and can be connected to
_log.LogDebug("BOOT: Testing database server connection...");
_newLog.LogDebug("BOOT: Testing database server connection...");
//parse the connection string properly
DbUtil.ParseConnectionString(_log, _connectionString);
DbUtil.ParseConnectionString(_newLog, _connectionString);
//Probe for database server
//Will retry every 10 seconds for up to 5 minutes before bailing
if (!DbUtil.DatabaseServerExists(_log, "BOOT: waiting for db server "))
if (!DbUtil.DatabaseServerExists(_newLog, "BOOT: waiting for db server "))
{
var err = $"BOOT: E1000 - AyaNova can't connect to the database server after trying for 5 minutes (connection string is:\"{DbUtil.DisplayableConnectionString}\")";
_log.LogCritical(err);
_newLog.LogCritical(err);
throw new System.ApplicationException(err);
}
_log.LogInformation("BOOT: Connected to database server - {0}", DbUtil.DisplayableConnectionString);
_newLog.LogInformation("BOOT: Connected to database server - {0}", DbUtil.DisplayableConnectionString);
//ensure database is ready and present
DbUtil.EnsureDatabaseExists(_log);
DbUtil.EnsureDatabaseExists(_newLog);
bool LOG_SENSITIVE_DATA = false;
@@ -123,7 +142,7 @@ namespace AyaNova
#endif
_log.LogDebug("BOOT: init EF service");
_newLog.LogDebug("BOOT: init EF service");
services.AddEntityFrameworkNpgsql().AddDbContext<AyContext>(
options => options.UseNpgsql(_connectionString
@@ -143,7 +162,7 @@ namespace AyaNova
// Add service and create Policy with options
_log.LogDebug("BOOT: init CORS service");
_newLog.LogDebug("BOOT: init CORS service");
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
@@ -223,7 +242,7 @@ namespace AyaNova
ServerBootConfig.AYANOVA_JWT_SECRET = secretKey;
var signingKey = new SymmetricSecurityKey(System.Text.Encoding.ASCII.GetBytes(ServerBootConfig.AYANOVA_JWT_SECRET));
_log.LogDebug("BOOT: init Authorization service");
_newLog.LogDebug("BOOT: init Authorization service");
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
@@ -254,7 +273,7 @@ namespace AyaNova
#endregion
_log.LogDebug("BOOT: init Generator service");
_newLog.LogDebug("BOOT: init Generator service");
services.AddSingleton<IHostedService, GeneratorService>();
}
@@ -267,7 +286,7 @@ namespace AyaNova
public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IWebHostEnvironment env,
AyContext dbContext, IApiVersionDescriptionProvider provider, AyaNova.Api.ControllerHelpers.ApiServerState apiServerState, IServiceProvider serviceProvider)
{
_log.LogDebug("BOOT: configuring request pipeline...");
_newLog.LogDebug("BOOT: configuring request pipeline...");
//this *may* be useful in the event of an issue so uncomment if necessary but errors during dev are handled equally by the logging, I think
// if (env.IsDevelopment())
@@ -286,7 +305,7 @@ namespace AyaNova
});
#region STATIC FILES
_log.LogDebug("BOOT: pipeline - static files");
_newLog.LogDebug("BOOT: pipeline - static files");
app.UseDefaultFiles();
app.UseStaticFiles();
//Might need the following if the page doesn't update in the client properly
@@ -304,19 +323,19 @@ namespace AyaNova
// });
#endregion
_log.LogDebug("BOOT: pipeline - ROUTING");
_newLog.LogDebug("BOOT: pipeline - ROUTING");
app.UseRouting();//this wasn't here for 2.2 but added for 3.0, needs to come before the stuff after
_log.LogDebug("BOOT: pipeline - CORS");
_newLog.LogDebug("BOOT: pipeline - CORS");
app.UseCors("CorsPolicy");
#region AUTH / ROLES
_log.LogDebug("BOOT: pipeline - authentication");
_newLog.LogDebug("BOOT: pipeline - authentication");
//Use authentication middleware
app.UseAuthentication();
_log.LogDebug("BOOT: pipeline - authorization");
_newLog.LogDebug("BOOT: pipeline - authorization");
app.UseAuthorization();
@@ -348,7 +367,7 @@ namespace AyaNova
#endregion
_log.LogDebug("BOOT: pipeline - ENDPOINTS");
_newLog.LogDebug("BOOT: pipeline - ENDPOINTS");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
@@ -356,7 +375,7 @@ namespace AyaNova
#region SWAGGER
_log.LogDebug("BOOT: pipeline - api explorer");
_newLog.LogDebug("BOOT: pipeline - api explorer");
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
app.UseSwaggerUI(
@@ -393,21 +412,21 @@ namespace AyaNova
if (ServerBootConfig.AYANOVA_PERMANENTLY_ERASE_DATABASE)
{
_log.LogWarning("BOOT: AYANOVA_PERMANENTLY_ERASE_DATABASE is true, dropping and recreating database");
Util.DbUtil.DropAndRecreateDb(_log);
AySchema.CheckAndUpdate(dbContext, _log);
_newLog.LogWarning("BOOT: AYANOVA_PERMANENTLY_ERASE_DATABASE is true, dropping and recreating database");
Util.DbUtil.DropAndRecreateDb(_newLog);
AySchema.CheckAndUpdate(dbContext, _newLog);
}
//Check schema
_log.LogDebug("BOOT: db schema check");
AySchema.CheckAndUpdate(dbContext, _log);
_newLog.LogDebug("BOOT: db schema check");
AySchema.CheckAndUpdate(dbContext, _newLog);
//Check database integrity
_log.LogDebug("BOOT: db integrity check");
DbUtil.CheckFingerPrint(AySchema.EXPECTED_COLUMN_COUNT, AySchema.EXPECTED_INDEX_COUNT, _log);
_newLog.LogDebug("BOOT: db integrity check");
DbUtil.CheckFingerPrint(AySchema.EXPECTED_COLUMN_COUNT, AySchema.EXPECTED_INDEX_COUNT, _newLog);
//Initialize license
AyaNova.Core.License.Initialize(apiServerState, dbContext, _log);
AyaNova.Core.License.Initialize(apiServerState, dbContext, _newLog);
//Ensure locales are present, not missing any keys and that there is a server default locale that exists
LocaleBiz lb = new LocaleBiz(dbContext, 1, ServerBootConfig.AYANOVA_DEFAULT_LANGUAGE_ID, AuthorizationRoles.OpsAdminFull);
@@ -419,7 +438,7 @@ namespace AyaNova
//TESTING
if (TESTING_REFRESH_DB)
{
AyaNova.Core.License.Fetch(apiServerState, dbContext, _log);
AyaNova.Core.License.Fetch(apiServerState, dbContext, _newLog);
Util.Seeder.SeedDatabase(Util.Seeder.SeedLevel.SmallOneManShopTrialDataSet, -7);//#############################################################################################
}
//TESTING
@@ -446,10 +465,10 @@ namespace AyaNova
//Log the active user count so it's in the log record
_log.LogInformation($"BOOT: Active techs - {UserBiz.ActiveCount}");
_newLog.LogInformation($"BOOT: Active techs - {UserBiz.ActiveCount}");
//Log the license info so it's on the record
_log.LogInformation($"BOOT: License -\r\n=-=-=-=-=-=-=-=-=-=-\r\n{AyaNova.Core.License.LicenseInfo}=-=-=-=-=-=-=-=-=-=-");
_newLog.LogInformation($"BOOT: License -\r\n=-=-=-=-=-=-=-=-=-=-\r\n{AyaNova.Core.License.LicenseInfo}=-=-=-=-=-=-=-=-=-=-");
@@ -457,7 +476,7 @@ namespace AyaNova
apiServerState.SetOpen();
//final startup log
_log.LogInformation("BOOT: COMPLETED - SERVER IS NOW OPEN");
_newLog.LogInformation("BOOT: COMPLETED - SERVER IS NOW OPEN");
}

View File

@@ -90,7 +90,7 @@ namespace AyaNova.Generator
}
catch (Exception ex)
{
log.LogError("Generate::ProcessJobs resulted in exception error ", ex);
log.LogError(ex,"Generate::ProcessJobs result in exception error ");
}
//=================================================================

View File

@@ -1,5 +1,5 @@
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
namespace AyaNova.Util
{
@@ -8,9 +8,17 @@ namespace AyaNova.Util
/// </summary>
internal static class ApplicationLogging
{
internal static ILoggerFactory LoggerFactory { get; set; }// = new LoggerFactory();
internal static ILogger CreateLogger<T>() => LoggerFactory.CreateLogger<T>();
internal static ILogger CreateLogger(string categoryName) => LoggerFactory.CreateLogger(categoryName);
internal static ILogger theLogger{get;set;}
internal static NLogLoggerProvider LoggerProvider { get; set; }// = new LoggerFactory();
internal static ILogger CreateLogger<T>() => LoggerProvider.CreateLogger(typeof(T).FullName);
//internal static ILogger CreateLogger(string categoryName) => theLogger;
internal static ILogger CreateLogger(string categoryName)=> LoggerProvider.CreateLogger(categoryName);
// internal static ILoggerFactory LoggerFactory { get; set; }// = new LoggerFactory();
// internal static ILogger CreateLogger<T>() => LoggerFactory.CreateLogger<T>();
// internal static ILogger CreateLogger(string categoryName) => LoggerFactory.CreateLogger(categoryName);
}
}