aws / aws-logging-dotnet

.NET Libraries for integrating Amazon CloudWatch Logs with popular .NET logging libraries
Apache License 2.0
296 stars 133 forks source link

AWS logger logs to cloudwatch twice #199

Open lanierhall opened 2 years ago

lanierhall commented 2 years ago

Describe the bug

AWS logger code initializes twice in certain cases.

Expected Behavior

It should only log once

Current Behavior

When calling LogManager.GetLogger it calls initialization code for the logger/appender which calls AppConfigAWSCredentials which calls GetLogger on line 33 which starts logger code initialization all over again. The second attempt finds credentials as they were set in the first one and creates a listener. The first stack finally returns in AppConfigAWSCredentials and logs that credentials were found and then continues to setup/add a listener. There are now two listeners that both react to logs coming in and send them to cloudwatch. The fix I used was to add lock/isInitialized functionality.

Reproduction Steps

Create a project and add

    private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

And use the logger somewhere in main. Add the following sections to your config:

... ... SystemDeveloper us-east-1 c:\logs\awslog.txt Additionally: * There should be no AWS Credential providers other than the `AppConfigAWSCredentials` * In your app.config you should add an AWS key and secret entry ``` ... ``` To reproduce the issue, you need to cause the Amazon.Runtime.AppConfigAWSCredentials object to instantiate. This is done when the FallbackCredentialsFactory intantiates the CredentialsGenerators property. In other words, create a project with aws key/secret in your app.config project and have no other way to provide aws credentials so that it looks for them there. ### Possible Solution _No response_ ### Additional Information/Context _No response_ ### AWS .NET SDK and/or Package version used AWS.Logger.Core 3.1.0 AWS.Logger.Log4net 3.3.0 log4net 2.0.12 AWSSDK.CloudWatchLogs 3.7.2.39 ### Targeted .NET Platform 4.8 ### Operating System and version Windows Server 2016 Datacenter
lanierhall commented 2 years ago

PR #200 is a fix for this and we've run it for over two years in our system without any issues. https://github.com/aws/aws-logging-dotnet/pull/200

ashishdhingra commented 2 years ago

Thanks for submitting the PR. This needs review from team.

normj commented 2 years ago

@lanierhall I'm trying to replicate the AWSLoggerCore getting created multiple times and I have not been successful yet. I have removed my shared credentials so I'm sure the only place credentials are coming from is my static credentials in app.config. My code looks like this and I can verify credentials are getting recorded to CloudWatch Logs and the AWSLoggerCore constructor is only be called. Can you help understand what I'm not doing correctly?

[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config")]

namespace LoggingAppSettingstEST
{
    internal class Program
    {
        private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        static void Main(string[] args)
        {
            try
            {
                AWSConfigs.LoggingConfig.LogTo = LoggingOptions.Log4Net;
                AWSConfigs.LoggingConfig.LogResponses = ResponseLoggingOption.Always;

                Logger.Debug("Info Hello Log");
                Logger.Error("Error Hello Log");

                var s3Client = new AmazonS3Client();
                s3Client.ListBuckets();

                Thread.Sleep(5000);

            }
            finally
            {
                Console.WriteLine("Hello");
            }
        }
    }
}
lanierhall commented 2 years ago

Can you put a breakpoint on StartMonitor() in the constructor of AWSLoggerCore (AWS.Logger.Core.AWSLoggerCore.cs: line 80) and share your call stack? I'd be interested to compare it with this one:

image