Configuring NLog with ServiceStack to not be NullDebugLogger - servicestack

I'm new to NLog and have chosen to add it to my ServiceStack (4.0.44) web services however it's not working as I expect as I always end up with a NullDebugLogger.
I have
Global.Asax
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
LogManager.LogFactory = New NLogFactory()
Dim appHost As New MyAppHost
appHost.Init()
End Sub
I've also manually added an NLog.config file to log to the debugger
<?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"
xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
autoReload="true"
throwExceptions="true"
internalLogLevel="Trace" internalLogFile="c:\temp\nlog-internal.log" >
<targets>
<!-- log to the debugger -->
<target xsi:type="Debugger" name="debugger" layout="${logger}::${message}"/>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="debugger" />
</rules>
</nlog>
and finally in my class I have the following
public class MyClass
{
public static ILog Log;
public MyClass()
{
Log = LogManager.GetLogger(typeof(MyClass));
}
public void LogSomething()
{
Log.Debug("Starting to LogSomething");
}
}
When I debug, the Log object in my class shows as a ServiceStack.Logging.NullDebugLogger which I believe is the default but I can't figure out how to change it to something I can use. I'm sure I'm missing something simple but can't figure out what it is. My web services are in a different project (in the same solution) which is why my Global.asax is VB and the class is C#. I also have no reference in web.config to NLog.config but I assume that Nlog picks that up anyway.

The way logging works is very simple, LogManager.LogFactory just sets a static property where all subsequent calls to LogManager.GetLogger(Type) will use that concrete factory to return the preferred logger implementation. So it just needs to be sent once on Application Start before any calls to LogManager.GetLogger() is made.
LogManager.LogFactory defaults to NullLogFactory but never gets set by ServiceStack, so the only reasons why it wouldn't retain the NLogFactory is if LogManager.GetLogger() isn't being retrieved in the same AppDomain where it was set or it's only being set after LogManager.GetLogger() is called or some of your code is reverting it back to LogManager.LogFactory = new NullLogFactory().
My hunch since you've shown both C# and VB.NET code is that it's not being set in the same Web Application, i.e. your static property set in VB.NET is not visible in the AppDomain where your C# code is running.

Related

Logging With NLog In Azure WebJobs

I've got an NLog configuration which works just fine for my web app (ASP.NET Core).
Now I'm trying to add NLog to my webjobs, but I can't figure out how to do it.
In Program.cs within the webjob project, I need to somehow inject IHostingEnvironment and ILoggerFactory (Both of which I inject into the StartUp constructor of the web app).
Once I know how to do that, I should be able to finish off the configuration.
If that's not possible, what alternatives do I have?
I'm not keen to use the TextWriter class passed into the webjob methods, as I imagine it would be difficult to extract the logs and route them to where I ultimately want it to go.
Following are steps of using NLog in WebJob.
Step 1, install NLog.Config package for your WebJob.
Install-Package NLog.Config
Step 2, add rules and targets to NLog.config files. Following is the sample of writing logs to a file.
<?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">
<targets>
<target name="logfile" xsi:type="File" fileName="file.txt" />
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="logfile" />
</rules>
</nlog>
Step 3, get logger instance using LogManager class.
private static Logger logger = LogManager.GetLogger("MyLog");
Step 4, after got the logger instance, you could write log using following code.
logger.Trace("Sample trace message");
logger.Debug("Sample debug message");

How do I add a service stack license to a .NET core project?

For my service stack license I am used to adding a web config entry
<add key="servicestack:license" ... />
How do I achieve a similar effect in ServiceStack.Core since there is no web config?
The license key can be registered using any of the options listed at: https://servicestack.net/download#register
So while there's no Web.config you can use any of the other 3 options like registering the SERVICESTACK_LICENSE Environment Variable.
Also whilst .NET Core doesn't need to use Web.config or App.config you can still use one in .NET Core in ServiceStack for storing any <appSettings>, e.g:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="servicestack:license" value="{LicenseKey}" />
</appSettings>
</configuration>
But you'll need to register the license key explicitly from the AppSettings with:
using ServiceStack;
public class AppHost : AppHostBase
{
public AppHost()
: base("Service Name", typeof(MyServices).GetAssembly())
{
var licenseKeyText = AppSettings.GetString("servicestack:license");
Licensing.RegisterLicense(licenseKeyText);
}
public override void Configure(Container container)
{
}
}
Or if you don't want to use Web.config you can use any other AppSettings options.

Azure AppInsight with Log4Net

I have been trying to write Logs(Trace, Information & Exception) in Azure AppInsights using Log4Net instead of default api Telemetry client. When I run the application from VS2013 neither I get any error message nor am seeing logs in Azure portal.
Pleaes help me figure out this issue.
Note: Am using Log4net appender for AppIinsights.
Web.Config
<log4net>
<root>
<level value="ALL" />
<appender-ref ref="aiAppender" />
</root>
<appender name="aiAppender" type="Microsoft.ApplicationInsights.Log4NetAppender.ApplicationInsightsAppender, Microsoft.ApplicationInsights.Log4NetAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message%newline" />
</layout>
</appender>
MVC Controller
public class HomeController : Controller
{
private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public ActionResult Index()
{
//Trace.TraceInformation("Home accessed at : {0}", DateTime.UtcNow);
Log.Info(string.Format("Home accessed at : {0}", DateTime.UtcNow));
return View();
}
}
Regards,
Rajaram.
If you are not seeing any log4net output, i'm presuming you are missing some log4net startup code, like this:
log4net.Config.XmlConfigurator.Configure();
which you might want in your startup class / code somewhere. Without that, log4net doesn't know wo read the configuration that's in web.config.
In addition to the answer from #JohnGardner, you can instead add a line to your AssemblyInfo.cs file as so: -
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
There is more discussion on the two approaches in the following question: -
Configure Log4Net in web application
And in a comment in somewhere in that discussion is a link to the log4net FAQs that touches on the differences in the question "When should I log my first message?": -
https://logging.apache.org/log4net/release/faq.html#first-log
I found both of these to be of further use to me.

NLog with DNX Core 5.0

I am attempting to implement NLog logging using ASP.Net 5 and MVC 6. Be default, both DNX 451 and DNX Core 50 are included in the project template.
I am attempting to implement NLog Logging by following the example here.
However, in the sample app, there is the following line -
#if !DNXCORE50
factory.AddNLog(new global::NLog.LogFactory());
#endif
And if I run the app, this line never gets hit because the mvc application has dnx core 50 installed by default.
Is there any loggers that are available for DNX Core 50? If not, what purpose does dnx core serve in the default mvc app - is it actually needed?
Edit: If I remove the #if !DNXCORE50.... line above, I get a the following error -
DNX Core 5.0 error - The type or namespace name 'NLog' could not be found in the global namespace'
DNX Core 5.0 is only necessary if you want the cloud-optimized cross-platform version of the .Net framework; if you still plan on using the MVC app within only a Windows environment, you can remove your dnxcore50 framework reference from your project.json.
NLog for .NET Core (DNX environment) is currently available in version 4.4.0-alpha1.
Steps:
Create NLog.config
<?xml version="1.0" encoding="utf-8" ?>
<targets>
<target xsi:type="ColoredConsole" name="ToConsole" />
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="ToConsole" />
</rules>
Load and parse configuration
private static ILogger _logger;
public static void LoggerSetup()
{
var reader = XmlReader.Create("NLog.config");
var config = new XmlLoggingConfiguration(reader, null); //filename is not required.
LogManager.Configuration = config;
_logger = LogManager.GetCurrentClassLogger();
}
public static void Main(string[] args)
{
LoggerSetup();
// Log anything you want
}
When dealing with the MVC tooling in MVC6 (dnx stuff), the answer to this is very fluid.
In order to get NLog to work with my web app, I had to do a couple steps:
-> Big thanks to two NLog discussions(here and here)
I just needed to add the configuration setup in my Startup.cs's constructor:
public Startup(IHostingEnvironment env)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
// Set up logging configuration
// from: https://github.com/NLog/NLog/issues/641
// and: https://github.com/NLog/NLog/issues/1172
var reader = XmlTextReader.Create(File.OpenRead(Path.Combine(builder.GetBasePath(),"NLog.config"))); //stream preferred above byte[] / string.
LogManager.Configuration = new XmlLoggingConfiguration(reader, null); //filename is not required.
log.Info("NLogger starting");
Configuration = builder.Build();
}
I consider this a bit of a stop-gap as Microsoft is introducing a new Logging interface (that I hope will end up being like SLF4J.org is in Java). Unfortunately, documentation on that is a bit thin at the time I'm writing this. NLog is working diligently on getting themselves an implementation of the new dnx ILoggingProvider interface.
Additional information about my project setup
My NLog.config file is located in the project root folder, next to
the project.json and appsettings.json. I had to do a little digging
inside AddJsonFile() to see how they handled pathing.
I used yeoman.io and their aspnet generator to set up the web project.
Version of NLog, thanks to Lukasz Pyrzyk above:
"NLog": "4.4.0-alpha1"

log4net config settings

I am into the development of a core dll where I have a class library.I want to use log4net to enable logging for exceptions. I have an app.config file in the class library where i have given the settings for the log4net.However when I test the class library the log4net does'nt create logs until i add the app.config in the calling project inspite of the fact that i had added [assembly: log4net.Config.XmlConfigurator(Watch = true)] in the class libary's assemblyinfo.cs and I am using log4net.ILog logger = log4net.LogManager.GetLogger(typeof(ErrorHandler)) where ErrorHandler is the name of my class library's class where log4net's calling functions are handled.Any ideas on what is going wrong?
Secondly, what I want to acheive is the users of my dll will just pass the location where they want to create logs and whether they want to create logs in event viewer or log files from their app.config? They will not handle any other setting of log4net.
Any suggestions or code snippets for the first issue and the second problem?
Only the "main" app.config is active for a .Net application. Your library config file is simply ignored. Either you transfer your settings to the main config file or you use an external config file for log4net. You configure it then for instance like this (assuming you call it log4net.config):
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
Please note that the structure of the config file is a bit different:
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="YourAppender" type="..." >
....
</appender>
<root>
<level value="ALL" />
<appender-ref ref="YourAppender" />
</root>
</log4net>
As for your second problem: I am not sure how flexible this has to be. Is it just switching from file appender to event log appender? Depending on your answer you may consider two prepare to configuration files (e.g. file.log4net and eventlog.log4net) and read the configuration as needed (in that case you cannot use the attribute: you call the Configure() method directly) or if your requirements are more complex you might even end up configuring log4net programatically.

Resources