Skip to content

Commit 2172c9e

Browse files
authored
Support host-appname and host-basedir and host-environment (#789)
1 parent 1ca1fa5 commit 2172c9e

File tree

6 files changed

+330
-2
lines changed

6 files changed

+330
-2
lines changed

examples/NetCore2/HostingExample/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ private static async Task Main()
1818
var config = new ConfigurationBuilder().Build();
1919

2020
var logger = LogManager.Setup()
21-
.SetupExtensions(ext => ext.RegisterConfigSettings(config))
21+
.SetupExtensions(ext => ext.RegisterHostSettings(config))
2222
.GetCurrentClassLogger();
2323

2424
try
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using Microsoft.Extensions.Configuration;
2+
using Microsoft.Extensions.Hosting;
3+
using NLog.Config;
4+
using NLog.Extensions.Logging;
5+
6+
namespace NLog.Extensions.Hosting
7+
{
8+
/// <summary>
9+
/// Extension methods to setup NLog extensions, so they are known when loading NLog LoggingConfiguration
10+
/// </summary>
11+
public static class SetupExtensionsBuilderExtensions
12+
{
13+
/// <summary>
14+
/// Setup the MEL-configuration for the ${configsetting} layoutrenderer
15+
/// </summary>
16+
public static ISetupExtensionsBuilder RegisterHostSettings(this ISetupExtensionsBuilder setupBuilder, IConfiguration? configuration)
17+
{
18+
setupBuilder.RegisterConfigSettings(configuration);
19+
return setupBuilder.RegisterLayoutRenderer<HostAppNameLayoutRenderer>("host-appname")
20+
.RegisterLayoutRenderer<HostBaseDirLayoutRenderer>("host-basedir")
21+
.RegisterLayoutRenderer<HostEnvironmentLayoutRenderer>("host-environment");
22+
}
23+
}
24+
}

src/NLog.Extensions.Hosting/Extensions/ConfigureExtensions.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public static IHostBuilder UseNLog(this IHostBuilder builder, NLogProviderOption
6060
builder.ConfigureServices((builderContext, services) => AddNLogLoggerProvider(services, builderContext.Configuration, builderContext.HostingEnvironment, options, (serviceProvider, config, hostEnv, opt) =>
6161
#endif
6262
{
63+
RegisterHostNLogExtensions(LogManager.LogFactory, serviceProvider, hostEnv);
6364
config = serviceProvider.SetupNLogConfigSettings(config, LogManager.LogFactory);
6465

6566
// Delay initialization of targets until we have loaded config-settings
@@ -107,6 +108,7 @@ public static IHostApplicationBuilder UseNLog(this IHostApplicationBuilder build
107108
Guard.ThrowIfNull(builder);
108109
builder.Services.TryAddNLogLoggingProvider((svc, addlogging) => svc.AddLogging(addlogging), builder.Configuration, options, (serviceProvider, config, opt) =>
109110
{
111+
RegisterHostNLogExtensions(LogManager.LogFactory, serviceProvider, builder.Environment);
110112
config = serviceProvider.SetupNLogConfigSettings(config, LogManager.LogFactory);
111113

112114
// Delay initialization of targets until we have loaded config-settings
@@ -125,11 +127,13 @@ private static void AddNLogLoggerProvider(IServiceCollection services, IConfigur
125127

126128
private static NLogLoggerProvider CreateNLogLoggerProvider(IServiceProvider serviceProvider, IConfiguration? hostConfiguration, IHostEnvironment? hostEnvironment, NLogProviderOptions options)
127129
{
128-
return serviceProvider.CreateNLogLoggerProvider(hostConfiguration, options, LogManager.LogFactory);
130+
return CreateNLogLoggerProvider(serviceProvider, hostConfiguration, hostEnvironment, options, LogManager.LogFactory);
129131
}
130132

131133
private static NLogLoggerProvider CreateNLogLoggerProvider(IServiceProvider serviceProvider, IConfiguration? hostConfiguration, IHostEnvironment? hostEnvironment, NLogProviderOptions options, LogFactory logFactory)
132134
{
135+
RegisterHostNLogExtensions(logFactory, serviceProvider, hostEnvironment);
136+
133137
NLogLoggerProvider provider = serviceProvider.CreateNLogLoggerProvider(hostConfiguration, options, logFactory);
134138

135139
string nlogConfigFile = string.Empty;
@@ -158,6 +162,20 @@ private static NLogLoggerProvider CreateNLogLoggerProvider(IServiceProvider serv
158162
return provider;
159163
}
160164

165+
private static void RegisterHostNLogExtensions(LogFactory logFactory, IServiceProvider serviceProvider, IHostEnvironment? hostingEnvironment)
166+
{
167+
(logFactory ?? LogManager.LogFactory).Setup().SetupExtensions(ext =>
168+
{
169+
if (serviceProvider != null)
170+
ext.RegisterServiceProvider(serviceProvider);
171+
if (hostingEnvironment != null)
172+
ext.RegisterSingletonService(hostingEnvironment);
173+
ext.RegisterLayoutRenderer<HostEnvironmentLayoutRenderer>("host-environment");
174+
ext.RegisterLayoutRenderer<HostBaseDirLayoutRenderer>("host-basedir");
175+
ext.RegisterLayoutRenderer<HostAppNameLayoutRenderer>("host-appname");
176+
});
177+
}
178+
161179
private static string ResolveEnvironmentNLogConfigFile(string? basePath, string? environmentName)
162180
{
163181
if (!string.IsNullOrWhiteSpace(basePath))
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System;
2+
using System.Text;
3+
using Microsoft.Extensions.Hosting;
4+
using NLog.Config;
5+
using NLog.LayoutRenderers;
6+
7+
#if NETSTANDARD2_0
8+
using IHostEnvironment = Microsoft.Extensions.Hosting.IHostingEnvironment;
9+
#endif
10+
11+
namespace NLog.Extensions.Hosting
12+
{
13+
/// <summary>
14+
/// Rendering development environment. <see cref="IHostingEnvironment.ApplicationName" />
15+
/// </summary>
16+
/// <remarks>
17+
/// <code>${host-environment}</code>
18+
/// </remarks>
19+
/// <seealso href="https://github.com/NLog/NLog/wiki/Host-AppName-layout-renderer">Documentation on NLog Wiki</seealso>
20+
[LayoutRenderer("host-appname")]
21+
[ThreadAgnostic]
22+
public class HostAppNameLayoutRenderer : LayoutRenderer
23+
{
24+
/// <summary>
25+
/// Provides access to the current IHostEnvironment
26+
/// </summary>
27+
/// <returns>IHostEnvironment or <c>null</c></returns>
28+
internal IHostEnvironment? HostEnvironment => _hostEnvironment ?? (_hostEnvironment = ResolveHostEnvironment());
29+
private IHostEnvironment? _hostEnvironment;
30+
private string? _hostAppName;
31+
private static string? _currentProcessName;
32+
33+
/// <inheritdoc />
34+
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
35+
{
36+
var environmentName = _hostAppName ?? (_hostAppName = ResolveHostAppName());
37+
builder.Append(environmentName ?? ResolveProcessName());
38+
}
39+
40+
private IHostEnvironment? ResolveHostEnvironment()
41+
{
42+
return ResolveService<IHostEnvironment>();
43+
}
44+
45+
private string? ResolveHostAppName()
46+
{
47+
try
48+
{
49+
var appName = HostEnvironment?.ApplicationName;
50+
return string.IsNullOrWhiteSpace(appName) ? null : appName;
51+
}
52+
catch
53+
{
54+
return null;
55+
}
56+
}
57+
58+
private static string ResolveProcessName()
59+
{
60+
if (_currentProcessName is null)
61+
_currentProcessName = System.Diagnostics.Process.GetCurrentProcess()?.ProcessName ?? "UnknownHostName";
62+
return _currentProcessName;
63+
}
64+
65+
/// <inheritdoc/>
66+
protected override void CloseLayoutRenderer()
67+
{
68+
_hostEnvironment = null;
69+
_hostAppName = null;
70+
base.CloseLayoutRenderer();
71+
}
72+
}
73+
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
using System;
2+
using System.IO;
3+
using System.Text;
4+
using NLog;
5+
using NLog.Config;
6+
using NLog.LayoutRenderers;
7+
8+
#if NETSTANDARD2_0
9+
using IHostEnvironment = Microsoft.Extensions.Hosting.IHostingEnvironment;
10+
#endif
11+
12+
namespace Microsoft.Extensions.Hosting
13+
{
14+
/// <summary>
15+
/// Rendering Application Host <see cref="IHostEnvironment.ContentRootPath" />
16+
/// </summary>
17+
/// <remarks>
18+
/// <code>${host-basedir}</code>
19+
/// </remarks>
20+
/// <seealso href="https://github.com/NLog/NLog/wiki/Host-BaseDir-layout-renderer">Documentation on NLog Wiki</seealso>
21+
[LayoutRenderer("host-basedir")]
22+
[ThreadAgnostic]
23+
public class HostBaseDirLayoutRenderer : LayoutRenderer
24+
{
25+
/// <summary>
26+
/// Provides access to the current IHostEnvironment
27+
/// </summary>
28+
/// <returns>IHostEnvironment or <c>null</c></returns>
29+
internal IHostEnvironment? HostEnvironment => _hostEnvironment ?? (_hostEnvironment = ResolveHostEnvironment());
30+
private IHostEnvironment? _hostEnvironment;
31+
private string? _contentRootPath;
32+
private static string? _currentAppPath;
33+
34+
/// <inheritdoc />
35+
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
36+
{
37+
var contentRootPath = _contentRootPath ?? (_contentRootPath = ResolveContentRootPath());
38+
builder.Append(contentRootPath ?? ResolveCurrentAppDirectory());
39+
}
40+
41+
private IHostEnvironment? ResolveHostEnvironment()
42+
{
43+
return ResolveService<IHostEnvironment>();
44+
}
45+
46+
private string? ResolveContentRootPath()
47+
{
48+
string? contentRootPath = null;
49+
try
50+
{
51+
contentRootPath = HostEnvironment?.ContentRootPath;
52+
}
53+
catch
54+
{
55+
contentRootPath = null;
56+
}
57+
if (string.IsNullOrEmpty(contentRootPath))
58+
{
59+
contentRootPath = GetDotnetHostEnvironment("ASPNETCORE_CONTENTROOT") ?? GetDotnetHostEnvironment("DOTNET_CONTENTROOT");
60+
}
61+
return TrimEndDirectorySeparator(contentRootPath);
62+
}
63+
64+
private static string? TrimEndDirectorySeparator(string? directoryPath)
65+
{
66+
return (directoryPath is null || string.IsNullOrEmpty(directoryPath)) ? null : directoryPath.TrimEnd(Path.DirectorySeparatorChar).TrimEnd(Path.AltDirectorySeparatorChar);
67+
}
68+
69+
private static string? ResolveCurrentAppDirectory()
70+
{
71+
if (!string.IsNullOrEmpty(_currentAppPath))
72+
return _currentAppPath;
73+
74+
var currentAppPath = AppContext.BaseDirectory;
75+
76+
try
77+
{
78+
var currentBasePath = Environment.CurrentDirectory;
79+
var normalizeCurDir = Path.GetFullPath(currentBasePath).TrimEnd(Path.DirectorySeparatorChar).TrimEnd(Path.AltDirectorySeparatorChar).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
80+
var normalizeAppDir = Path.GetFullPath(currentAppPath).TrimEnd(Path.DirectorySeparatorChar).TrimEnd(Path.AltDirectorySeparatorChar).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
81+
if (string.IsNullOrEmpty(normalizeCurDir) || !normalizeCurDir.StartsWith(normalizeAppDir, StringComparison.OrdinalIgnoreCase))
82+
{
83+
currentBasePath = currentAppPath; // Avoid using Windows-System32 as current directory
84+
}
85+
return _currentAppPath = TrimEndDirectorySeparator(currentBasePath);
86+
}
87+
catch
88+
{
89+
// Not supported or access denied
90+
return _currentAppPath = TrimEndDirectorySeparator(currentAppPath);
91+
}
92+
}
93+
94+
/// <inheritdoc/>
95+
protected override void InitializeLayoutRenderer()
96+
{
97+
ResolveCurrentAppDirectory(); // Capture current directory at startup, before it changes
98+
base.InitializeLayoutRenderer();
99+
}
100+
101+
/// <inheritdoc/>
102+
protected override void CloseLayoutRenderer()
103+
{
104+
_hostEnvironment = null;
105+
_contentRootPath = null;
106+
base.CloseLayoutRenderer();
107+
}
108+
109+
private static string? GetDotnetHostEnvironment(string variableName)
110+
{
111+
try
112+
{
113+
var environment = Environment.GetEnvironmentVariable(variableName);
114+
if (string.IsNullOrWhiteSpace(environment))
115+
return null;
116+
117+
return environment.Trim();
118+
}
119+
catch (Exception ex)
120+
{
121+
NLog.Common.InternalLogger.Error(ex, "Failed to lookup environment variable {0}", variableName);
122+
return null;
123+
}
124+
}
125+
}
126+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
using System;
2+
using System.Text;
3+
using Microsoft.Extensions.Hosting;
4+
using NLog.Config;
5+
using NLog.LayoutRenderers;
6+
7+
#if NETSTANDARD2_0
8+
using IHostEnvironment = Microsoft.Extensions.Hosting.IHostingEnvironment;
9+
#endif
10+
11+
namespace NLog.Extensions.Hosting
12+
{
13+
/// <summary>
14+
/// Rendering development environment. <see cref="IHostingEnvironment.EnvironmentName" />
15+
/// </summary>
16+
/// <remarks>
17+
/// <code>${host-environment}</code>
18+
/// </remarks>
19+
/// <seealso href="https://github.com/NLog/NLog/wiki/Host-Environment-layout-renderer">Documentation on NLog Wiki</seealso>
20+
[LayoutRenderer("host-environment")]
21+
[ThreadAgnostic]
22+
public class HostEnvironmentLayoutRenderer : LayoutRenderer
23+
{
24+
/// <summary>
25+
/// Provides access to the current IHostEnvironment
26+
/// </summary>
27+
/// <returns>IHostEnvironment or <c>null</c></returns>
28+
internal IHostEnvironment? HostEnvironment => _hostEnvironment ?? (_hostEnvironment = ResolveHostEnvironment());
29+
private IHostEnvironment? _hostEnvironment;
30+
private string? _environmentName;
31+
32+
/// <inheritdoc />
33+
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
34+
{
35+
var environmentName = _environmentName ?? (_environmentName = ResolveEnvironmentName());
36+
builder.Append(environmentName ?? "Production");
37+
}
38+
39+
private IHostEnvironment? ResolveHostEnvironment()
40+
{
41+
return ResolveService<IHostEnvironment>();
42+
}
43+
44+
private string? ResolveEnvironmentName()
45+
{
46+
string? environmentName = null;
47+
try
48+
{
49+
environmentName = HostEnvironment?.EnvironmentName;
50+
}
51+
catch
52+
{
53+
environmentName = null;
54+
}
55+
if (string.IsNullOrEmpty(environmentName))
56+
{
57+
environmentName = GetDotnetHostEnvironment("ASPNETCORE_ENVIRONMENT") ?? GetDotnetHostEnvironment("DOTNET_ENVIRONMENT");
58+
}
59+
return string.IsNullOrEmpty(environmentName) ? null : environmentName;
60+
}
61+
62+
/// <inheritdoc/>
63+
protected override void CloseLayoutRenderer()
64+
{
65+
_hostEnvironment = null;
66+
_environmentName = null;
67+
base.CloseLayoutRenderer();
68+
}
69+
70+
private static string? GetDotnetHostEnvironment(string variableName)
71+
{
72+
try
73+
{
74+
var environment = Environment.GetEnvironmentVariable(variableName);
75+
if (string.IsNullOrWhiteSpace(environment))
76+
return null;
77+
78+
return environment.Trim();
79+
}
80+
catch (Exception ex)
81+
{
82+
NLog.Common.InternalLogger.Error(ex, "Failed to lookup environment variable {0}", variableName);
83+
return null;
84+
}
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)