Coder Social home page Coder Social logo

nimaara / easy.logger Goto Github PK

View Code? Open in Web Editor NEW
135.0 17.0 32.0 1.25 MB

A modern, high performance cross platform wrapper for Log4Net.

Home Page: http://www.nimaara.com/2016/01/01/high-performance-logging-log4net

License: MIT License

C# 99.40% Batchfile 0.60%
dotnet dotnet-core csharp log4net logging performance cross-platform easy-to-use easy

easy.logger's People

Contributors

dependabot[bot] avatar nimaara avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

easy.logger's Issues

Is .NET Framework 4.7.2 still supported

I noticed the releases list mentions "Remove support for old .NET versions" for Easy.Logger - 4.0.0. Does that mean .NET Framework 4.7.2 is no longer supported or which versions are affected by this?

We tried updating but started running into issues with loading configuration which caused some automatic tests to fail with the following error. It seems to currently only affect automatic tests (we're using Nunit) and our investigations so far indicate it might have something to do with types being loaded into different AppDomains, but it's unclear if that's solvable.

System.Runtime.Serialization.SerializationException : Type is not resolved for member 'log4net.Util.PropertiesDictionary,log4net, Version=2.0.14.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a'.

Is ordering really preserved?

Hi,

Thank you for your article and library. Great work!

I've found out that you are using BlockingCollection with it's default collection ConcurrentQueue. Which is FIFO collection. In this case I presume we actually might have events in wrong order if consumer is suffering from performance.
Would it be more convenient to use ConcurrentStack?

Deadlock

I tried to use the package on the server, and catch a deadlock.
About 1000 threads write to log files, and ServiceCall logger called about 1000 or more times per seconds.
I have a config like

<?xml version="1.0" encoding="utf-8"?>
<log4net>
  <root>
    <level value="ALL" />
    <appender-ref ref="AsyncBufferingForwarder" />
  </root>
  <!--Appenders-->
  <appender name="AsyncBufferingForwarder" type="Easy.Logger.AsyncBufferingForwardingAppender, Easy.Logger">
    <lossy value="false" />
    <bufferSize value="512" />
    <Fix value="268" />
    <appender-ref ref="GlobalLogFileAppender" />
  </appender>

  <appender name="ServiceAsyncBufferingForwarder" type="Easy.Logger.AsyncBufferingForwardingAppender, Easy.Logger">
    <lossy value="false" />
    <bufferSize value="512" />
    <Fix value="268" />
    <appender-ref ref="ServiceCallAppender" />
  </appender>

  <appender name="GlobalLogFileAppender" type="log4net.Appender.RollingFileAppender">
    <encoding value="utf-8" />
    <file value="logs\Log" />
    <appendToFile value="true" />
    <rollingStyle value="Composite" />
    <maximumFileSize value="10000MB" />
    <maxSizeRollBackups value="-1" />
    <datePattern value="yyyy.MM.dd&quot;.log&quot;" />
    <staticLogFileName value="false" />
    <preserveLogFileNameExtension value="true" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
    </layout>
  </appender>

  <appender name="ServiceCallAppender" type="log4net.Appender.RollingFileAppender">
    <encoding value="utf-8" />
    <file value="logs\ServiceCall" />
    <appendToFile value="true" />
    <rollingStyle value="Composite" />
    <maximumFileSize value="10000MB" />
    <maxSizeRollBackups value="-1" />
    <datePattern value="yyyy.MM.dd&quot;.log&quot;" />
    <staticLogFileName value="false" />
    <preserveLogFileNameExtension value="true" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] - %message%newline" />
    </layout>
  </appender>
  <!--Loggers-->
  <logger name="ServiceCallLogger" additivity="false">
    <appender-ref ref="ServiceAsyncBufferingForwarder" />
    <appender-ref ref="AsyncBufferingForwarder" />
     </logger>
</log4net>

And exception looks like:
1.First Error

(System.Threading.Monitor.ObjWait)
System.Threading.SemaphoreSlim.WaitUntilCountOrTimeout(Int32, UInt32, System.Threading.CancellationToken)
System.Threading.SemaphoreSlim.Wait(Int32, System.Threading.CancellationToken)
System.Collections.Concurrent.BlockingCollection`1[[System.__Canon, mscorlib]].TryAddWithNoTimeValidation(System.__Canon, Int32, System.Threading.CancellationToken)
Easy.Logger.Sequencer`1[[System.__Canon, mscorlib]].Enqueue(System.__Canon)
log4net.Appender.BufferingAppenderSkeleton.SendFromBuffer(log4net.Core.LoggingEvent, log4net.Util.CyclicBuffer)
log4net.Appender.BufferingAppenderSkeleton.Flush(Boolean)
Easy.Logger.AsyncBufferingForwardingAppender.InvokeFlushIfIdle()
Easy.Logger.Sequencer`1+<>c__DisplayClass22_0[[System.__Canon, mscorlib]].<GetConsumer>b__0()
System.Threading.Tasks.Task.Execute()
System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef)
System.Threading.Tasks.Task.ExecuteEntry(Boolean)
System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
System.Threading.ThreadHelper.ThreadStart(System.Object)
  1. Second Error
(System.Threading.Monitor.Enter)
log4net.Appender.AppenderSkeleton.DoAppend(log4net.Core.LoggingEvent)
log4net.Util.AppenderAttachedImpl.AppendLoopOnAppenders(log4net.Core.LoggingEvent)
log4net.Repository.Hierarchy.Logger.CallAppenders(log4net.Core.LoggingEvent)
log4net.Repository.Hierarchy.Logger.Log(System.Type, log4net.Core.Level, System.Object, System.Exception)
log4net.Core.LogImpl.Info(System.Object)
Kernel.ServerSink.ProcessMessage(System.Runtime.Remoting.Channels.IServerChannelSinkStack, System.Runtime.Remoting.Messaging.IMessage, System.Runtime.Remoting.Channels.ITransportHeaders, System.IO.Stream, System.Runtime.Remoting.Messaging.IMessage ByRef, System.Runtime.Remoting.Channels.ITransportHeaders ByRef, System.IO.Stream ByRef)
Kernel.ServerSink.ProcessMessage(System.Runtime.Remoting.Channels.IServerChannelSinkStack, System.Runtime.Remoting.Messaging.IMessage, System.Runtime.Remoting.Channels.ITransportHeaders, System.IO.Stream, System.Runtime.Remoting.Messaging.IMessage ByRef, System.Runtime.Remoting.Channels.ITransportHeaders ByRef, System.IO.Stream ByRef)
System.Runtime.Remoting.Channels.BinaryServerFormatterSink.ProcessMessage(System.Runtime.Remoting.Channels.IServerChannelSinkStack, System.Runtime.Remoting.Messaging.IMessage, System.Runtime.Remoting.Channels.ITransportHeaders, System.IO.Stream, System.Runtime.Remoting.Messaging.IMessage ByRef, System.Runtime.Remoting.Channels.ITransportHeaders ByRef, System.IO.Stream ByRef)
System.Runtime.Remoting.Channels.Tcp.TcpServerTransportSink.ServiceRequest(System.Object)
System.Runtime.Remoting.Channels.SocketHandler.ProcessRequestNow()
System.Runtime.Remoting.Channels.SocketHandler.BeginReadMessageCallback(System.IAsyncResult)
System.Net.LazyAsyncResult.Complete(IntPtr)
System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
System.Net.ContextAwareResult.Complete(IntPtr)
System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32, UInt32, System.Threading.NativeOverlapped*)
System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32, UInt32, System.Threading.NativeOverlapped*)

Provide a generic logger for an improved Dependency Injection experience

Currently, Dependency Injection can be achieved by doing the following:

public sealed class MyService : IService
{
    private readonly IEasyLogger _logger;
    
    public MyService(ILogService logService)
    {
        _logger = logService.GetLogger<MyService>(); // or
        _logger = logService.GetLogger(this.GetType()); // or
        _logger = logService.GetLogger("MyService");
    }
}

This can be simplified by injecting the logger itself. e.g.

public sealed class MyService : IService
{
    private readonly IEasyLogger<MyService> _logger;
    
    public MyService(IEasyLogger<MyService> logger)
    {
        _logger = logger;
    }
}

.net Standard Version 2.0 support?

Any future release for .net standards 2.0 expected? Have used this in some old .net framework 4.5 application. now thinking of whether it is usable in my .net core 2.1.6 application or not

Lockup using easy.logger forwarding appender under large transaction load

We are attempting to use Easy.Logger (Easy.Logger.1.8.0.nupkg with log4net 2.0.5) in a large web API application. We're forwarding thru easy.logger into a rolling file appender. While it works fine for low loads, on higher volume of transactions, within a few minutes, the IIS site serving the web API application locks up. It stops logging to the file and it blocks all further requests and starts throwing 503 errors to the client. I've debugged thru the issue and found that easy.logger is blocked in a semaphore and all request threads are waiting to complete the log4net logging call. Due to this we've had to remove Easy.Logger from our system. Would like to know if this is something in our configuration or if there is an underlying code issue.

I'm attaching a zip file which contains the following:

  • 2 screenshots: one of threads shown by Visual studio of many many requests hung up on logging calls and another showing one Easy.Logger thread blocked waiting on the blocking collection
  • our sample log4net config file using easy.logger

Any help will be greatly appreciated as we want to get the bottom of this issue and use easy.logger in our infrastructure!

easy_logger_issue.zip

-Srikanth Subramanian

Retrieve the list of loggers

Hello Nima, I am contacting you because I use Easy.Logger.
I'm trying to find a solution to retrieve the list of loggers (ILogger) that are initialized in the config file or added from the Log4NetService.
I see that you are added, a few hours ago, the property name in the Logger class, it is not possible to add in the service class the list of ILogger ?

Thank you
Best regards

Log4NetService needs to be configured with a valid configuration file

System.InvalidOperationException: "Log4NetService needs to be configured with a valid configuration file."

tho i've created the log repo manually

Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();
            hierarchy.ResetConfiguration();
            var logFileAppender = new FileAppender();
            PatternLayout patternLayout = new PatternLayout();
            patternLayout.ConversionPattern = "[%date][%thread][%-5level][%logger]: %message%newline";
            patternLayout.ActivateOptions();

            RollingFileAppender roller = new RollingFileAppender();
            roller.AppendToFile = true;
            roller.File = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, this.GetType().Assembly.GetName().Name + ".log");
            roller.Layout = patternLayout;
            roller.MaxSizeRollBackups = 5;
            roller.MaximumFileSize = "1GB";
            roller.RollingStyle = RollingFileAppender.RollingMode.Size;
            roller.StaticLogFileName = true;
            roller.ActivateOptions();
            hierarchy.Root.AddAppender(roller);

Please sign the dlls

Hello,
I want to reference Easy.Logger in signed application. This means all references need to be signed as well.
Please sign all dlls in the nuget. I made few changes in PR #11 but Easy.Logger.Interfaces nuget needs to be updated to signed version.

How can I use EasyLogger with other component using Log4NetLogger

If I already have a component thet implements the Log4NetLogger interface.

public class Log4NetLogger : Inetlab.SMPP.Logging.ILog
vs
public class Log4NetLogger : IEasyLogger

How can I use Easy.Logger to improve logging performance in my Inetlab.SMPP modules?

'AsyncBufferingForwardingAppender' blocks the configuration file

I am using AsyncBufferingForwardingAppender to forward logs to AdoNetAppender. In my application I have requirement that administrator can control log level. In that case our tool modifies the log level in config file at root level. I have used 'XmlConfigurator.ConfigureAndWatch()' method for that purpose.
I noticed that if the logging is going on and if we try to change the config file at that time, its get blocked.

After further investigation in code. I noticed following probable issue

  • On log level change, log4net calls 'protected override void OnClose()' method of appender
  • OnClose, AsyncBufferingForwardingAppender calls _sequencer.Shutdown();
  • Shutdown method accepts 'waitForPendingItems' optional parameter, which is by default 'true'
  • So Sequencer keeps waiting to forward previous received logs.

In this scenario, I don't want those logs. So there should be a provision to discard the logs and shutdown sequencer immediately.

Thanks in advance.

Question: caching of ILogger instances

Hi,

I would like to avoid having a static named logger in each class file of my project. I was thinking about having an abstraction that takes the log source and then builds easylogger like so:

var easyLogger = Log4NetService.Instance.GetLogger(sourceType);

The problem with this approach is that it this seems to cut logging from roughly 5 million per 10 seconds to 2.5 million per 10 seconds.

So then I was thinking about caching each logger (using a singleton pattern) after it is created the first time and reusing the cach rather than creating a new one every call.
So something like this...


public class AnAbstraction {

private static volatile Dictionary<string, ILogger> loggers;
private ILogger easyLogger;

public void DebugFormat(object source, string debugMessage, params object[] parameters)
        {
            var sourceType = source.GetType();
            lock (sourceType)
            {
                if (loggers.ContainsKey(sourceType.FullName))
                {
                    easyLogger = loggers[sourceType.FullName];
                    return;
                }

                easyLogger = Log4NetService.Instance.GetLogger(sourceType);
                loggers.Add(sourceType.FullName, easyLogger);
            }

            easyLogger.DebugFormat(debugMessage, parameters);
        }

Doing this pushes logging back up to 5 million per 10 seconds.

Do you see any issues with this approach? Or could you recommend a better approach, given that I wish to use dependency injection to inject my abstraction into classes rather than use static named loggers?

Thanks for your time

log4net not serializing the immutable list

Using AsyncBufferForwarder
Immutable lists are not serialized where as if I change it to List its getting logged
public ImmutableList DbOperationLogs
{
get
{
return _dbOperationLogs;
}
}

Using scoping feature to identify a complete operation

Greetings!

I'm using this magnificent logging library in a few projects. Recently, I have been working on a finance system. I noticed that if I could somehow have the scope variable (name of a scope, a Guid in my case) as a log row property (like a timestamp) so that I can start logging from a website -> Client -> Service -> Business Laer -> Data Layer - > Entity Framework Layer passing the same Guid and logging it as a property of every log along the way. Output would be like:

[2018-05-29 00:11:24,590] [DEBUG] [ 1] [EF312386-5DF0-4911-A072-404F934A79CF] [MvcWeb] - GetListOfCompanies
[2018-05-29 00:11:24,595] [DEBUG] [ 1] [EF312386-5DF0-4911-A072-404F934A79CF] [WcfClient] - GetListOfCompanies
[2018-05-29 00:11:25,195] [DEBUG] [ 1] [EF312386-5DF0-4911-A072-404F934A79CF] [WcfService] - 
GetListOfCompanies
[2018-05-29 00:11:25,295] [DEBUG] [ 1] [EF312386-5DF0-4911-A072-404F934A79CF] [BusinessLogic] - GetListOfActiveCompaniesSortedByName
[2018-05-29 00:11:26,95] [DEBUG] [ 1] [EF312386-5DF0-4911-A072-404F934A79CF] [DataLayer] - GetListOfActiveCompaniesSortedByName
[2018-05-29 00:11:27,5] [DEBUG] [ 1] [EF312386-5DF0-4911-A072-404F934A79CF] [EntityFramework] - GetListOfCompaniesByFilters

And then the return journey with the same Guid. Is this possible with EasyLogger? The Scope fulfills this but the way the output is generated, it is not possible to parse the log file to extract one complete operation.

Can we config the idle time?

Can we config the idle time in AsyncBufferingForwardingAppender?
e.g. idleTime in the following config snippet.

<appender name="AsyncBufferingForwarder" type="Easy.Logger.AsyncBufferingForwardingAppender">
        <lossy value="false" />
        <bufferSize value="512" />    
        <Fix value="268" />
        <idleTime value="1000" />

        <appender-ref ref="ManagedColoredConsoleAppender"/>
</appender>

The attachment is the modified code.
AsyncBufferingForwardingAppender.zip

LogicalThreadContext Properties not logged.

Hello,

While trying to implement this in a project we noticed that objects put into the LogicalThreadContext Properties collection are not included with the log entry when we use the AsyncBufferingForwardingAppender. Using our existing appenders directly we do see the objects included in our logs. Is this a side effect of the async buffering approach used in this appender?
Or was there any reason these were intentionally not included when using AsyncBufferingForwardingAppender?

While debugging the AsyncBufferingForwardingAppender I noticed that the properties are accessible in the SendBuffer function as I was able to view them checking the context directly like so: log4net.LogicalThreadContext.Properties["objectName"]. The Properties collection of the events passed to SendBuffer lack the object but if I copy the object from LogicalThreadContext.Properties into them then our logs include the objects as we expect.

Issues with Dependency Injection via Unity in Web API

Hi, thanks for the code and I'm trying to implement it in my Web API project via Dependency Injection using Unity.

Here's a rough overview of my code...

Controller

namespace MyLog4NetEasyLogger.Controllers
{
    [RoutePrefix("api/")]
    public class TestController : ApiController
    {

        private readonly IEasyLogger _log;

        public TestController(ILogService logService)
        {
            _log = logService.GetLogger(this.GetType());
        }

        [HttpGet]
        [Route("details")]
        public HttpResponseMessage GetUserDetails()
        {
            try
            {
                throw new Exception("WOOH A BIG ERROR!!!!");
            }
            catch (Exception e)
            {
                _log.Error("Exception " + e);
            }
            return Request.CreateResponse(HttpStatusCode.OK, new JsonResponse().SetOk());
        }
    }
}

UnityConfig.cs

public static class UnityConfig
    {
        public static void RegisterComponents()
        {
            var container = new UnityContainer();
            
            container.RegisterType<ILogService, Log4NetService>();

            GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
        }
    }

I also have
UnityConfig.RegisterComponents();
in my Global.asax.cs file

Yet when I call the controller method I'm getting the error:

An error occurred when trying to create a controller of type 'TestController'. Make sure that the controller has a parameterless public constructor.

and the inner exception says:

The type Log4NetService does not have an accessible constructor.

so I think it seems to be an issue with "container.RegisterType<ILogService, Log4NetService>();" in the UnityConfig.cs file.

Is there anything I'm missing here? Many thanks

Log4NetService throws System.NullReferenceException if no the default log4net.config

If there isn't the default log4net.config in the program running directory,
and use a custom log4net config file such as log4net-test.config.
code as follows:

var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log4net-test.config");
Log4NetService.Instance.Configure(new FileInfo(filePath));

The program will throw exception:

Unhandled Exception:
System.NullReferenceException: Object reference not set to an instance of an object
  at log4net.Config.XmlConfigurator.InternalConfigureAndWatch(ILoggerRepository repository, FileInfo configFile)
  at log4net.Config.XmlConfigurator.ConfigureAndWatch(ILoggerRepository repository, FileInfo configFile)
  at Easy.Logger.Log4NetService.Configure(FileInfo configFile)

I found the reason is that the _repository is null if no default log4net.config

Configuration in app.config

Hi,

I am currently using app.config for my log4net config. Can I specify this with Easy.Logger? I normally use the attribute as such: [assembly: log4net.Config.XmlConfigurator(Watch = true)]

Cheers,
Luke

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.