简体   繁体   中英

Log4Net in .Net Core application: LoggingEvent not set properly (LocationInformation porperties are set to “?”)

So far we've been using log4net in projects targeting .NET 4.6.1, which works like a charm. Some months ago we started implementing our first .NET core projects. But log4net seems to have it's problems with this framework. We have written our own appender pushing all log events to our logging system. However in core projects essential information is missing in the LoggingEvent objects.

I've set up a minimal test project called Log4NetUnitTest to repeat that behaviour.

The csproj file:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>

    <IsPackable>false</IsPackable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="log4net" Version="2.0.8" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
    <PackageReference Include="MSTest.TestAdapter" Version="1.4.0" />
    <PackageReference Include="MSTest.TestFramework" Version="1.4.0" />
    <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
  </ItemGroup>

</Project>

The unit test class configures the logger programmatically (I've also tested configuration by file with the same result):

[TestClass]
public class LoggingTests
{
    [TestMethod]
    public void Log()
    {
        var logger = LogManager.GetLogger(typeof(LoggingTests));
        var appender = new MyAppender();

        var loggerLogger = (log4net.Repository.Hierarchy.Logger)logger.Logger;
        loggerLogger.Level = Level.All;
        loggerLogger.AddAppender(appender);
        loggerLogger.Hierarchy.Configured = true;

        try
        {
            throw new Exception("Some exception");
        }
        catch (Exception e)
        {
            logger.Error("Some error text", e);
        }
    }
}

The custom appender (which simply writes the JSON formatted event to the console):

public sealed class MyAppender : AppenderSkeleton
{
    private static readonly JsonSerializerSettings _settings = new JsonSerializerSettings
    {
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
        Formatting = Formatting.Indented
    };

    protected override void Append(LoggingEvent loggingEvent)
    {
        var loggingObject = new
        {
            ApplicationName = System.Reflection.Assembly.GetEntryAssembly()?.GetName().Name ?? System.Reflection.Assembly.GetExecutingAssembly().GetName().Name,
            Method = loggingEvent.LocationInformation.MethodName,
            Line = loggingEvent.LocationInformation.LineNumber,
            Class = loggingEvent.LocationInformation.ClassName,
            loggingEvent.LoggerName,
            Environment.MachineName,
            ExceptionMessage = loggingEvent.ExceptionObject?.Message,
            Message = loggingEvent.MessageObject,
            Level = loggingEvent.Level.Name
        };

        string serializedLog = JsonConvert.SerializeObject(loggingObject, _settings);

        Console.WriteLine(serializedLog);
    }
}

When you run the test, you will get the following output:

{
  "ApplicationName": "testhost",
  "Method": "?",
  "Line": "?",
  "Class": "?",
  "LoggerName": "Log4NetUnitTest.LoggingTests",
  "MachineName": "NBG-ITSD-138",
  "ExceptionMessage": "Some exception",
  "Message": "Some error text",
  "Level": "ERROR"
}

So Method , Line and Class cannot be resolved. Also some other properties (which we are not using) like Domain , Identity and UserName are just set to "NOT AVAILABLE". When you change TargetFramework to net461 all properties are set correctly:

{
  "ApplicationName": "Log4NetUnitTest",
  "Method": "Log",
  "Line": "31",
  "Class": "Log4NetUnitTest.LoggingTests",
  "LoggerName": "Log4NetUnitTest.LoggingTests",
  "MachineName": "NBG-ITSD-138",
  "ExceptionMessage": "Some exception",
  "Message": "Some error text",
  "Level": "ERROR"
}

Some years ago someone had a similar problem (not NET core), which could be solved adding loggingEvent.Fix = FixFlags.All; at the beginning of the Append() method. Didn't work for me though:-(

I guess there's some configuration or an additional package I need to add, but I have no clue what's wrong. Any suggestions are greatly appreciated.

Looking at the source for LocationInfo.cs it seems that a lot of functionality is wrapped in a #if !(NETCF || NETSTANDARD1_3) block, which is why none of it is set when using .NET Core. I presume this functionality was not available in .NET Standard 1.3.

There is an issue LOG4NET-606 in the Apache JIRA which mentions that later version of .NET Standard added the missing functionality, and these values could be restored if log4Net was upgraded to target a higher .NET Standard version. Voting and commenting on this issue may help things along.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM