Log4Net can't locate logfile anywhere - asp.net-mvc

I have followed many different guides on how to configure the log4net, it is up and running but i can't find a log file anywhere ...
This is how my configuration look like:
Web.Config
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
<log4net debug="true">
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="C:\\temp\\Log.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5p %d %5rms %-22.22c{1} %-18.18M - %m%n" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="RollingLogFileAppender" />
</root>
</log4net>
Global.asax:
XmlConfigurator.Configure(new FileInfo(Server.MapPath("~/Web.config")));
//XmlConfigurator.Configure();
StartUp.cs
//[assembly: XmlConfigurator(ConfigFile = "Web.config", Watch = true)]
[assembly: XmlConfigurator(Watch = true)]
Declaration
readonly log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
Logging
BasicConfigurator.Configure();
logger.Info("Info logging ...");
logger.Error("Homepage loading test logging ...");
Where my file value is: <file value="C:\\temp\\Log.txt" />
I have tried several paths, and commented out what above but no success.
What am i doing wrong?
UPDATE:
As suggested by John H i have tried configuring and calling the logger in the Application_Start method and tried several alternative configs with it but with no luck. Here are 2 screenshots of some debugging info:
Main properties:
Below are the Logger properties:
What am i doing wrong?

OK so i got it to work following this tutorial: log4net-guide-dotnet-logging
I have created a log4net.config file with content as showed in tutorial.
used [assembly: XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
Called it like this:
ILog logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
logger.Info("Application started.");
file is created and content logged as well.
I am gonna compare the config files content and see if the difference is in there and go gradually comparing everything till i have found what caused it not to work.
Thank you for helping me!
Kind regards

From your screenshots, we can see that your logger is not being initialised with your configuration, because IsDebug is false. One thing I notice from your screenshot, is you're trying to pass the path to Web.config directly to the Configure() method. I realise that may be an attempt to solve the problem, so you may have already tried my next suggestion, but calling Configure() in the manner you currently have won't work because Web.config is not published to your bin\debug folder. It will called Web.projectname.config. Calling
XmlConfigurator.Configure()
with no parameters, will automatically resolve the correct configuration file in your output directory. I'm guessing you've tried that, but if that still doesn't work, try this as well:
using log4net;
protected void Application_Start(object sender, EventArgs e)
{
// Initialising configuration before requesting a logger.
XmlConfigurator.Configure();
// Requesting a logger only after the configuration has been initialised.
var logger = LogManager.GetLogger(typeof(Global));
logger.Info("Application started.");
}
I'm not sure it will make any difference, but your configuration looks fine to me.
But by inspecting the IsDebug property on the logger, you'll at least be able to tell if the configuration has even been read.
Edit: One other thing, make sure the application will have the permissions to write to the file. From the documentation:
The RollingFileAppender extends the FileAppender and has the same behavior when opening the log file. The appender will first try to open the file for writing when ActivateOptions() is called. This will typically be during configuration. If the file cannot be opened for writing the appender will attempt to open the file again each time a message is logged to the appender. If the file cannot be opened for writing when a message is logged then the message will be discarded by this appender.

Related

Not able to send log4net logs to application insights

I have dotnetcore service which is running in Kubernetes. For logging, I have used the log4net. I am trying to send the logs of service to application-insights but the logs are not showing there.
I have added the below configuration in my service for application insights.
Runtime version: netcoreapp3.1 version-2.31.0.1
Hosting environment: Azure-cluster
app-service.csproj
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.16.0" />
<PackageReference Include="Microsoft.ApplicationInsights.Log4NetAppender" Version="2.16.0" />
...
<ItemGroup>
log4net.config
...
<appender name="aiAppender" type="Microsoft.ApplicationInsights.Log4NetAppender.ApplicationInsightsAppender, Microsoft.ApplicationInsights.Log4NetAppender">
<InstrumentationKey name="AppInsightsKey" value="abcdefgh-abcd-abcd-abcd-abcdefghijkl" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message%newline"/>
</layout>
</appender>
startup.cs
public Startup(IConfiguration configuration)
{
Configuration = configuration;
Logger.ConfigureLog4Net("./logs/app.log", Configuration)
...
}
public void ConfigureServices(IServiceCollection services)
{
// The following line enables Application Insights telemetry collection.
services.AddApplicationInsightsTelemetry();
services.AddSingleton<ITelemetryInitializer, CloudRoleNameTelemetryInitializer>();
// This code adds other services for the application.
services.AddMvc();
...
}
CloudRoleNameTelemetryInitializer.cs
using System.Net;
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.Extensibility;
public class CloudRoleNameTelemetryInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
// set custom role name here
telemetry.Context.Cloud.RoleName = "app-service";
}
}
I have also added the APPINSIGHTS_INSTRUMENTATIONKEY environment variable for service. I am able to see the request information for service but not logs. Only 2 logs are showing in the log section of application-insights but it is not from the application(log4net).
No XML encryptor configured. Key {XXX-XXX-XXX-XXX-XXX} may be persisted to storage in unencrypted form.
Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when the container is destroyed.
Below are some links I have explored.
https://learn.microsoft.com/en-us/azure/azure-monitor/app/asp-net-trace-logs
https://medium.com/#muralimohan.mothupally/application-insights-integration-with-log4net-e1bef68fe3c8
https://blog.ehn.nu/2014/11/using-log4net-for-application-insights/
https://jan-v.nl/post/using-application-insights-in-your-log4net-application/
But still, logs are not adding in the application insights. Is there anything I am missing here? Also is it possible to add Console.WriteLine logs to application-insights as like in nodejs app we can send it by enabling the application-insights module's configuration? Can you please help me?
Thanks...
Thanks for Peter Drier's answer, I thinks below code he provided is useful to you.
For more details, you can refer the orgin post.
Log4Net and Application Insights-no data is coming through
<appender name="aiAppender" type="Microsoft.ApplicationInsights.Log4NetAppender.ApplicationInsightsAppender, Microsoft.ApplicationInsights.Log4NetAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message%newline" />
</layout>
<threshold value="INFO" />
<InstrumentationKey value="12345678-7946-1234-1234-8b330fbe1234" />
</appender>

NLog extensibility - How to add custom field using ExtendValues?

I try to add some custom fields to NLog using extensibility.
Part of my nlog.config file looks like that : (simplified for exhibit)
<nlog>
<extensions>
<add assembly="Logzio.DotNet.NLog"/>
</extensions>
<variable name="currentUser" value="test" />
<targets async="true">
<target name="logzio" type="Logzio" token="myToken">
<contextproperty name="currentUser" layout="${currentUser}" />
</target>
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="logzio" />
</rules>
</nlog>
In every controller, I have something like that (I'm using ASP.NET MVC5)
private static Logger logger = LogManager.GetCurrentClassLogger();
Then I send my logs to logzio using
logger.Fatal("Something bad happens");
Right now, currentUser always have the value test, which is logical.
However, despite of the documentation, I don't understand how to dynamically change currentUser value by the ID of my current logged user.
Should I create a sort of factory ? (if yes, how ? I'm not at ease with factories)
Should I change my logger variable ? If so, how ?
A piece of code would be extremly welcome.
Thank you for pointing my out where I'm wrong
EDIT
After #Rolf's answer, I've created this custom layout renderer
[LayoutRenderer("custom-layout")]
public class CustomLayoutRenderer : LayoutRenderer
{
public string IdUser { get; set; }
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
logEvent.Properties.Add("currentUser", "HowToPassCustomDataHere?");
builder.Append("test from custom-layout");
}
}
and I changed the nlog.config accordingly, adding
layout="${message} ${custom-layout}"
to my <target>
However, I still don't understand how to pass custom value to currentUser. In logz.io, I have "HowToPassCustomDataHere?" as a value of currentUser.
(BTW, ${aspnet-user-identity} is great and works fine ; however I'd like to understand how to pass a custom value to my layout renderer. In my case, something like ${aspnet-user-id})
You can try one of these NLog layoutrenderers to acquire the current username:
${aspnet-user-identity} Wiki
${windows-identity} Wiki
You can also create your own custom NLog LayoutRenderer: https://github.com/NLog/NLog/wiki/How-to-write-a-custom-layout-renderer
Example of how to provide it as currentUser:
<target name="logzio" type="Logzio" token="myToken">
<contextproperty name="currentUser" layout="${aspnet-user-identity}" />
</target>

Shipping logs to Logz.io with NLog fails

I'm just trying to ship some error logs from my ASP.NET MVC 5 app to Logz.io
I'm using NLog to ship my logs.
I've installed NLog and NLog.Web packages
I have the following nlog.config 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"
autoReload="true"
throwExceptions="true"
internalLogLevel="ERROR"
internalLogFile="C:\Temp\nlog-internal.log">
<extensions>
<add assembly="Logzio.DotNet.NLog"/>
</extensions>
<targets async="true">
<target name="file" type="File"
fileName="<pathToFileName>"
archiveFileName="<pathToArchiveFileName>"
keepFileOpen="false"
layout="<long layout patten>"/>
<target name="logzio"
type="Logzio"
token="LRK......"
logzioType="nlog"
listenerUrl="https://listener.logz.io:8071"
bufferSize="1"
bufferTimeout="00:00:05"
retriesMaxAttempts="3"
retriesInterval="00:00:02"
debug="false" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="logzio" />
</rules>
</nlog>
Then, each of my C# controller have this line :
private static Logger logger = LogManager.GetCurrentClassLogger();
and then I try to ship my logs using something like :
logger.Fatal("Something bad happens");
However, when I writeTo="file" in the nlog.config file, I can find a log file on my local disk with "Something bad happens", so everything is fine.
However, nothing appear on my LogzIo web interface when I writeTo="logzio", no logs are shipped there.
What did I miss ?
Answering my own question after I found how to solve this.
Actually, my whole project use HTTPS.
In internal Nlog logs, I had this error
Error : System.Net.WebException : The request was aborted: Could not create SSL/TLS secure channel
I've just added this line of code at the very beginning of ApplicationStart in Global.asax.cs
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
After testing the whole project during some days, it seems it doesn't affect the other parts of the project.
However, just be careful as it is a global setting
I had the same issue, and it turned out that in my published app the logzio dlls were missing. I added them and it resolved the issue.
Check if you're missing these files in your bin folder:
Logzio.DotNet.NLog.dll
Logzio.DotNet.Core.dll

Log4j2: Empty log file in case of parallel tests

I have in my test automation project problem with logging. I'm using log4j2 logger with FileAppender. The way I'm using it is:
Logger logger = (Logger) LogManager.getLogger(loggerName);
Appender appender = FileAppender.newBuilder()
.withAppend(false)
.withBufferedIo(true)
.withFileName(DIR_NAME + File.separator + loggerName + ".log")
.withIgnoreExceptions(false)
.withImmediateFlush(true)
.withLocking(false)
.withLayout(PatternLayout.newBuilder().withPattern("%d{HH:mm:ss.SSS} [%-5level] %msg%n").withCharset(Charset.forName("UTF-8")).build())
.withName(loggerName)
.build();
appender.start();
logger.addAppender(appender);
It works when I'm running single test. All data are visible in console, the file is created and test log is written in the file. Problem occurs in case of tests are running in parallel - in different threads.
In this case, two different loggers and file appenders are created. Log files from both file appenders are created too and logs from both tests are visible in console. Everything seems to be fine, but every time one of these log files is empty. The empty log belongs to test which started later.
I suspect problem with caching. The first file appender holds all cache for writing so the second one is not able to write. Am I right? What is the solution for this?
Thank you.
You should be able to achieve what you want without using programmatic configuration. There are many reasons not to configure log4j2 programmatically, but the best one, in my opinion, is that in doing so you would make your code dependent on aspects of log4j2 that are not part of the public API. This means that if the implementation of log4j2 changes your code has to change as well. This creates more work for you in the long run.
So, with that in mind I will provide a demo of how to set up log4j2 using an XML config file such that it will generate separate logs for each test. I am assuming, since it was not specified in your question, that your goal is to create a log for each method with a Test annotation and that each of these methods is executed in parallel.
First, here is my TestNG class:
package testpkg;
import java.lang.reflect.Method;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class NewTest {
private static final Logger log = LogManager.getLogger();
#BeforeMethod
public void setThreadName(Method method){
ThreadContext.put("threadName", method.getName());
}
#Test
public void test1() {
log.info("This is the first test!");
log.warn("Something may be wrong, better take a look.");
}
#Test
public void test2() {
log.info("Here's the second test!");
log.error("There's a problem, better fix it");
}
}
As you can see here I have two Test methods and a BeforeMethod called setThreadName. The setThreadName method is, obviously, executed before each of the Test methods. It places a key named threadName into the log4j2 ThreadContext using the name of the method that is about to be run. This will be used as part of the log file name in the log4j2 config file.
Here is the log4j2.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Routing name="MyRoutingAppender">
<Routes pattern="$${ctx:threadName}">
<Route>
<File
fileName="logs/${ctx:threadName}.log"
name="appender-${ctx:threadName}"
append="false">
<PatternLayout>
<Pattern>[%date{ISO8601}][%-5level][%t] %m%n</Pattern>
</PatternLayout>
</File>
</Route>
</Routes>
</Routing>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="[%date{ISO8601}][%-5level][%t] %m%n" />
</Console>
</Appenders>
<Loggers>
<Logger name="testpkg" level="TRACE" additivity="false">
<AppenderRef ref="STDOUT" />
<AppenderRef ref="MyRoutingAppender" />
</Logger>
<Root level="WARN">
<AppenderRef ref="STDOUT" />
</Root>
</Loggers>
</Configuration>
As you can see I've set up the config file to use a RoutingAppender to dynamically generate appenders at runtime based on the ThreadContext key threadName and that threadName is also used in the fileName attribute of the FileAppender.
Here is my testNG config file:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="My suite" parallel="methods" thread-count="5" verbose="1">
<test name="testpkg" >
<classes>
<class name="testpkg.NewTest" />
</classes>
</test>
</suite>
As you can see here I've set it up so that each Test method within my class is run in parallel.
When executed this results in the following console output:
[RemoteTestNG] detected TestNG version 6.14.3
[2018-05-04T21:54:54,703][INFO ][TestNG-test=testpkg-2] Here's the second test!
[2018-05-04T21:54:54,703][INFO ][TestNG-test=testpkg-1] This is the first test!
[2018-05-04T21:54:54,709][WARN ][TestNG-test=testpkg-1] Something may be wrong, better take a look.
[2018-05-04T21:54:54,709][ERROR][TestNG-test=testpkg-2] There's a problem, better fix it
===============================================
My suite
Total tests run: 2, Failures: 0, Skips: 0
===============================================
You can clearly see that the output of the two methods is interleaved, so we know that the methods are indeed running in parallel.
The execution of the test class also creates two log files as expected. They are named test1.log and test2.log
Here are their contents:
test1.log:
[2018-05-04T21:54:54,703][INFO ][TestNG-test=testpkg-1] This is the first test!
[2018-05-04T21:54:54,709][WARN ][TestNG-test=testpkg-1] Something may be wrong, better take a look.
test2.log:
[2018-05-04T21:54:54,703][INFO ][TestNG-test=testpkg-2] Here's the second test!
[2018-05-04T21:54:54,709][ERROR][TestNG-test=testpkg-2] There's a problem, better fix it
So we see here that as expected the logs from the first method went to test1.log and the logs from the second method went to test2.log
Enjoy!

Log4net logging not working - asp.net mvc

My log4net configuration is this,
<?xml version="1.0" encoding="utf-8" ?>
<log4netConfiguration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<appSettings>
<add key="log4net.Config" value="log4net.config" />
</appSettings>
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="C:\my_logs/my_web_logs/my_log_%date{ddMMyyyy}.log" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="5" />
<maximumFileSize value="30MB" />
<datePattern value="yyyyMMdd" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%4t %d{ABSOLUTE} %-5p %m%n"/>
<!--<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] – %message%newline" />-->
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="RollingFileAppender" />
</root>
</log4net>
</log4netConfiguration>
I have a Logger helper class as,
public static class Logger
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public static log4net.ILog Log
{
get { return log; }
}
}
In my assembly info, I have this entry,
// Configure log4net using the .config file
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
log4net.config is the config file added to the web project.
In the code I log using the logger class,
Logger.Log.Info("User visits Sign In Page.");
Logging has been working when I set up the above setting. But suddenly logging has stopped working.
But when I created a new asp.net mvc website with above settings, logging works for that.
I tried with IIS Express and Local IIS. In both cases logging works for the test application I have created.
I cannot figure out why it's not logging? How can I diagnose this? What are the possible issues?
Solved by myself, reason was "for some reason" log4net configuration was not loaded from assembly info. Still I do not know why that happens.
I tried so many fixes proposed by different posts. Finally fixed the issue.
Solution mentioned in this post helped me to solve the issue.
I have added following configuration,
<!--These settings load the log4net configuration.-->
<add key="log4net.Config" value="log4net.config"/>
<add key="log4net.Config.Watch" value="True"/>
It starts logging!
Then I removed following line from assembly info,
// Configure log4net using the .config file
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
The reason is that Log4Net tries to load the config from the assembly that first uses LogManager.GetLogger(). If it's one of your class libraries it will simply ignore the attribute in all other assemblies.
The easiest way to fix it is to invoke LogManager in your start file (like Program.cs or Global.asax):
var logger = LogManager.GetLogger(typeof(Program));
logger.Info("Application started.");
//rest of app init.
Doing that will get you the expected behavior with the assembly attribute.
I found log4net won't load the webconfig configuration unless you call log4net.Config.XmlConfigurator.Configure(); on start up.
protected void Application_Start()
{
// your other codes
log4net.Config.XmlConfigurator.Configure(); // must have this line
Logger = log4net.LogManager.GetLogger(typeof(MvcApplication));
}
I had a similar issue: I would not get any logging output, when I ran my assembly from IIS or IISExpress.
However, none of the answers above worked for me.
In my case the solution was to specify the path to the config file as an absolute path. It turned out that IISExpress does not set the current directory to the bin folder and log4net would not find the config file, so I had to use this workaround:
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
// remove file:// part from uri
UriBuilder ub = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(ub.Path);
var fi = new FileInfo(Path.Combine(Path.GetDirectoryName(path), "Logging.config.xml"));
if (fi.Exists)
{
log4net.Config.XmlConfigurator.ConfigureAndWatch(fi);
var logger = log4net.LogManager.GetLogger(typeof(WebApiApplication));
logger.Info("Application started.");
}
else
{
throw new FileNotFoundException("log4net config file not found", fi.FullName);
}

Resources