nimaara / easy.logger Goto Github PK
View Code? Open in Web Editor NEWA modern, high performance cross platform wrapper for Log4Net.
Home Page: http://www.nimaara.com/2016/01/01/high-performance-logging-log4net
License: MIT License
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
log4net.config is hard coded. May I know why?
I have 3 projects in one solution and each one of them want to log differently.
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 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
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
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:
Any help will be greatly appreciated as we want to get the bottom of this issue and use easy.logger in our infrastructure!
-Srikanth Subramanian
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;
}
}
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?
I use the last release of the package in my project:
<PackageReference Include="Easy.Logger" Version="4.0.0" />
I am receiving warning that refereced library is vulnerable.
https://devhub.checkmarx.com/cve-details/CVE-2018-8292/
Would it be possible to fix it?
AsyncBufferingForwardingAppender is great feature.
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
Dear all,
while building my test solution with Easy.Logger I am getting this warning on assembly from the standard released nugget.
CSC : warning CS8002: Referenced assembly 'Easy.Logger, Version=4.1.0.0, Culture=neutral, PublicKeyToken=null' does not have a strong name.
Is there a reason for this dll to be distributed without strong name?
How to solve this warning correctly?
Jan
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
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.
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
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
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.
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);
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?
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".log"" />
<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".log"" />
<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)
(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*)
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
Using AsyncBufferForwarder
Immutable lists are not serialized where as if I change it to List its getting logged
public ImmutableList DbOperationLogs
{
get
{
return _dbOperationLogs;
}
}
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.
As of log4net 2.0.6 the library supports netstandard1.3
. Upgrade Easy.Logger to support netstandard.
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'.
Hello,
On using AsyncBufferingForwarder basic log4net properties such as AppDomain, log4net.UserName , log4net.Identitiy are not getting logged. If I use ElasticSearchAppender with out Async it logs the details
below is the AsyncBufferingForwarder configuration that I am using
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
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.