NLog fails to open file on Windows with Mono - mono

I have a small set of ServiceStack REST services that is using NLog 2.1 (from NuGet) for logging.
My test server is running:
Windows 7
IIS 7.5
.NET 4.5
NLog config:
<nlog throwExceptions="true" internalLogToConsole="true" internalLogLevel="Debug" xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="c" xsi:type="Console" />
<target name="f1" xsi:type="File" fileName="C:\logs\test.log" />
</targets>
<rules>
<logger name="*" writeTo="c,f1" />
</rules>
</nlog>
My NLog config is exceedingly simple... just trying to get it working...
and in this configuration, everything works fine. NLog creates the log files correctly.
On my DEVELOPMENT machine, I am using:
Windows 7
Xamarin Studio / XSP4
Mono 3.2.3
Here is my Application_Start...
protected void Application_Start() {
LogManager.LogFactory = new NLogFactory();
ILog log = LogManager.GetLogger(typeof(Global));
log.Info("Application_Start called");
try {
new AppHost().Init();
} catch (Exception e) {
log.Error("Exception caught initializing AppHost");
}
}
In this configuration, my service's AppHost().Init() throws an exception as ServiceStack is registering my services in ServiceController.cs. I believe that part is irrelevant except that it is the first time something is logged outside of Application_Start (because both of the calls in Application_Start work... the log.info before the exception and the log.error after the exception).
Here is the exception that is shown:
The most relevant bit is that there was a System.NotImplementedException thrown at NLog.Internal.FileAppenders.BaseFileAppender.WindowsCreateFile (System.String fileName, Boolean allowConcurrentWrite).
I have found a workaround (in the accepted answer below). Hopefully anyone else who runs into this will quickly come upon this solution.

Some digging around on Google led me to this NLog pull request:
Avoid Win32-specific file functions in Mono where parts not implemented.
It appears that this change tries to use the preprocessor to NOT call WindowsCreateFile at all. However, for some reason, this still executes.
So I then went to check the newest version of BaseFileAppender.cs in the NLog GitHub repository to make sure someone didn't at some later point break this again.
#if !NET_CF && !SILVERLIGHT && !MONO
try
{
if (!this.CreateFileParameters.ForceManaged && PlatformDetector.IsDesktopWin32)
{
return this.WindowsCreateFile(this.FileName, allowConcurrentWrite);
}
}
catch (SecurityException)
{
InternalLogger.Debug("Could not use native Windows create file, falling back to managed filestream");
}
#endif
Hmmm... it's still there. What gives? Why doesn't MONO seem to be defined by the preprocessor, thus allowing this block to execute? I'm not sure. Before I started down that path of investigation, I noticed another change...
if (!this.CreateFileParameters.ForceManaged && ...
So after following that tracing that ForceManaged boolean back to it's origin, it appeared that I could set forceManaged="true" on my FileTarget declaration in my NLog config. Could it really be that simple?!
<nlog throwExceptions="true" internalLogToConsole="true" internalLogLevel="Debug" xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="c" xsi:type="Console" />
<target name="f1" xsi:type="File" forceManaged="true" fileName="C:\logs\test.log" />
</targets>
<rules>
<logger name="*" writeTo="c,f1" />
</rules>
</nlog>
Once that change was made, everything worked... the call to WindowsCreateFile that was throwing the exception was skipped & a managed filestream was used instead, which works great. Hallelujah!
Lastly, I could not find that forceManaged flag in the NLog documentation anywhere. Would likely have found this solution sooner if it was.

Related

How to combine NLog Targets with Microsoft ILogger filters?

We are using NLog in our .net 5.0 Web API and feel like log levels are set in multiple places. Is there a way we can configure nLog to use the app settings and ignore nLog.config log levels?
nlog.config:
<rules>
<logger name="*" levels="Trace,Debug,Info,Warn,Error,Fatal" writeTo="NLogTarget"/>
</rules>
AppSettings.json:
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Debug"
}
}
Thanks in advance.
If only using Microsoft ILogger then you can just use this in NLog (and rely on Microsoft LoggerFactory filtering from appsettings.json):
<rules>
<logger name="*" writeTo="NLogTarget"/>
</rules>
Notice when upgrading to NLog 5.0, then remember to configure NLogProviderOptions.RemoveLoggerFactoryFilter = false on AddNLog or UseNLog (With latest NLog then the setting is already there, so you can set it upfront already now).
Most users gets confused by having 2 log-filtering systems, and expects when using NLog that it is NLog filters that applies. Therefore changed it to to ignore Microsoft LoggerFactory filters by default.
Notice you can also have the NLog config in appsettings.json. See also https://github.com/NLog/NLog.Extensions.Logging/wiki/NLog-configuration-with-appsettings.json

How can you prevent NLog from handling log statements in referenced libraries?

Whenever an error occurs within our API, we end up getting multiple emails for a single error. Based on the log messages; we can see that these other emails seem to be getting generated because various Microsoft libraries are calling something like _logger.LogError as well as our own _logger.LogError that happens when we handle the error.
For example, when there is a database timeout, we see 4 emails from these different classes:
Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware
Microsoft.EntityFrameworkCore.Database.Command
Microsoft.EntityFrameworkCore.Query
Web.Controllers.ErrorController (Our own exception handler; this is
the only one we want to see)
The last one is the only one that has our own error formatting with helpful information in it such as current user, etc. The others just contain a stack trace, which is already within our own formatted email.
We can't figure out for sure where these other log messages are coming from; but the most likely thing I can think of is that within Microsoft's libraries, they are calling _logger.LogError(), and our own NLog configuration is handling all instances of LogError; instead of just handling our own.
How can we prevent these other log statements from being logged and especially emailed to us?
This is our setup in Program.cs:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
})
.UseNLog();
You could filter this in .NET Core - because your using the Microsoft.Extensions.Logging integration and Microsoft send the messages to that - and in NLog.
Configure in .NET Core
Modify you config, e.g. appsettings.json. For example at least an error for all Microsoft.* and Warning for Microsoft.EntityFrameworkCore.*
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Trace",
"Microsoft": "Error",
"Microsoft.EntityFrameworkCore": "Warning"
}
}
}
Note, this isn't NLog specific so you can't use the NLog level names. possible level names
Read more about this approach here.
Configure NLog
Or you could configure in the NLog config.
In the NLog.config, edit the <rules> .Those rules are processed from top to bottom.
You could filter the namespace with the name attribute (* are allowed)
Without a writeTo attribute, the logs are discarded
If a rule has final="true" and matching the events, the next rule won't be processed.
For example:
<rules>
<!--All logs, including from Microsoft-->
<logger name="*" minlevel="Trace" writeTo="allfile" />
<!--Skip non-critical Microsoft logs and so log only own logs-->
<logger name="Microsoft.*" maxlevel="Info" final="true" /> <!-- BlackHole without writeTo -->
<logger name="*" minlevel="Trace" writeTo="ownFile-web" />
</rules>
You could read about the nlog.config rules here.
This is also possible with the same approach from code, see here.

Serilog only logging the first time it is called after build

I have an ASP NET MVC project which uses Ninject for IoC. Have added a Serilog logger
public class LoggingModule : BaseModule
{
public override void Load()
{
var fileName = "c:\path\file.log";
var loggerConfiguration = new LoggerConfiguration()
.WriteTo.RollingFile(fileName, LogEventLevel.Debug)
.MinimumLevel.Verbose();
var logger = loggerConfiguration.CreateLogger();
Log.Logger = logger;
Bind<ILogger>().ToConstant(logger);
}
}
And am injecting this into a Controller.
When I exercise the code that uses it to log it will log once and then never again until I restart the web app.
I'm using the same configuration code (without ninject) in a windows service which works fine.
Versions installed are
<package id="Serilog" version="2.3.0" targetFramework="net45" />
<package id="Serilog.Sinks.File" version="3.1.0" targetFramework="net45" />
<package id="Serilog.Sinks.RollingFile" version="3.2.0" targetFramework="net45" />
<package id="Ninject" version="3.2.2.0" targetFramework="net45" />
<package id="Ninject.MVC3" version="3.2.1.0" targetFramework="net45" />
<package id="Ninject.Web.Common" version="3.2.3.0" targetFramework="net45" />
<package id="Ninject.Web.Common.WebHost" version="3.2.3.0" targetFramework="net45" />
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net45" />
Update:
Following on from Caio's answer. I added in the SelfLog and see...
2016-11-22T14:29:25.6317957Z Caught exception while emitting to sink Serilog.Core.Sinks.RestrictedSink: System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'The rolling log file has been disposed.'.
at Serilog.Sinks.RollingFile.RollingFileSink.Emit(LogEvent logEvent)
at Serilog.Core.Sinks.SafeAggregateSink.Emit(LogEvent logEvent)
Update 2:
This turned out to be a bug in the way that IDependencyResolver had been implemented in our project. IDependencyResolver implements IDisposable and our implementation called dispose on the kernel. (Un?)luckily this had just never caused an issue before.
I've marked Caio's answer as the answer because him pointing me to the SelfLog gave me the tool to unwind what was happening. Thanks to all the helped though!
Have you tried checking the output from Serilog's self log, to see if there's any error occurring internally?
e.g.
Serilog.Debugging.SelfLog.Enable(msg => Console.WriteLine(msg));
https://github.com/serilog/serilog/wiki/Debugging-and-Diagnostics
First question: Are you using one of the Ninject.MVC packages? If not, I'd try this first as they plug the Ninject container into the MVC pipeline correctly.
https://www.nuget.org/packages/Ninject.MVC5/
Also:
You can sometimes have an order-of-operations problem with DI containers. For this reason I find that it's unsafe to do much setup logic directly in the NinjectModule. I'd try something like this instead:
Bind<ILogger>().ToMethod(context => {
var fileName = "c:\path\file.log";
var loggerConfiguration = new LoggerConfiguration()
.WriteTo.RollingFile(fileName, LogEventLevel.Debug)
.MinimumLevel.Verbose();
var logger = loggerConfiguration.CreateLogger();
Log.Logger = logger;
}).In <whatever> Scope()

Access denied error when accessing usb stick files in Windows IoT core app

I want to access files (images, text files etc.) from an USB stick on my Raspberry Pi 2 using Windows 10 IoT Core.
So I've added the to the appxmanifest file.
When using this code in my IBackgroundTask I get an access denied error in the second line:
public sealed class StartupTask : IBackgroundTask
{
public async void Run(IBackgroundTaskInstance taskInstance)
{
//...
Windows.Storage.StorageFolder sf = Windows.Storage.KnownFolders.RemovableDevices;
//get list of drives
IReadOnlyList<Windows.Storage.StorageFolder> list = await sf.GetFoldersAsync();
...
}
}
I found that I should add the fileTypeAssociation with the file types I'd like to access in Package.appxmanifest so I did that:
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:iot="http://schemas.microsoft.com/appx/manifest/iot/windows10" IgnorableNamespaces="uap mp iot">
<Identity Name="test-uwp" Publisher="CN=user" Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="8f31dff8-3a2b-4df1-90bb-2c5267f32980" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties>
<DisplayName>test</DisplayName>
<PublisherDisplayName>user</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application Id="App">
<uap:VisualElements DisplayName="test" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" Description="test" BackgroundColor="transparent" AppListEntry="none">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png">
</uap:DefaultTile>
<uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements>
<Extensions>
<Extension Category="windows.backgroundTasks" EntryPoint="test.StartupTask">
<BackgroundTasks>
<iot:Task Type="startup" />
</BackgroundTasks>
</Extension>
<uap:Extension Category="windows.fileTypeAssociation">
<uap:FileTypeAssociation Name="myimages">
<uap:SupportedFileTypes>
<uap:FileType ContentType="image/jpeg">.jpg</uap:FileType>
</uap:SupportedFileTypes>
</uap:FileTypeAssociation>
</uap:Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
<uap:Capability Name="removableStorage" />
</Capabilities>
</Package>
If I want to deploy that, I get the following error:
Severity Code Description Project File Line Suppression State
Error Error : DEP0700 : Registration of the app failed.
AppxManifest.xml(37,10): error 0x80070490: Cannot register the
test-uwp_1.0.0.0_arm__yzekw4x8qxe1g package because the following
error was encountered while parsing the windows.fileTypeAssociation
Extension element: Element not found. . Try again and contact the
package publisher if the problem persists. (0x80073cf6)
As soon as I remove the uap:Extension element, the error goes away (but the access denied is still there).
Did I miss anything? Is it not possible to access files from an USB stick using a background service (I want to run that headless with no user interaction)?
At the moment you can't register a headless app that uses filetypeAssociation.
There is a workaround - see here: https://github.com/ms-iot/ntvsiot/issues/62
Simply add a headed app (project) to your solution (no need for any special code there).
Add a reference to this project in your headless app.
Now change the manifest of the headless (file asso..) and add Executable: YourHeadedApp.exe and EntryPoint: YourHeadedApp.App now with the next deploy the EXE will be included in deployment - so it can be found when the manifest is checked.

no configuration section <common/logging> found

I'm using system.diagnostic to log all the errors to a log file
Web.Config:
<system.diagnostics>
<trace autoflush="true" indentsize="4">
<listeners>
<add name="MyListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="MyListenerLog.txt" />
<remove name="Default" />
</listeners>
</trace>
</system.diagnostics>
Code:
private static void AddToMyListner(string message)
{
try
{
System.Diagnostics.Trace.WriteLine("Text: " +message + "," + DateTime.UtcNow);
System.Diagnostics.Trace.Close();
}
catch (Exception ex)
{
throw ex;
}
}
In the Log file the first log i got was
no configuration section <common/logging> found - suppressing logging output
This log is printed only once i.e. only when I create a new log file. I'm not using Common.Logging so i was wondering what is causing this issue.
Common.Logging is commonly integrated with tracing. If you're getting this error and you're not deliberately referencing Common.Logging then you're probably referencing some external library that uses Common.Logging and subscribes to the trace by default. If there's no configuration in place (reasonable, since you're not intending to use Common.Logging) then this would happen when Common.Logging receives a notification that something was written to the trace and doesn't know what to do about it.