This commit is contained in:
2020-05-18 15:59:40 +00:00
parent 2b1c84ade0
commit 49ef9d1a20
3 changed files with 55 additions and 124 deletions

View File

@@ -153,40 +153,36 @@ namespace AyaNova
} }
// NLog: setup the logger first to catch all errors // NLog: setup the logger first to catch all errors
var logger = NLogBuilder.ConfigureNLog(logConfig).GetLogger("Init");//.GetCurrentClassLogger(); var logger = NLogBuilder.ConfigureNLog(logConfig).GetLogger("BOOT");
//This is the first log entry //This is the first log entry
logger.Info("AYANOVA SERVER BOOTING (log level: \"{0}\")", ServerBootConfig.AYANOVA_LOG_LEVEL); logger.Info($"AYANOVA SERVER {AyaNovaVersion.VersionString} BOOTING");
logger.Info(AyaNovaVersion.FullNameAndVersion);
//log configuration //log configuration
try try
{ {
var AyaNovaConfig=config.AsEnumerable().Where(m => m.Key.StartsWith("AYANOVA") && m.Key!="AYANOVA_JWT_SECRET").Select(m=>m.Key+ "="+ m.Value).ToList();
var AyaNovaConfig=config.AsEnumerable().Where(m => m.Key.StartsWith("AYANOVA") && m.Key!="AYANOVA_JWT_SECRET").Select(m=>m.Key+ "="+ m.Value).ToList();
var DiagConfig=string.Join(",", AyaNovaConfig); var DiagConfig=string.Join(",", AyaNovaConfig);
DiagConfig=DbUtil.PasswordRedactedConnectionString(DiagConfig); DiagConfig=DbUtil.PasswordRedactedConnectionString(DiagConfig);
logger.Info($"BOOT: configuration {DiagConfig}"); logger.Info($"Config {DiagConfig}");
} }
catch (Exception ex) catch (Exception ex)
{ {
logger.Error(ex, "BOOT: error fetching configuration"); logger.Error(ex, "Error fetching configuration");
} }
logger.Debug($"BOOT: Full configuration is {config.GetDebugView()}"); logger.Debug($"Full configuration is {config.GetDebugView()}");
logger.Debug("BOOT: Log path is \"{0}\" ", ServerBootConfig.AYANOVA_LOG_PATH);
if (ServerBootConfig.AYANOVA_LOG_ENABLE_LOGGER_DIAGNOSTIC_LOG) if (ServerBootConfig.AYANOVA_LOG_ENABLE_LOGGER_DIAGNOSTIC_LOG)
{ logger.Warn("AYANOVA_LOG_ENABLE_LOGGER_DIAGNOSTIC_LOG is enabled, this will cause the server to run very slowly");
logger.Warn("BOOT: AYANOVA_LOG_ENABLE_LOGGER_DIAGNOSTIC_LOG is enabled! Disable as soon as no longer required.");
}
//Log environmental settings //Log environmental settings
logger.Info("BOOT: OS - {0}", Environment.OSVersion.ToString()); logger.Info("OS - {0}", Environment.OSVersion.ToString());
logger.Debug("BOOT: Machine - {0}", Environment.MachineName); logger.Debug("Machine - {0}", Environment.MachineName);
logger.Debug("BOOT: User - {0}", Environment.UserName); logger.Debug("User - {0}", Environment.UserName);
logger.Debug("BOOT: .Net Version - {0}", Environment.Version.ToString()); logger.Debug(".Net Version - {0}", Environment.Version.ToString());
logger.Debug("BOOT: CPU count - {0}", Environment.ProcessorCount); logger.Debug("CPU count - {0}", Environment.ProcessorCount);
logger.Debug("BOOT: Default language - \"{0}\"", ServerBootConfig.AYANOVA_DEFAULT_TRANSLATION);
#endregion #endregion
@@ -201,7 +197,7 @@ namespace AyaNova
//AyaNova won't be able to serve static files //AyaNova won't be able to serve static files
if (!Directory.Exists(wwwRootFolder)) 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); var err = string.Format("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); logger.Fatal(err);
throw new System.ApplicationException(err); throw new System.ApplicationException(err);
} }
@@ -213,7 +209,7 @@ namespace AyaNova
} }
catch (Exception e) catch (Exception e)
{ {
logger.Fatal(e, "BOOT: E1090 - AyaNova server can't start due to unexpected exception during initialization"); logger.Fatal(e, "E1090 - AyaNova server can't start due to unexpected exception during initialization");
throw; throw;
} }
finally finally
@@ -231,7 +227,7 @@ namespace AyaNova
public static IHostBuilder BuildHost(string[] args, NLog.Logger logger) public static IHostBuilder BuildHost(string[] args, NLog.Logger logger)
{ {
logger.Debug("BOOT: building host"); logger.Debug("Building host");
var configuration = new ConfigurationBuilder().AddCommandLine(args).Build(); var configuration = new ConfigurationBuilder().AddCommandLine(args).Build();
return Host.CreateDefaultBuilder(args) return Host.CreateDefaultBuilder(args)
@@ -289,73 +285,8 @@ namespace AyaNova
logging.ClearProviders(); logging.ClearProviders();
}) })
.UseNLog(); // NLog: setup NLog for Dependency injection .UseNLog(); // NLog: setup NLog for Dependency injection
}); });
}
}
/* Dotnet 2.2 buildwebhost will be deprecated in favor of buildhost
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_RETENTION_POLICY))
{
options.InfluxDb.RetentionPolicy = ServerBootConfig.AYANOVA_METRICS_INFLUXDB_RETENTION_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 }//eoc

View File

@@ -35,7 +35,7 @@ namespace AyaNova
var nlogLoggerProvider = new NLogLoggerProvider(); var nlogLoggerProvider = new NLogLoggerProvider();
// Create an ILogger. // Create an ILogger.
_newLog = nlogLoggerProvider.CreateLogger("Server"); _newLog = nlogLoggerProvider.CreateLogger("SERVER");
//x_log = logger; //x_log = logger;
_hostingEnvironment = hostingEnvironment; _hostingEnvironment = hostingEnvironment;
@@ -59,16 +59,16 @@ namespace AyaNova
// //
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
_newLog.LogDebug("BOOT: initializing services..."); _newLog.LogDebug("Initializing services...");
//Server state service for shutting people out of api //Server state service for shutting people out of api
_newLog.LogDebug("BOOT: init ApiServerState service"); _newLog.LogDebug("ApiServerState");
services.AddSingleton(new AyaNova.Api.ControllerHelpers.ApiServerState()); services.AddSingleton(new AyaNova.Api.ControllerHelpers.ApiServerState());
//Init controllers //Init controllers
_newLog.LogDebug("BOOT: init controllers"); _newLog.LogDebug("Controllers");
var MvcBuilder = services.AddControllers(config => 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));
@@ -85,7 +85,7 @@ namespace AyaNova
options.SuppressModelStateInvalidFilter = true; options.SuppressModelStateInvalidFilter = true;
}); });
_newLog.LogDebug("BOOT: init JSON"); _newLog.LogDebug("JSON");
MvcBuilder.AddNewtonsoftJson(options => MvcBuilder.AddNewtonsoftJson(options =>
{ {
@@ -97,39 +97,39 @@ namespace AyaNova
//HTTP CLIENT FACTORY USED BY LICENSE.CS //HTTP CLIENT FACTORY USED BY LICENSE.CS
//https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-3.1 //https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-3.1
_newLog.LogDebug("BOOT: init HTTPClientFactory"); _newLog.LogDebug("HTTPClientFactory");
services.AddHttpClient(); services.AddHttpClient();
//2019-10-17 METRICS will not work just yet with .netcore 3.1 see here https://github.com/AppMetrics/AppMetrics/issues/480 //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 //awaiting a new release from them
_newLog.LogDebug("BOOT: init Metrics service"); _newLog.LogDebug("Metrics");
services.AddMetrics(); services.AddMetrics();
_newLog.LogDebug("BOOT: ensuring user and backup folders exist and are separate locations..."); _newLog.LogDebug("Ensuring user and backup folders exist and are separate locations...");
FileUtil.EnsureUserAndUtilityFoldersExistAndAreNotIdentical(_hostingEnvironment.ContentRootPath); FileUtil.EnsureUserAndUtilityFoldersExistAndAreNotIdentical(_hostingEnvironment.ContentRootPath);
#region DATABASE #region DATABASE
_connectionString = ServerBootConfig.AYANOVA_DB_CONNECTION; _connectionString = ServerBootConfig.AYANOVA_DB_CONNECTION;
//Check DB server exists and can be connected to //Check DB server exists and can be connected to
_newLog.LogDebug("BOOT: Testing database server connection..."); _newLog.LogDebug("Testing database server connection...");
//parse the connection string properly //parse the connection string properly
DbUtil.ParseConnectionString(_newLog, _connectionString); DbUtil.ParseConnectionString(_newLog, _connectionString);
//Probe for database server //Probe for database server
//Will retry every 10 seconds for up to 5 minutes before bailing //Will retry every 10 seconds for up to 5 minutes before bailing
if (!DbUtil.DatabaseServerExists(_newLog, "BOOT: waiting for db server ")) if (!DbUtil.DatabaseServerExists(_newLog, "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}\")"; var err = $"E1000 - AyaNova can't connect to the database server after trying for 5 minutes (connection string is:\"{DbUtil.DisplayableConnectionString}\")";
_newLog.LogCritical(err); _newLog.LogCritical(err);
throw new System.ApplicationException(err); throw new System.ApplicationException(err);
} }
_newLog.LogInformation("BOOT: Connected to database server - {0}", DbUtil.DisplayableConnectionString); _newLog.LogInformation("Connected to database server - {0}", DbUtil.DisplayableConnectionString);
//ensure database is ready and present //ensure database is ready and present
@@ -142,7 +142,7 @@ namespace AyaNova
#endif #endif
_newLog.LogDebug("BOOT: init EF service"); _newLog.LogDebug("EF Core");
services.AddEntityFrameworkNpgsql().AddDbContext<AyContext>( services.AddEntityFrameworkNpgsql().AddDbContext<AyContext>(
options => options.UseNpgsql(_connectionString options => options.UseNpgsql(_connectionString
@@ -162,7 +162,7 @@ namespace AyaNova
// Add service and create Policy with options // Add service and create Policy with options
_newLog.LogDebug("BOOT: init CORS service"); _newLog.LogDebug("CORS");
services.AddCors(options => services.AddCors(options =>
{ {
options.AddPolicy("CorsPolicy", options.AddPolicy("CorsPolicy",
@@ -254,7 +254,7 @@ namespace AyaNova
ServerBootConfig.AYANOVA_JWT_SECRET = secretKey; ServerBootConfig.AYANOVA_JWT_SECRET = secretKey;
var signingKey = new SymmetricSecurityKey(System.Text.Encoding.ASCII.GetBytes(ServerBootConfig.AYANOVA_JWT_SECRET)); var signingKey = new SymmetricSecurityKey(System.Text.Encoding.ASCII.GetBytes(ServerBootConfig.AYANOVA_JWT_SECRET));
_newLog.LogDebug("BOOT: init Authorization service"); _newLog.LogDebug("Authorization");
services.AddAuthentication(options => services.AddAuthentication(options =>
{ {
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
@@ -285,7 +285,7 @@ namespace AyaNova
#endregion #endregion
_newLog.LogDebug("BOOT: init Generator service"); _newLog.LogDebug("Generator");
services.AddSingleton<IHostedService, GeneratorService>(); services.AddSingleton<IHostedService, GeneratorService>();
} }
@@ -298,7 +298,7 @@ namespace AyaNova
public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IWebHostEnvironment env, public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IWebHostEnvironment env,
AyContext dbContext, IApiVersionDescriptionProvider provider, AyaNova.Api.ControllerHelpers.ApiServerState apiServerState, IServiceProvider serviceProvider) AyContext dbContext, IApiVersionDescriptionProvider provider, AyaNova.Api.ControllerHelpers.ApiServerState apiServerState, IServiceProvider serviceProvider)
{ {
_newLog.LogDebug("BOOT: configuring request pipeline..."); _newLog.LogDebug("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 //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()) // if (env.IsDevelopment())
@@ -326,7 +326,7 @@ namespace AyaNova
#region STATIC FILES #region STATIC FILES
_newLog.LogDebug("BOOT: pipeline - static files"); _newLog.LogDebug("Static files");
app.UseDefaultFiles(); app.UseDefaultFiles();
app.UseStaticFiles(); app.UseStaticFiles();
//Might need the following if the page doesn't update in the client properly //Might need the following if the page doesn't update in the client properly
@@ -344,19 +344,19 @@ namespace AyaNova
// }); // });
#endregion #endregion
_newLog.LogDebug("BOOT: pipeline - ROUTING"); _newLog.LogDebug("Routing pipeline");
app.UseRouting();//this wasn't here for 2.2 but added for 3.0, needs to come before the stuff after app.UseRouting();//this wasn't here for 2.2 but added for 3.0, needs to come before the stuff after
_newLog.LogDebug("BOOT: pipeline - CORS"); _newLog.LogDebug("CORS pipeline");
app.UseCors("CorsPolicy"); app.UseCors("CorsPolicy");
#region AUTH / ROLES CUSTOM MIDDLEWARE #region AUTH / ROLES CUSTOM MIDDLEWARE
_newLog.LogDebug("BOOT: pipeline - authentication"); _newLog.LogDebug("Authentication pipeline");
//Use authentication middleware //Use authentication middleware
app.UseAuthentication(); app.UseAuthentication();
_newLog.LogDebug("BOOT: pipeline - authorization"); _newLog.LogDebug("Authorization pipeline");
app.UseAuthorization(); app.UseAuthorization();
@@ -414,7 +414,7 @@ namespace AyaNova
#endregion #endregion
_newLog.LogDebug("BOOT: pipeline - ENDPOINTS"); _newLog.LogDebug("Endpoints pipeline");
app.UseEndpoints(endpoints => app.UseEndpoints(endpoints =>
{ {
endpoints.MapControllers(); endpoints.MapControllers();
@@ -422,7 +422,7 @@ namespace AyaNova
#region SWAGGER #region SWAGGER
_newLog.LogDebug("BOOT: pipeline - api explorer"); _newLog.LogDebug("API explorer pipeline");
// Enable middleware to serve generated Swagger as a JSON endpoint. // Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger(); app.UseSwagger();
app.UseSwaggerUI( app.UseSwaggerUI(
@@ -464,29 +464,29 @@ namespace AyaNova
{ {
if (ServerBootConfig.AYANOVA_SERVER_TEST_MODE) if (ServerBootConfig.AYANOVA_SERVER_TEST_MODE)
{ {
_newLog.LogWarning("BOOT: AYANOVA_SERVER_TEST_MODE is true, dropping and recreating database"); _newLog.LogWarning("AYANOVA_SERVER_TEST_MODE, dropping and recreating database");
} }
else else
{ {
_newLog.LogWarning("BOOT: AYANOVA_PERMANENTLY_ERASE_DATABASE is true, dropping and recreating database"); _newLog.LogWarning("AYANOVA_PERMANENTLY_ERASE_DATABASE, dropping and recreating database");
} }
Util.DbUtil.DropAndRecreateDbAsync(_newLog).Wait(); Util.DbUtil.DropAndRecreateDbAsync(_newLog).Wait();
AySchema.CheckAndUpdateAsync(dbContext, _newLog).Wait(); AySchema.CheckAndUpdateAsync(dbContext, _newLog).Wait();
} }
//Check schema //Check schema
_newLog.LogDebug("BOOT: db schema check"); _newLog.LogDebug("DB schema check");
AySchema.CheckAndUpdateAsync(dbContext, _newLog).Wait(); AySchema.CheckAndUpdateAsync(dbContext, _newLog).Wait();
//Check database integrity //Check database integrity
_newLog.LogDebug("BOOT: db integrity check"); _newLog.LogDebug("DB integrity check");
DbUtil.CheckFingerPrintAsync(AySchema.EXPECTED_COLUMN_COUNT, AySchema.EXPECTED_INDEX_COUNT, _newLog).Wait(); DbUtil.CheckFingerPrintAsync(AySchema.EXPECTED_COLUMN_COUNT, AySchema.EXPECTED_INDEX_COUNT, _newLog).Wait();
//Initialize license //Initialize license
AyaNova.Core.License.InitializeAsync(apiServerState, dbContext, _newLog).Wait(); AyaNova.Core.License.InitializeAsync(apiServerState, dbContext, _newLog).Wait();
//Set static global biz settings //Set static global biz settings
_newLog.LogDebug("BOOT: init global settings"); _newLog.LogDebug("Global settings");
ServerGlobalBizSettings.Initialize(null, dbContext); ServerGlobalBizSettings.Initialize(null, dbContext);
//Ensure translations are present, not missing any keys and that there is a server default translation that exists //Ensure translations are present, not missing any keys and that there is a server default translation that exists
@@ -497,7 +497,7 @@ namespace AyaNova
//TESTING //TESTING
if (ServerBootConfig.AYANOVA_SERVER_TEST_MODE) if (ServerBootConfig.AYANOVA_SERVER_TEST_MODE)
{ {
_newLog.LogInformation($"BOOT: server test mode seeding, level is {ServerBootConfig.AYANOVA_SERVER_TEST_MODE_SEEDLEVEL}, tz offset is {ServerBootConfig.AYANOVA_SERVER_TEST_MODE_TZ_OFFSET}"); _newLog.LogInformation($"Server test mode seeding, level is {ServerBootConfig.AYANOVA_SERVER_TEST_MODE_SEEDLEVEL}, tz offset is {ServerBootConfig.AYANOVA_SERVER_TEST_MODE_TZ_OFFSET}");
AyaNova.Core.License.FetchKeyAsync(apiServerState, dbContext, _newLog).Wait(); AyaNova.Core.License.FetchKeyAsync(apiServerState, dbContext, _newLog).Wait();
//NOTE: For unit testing make sure the time zone is same as tester to ensure list filter by date tests will work because server is on same page as user in terms of time //NOTE: For unit testing make sure the time zone is same as tester to ensure list filter by date tests will work because server is on same page as user in terms of time
Util.Seeder.SeedDatabaseAsync(Util.Seeder.StringToSeedLevel(ServerBootConfig.AYANOVA_SERVER_TEST_MODE_SEEDLEVEL), ServerBootConfig.AYANOVA_SERVER_TEST_MODE_TZ_OFFSET).Wait(); Util.Seeder.SeedDatabaseAsync(Util.Seeder.StringToSeedLevel(ServerBootConfig.AYANOVA_SERVER_TEST_MODE_SEEDLEVEL), ServerBootConfig.AYANOVA_SERVER_TEST_MODE_TZ_OFFSET).Wait();
@@ -522,10 +522,10 @@ namespace AyaNova
//Log the active user count so it's in the log record //Log the active user count so it's in the log record
_newLog.LogInformation($"BOOT: Active techs - {UserBiz.ActiveCountAsync().Result}"); _newLog.LogInformation($"Active techs - {UserBiz.ActiveCountAsync().Result}");
//Log the license info so it's on the record //Log the license info so it's on the record
_newLog.LogInformation($"BOOT: License - [{AyaNova.Core.License.LicenseInfoLogFormat}]"); _newLog.LogInformation($"License - [{AyaNova.Core.License.LicenseInfoLogFormat}]");
@@ -533,7 +533,7 @@ namespace AyaNova
apiServerState.SetOpen(); apiServerState.SetOpen();
//final startup log //final startup log
_newLog.LogInformation("BOOT: COMPLETED - SERVER IS NOW OPEN"); _newLog.LogInformation("Boot complete - server open");
#if (DEBUG) #if (DEBUG)
//Show in dev console that server is open (so I don't need to look in the log to see it) //Show in dev console that server is open (so I don't need to look in the log to see it)

View File

@@ -62,7 +62,7 @@ namespace AyaNova.Util
try try
{ {
await LogStatusAsync(JobId, LogJob, log, $"SEEDER: Seeding data level is {slevel.ToString()}, time zone offset is {timeZoneOffset.ToString()}"); await LogStatusAsync(JobId, LogJob, log, $"Seeding data, level {slevel.ToString()}, time zone offset {timeZoneOffset.ToString()}");
//Only allow this in a trial database //Only allow this in a trial database
if (!AyaNova.Core.License.ActiveKey.TrialLicense) if (!AyaNova.Core.License.ActiveKey.TrialLicense)