Log4Net how to log - log4net

I am new with log4net and am wondering how to properly be able to log. I have seen examples of people doing Logs.Enter, Logs.Exit. It properly logs and helps users when testing/debugging. Examples of how to define is greatly appreciated

You define a log4net log like so:
private static log4net.ILog log = log4net.LogManager.GetLogger(ConfigurationManager.AppSettings["LogName"]);
I defined it so that it is defined in app config. Afterwards, I define methods to determine the type of log i.e. Error, Info, Enter, Exit etc.
Enter/Exit method example:
[Conditional("ENTEREXIT")]
public static void Enter()
{
_log.Info(GetMethodName() + ": In");
}
[Conditional("ENTEREXIT")]
public static void Exit()
{
_log.Info(GetMethodName() + ": Out");
}
Save this in a separate class called Logs.cs
Then, whenever you want to log, you simple do Logs.Enter and then stop logging with Logs.Exit. You can do Logs.Info or Logs.Error without the Enter/Exit Logs.

Related

ServiceStack with MiniProfiler for .Net 6

I was attempting to add Profiling into ServiceStack 6 with .Net 6 and using the .Net Framework MiniProfiler Plugin code as a starting point.
I noticed that ServiceStack still has Profiler.Current.Step("Step Name") in the Handlers, AutoQueryFeature and others.
What is currently causing me some stress is the following:
In ServiceStackHandlerBase.GetResponseAsync(IRequest httpReq, object request) the Async Task is not awaited. This causes the step to be disposed of the when it reaches the first async method it must await, causing all the subsequent nested steps to not be children. Is there something simple I'm missing here or is this just a bug in a seldom used feature?
In SqlServerOrmLiteDialectProvider most of the async methods make use of an Unwrap function that drills down to the SqlConnection or SqlCommand this causes an issue when attempting to wrap a command to enable profiling as it ignores the override methods in the wrapper in favour of the IHasDbCommand.DbCommand nested within. Not using IHasDbCommand on the wrapping command makes it attempt to use wrapping command but hits a snag because of the forced cast to SqlCommand. Is there an easy way to combat this issue, or do I have to extend each OrmliteDialectProvider I wish to use that has this issue to take into account the wrapping command if it is present?
Any input would be appreciated.
Thanks.
Extra Information Point 1
Below is the code from ServiceStackHandlerBase that appears (to me) to be a bug?
public virtual Task<object> GetResponseAsync(IRequest httpReq, object request)
{
using (Profiler.Current.Step("Execute " + GetType().Name + " Service"))
{
return appHost.ServiceController.ExecuteAsync(request, httpReq);
}
}
I made a small example that shows what I am looking at:
using System;
using System.Threading.Tasks;
public class Program
{
public static async Task<int> Main(string[] args)
{
Console.WriteLine("App Start.");
await GetResponseAsync();
Console.WriteLine("App End.");
return 0;
}
// Async method with a using and non-awaited task.
private static Task GetResponseAsync()
{
using(new Test())
{
return AdditionAsync();
}
}
// Placeholder async method.
private static async Task AdditionAsync()
{
Console.WriteLine("Async Task Started.");
await Task.Delay(2000);
Console.WriteLine("Async Task Complete.");
}
}
public class Test : IDisposable
{
public Test()
{
Console.WriteLine("Disposable instance created.");
}
public void Dispose()
{
Console.WriteLine("Disposable instance disposed.");
}
}
My Desired Result:
App Start.
Disposable instance created.
Async Task Started.
Async Task Complete.
Disposable instance disposed.
App End.
My Actual Result:
App Start.
Disposable instance created.
Async Task Started.
Disposable instance disposed.
Async Task Complete.
App End.
This to me shows that even though the task is awaited at a later point in the code, the using has already disposed of the contained object.
Mini Profiler was coupled to System.Web so isn't supported in ServiceStack .NET6.
To view the generated SQL you can use a BeforeExecFilter to inspect the IDbCommand before it's executed.
This is what PrintSql() uses to write all generated SQL to the console:
OrmLiteUtils.PrintSql();
Note: when you return a non-awaited task it just means it doesn't get awaited at that point, it still gets executed when the return task is eventually awaited.
To avoid the explicit casting you should be able to override a SQL Server Dialect Provider where you'll be able to replace the existing implementation with your own.

singleton in azure queuetrigger not working as expected

My understanding of this is obviously wrong, any clarification would be helpful.
I thought that adding [Singleton] to a web job would force it to run one after another.
This does not seem to be the case.
This is my very basic test code (against a queue with about 149 messages)
[Singleton] //just run one at a time
public static void ProcessQueueMessage([QueueTrigger("datatrac-stops-to-update")] string message, TextWriter log)
{
monitorEntities mDb = new monitorEntities();
//go get the record
int recordToGet = Convert.ToInt32(message);
var record = (from r in mDb.To_Process where r.Id == recordToGet select r).FirstOrDefault();
record.status = 5;
mDb.SaveChanges();
Console.WriteLine($"Finished record {message}");
}
When it runs I get this on the console:
and as I step though it I am getting conflict errors.
What am I not understanding?
RESOLVED - MORE INFO
Here is what I did to address this, like Haitham said in his answer [Singleton] refers to how many instances of the webjob itself is running -- not how many items are processed per instance.
That was addressed by modifying my Main like:
static void Main(string[] args)
{
var config = new JobHostConfiguration();
config.Queues.BatchSize = 2;
Which when set to 1 only ran 1 at a time.
When set to 2 like above then modifying the below code:
public static void ProcessQueueMessage([QueueTrigger("datatrac-stops-to-update")] string message, TextWriter log)
{
var threadID = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"{threadID} : started record {message}");
Produces this behavior (which is what was expected):
Link where I found documentation on above:
https://github.com/Azure/azure-webjobs-sdk/wiki/Queues#config
Singleton does not mean it will run it one after another but mainly about instantiation the instance for the web job class.
If you need to run just one at a time, you can use locks on a static variable to prevent the code to execute more than one time.
But I would not recommend that anyway and you have to see why there are conflict errors

TrackTrace is not logging In to Application Insight

I have the below code. It's Not logging to Trace.I am not sure why. If possible can you help me on this?
public static void SAPLogger(string Message)
{
TelemetryConfiguration.Active.InstrumentationKey = "XXX-XXX-XXX";
TelemetryClient TelePositive = new TelemetryClient
{
InstrumentationKey = "XXX-XXX" (Optional Value)
};
//TelePositive.TrackRequest(Req);
TelePositive.TrackTrace(Message, SeverityLevel.Verbose, new Dictionary<string, string> { { "Information", "SAP" } });
}
I am calling this method in the Main() method.
static void Main(string[] args)
{
try
{
int a = 5;
int c = a / 2;
SAPLogger("The value is Success" + c);
}
}
I am totally not sure why this is not logging. Please help
Your example app is probably exiting before your telemetry gets sent.
DeveloperMode should cause it to send immediately, however, if your process exists immediately like your test app appears to, the process might still end before the web request gets created and sent.
For short lived applications like that test app, you'll probably need a flush and a sleep call of some kind at the end to ensure telemetry has a chance to send before the app quits.
For a real application that lives for a long time, telemetry will be batched and sent after an amount of time, or number of events is met, then that batch will be sent. you app probably still would want to flush/wait at the end just to make sure any batched up telemetry gets sent.
but in either case, the flush/wait should only occur once, at the end. not with every call to track telemetry.

Async Logger. Can I lose/delay log entries?

I'm implementing my own logging framework. Following is my BaseLogger which receives the log entries and push it to the actual Logger which implements the abstract Log method.
I use the C# TPL for logging in an Async manner. I use Threads instead of TPL. (TPL task doesn't hold a real thread. So if all threads of the application end, tasks will stop as well, which will cause all 'waiting' log entries to be lost.)
public abstract class BaseLogger
{
// ... Omitted properties constructor .etc. ... //
public virtual void AddLogEntry(LogEntry entry)
{
if (!AsyncSupported)
{
// the underlying logger doesn't support Async.
// Simply call the log method and return.
Log(entry);
return;
}
// Logger supports Async.
LogAsync(entry);
}
private void LogAsync(LogEntry entry)
{
lock (LogQueueSyncRoot) // Make sure we ave a lock before accessing the queue.
{
LogQueue.Enqueue(entry);
}
if (LogThread == null || LogThread.ThreadState == ThreadState.Stopped)
{ // either the thread is completed, or this is the first time we're logging to this logger.
LogTask = new new Thread(new ThreadStart(() =>
{
while (true)
{
LogEntry logEntry;
lock (LogQueueSyncRoot)
{
if (LogQueue.Count > 0)
{
logEntry = LogQueue.Dequeue();
}
else
{
break;
// is it possible for a message to be added,
// right after the break and I leanve the lock {} but
// before I exit the loop and task gets 'completed' ??
}
}
Log(logEntry);
}
}));
LogThread.Start();
}
}
// Actual logger implimentations will impliment this method.
protected abstract void Log(LogEntry entry);
}
Note that AddLogEntry can be called from multiple threads at the same time.
My question is, is it possible for this implementation to lose log entries ?
I'm worried that, is it possible to add a log entry to the queue, right after my thread exists the loop with the break statement and exits the lock block, and which is in the else clause, and the thread is still in the 'Running' state.
I do realize that, because I'm using a queue, even if I miss an entry, the next request to log, will push the missed entry as well. But this is not acceptable, specially if this happens for the last log entry of the application.
Also, please let me know whether and how I can implement the same, but using the new C# 5.0 async and await keywords with a cleaner code. I don't mind requiring .NET 4.5.
Thanks in Advance.
While you could likely get this to work, in my experience, I'd recommend, if possible, use an existing logging framework :) For instance, there are various options for async logging/appenders with log4net, such as this async appender wrapper thingy.
Otherwise, IMHO since you're going to be blocking a threadpool thread during your logging operation anyway, I would instead just start a dedicated thread for your logging. You seem to be kind-of going for that approach already, just via Task so that you'd not hold a threadpool thread when nothing is logging. However, the simplification in implementation I think benefits just having the dedicated thread.
Once you have a dedicated logging thread, you then only need have an intermediate ConcurrentQueue. At that point, your log method just adds to the queue and your dedicated logging thread just does that while loop you already have. You can wrap with BlockingCollection if you need blocking/bounded behavior.
By having the dedicated thread as the only thing that writes, it eliminates any possibility of having multiple threads/tasks pulling off queue entries and trying to write log entries at the same time (painful race condition). Since the log method is now just adding to a collection, it doesn't need to be async and you don't need to deal with the TPL at all, making it simpler and easier to reason about (and hopefully in the category of 'obviously correct' or thereabouts :)
This 'dedicated logging thread' approach is what I believe the log4net appender I linked to does as well, FWIW, in case that helps serve as an example.
I see two race conditions off the top of my head:
You can spin up more than one Thread if multiple threads call AddLogEntry. This won't cause lost events but is inefficient.
Yes, an event can be queued while the Thread is exiting, and in that case it would be "lost".
Also, there's a serious performance issue here: unless you're logging constantly (thousands of times a second), you're going to be spinning up a new Thread for each log entry. That will get expensive quickly.
Like James, I agree that you should use an established logging library. Logging is not as trivial as it seems, and there are already many solutions.
That said, if you want a nice .NET 4.5-based approach, it's pretty easy:
public abstract class BaseLogger
{
private readonly ActionBlock<LogEntry> block;
protected BaseLogger(int maxDegreeOfParallelism = 1)
{
block = new ActionBlock<LogEntry>(
entry =>
{
Log(entry);
},
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = maxDegreeOfParallelism,
});
}
public virtual void AddLogEntry(LogEntry entry)
{
block.Post(entry);
}
protected abstract void Log(LogEntry entry);
}
Regarding the loosing waiting messages on app crush because of unhandled exception, I've bound a handler to the event AppDomain.CurrentDomain.DomainUnload. Goes like this:
protected ManualResetEvent flushing = new ManualResetEvent(true);
protected AsyncLogger() // ctor of logger
{
AppDomain.CurrentDomain.DomainUnload += CurrentDomain_DomainUnload;
}
protected void CurrentDomain_DomainUnload(object sender, EventArgs e)
{
if (!IsEmpty)
{
flushing.WaitOne();
}
}
Maybe not too clean, but works.

Log4net, how to log a verbose message?

I can log info messages without a problem, but can't figure out how to log verbose messages.
Any help would be welcomed.
My problem is:
loggingEvent.Level can be checked in the Format function. The possible values are amongst others, Info, Debug, Error, Verbose. There are more, but these are the ones I'll be using mostly.
The actual log object only has the following methods:
Log.Info
Log.Debug
Log.Warn
Log.Error
As you can see - no verbose!
So how can I Log a verbose message, this is different to debug
Thanks in advance
You can add a Verbose (or Trace level) to log4net by using extension methods. This is what I'm using:
public static class ILogExtentions
{
public static void Trace(this ILog log, string message, Exception exception)
{
log.Logger.Log(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType,
log4net.Core.Level.Trace, message, exception);
}
public static void Trace(this ILog log, string message)
{
log.Trace(message, null);
}
public static void Verbose(this ILog log, string message, Exception exception)
{
log.Logger.Log(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType,
log4net.Core.Level.Verbose, message, exception);
}
public static void Verbose(this ILog log, string message)
{
log.Verbose(message, null);
}
}
Usage example:
public class ClientDAO
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(ClientDAO));
public void GetClientByCode()
{
log.Trace("your verbose message here");
//....
}
}
Source:
http://www.matthewlowrance.com/post/2010/07/14/Logging-to-Trace-Verbose-etc-with-log4net.aspx
You cannot figure out, because, AFAIK there is no "verbose" level in log4net. Is there one in log4j?
Following are the levels
ALL
DEBUG
INFO
WARN
ERROR
FATAL
OFF
Informational messages are the ones where you specify what you are doing currently in your application. Those messages spit out by OS commands or tools when you say -verbose, would be these kind of messages.
Debug messages are mostly for programmers and they allow you to write information such as variable creation, life-cycle, exception stack traces etc. Something that only the programmer/ support staff would be interested in.
[Edit]
Just thought of this. You can very well add a switch or config element to your application named "verbose" and then spit out the informational messages if set to true. Or wrap the logging in a helper method, which will log in log4net as well as send the same message to console. Also, you can use the ConsoleAppender to log messages to console. I have never used it though. Is this what you were looking for?
Hope this helps.
Apache log4net has the following log levels:
DEBUG < INFO < WARN < ERROR < FATAL
For messages considered more verbose than informational messages (INFO), the DEBUG level is the option to go for. Writing debug messages should be as simple as:
myLog.Debug("This is a pretty verbose message");
If you write extremely many debug messages and/or the messages are costly to produce (eg involves heavy string concatenation), consider adding a conditional around the logging:
if (myLog.IsDebugEnabled)
{
myLog.Debug("This is a pretty verbose message");
}
If you find yourself doing this often and want to DRY up your code, consider using extension methods for deferred message formatting, which will turn the above statement into this:
Log.Debug( () => "This is a pretty verbose message" );
In case off someone still need the answer (without using System.Reflection)
It's not necessary to set DeclaringType, just set null (auto resolve in Lo4Net)
public bool IsVerboseEnable { get { return _log.Logger.IsEnabledFor(Level.Verbose); } }
public string Verbose(string text)
{
_log.Logger.Log(null, Level.Verbose, text, null);
return text;
}
Tested & Validated
Code use in log4net
public virtual void Log(Type callerStackBoundaryDeclaringType, Level level, object message, Exception exception)
{
try
{
if (this.IsEnabledFor(level))
{
this.ForcedLog((callerStackBoundaryDeclaringType != null) ? callerStackBoundaryDeclaringType : Logger.declaringType, level, message, exception);
}
}
catch (Exception exception2)
{
LogLog.Error(Logger.declaringType, "Exception while logging", exception2);
}
}
I did not try it, but I think it should be quite straight-forward: Internally log4net knows a level "verbose"; it is only the ILog interface that does not expose it. Therefore it should be quite simple to add a IsVerboseEnabled and Verbose() method to this interface. Of course you need to be willing to change the log4net source code...
I've tested log4net with BasicConfigurator, and writing log messages generated output for all levels from EMERGENCY down to DEBUG, but not for TRACE or VERBOSE.
I needed to execute the code below for them to start logging.
var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
((Hierarchy)logRepository).Root.Level = Level.All;

Resources