using AppData location in NLog - nlog

My NLog targets is like this:
<targets>
<target xsi:type="Console" name="console"
layout="${longdate}|${level}|${message}" />
<target xsi:type="File" name="ErrorLog" fileName="${basedir}/error.txt"
layout="${longdate}
Trace: ${stacktrace}
${message}" />
<target xsi:type="File" name="AccessLog" fileName="${basedir}/access.txt"
layout="${shortdate} | ${message}" />
</targets>
But this causes problems if the user isn't an admin on their machine, because they will not have write access to "Program Files". How can I get something like %AppData% to NLog instead of BaseDir?

You're looking for the NLog special folders.
Example:
...fileName="${specialfolder:folder=ApplicationData}/Program/file.txt"...

Oren's answer should be the right answer. However, for the life of me I couldn't get it to work with my .NET 4.0 website using nLog 2.0.0.0. I ended up using simply
fileName="${basedir}app_data\logs\${shortdate}.log"

${specialfolder:ApplicationData} also works

The previous answers helped solve the problem I was having, but a couple of years later and the solution is now somewhat different under v4.3. The directory and filename are combined with the path.
#theGecko's link is still current for the syntax, but the page is deficient of an example:
https://github.com/nlog/NLog/wiki/Special-Folder-Layout-Renderer
The following example would write the file myLog.log to the current users application data roaming directory C:\USers\current.user\AppData\Roaming\My\Path\Somewhere:
fileName="${specialfolder:dir=My/Path/Somewhere/:file=myFile.log:folder=ApplicationData}"

For logging to the project directory:
While the previous answers work for the original question, searching for how to log to the project APP_DATA directory leads to this question. And while bkaid's answer works for ASP.NET and for using the APP_DATA folder specifically, for .NET Core and .NET 5 the solution is a bit different, because that motif has been abandoned in favor of defining a wwwroot folder for only those things which should be served, and the remainder being private. The answer for .NET Core/5, then, is to write to the solution root directory:
First, ensure the NLog.Web.AspNetCore assembly is added to nlog.config:
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
Then use one of the layout renderers provided by that extension, in this case ${aspnet-appbasepath} which references the solution root directory:
<targets>
<target name="file"
type="File"
xsi:type="File"
fileName="${aspnet-appbasepath}/log/${shortdate}.log"
layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}"/>
</targets>
This will write the file to <solution folder>/log/2021-07-01.log, which will never be served by the public-facing website. Other layout renderers provided by this assembly are listed on the NLog website.

Related

${currentdir} target is not generating file anymore

I have recently upgraded my asp.net core project to .net core 2.2 and at same time updated NLog.Web.AspNetCore.
After I did this (maybe coincidence?) I noticed that log files are not being generated.
In my config this is my target:
<target xsi:type="File" name="allfile" fileName="${currentdir}/Logs/nlog-all-${shortdate}.log"
layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" />
After some debugging I realised that if I specified the path explicitly then it would generate log file:
<target xsi:type="File" name="allfile" fileName="E:\Project\Logs\nlog-all-${shortdate}.log"
layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" />
I have throwExceptions="true" set in config but when a file is not generated no exception is thrown, it just silently doesn't create the file.
To further debug this I created a console project and added nuget NLog.Web.AspNetCore and copied my config. Now in the console project it works fine and is creating log files in the debug output directory.
Is there any way to debug why the log file isn't being generated with this target in my main project?
Instead of using ${currentdir} then consider using ${aspnet-appbasepath} (Or ${basedir} if not in-process-hosting)
NLog InternalLogger usually gives very good hints when something is not working as expected.
Please avoid using throwExceptions="true" as it is for unit-testing, and not for production environments.

Adding additional content folders to Azure package

Im using Azure SDK 2.5
I have a web role in a cloud service project. I would like to add a folder in some fashion such that it is deployed in the parent directory of the approot. I havent found a way to do this which kind of makes me wonder what use is the ability to define virtual directories in csdef.
So I thought I would try adding folders via the Contents/Content xml config in the csdef. I am either fundamentally misunderstanding what this bit of config does or its hopelessly broken.
Assuming this folder structure
/
/CloudService
/SomeOtherContent
If I define the following:
<Contents>
<Content destination="frontend">
<SourceDirectory path="..\SomeOtherContent" />
</Content>
</Contents>
and build I get:
error CloudServices089: Cannot find the source directory
'C:\src\template\src\Template.CloudService\bin\Debug\..\SomeOtherContent'
Ok so its starting the bin\Debug, so I'll just make it ..\..\..\SomeOtherContent
error CloudServices089: Cannot find the source directory
'C:\src\template\src\Template.CloudService\..\..\..\SomeOtherContent'
Yes thats right, the folder at which my relative path is resolved has changed!!! Its no longer bin\Debug. Wtf!? How can this be made to work? It works if i enter a full drive qualified absolute path.
So I solved this by having MSBuild resolve the path and push it in to an environment variable which I called FrontendDir.
<Contents>
<Content destination="frontend">
<SourceDirectory path="%FrontendDir%" />
</Content>
</Contents>
and in the ccproj I added:
<UsingTask
TaskName="SetEnvironmentVariableTask"
TaskFactory="CodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v$(MSBuildToolsVersion).dll">
<ParameterGroup>
<Name ParameterType="System.String" Required="true" />
<Value ParameterType="System.String" Required="true" />
</ParameterGroup>
<Task>
<Using Namespace="System" />
<Code Type="Fragment" Language="cs">
<![CDATA[
Environment.SetEnvironmentVariable(Name, Value);
]]>
</Code>
</Task>
</UsingTask>
<Target Name="BeforeBuild" Condition=" '$(FrontendDir)' == '' ">
<Message Text="Setting Project Dir" Importance="high" />
<SetEnvironmentVariableTask Name="FrontendDir" Value="$(ProjectDir)\..\Template.FrontEnd\dist" />
</Target>
Its preferable to put the entire path into the env var here as you can then override it easily in your different build scenarios by overriding the value (eg. /p:FrontendDir="c:\foo")
So that works and works fairly well. I still say the behaviour I was seeing before with the relative path resolution changing folders is... broken. It just doesn't work with relative paths in any usable way.
You are seeing the same error but from different msbuild targets.
The first error (when using ..\..\) is thrown at PreValidateServiceModel which passes in the Source location and checks the path
ServiceDefinitionFile="#(SourceServiceDefinition)"
ServiceConfigurationFile="#(SourceServiceConfiguration)"
C:\src\Azure\ServiceDefinition.csdef : error CloudServices089: Cannot
find the source directory 'C:\src\Azure\..\..\Installers\' in role
WebHost. [C:\src\Azure\Azure.ccproj]
Done building target "PreValidateServiceModel" in project "Azure.ccproj" -- FAILED.
The second error is thrown at ValidateServiceFiles which passes in the Target location
ServiceDefinitionFile="#(TargetServiceDefinition)"
ServiceConfigurationFile="#(TargetServiceConfiguration)">
C:\src\Azure\bin\Release\ServiceDefinition.csdef : error CloudServices089: Cannot
find the source directory
'C:\src\Azure\bin\Release\Installers\'
in role WebHost. [C:\src\Azure\Azure.ccproj]
Done building target "ValidateServiceFiles" in project "Azure.ccproj" -- FAILED.
If you reflect on C:\Program Files\Microsoft SDKs\Azure.NET SDK\v2.9\bin\ServiceDescription.dll you can see the ProcessRoleContents method doing the validation but using the SourceFile to resolve the location.
One option is to make sure the target folder exists (even if empty) before the build starts.
It would be better if the PreValidation resolved the path and when the Target is saved, it had the full path.
I ended up editing the ccproj, and adding this
<Target Name="BeforeAddRoleContent">
<ItemGroup>
<AzureRoleContent Include="Installers\">
<RoleName>Azure</RoleName>
<Destination></Destination>
</AzureRoleContent>
</ItemGroup>
</Target>
Referencing runtime content from .ccproj (Azure SDK 2.9)

How to allow web.config files as normal files and allow download IIS inside a virtual directory

I am working on a Unity 3D game which upon build for Windows generates game.exe and game_Data file and folder. The Game_Data folder contains a directory called **Game_Data\Mono\etc\mono\2.0**.
The directory files are shown in image.
The Browsers directory contains one file called Compact.browser.
The Current Scenario.
1. These game files are hosted on a server where IIS 7.5 is running.
The game resource files are served in virtual directory of the game website.
I've made few changes to the website's root web.config file so that all filetypes are allowed to download only in the game resources folder on server.
Yes, all file types including .html, .aspx, .xml, .config, .browser, .map etc are all downloading as normal files.
The problem
As you see the directory structure there is a web.config file inside the game resources folder. The file has nothing to do with website configuration but with the game (which is on client side after downloading).
As the files are served as individual files each file is downloaded separately. So when the client tries to download all files including the contents of the above folder.
Due to this web.config file, contents of the directory is not downloading. If I delete this web.config file all of the .aspx, .config, .map files are downloading. Also there are some other folders where many different files are downloading properly.
But this web.config file is also required for the game, and it is not allowing it be downloaded with other files too in the directory shown above.
I've tried to look into the solution. Found some hints to avoid inheritance in nested config files. But actually I want to completely treat this file as a normal file, not as a site configuration file.
I think you got my problem. Please let me know your suggestions. You can say adding Mime types. But actuall all of the file types are downloading including .config files. Except the file named web.config.
I'm having the same problem, and I think I found the solution: there is a way to tell IIS not to interpret web.config files.
To do this, modify the C:\Windows\System32\inetsrv\config\applicationHost.config file (I haven't found a way to do this in the IIS user interface), by specifying allowSubDirConfig="false" for the relevant <virtualDirectory> element:
<configuration>
<system.applicationHost>
<!-- ... -->
<sites>
<site name="Default Web Site" id="1">
<application path="/">
<virtualDirectory path="/" physicalPath="%SystemDrive%\inetpub\wwwroot" />
<virtualDirectory path="/Staging" physicalPath="C:\inetpub\wwwroot\Staging" allowSubDirConfig="false" />
</application>
<bindings> <!-- ... --> </bindings>
</site>
See http://www.iis.net/configreference/system.applicationhost/sites/site/application/virtualdirectory for the details.
The problem is, it still won't let you download the web.config file, it keeps returning a 404 - Not found, even after removing all handlers.
Edit - found the solution. The short answer is that in your web.config, you should clear the fileExtensions and hiddenSegments lists:
<system.webServer>
<security>
<requestFiltering>
<hiddenSegments>
<clear />
</hiddenSegments>
<fileExtensions>
<clear />
</fileExtensions>
</requestFiltering>
</security>
I've written a blog article about it that explains all the details.

Creating folder for log files for NLog with InnoSetup

I'm having an issue where I need my users to be able to run my application without administrator rights, but at the same time, I need NLog to be able to create it's log files, which it needs administrator rights to create them in the same folder the application is installed in.
I'm trying to create a directory under the application directory, named Logs, and give everyone-modify permissions with inno setup. I'm going to set up my NLog config to write to this new Logs folder instead of the application directory, so even when the application is run by non-administrators, NLog has sufficient privileges to create the logs.
My question is, is this the proper way to do this? I'm not very experienced with NLog or InnoSetup, so I'm not sure if there is something I'm missing, or if this will possibly create security problems?
I have my NLog config section set up like so
NLog
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="el" xsi:type="EventLog" log="ASI" layout="${message} ${exception:innerFormat=tostring:maxInnerExceptionLevel=10:format=tostring}" />
<target name="fl" xsi:type="File" fileName="Logs\iDocClientLog.log" layout="${date}: ${message} ${exception:innerFormat=tostring:maxInnerExceptionLevel=10:format=tostring}" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="el,fl" />
</rules>
</nlog>
And my InnoSetup installer script Dirs section is like this
InnoSetup
[Dirs]
Name: "{app}\Logs"; Permissions: everyone-modify

NLog can't write to the log file in the install directory

I have an application that logs, and I don't get any file-based logging when I deploy it to the default directory. It seems clear that the reason is that writing to "c:\program files (x86)\blah" requires elevated privelege levels which my app doesn't have. So I end up telling users "install to "c:\blah" and it will work fine, which it does. But that seems rubbish. Any alternative?
You could configure NLog to log to a different folder. NLog has SpecialFolderLayoutRenderer that allows you to use .NET's special folders. You should be able to specify the log file name using the SpecialFolderLayoutRenderer. Maybe something like this (I have not tried this):
<target name="file" xsi:type="File" layout="${longdate} | ${logger} | "${level} | ${message}" fileName="${specialfolder:folder=MyDocuments:dir=LogFiles:file=${shortdate}.log}" />
That should (if it works) create log files in a LogFiles subfolder in the user's Documents folder, with the actual log file names corresponding to the date. I don't know, but I would guess that NLog will create the LogFiles folder the first time anything is logged.
Good luck!
For me it worked like this:
fileName="${specialfolder:folder=ApplicationData}/newDMS ClientApplication/Logs/${shortdate}.log"

Resources