diff --git a/src/Umbraco.Infrastructure/Logging/Serilog/LoggerConfigExtensions.cs b/src/Umbraco.Infrastructure/Logging/Serilog/LoggerConfigExtensions.cs index 1060b0ac21..84270b95bf 100644 --- a/src/Umbraco.Infrastructure/Logging/Serilog/LoggerConfigExtensions.cs +++ b/src/Umbraco.Infrastructure/Logging/Serilog/LoggerConfigExtensions.cs @@ -22,16 +22,18 @@ namespace Umbraco.Core.Logging.Serilog /// It is highly recommended that you keep/use this default in your own logging config customizations /// /// A Serilog LoggerConfiguration + /// /// public static LoggerConfiguration MinimalConfiguration( this LoggerConfiguration logConfig, + IHostingEnvironment hostingEnvironment, ILoggingConfiguration loggingConfiguration) { global::Serilog.Debugging.SelfLog.Enable(msg => System.Diagnostics.Debug.WriteLine(msg)); //Set this environment variable - so that it can be used in external config file //add key="serilog:write-to:RollingFile.pathFormat" value="%BASEDIR%\logs\log.txt" /> - Environment.SetEnvironmentVariable("BASEDIR", loggingConfiguration.LogDirectory.TrimEnd("\\"), EnvironmentVariableTarget.Process); + Environment.SetEnvironmentVariable("BASEDIR", hostingEnvironment.MapPathContentRoot("/").TrimEnd("\\"), EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable("UMBLOGDIR", loggingConfiguration.LogDirectory, EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable("MACHINENAME", Environment.MachineName, EnvironmentVariableTarget.Process); @@ -40,7 +42,7 @@ namespace Umbraco.Core.Logging.Serilog .Enrich.WithProcessName() .Enrich.WithThreadId() .Enrich.WithProperty(AppDomainId, AppDomain.CurrentDomain.Id) - .Enrich.WithProperty("AppDomainAppId", AppDomain.CurrentDomain.Id.ToString().ReplaceNonAlphanumericChars(string.Empty)) + .Enrich.WithProperty("AppDomainAppId", hostingEnvironment.ApplicationId.ReplaceNonAlphanumericChars(string.Empty)) .Enrich.WithProperty("MachineName", Environment.MachineName) .Enrich.With() .Enrich.FromLogContext(); // allows us to dynamically enrich diff --git a/src/Umbraco.Infrastructure/Logging/Serilog/SerilogLogger.cs b/src/Umbraco.Infrastructure/Logging/Serilog/SerilogLogger.cs index 1be056bc9f..9e14a6407a 100644 --- a/src/Umbraco.Infrastructure/Logging/Serilog/SerilogLogger.cs +++ b/src/Umbraco.Infrastructure/Logging/Serilog/SerilogLogger.cs @@ -39,11 +39,12 @@ namespace Umbraco.Core.Logging.Serilog /// /// Used by UmbracoApplicationBase to get its logger. public static SerilogLogger CreateWithDefaultConfiguration( + IHostingEnvironment hostingEnvironment, ILoggingConfiguration loggingConfiguration, IConfiguration configuration) { var loggerConfig = new LoggerConfiguration() - .MinimalConfiguration(loggingConfiguration) + .MinimalConfiguration(hostingEnvironment, loggingConfiguration) .ReadFrom.Configuration(configuration); return new SerilogLogger(loggerConfig); diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs index 31c6e3155d..b8ecb8e793 100644 --- a/src/Umbraco.Tests.Integration/RuntimeTests.cs +++ b/src/Umbraco.Tests.Integration/RuntimeTests.cs @@ -61,7 +61,7 @@ namespace Umbraco.Tests.Integration services.AddRequiredNetCoreServices(testHelper, webHostEnvironment); // Add it! - var typeLoader = services.AddTypeLoader(GetType().Assembly, webHostEnvironment, + var typeLoader = services.AddTypeLoader(GetType().Assembly, webHostEnvironment, testHelper.GetHostingEnvironment(), testHelper.ConsoleLoggerFactory, AppCaches.NoCache, hostContext.Configuration); var builder = new UmbracoBuilder(services, hostContext.Configuration, typeLoader, testHelper.ConsoleLoggerFactory); @@ -106,7 +106,7 @@ namespace Umbraco.Tests.Integration // Add it! var typeLoader = services.AddTypeLoader(GetType().Assembly, - webHostEnvironment, testHelper.ConsoleLoggerFactory, AppCaches.NoCache, + webHostEnvironment, testHelper.GetHostingEnvironment(), testHelper.ConsoleLoggerFactory, AppCaches.NoCache, hostContext.Configuration); var builder = new UmbracoBuilder(services, hostContext.Configuration, typeLoader, testHelper.ConsoleLoggerFactory); diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs index 5d43d7c8d1..64c2292252 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs @@ -130,7 +130,7 @@ namespace Umbraco.Tests.Integration.TestServerTest public override void ConfigureServices(IServiceCollection services) { - var typeLoader = services.AddTypeLoader(GetType().Assembly, TestHelper.GetWebHostEnvironment(), + var typeLoader = services.AddTypeLoader(GetType().Assembly, TestHelper.GetWebHostEnvironment(), TestHelper.GetHostingEnvironment(), TestHelper.ConsoleLoggerFactory, AppCaches.NoCache, Configuration); var builder = new UmbracoBuilder(services, Configuration, typeLoader); diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index 7d3f8886f7..c92fbb7341 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -174,11 +174,11 @@ namespace Umbraco.Tests.Integration.Testing // Add it! - var typeLoader = services.AddTypeLoader(GetType().Assembly, webHostEnvironment, TestHelper.ConsoleLoggerFactory, AppCaches.NoCache, Configuration); + var typeLoader = services.AddTypeLoader(GetType().Assembly, webHostEnvironment, TestHelper.GetHostingEnvironment(), TestHelper.ConsoleLoggerFactory, AppCaches.NoCache, Configuration); var builder = new UmbracoBuilder(services, Configuration, typeLoader, TestHelper.ConsoleLoggerFactory); - builder.Services.AddLogger(TestHelper.GetLoggingConfiguration(), Configuration); + builder.Services.AddLogger(TestHelper.GetHostingEnvironment(), TestHelper.GetLoggingConfiguration(), Configuration); builder.AddConfiguration() .AddUmbracoCore(); diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironmentWithoutOptionsMonitor.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironmentWithoutOptionsMonitor.cs deleted file mode 100644 index a2b441c29d..0000000000 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironmentWithoutOptionsMonitor.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Options; -using Umbraco.Core; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Models; - -namespace Umbraco.Web.Common.AspNetCore -{ - public class AspNetCoreHostingEnvironmentWithoutOptionsMonitor : Core.Hosting.IHostingEnvironment - { - - private HostingSettings _hostingSettings; - private readonly IWebHostEnvironment _webHostEnvironment; - - private string _localTempPath; - - public AspNetCoreHostingEnvironmentWithoutOptionsMonitor(HostingSettings hostingSettings, IWebHostEnvironment webHostEnvironment) - { - _hostingSettings = hostingSettings ?? throw new ArgumentNullException(nameof(hostingSettings)); - _webHostEnvironment = webHostEnvironment ?? throw new ArgumentNullException(nameof(webHostEnvironment)); - - SiteName = webHostEnvironment.ApplicationName; - ApplicationId = AppDomain.CurrentDomain.Id.ToString(); - ApplicationPhysicalPath = webHostEnvironment.ContentRootPath; - - IISVersion = new Version(0, 0); // TODO not necessary IIS - } - - - public bool IsHosted { get; } = true; - public string SiteName { get; } - public string ApplicationId { get; } - public string ApplicationPhysicalPath { get; } - public string ApplicationServerAddress { get; } - - //TODO how to find this, This is a server thing, not application thing. - public string ApplicationVirtualPath => _hostingSettings.ApplicationVirtualPath?.EnsureStartsWith('/') ?? "/"; - public bool IsDebugMode => _hostingSettings.Debug; - - public Version IISVersion { get; } - public string LocalTempPath - { - get - { - if (_localTempPath != null) - return _localTempPath; - - switch (_hostingSettings.LocalTempStorageLocation) - { - case LocalTempStorage.AspNetTemp: - - // TODO: I don't think this is correct? but also we probably can remove AspNetTemp as an option entirely - // since this is legacy and we shouldn't use it - return _localTempPath = System.IO.Path.Combine(Path.GetTempPath(), ApplicationId, "UmbracoData"); - - case LocalTempStorage.EnvironmentTemp: - - // environment temp is unique, we need a folder per site - - // use a hash - // combine site name and application id - // site name is a Guid on Cloud - // application id is eg /LM/W3SVC/123456/ROOT - // the combination is unique on one server - // and, if a site moves from worker A to B and then back to A... - // hopefully it gets a new Guid or new application id? - - var hashString = SiteName + "::" + ApplicationId; - var hash = hashString.GenerateHash(); - var siteTemp = System.IO.Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", hash); - - return _localTempPath = siteTemp; - - //case LocalTempStorage.Default: - //case LocalTempStorage.Unknown: - default: - return _localTempPath = MapPathContentRoot("~/App_Data/TEMP"); - } - } - } - - public string MapPathWebRoot(string path) - { - var newPath = path.TrimStart('~', '/').Replace('/', Path.DirectorySeparatorChar); - return Path.Combine(_webHostEnvironment.WebRootPath, newPath); - } - - public string MapPathContentRoot(string path) - { - var newPath = path.TrimStart('~', '/').Replace('/', Path.DirectorySeparatorChar); - return Path.Combine(_webHostEnvironment.ContentRootPath, newPath); - } - - public string ToAbsolute(string virtualPath) - { - if (!virtualPath.StartsWith("~/") && !virtualPath.StartsWith("/")) - throw new InvalidOperationException($"The value {virtualPath} for parameter {nameof(virtualPath)} must start with ~/ or /"); - - // will occur if it starts with "/" - if (Uri.IsWellFormedUriString(virtualPath, UriKind.Absolute)) - return virtualPath; - - var fullPath = ApplicationVirtualPath.EnsureEndsWith('/') + virtualPath.TrimStart("~/").TrimStart("/"); - - return fullPath; - } - } -} diff --git a/src/Umbraco.Web.Common/AspNetCore/OptionsMonitorAdapter.cs b/src/Umbraco.Web.Common/AspNetCore/OptionsMonitorAdapter.cs new file mode 100644 index 0000000000..d8b50fedf1 --- /dev/null +++ b/src/Umbraco.Web.Common/AspNetCore/OptionsMonitorAdapter.cs @@ -0,0 +1,31 @@ +using System; +using Microsoft.Extensions.Options; + +namespace Umbraco.Web.Common.AspNetCore +{ + /// + /// OptionsMonitor but without the monitoring + /// + public class OptionsMonitorAdapter : IOptionsMonitor where T : class, new() + { + private readonly T _inner; + + public OptionsMonitorAdapter(T inner) + { + _inner = inner ?? throw new ArgumentNullException(nameof(inner)); + } + + public T Get(string name) + { + return _inner; + } + + public IDisposable OnChange(Action listener) + { + throw new NotImplementedException(); + } + + public T CurrentValue => _inner; + + } +} diff --git a/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs index 408baf0b4f..b54558174f 100644 --- a/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs @@ -54,8 +54,10 @@ namespace Umbraco.Web.Common.Builder if (config is null) throw new ArgumentNullException(nameof(config)); var loggingConfig = new LoggingConfiguration(Path.Combine(webHostEnvironment.ContentRootPath, "umbraco", "logs")); - services.AddSingleton(loggingConfig); - services.AddLogger(loggingConfig, config); + + var hostingSettings = config.GetSection(Core.Constants.Configuration.ConfigHosting).Get() ?? new HostingSettings(); + var hostingEnvironment = new AspNetCoreHostingEnvironment(new OptionsMonitorAdapter(hostingSettings), webHostEnvironment); + services.AddLogger(hostingEnvironment, loggingConfig, config); IHttpContextAccessor httpContextAccessor = new HttpContextAccessor(); services.AddSingleton(httpContextAccessor); @@ -65,7 +67,7 @@ namespace Umbraco.Web.Common.Builder services.AddUnique(appCaches); var loggerFactory = LoggerFactory.Create(cfg => cfg.AddSerilog(Log.Logger, false)); - var typeLoader = services.AddTypeLoader(Assembly.GetEntryAssembly(), webHostEnvironment, loggerFactory, appCaches, config); + var typeLoader = services.AddTypeLoader(Assembly.GetEntryAssembly(), webHostEnvironment, hostingEnvironment, loggerFactory, appCaches, config); return new UmbracoBuilder(services, config, typeLoader, loggerFactory); } diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs index 463a087f39..b41b4d515d 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs @@ -16,6 +16,7 @@ using Umbraco.Core.Logging.Serilog; using Umbraco.Core.Runtime; using Umbraco.Web.Common.AspNetCore; using Umbraco.Web.Common.Profiler; +using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; namespace Umbraco.Extensions { @@ -27,11 +28,12 @@ namespace Umbraco.Extensions /// public static IServiceCollection AddLogger( this IServiceCollection services, + IHostingEnvironment hostingEnvironment, ILoggingConfiguration loggingConfiguration, IConfiguration configuration) { // Create a serilog logger - var logger = SerilogLogger.CreateWithDefaultConfiguration(loggingConfiguration, configuration); + var logger = SerilogLogger.CreateWithDefaultConfiguration(hostingEnvironment, loggingConfiguration, configuration); // This is nessasary to pick up all the loggins to MS ILogger. Log.Logger = logger.SerilogLog; @@ -58,6 +60,7 @@ namespace Umbraco.Extensions // Consumed by user code services.AddSingleton(diagnosticContext); + services.AddSingleton(loggingConfiguration); return services; } @@ -104,13 +107,12 @@ namespace Umbraco.Extensions this IServiceCollection services, Assembly entryAssembly, IWebHostEnvironment webHostEnvironment, + IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory, AppCaches appCaches, IConfiguration configuration) { var typeFinder = services.AddTypeFinder(loggerFactory, webHostEnvironment, entryAssembly, configuration); - var hostingSettings = configuration.GetSection(Core.Constants.Configuration.ConfigHosting).Get() ?? new HostingSettings(); - var hostingEnvironment = new AspNetCoreHostingEnvironmentWithoutOptionsMonitor(hostingSettings, webHostEnvironment); var profilingLogger = new ProfilingLogger(loggerFactory.CreateLogger(), GetWebProfiler(configuration)); diff --git a/src/Umbraco.Web/UmbracoApplicationBase.cs b/src/Umbraco.Web/UmbracoApplicationBase.cs index 5d566f842b..9f3aa7dd0d 100644 --- a/src/Umbraco.Web/UmbracoApplicationBase.cs +++ b/src/Umbraco.Web/UmbracoApplicationBase.cs @@ -59,7 +59,7 @@ namespace Umbraco.Web var loggingConfiguration = new LoggingConfiguration( Path.Combine(hostingEnvironment.ApplicationPhysicalPath, "App_Data\\Logs")); var ioHelper = new IOHelper(hostingEnvironment); - var logger = SerilogLogger.CreateWithDefaultConfiguration(loggingConfiguration, new ConfigurationRoot(new List())); + var logger = SerilogLogger.CreateWithDefaultConfiguration(hostingEnvironment, loggingConfiguration, new ConfigurationRoot(new List())); var backOfficeInfo = new AspNetBackOfficeInfo(globalSettings, ioHelper, _loggerFactory.CreateLogger(), Options.Create(webRoutingSettings)); var profiler = GetWebProfiler(hostingEnvironment);