Windows 服务日志记录
Windows Service Logging
我有一个 Windows 服务,我想用 NLog 记录一些信息。我的 NLog 文件如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<time type="AccurateUtc" />
<targets>
<target name="debug-logfile" xsi:type="File" fileName="${specialfolder:folder=ApplicationData}/log/${date:format=yyyy-MM}.log" layout="${longdate} | ${level} | ${message}" />
<target name="trace-logfile" xsi:type="File" fileName="${specialfolder:folder=ApplicationData}/log/trace/${date:format=yyyy-MM-dd}.log" layout="${date:format=yyyy-MM-dd HH\:mm\:ss.fffffff} | ${level} | ${message}" />
<target name="errorfile" xsi:type="File" fileName="${specialfolder:folder=ApplicationData}/log/Error.log" layout="${longdate} | ${level} | ${message}" />
<target name="console" xsi:type="Console" layout="${longdate} | ${level} | ${callsite} | ${message}"/>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="trace-logfile" />
<logger name="*" minlevel="Debug" writeTo="debug-logfile" />
<logger name="*" minlevel="Error" writeTo="errorfile" />
</rules>
</nlog>
现在的问题是,我的服务的 %appdata% 文件夹是:C:\Windows\System32\config\systemprofile\AppData\Roaming
并且 NLog 无法写入此文件夹。有人可以告诉我如何访问此文件夹或将其更改为默认的 ServiceProfile 文件夹吗? (C:\Windows\ServiceProfiles\LocalService\AppData\Roaming\ATLED\log\trace
)
我认为当我为本地服务用户提供服务时可以更改它,但它是与 WIX 一起安装的,所以问题可能就在那里。这里是 WIX 代码示例:
<Component Id="CMP_Service" Feature="Core">
<File Source="$(var.Servie.TargetPath)" KeyPath="yes"/>
<ServiceInstall Id="ServiceInstallELS"
Name="Service"
Description="..."
Start="auto"
Account="[SERVICEACCOUNT]"
ErrorControl="normal"
Type="ownProcess"
Vital="no" />
<ServiceControl Id="ServiceControllELS"
Name="Service"
Start="install"
Stop="both"
Remove="uninstall"
Wait="no" />
</Component>
编辑
使用 installutil.exe 服务将其登录写入:C:\Windows\ServiceProfiles\LocalService\AppData\Roaming\ATLED\log\trace
我是 NLog 的新手。但是当我将 Log4Net 与 windows 服务一起使用时,我遇到了类似的问题。我从代码中手动设置 "appdata" 路径。 NLog 中也必须有一种方法可以从代码中手动设置此路径。
然而,当 windows 服务按照您提到的方式运行时,它将采用您提到的 "appdata" 路径。
为了克服这个问题,我使用了 WMI windows API。请参考以下示例。
这里的想法是从 WMI API 获取用户名并手动构建路径。
private string GetWindowsUserAccountName()
{
string userName = string.Empty;
ManagementScope ms = new ManagementScope("\\.\root\cimv2");
ObjectQuery query = new ObjectQuery("select * from win32_computersystem");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ms, query);
foreach (ManagementBaseObject mo in searcher?.Get())
{
userName = mo["username"]?.ToString();
}
userName = userName?.Substring(userName.IndexOf(@"\",StringComparison.InvariantCulture) + 1);
FCLogger.Logger.LogDebug("[ReturnWindowsUserAccountName]UserName Fetched:" + userName);
return userName;
}
你可以自己构造路径,因为这里只有UserName is unknown字段。
var userName = GetWindowsUserAccountName();
var appDataPath = Path.Combine(LoggerConstants.C, LoggerConstants.USERS, userName, LoggerConstants.APP_DATA, LoggerConstants.ROAMING);
//Ex: "C:\Users\" + userName from WMI +"\AppData"+"\Roaming" ;
我有一个 Windows 服务,我想用 NLog 记录一些信息。我的 NLog 文件如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<time type="AccurateUtc" />
<targets>
<target name="debug-logfile" xsi:type="File" fileName="${specialfolder:folder=ApplicationData}/log/${date:format=yyyy-MM}.log" layout="${longdate} | ${level} | ${message}" />
<target name="trace-logfile" xsi:type="File" fileName="${specialfolder:folder=ApplicationData}/log/trace/${date:format=yyyy-MM-dd}.log" layout="${date:format=yyyy-MM-dd HH\:mm\:ss.fffffff} | ${level} | ${message}" />
<target name="errorfile" xsi:type="File" fileName="${specialfolder:folder=ApplicationData}/log/Error.log" layout="${longdate} | ${level} | ${message}" />
<target name="console" xsi:type="Console" layout="${longdate} | ${level} | ${callsite} | ${message}"/>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="trace-logfile" />
<logger name="*" minlevel="Debug" writeTo="debug-logfile" />
<logger name="*" minlevel="Error" writeTo="errorfile" />
</rules>
</nlog>
现在的问题是,我的服务的 %appdata% 文件夹是:C:\Windows\System32\config\systemprofile\AppData\Roaming
并且 NLog 无法写入此文件夹。有人可以告诉我如何访问此文件夹或将其更改为默认的 ServiceProfile 文件夹吗? (C:\Windows\ServiceProfiles\LocalService\AppData\Roaming\ATLED\log\trace
)
我认为当我为本地服务用户提供服务时可以更改它,但它是与 WIX 一起安装的,所以问题可能就在那里。这里是 WIX 代码示例:
<Component Id="CMP_Service" Feature="Core">
<File Source="$(var.Servie.TargetPath)" KeyPath="yes"/>
<ServiceInstall Id="ServiceInstallELS"
Name="Service"
Description="..."
Start="auto"
Account="[SERVICEACCOUNT]"
ErrorControl="normal"
Type="ownProcess"
Vital="no" />
<ServiceControl Id="ServiceControllELS"
Name="Service"
Start="install"
Stop="both"
Remove="uninstall"
Wait="no" />
</Component>
编辑
使用 installutil.exe 服务将其登录写入:C:\Windows\ServiceProfiles\LocalService\AppData\Roaming\ATLED\log\trace
我是 NLog 的新手。但是当我将 Log4Net 与 windows 服务一起使用时,我遇到了类似的问题。我从代码中手动设置 "appdata" 路径。 NLog 中也必须有一种方法可以从代码中手动设置此路径。
然而,当 windows 服务按照您提到的方式运行时,它将采用您提到的 "appdata" 路径。 为了克服这个问题,我使用了 WMI windows API。请参考以下示例。
这里的想法是从 WMI API 获取用户名并手动构建路径。
private string GetWindowsUserAccountName()
{
string userName = string.Empty;
ManagementScope ms = new ManagementScope("\\.\root\cimv2");
ObjectQuery query = new ObjectQuery("select * from win32_computersystem");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ms, query);
foreach (ManagementBaseObject mo in searcher?.Get())
{
userName = mo["username"]?.ToString();
}
userName = userName?.Substring(userName.IndexOf(@"\",StringComparison.InvariantCulture) + 1);
FCLogger.Logger.LogDebug("[ReturnWindowsUserAccountName]UserName Fetched:" + userName);
return userName;
}
你可以自己构造路径,因为这里只有UserName is unknown字段。
var userName = GetWindowsUserAccountName();
var appDataPath = Path.Combine(LoggerConstants.C, LoggerConstants.USERS, userName, LoggerConstants.APP_DATA, LoggerConstants.ROAMING);
//Ex: "C:\Users\" + userName from WMI +"\AppData"+"\Roaming" ;