Logging With NLog In Azure WebJobs - azure

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");

Related

How to log HTTP requests sent by ODataQueryBuilder API / VDM API?

Using latest version of Java SAP Cloud SDK
We have some code which uses ODataQueryBuilder API and VDM API as well. We want to log the HTTP requests that are being sent by these API's. We want to log whole of the HTTP request - headers, body everything. Please note that our application is running on SAP Cloud Platform's Cloud Foundry PAAS offering and using cf set-logging-level doesn't seem to work.
I've been using this Java arg when debugging my requests, but I've been doing it locally.
-Dorg.slf4j.simpleLogger.log.org.apache.http.wire=debug
If you can pass it withing CF environment I think you should start seeing all the payloads. I'll research a bit more to provide a better guidance if this won't work for you.
For applications deployed on SCP CF, there are different setups for which recommend other logging practices. The goal is to configure individual log levels for specific packages of your application and third-party dependencies, e.g. SAP Cloud SDK or SAP Service SDK or Apache HTTP components.
TomEE based application:
Edit the manifest.yml to include the following env entry for environment variable:
SET_LOGGING_LEVEL: '{ROOT: INFO, com.sap.cloud.sdk: INFO, org.apache.http.wire: DEBUG}'
Feel free to customize.
Spring Boot based application:
We expect the logback framework.
Edit/Create the file: application/src/main/resources/logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<springProfile name="!cloud">
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<root level="INFO"/>
<logger name="org.springframework.web" level="INFO"/>
</springProfile>
<springProfile name="cloud">
<appender name="STDOUT-JSON" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="com.sap.hcp.cf.logback.encoder.JsonEncoder"/>
</appender>
<logger name="org.springframework.web" level="INFO"/>
<logger name="com.sap.cloud.sdk" level="INFO"/>
<logger name="org.apache.http.wire" level="DEBUG"/>
<root level="INFO">
<appender-ref ref="STDOUT-JSON"/>
</root>
</springProfile>
</configuration>
Feel free to customize.
Notice the different profile settings. Make sure the cloud profile is active for deployed applications. Edit the manifest.yml to include the following env entry for environment variable:
SPRING_PROFILES_ACTIVE: 'cloud'

.NET Standard 2.0 logging NLOG gives System.TypeInitializationException

I did 2 projects to test out NLog on a .NET Framework 4.6.1 standard console app and on .NET Standard 2.0 Library. My intention is to port as much code as I can to .NET Standard 2.0 for future multiplatform compatibility.
Both share the same code but the .NET Standard version produces an exception.
Here's the code
Console.WriteLine("Writing log");
Logger _errorLog = LogManager.GetLogger("ErrorsLogger");
Logger _tradesLog = LogManager.GetLogger("TradesLogger");
_errorLog.Error("This is the log message!!!");
Console.WriteLine("End log");
Console.Read();
Here's the App.Config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
</configSections>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="ErrorsLogger" xsi:type="File" fileName="ErrorsLog.txt" />
<target name="TradesLogger" xsi:type="File" fileName="TradesLog.txt" />
</targets>
<rules>
<logger name="ErrorsLogger" minlevel="Info" writeTo="ErrorsLogger" />
<logger name="TradesLogger" minlevel="Info" writeTo="TradesLogger" />
</rules>
</nlog>
</configuration>
I get the log fine in the .NET 4.6.1 Console app and produces the expected log file with the log message in it.
If I run the .NET Standard 2.0 library through some Microsoft Unit Test project I get this exception when it tries to call _errorLog.GetLogger
UnitTestProject.UnitTest1.TestMethod1 threw exception:
System.TypeInitializationException: The type initializer for
'NLog.LogManager' threw an exception. --->
System.TypeInitializationException: The type initializer for
'NLog.LogFactory' threw an exception. --->
System.MissingMethodException: Method not found:
'System.AppDomainSetup System.AppDomain.get_SetupInformation()'.
EDIT:
Nuget NLOG Version: 4.4.12
Exception thrown in a non static method:
About the non static method to get a better exception:
The exception is thrown at the GetLogger("X") level, which is a non static constructor. The initialization routine crashes even before trying to log something.
In addition, I get a WARNING (yellow exclamation mark) in the error list saying:
Warning The 'configuration' element is not declared.
Adding internal logging doesn't produce any output. This is the configuration i have used, starting from their Internal logging guide:
InternalLogger.LogLevel = LogLevel.Trace;
InternalLogger.LogFile = #"C:\temp\int.txt";
InternalLogger.LogToConsole = true;
InternalLogger.LogToConsoleError = true;
InternalLogger.LogWriter = new StringWriter(new StringBuilder());
InternalLogger.LogToTrace = true;
LogManager.ThrowConfigExceptions = true;
LogManager.ThrowExceptions = true;
Logger logger = LogManager.GetLogger("foo");
I'm administrator and Visual Studio 2017 is started as administrator and I have permission to write in C:\temp ad .NET 4.6.1 console application is able to write in that folder and it's in the same project.
The internal log file is empty and the Unit test project runs the test successfully.
I have no clue of what is happening. No error is thrown now.
Any suggestion to debug the issue is welcome.
An ISSUE on GitHub is already opened.
HERE is a test solution that I made to show you (PASSWORD: logging123). Now that I've updated to Nlog 4.5 you will see that the .NET framework solution throws an error trying to get an old version of Nlog (that I've never referenced) and that .NET Core unit test solution works but doesn't produce any file.
I was experiencing the same issue though I was running .NET 4.7. I updated my NLog package from 4.4.12 to 4.5.0-rc04 and it worked. Knowing its pre-release you may want to be cautions about putting it on live environment though.
Your zipped solution is password protected, so now it is just me guessing, but it looks like you are using app.config to hold nlog.config.
Pretty sure app.config are not being used by NetCoreApps. Try to put your Nlog-config in a separate file called nlog.config and make sure it is Copy Always (In Visual Studio File Properties).

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.

Configuring NLog with ServiceStack to not be NullDebugLogger

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.

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