如何在 ASP.NET web api 2 中使用 log4net 布局模式有条件地捕获用户名?
How to conditionally capture user name with log4net layout pattern in ASP.NET web api 2?
我有一个 Web api 2 应用程序,目前已配置 Windows 身份验证。该应用程序有一个名为 FlowManager 运行 使用 ApplicationPoolIdentity 的专用应用程序池。
这里是来自 web.config 文件的 log4net 配置,我在 PatternLayout 中使用 %username 来记录用户名。
<log4net>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="C:\Logs\FlowManager\FlowManager.log" />
<param name="AppendToFile" value="true" />
<datePattern value="yyyyMMdd" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="3" />
<maximumFileSize value="2MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d{MM-dd-yyyy HH:mm:ss:fff} %-5level [%property{log4net:HostName}, %username] %m%n" />
</layout>
</appender>
<root>
<level value="TRACE" />
<appender-ref ref="LogFileAppender" />
</root>
</log4net>
所以在我要登录的应用程序代码中,我正在使用
logger.Debug("Request entered"); //in a http module
logger.Debug("Test log entry"); //in the api controller
正在按预期生成日志。
06-08-2016 12:06:07:287 DEBUG [1178959001DLP, IIS
APPPOOL\FlowManager] Request entered
06-08-2016 12:06:09:257 DEBUG
[1178959001DLP, IIS APPPOOL\FlowManager] Test log entry
现在我被要求记录经过身份验证的用户名。我发现了这个很好的问题 Capture username with log4net 并按照说明进行操作并能够实现它。这是新的 log4net 配置的样子。为简单起见,我只展示 log4net 的 PatternLayout 部分。
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d{MM-dd-yyyy HH:mm:ss:fff} %-5level [%property{log4net:HostName}, %HTTPUser] %m%n" />
<converter>
<name value="HTTPUser" />
<type value="LoggerExtentions.ContextUserPatternConverter" />
</converter>
</layout>
如您所见,我创建了一个自定义模式转换器来捕获用户名。
using System.Threading;
using System.Web;
using log4net.Core;
using log4net.Layout.Pattern;
namespace LoggerExtentions
{
/// <summary>
/// Log4net custom pattern converter to log context user instaed of app pool user
/// </summary>
public class ContextUserPatternConverter : PatternLayoutConverter
{
protected override void Convert(System.IO.TextWriter writer, LoggingEvent loggingEvent)
{
var userName = string.Empty;
var context = HttpContext.Current;
if (context != null && context.User != null && context.User.Identity.IsAuthenticated)
{
userName = context.User.Identity.Name;
}
else
{
var threadPincipal = Thread.CurrentPrincipal;
if (threadPincipal != null && threadPincipal.Identity.IsAuthenticated)
{
userName = threadPincipal.Identity.Name;
}
}
writer.Write(userName);
}
}
}
这给了我以下日志消息
06-08-2016 13:06:09:123 DEBUG [1178959001DLP, ] Request entered
06-08-2016 13:06:09:257 DEBUG [1178959001DLP, DOMAIN\johnkl]
Test log entry
如果您注意到从 http 模块创建的日志条目没有用户名,我知道这是因为尚未为经过身份验证的用户设置上下文。在这种情况下,我被要求记录 log4net 捕获的默认用户名。我的问题是我怎样才能实现它?每当我没有 HttpContext 用户时,如何提供 log4net 捕获的默认用户名?有没有办法在 log4net Pattern 布局中提供条件语句?或者任何其他替代选项?
看来我找到了另一种捕获它的方法。由于 log4net %username 默认为应用程序池身份,我修改了自定义模式转换器以回退到应用程序池身份。
更新: 发现 loggingEvent 参数具有用户名 属性。我修改了我的代码以使用它而不是直接调用 System.Security.Principal.WindowsIdentity.GetCurrent().Name 。 LoggingEvent.UserName 内部调用相同,但我决定使用 loggingEvent.UserName 以防将来 log4net 实现修改其行为。
public class ContextUserPatternConverter : PatternLayoutConverter
{
protected override void Convert(System.IO.TextWriter writer, LoggingEvent loggingEvent)
{
var userName = string.Empty;
var context = HttpContext.Current;
if (context != null && context.User != null && context.User.Identity.IsAuthenticated)
{
userName = context.User.Identity.Name;
}
else
{
var threadPincipal = Thread.CurrentPrincipal;
if (threadPincipal != null && threadPincipal.Identity.IsAuthenticated)
{
userName = threadPincipal.Identity.Name;
}
}
if (string.IsNullOrEmpty(userName))
{
userName = loggingEvent.UserName;
//get app pool identity
//userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
}
writer.Write(userName);
}
}
我有一个 Web api 2 应用程序,目前已配置 Windows 身份验证。该应用程序有一个名为 FlowManager 运行 使用 ApplicationPoolIdentity 的专用应用程序池。
这里是来自 web.config 文件的 log4net 配置,我在 PatternLayout 中使用 %username 来记录用户名。
<log4net>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="C:\Logs\FlowManager\FlowManager.log" />
<param name="AppendToFile" value="true" />
<datePattern value="yyyyMMdd" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="3" />
<maximumFileSize value="2MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d{MM-dd-yyyy HH:mm:ss:fff} %-5level [%property{log4net:HostName}, %username] %m%n" />
</layout>
</appender>
<root>
<level value="TRACE" />
<appender-ref ref="LogFileAppender" />
</root>
</log4net>
所以在我要登录的应用程序代码中,我正在使用
logger.Debug("Request entered"); //in a http module
logger.Debug("Test log entry"); //in the api controller
正在按预期生成日志。
06-08-2016 12:06:07:287 DEBUG [1178959001DLP, IIS APPPOOL\FlowManager] Request entered
06-08-2016 12:06:09:257 DEBUG [1178959001DLP, IIS APPPOOL\FlowManager] Test log entry
现在我被要求记录经过身份验证的用户名。我发现了这个很好的问题 Capture username with log4net 并按照说明进行操作并能够实现它。这是新的 log4net 配置的样子。为简单起见,我只展示 log4net 的 PatternLayout 部分。
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d{MM-dd-yyyy HH:mm:ss:fff} %-5level [%property{log4net:HostName}, %HTTPUser] %m%n" />
<converter>
<name value="HTTPUser" />
<type value="LoggerExtentions.ContextUserPatternConverter" />
</converter>
</layout>
如您所见,我创建了一个自定义模式转换器来捕获用户名。
using System.Threading;
using System.Web;
using log4net.Core;
using log4net.Layout.Pattern;
namespace LoggerExtentions
{
/// <summary>
/// Log4net custom pattern converter to log context user instaed of app pool user
/// </summary>
public class ContextUserPatternConverter : PatternLayoutConverter
{
protected override void Convert(System.IO.TextWriter writer, LoggingEvent loggingEvent)
{
var userName = string.Empty;
var context = HttpContext.Current;
if (context != null && context.User != null && context.User.Identity.IsAuthenticated)
{
userName = context.User.Identity.Name;
}
else
{
var threadPincipal = Thread.CurrentPrincipal;
if (threadPincipal != null && threadPincipal.Identity.IsAuthenticated)
{
userName = threadPincipal.Identity.Name;
}
}
writer.Write(userName);
}
}
}
这给了我以下日志消息
06-08-2016 13:06:09:123 DEBUG [1178959001DLP, ] Request entered
06-08-2016 13:06:09:257 DEBUG [1178959001DLP, DOMAIN\johnkl] Test log entry
如果您注意到从 http 模块创建的日志条目没有用户名,我知道这是因为尚未为经过身份验证的用户设置上下文。在这种情况下,我被要求记录 log4net 捕获的默认用户名。我的问题是我怎样才能实现它?每当我没有 HttpContext 用户时,如何提供 log4net 捕获的默认用户名?有没有办法在 log4net Pattern 布局中提供条件语句?或者任何其他替代选项?
看来我找到了另一种捕获它的方法。由于 log4net %username 默认为应用程序池身份,我修改了自定义模式转换器以回退到应用程序池身份。
更新: 发现 loggingEvent 参数具有用户名 属性。我修改了我的代码以使用它而不是直接调用 System.Security.Principal.WindowsIdentity.GetCurrent().Name 。 LoggingEvent.UserName 内部调用相同,但我决定使用 loggingEvent.UserName 以防将来 log4net 实现修改其行为。
public class ContextUserPatternConverter : PatternLayoutConverter
{
protected override void Convert(System.IO.TextWriter writer, LoggingEvent loggingEvent)
{
var userName = string.Empty;
var context = HttpContext.Current;
if (context != null && context.User != null && context.User.Identity.IsAuthenticated)
{
userName = context.User.Identity.Name;
}
else
{
var threadPincipal = Thread.CurrentPrincipal;
if (threadPincipal != null && threadPincipal.Identity.IsAuthenticated)
{
userName = threadPincipal.Identity.Name;
}
}
if (string.IsNullOrEmpty(userName))
{
userName = loggingEvent.UserName;
//get app pool identity
//userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
}
writer.Write(userName);
}
}