Using .Net Core 3.1
I've implemented my event source like this:
[EventSource(Name = "RequestStatistics-Events")]
public sealed class RequestEventsProvider : EventSource
{
public RequestEventsProvider() : base(throwOnEventWriteErrors: false)
{
}
[Event(1, Level = EventLevel.Informational, Opcode = EventOpcode.Info)]
public void RequestProcessed(string requestPath, int responseCode, long processingTime)
{
WriteEvent(1, requestPath, responseCode, processingTime);
}
}
Then I collect tracing with dotnet-trace like this:
dotnet-trace collect --providers RequestStatistics-Events -p 23544
Then I open tracelog in PerfView and see my events:
As you can see every event contains stack within. It creates additional overhead though it is absolutely useless in my scenario. How can I disable stack collection?
Another question is: is it possible to disable stacks for Microsoft-Diagnostics-DiagnosticSource provider? I saw something like this in PerfView logs:
Enabling Provider:Microsoft-Diagnostics-DiagnosticSource Level:Informational Keywords:0xfffffffffffff7ff Stacks:1 Values:...blabla...
and I,ve tried to run collection with "stacks" key-value pair:
Microsoft-Diagnostics-DiagnosticSource:0xfffffffffffff7ff:4:Stacks=0
but it didn't affect anything.
Related
Quite a few questions/answers on this topic (only listing a couple that I found. There were many more).
C# Parallel - Adding items to the collection being iterated over, or equivalent?
ConcurrentQueue with multithreading
Thanks to many of them I've come up with what I'm hoping is a possible solution for my problem. I may also be overthinking it. I have an api that needs to write to a text file for logging purposes. Now the api is called N+ times and during each call, it needs to log the request. What I don't want to do is to stop the request from having to wait on the log to be recorded before returning the requested data. Now, the logs cannot just be dropped so it must also stack up on each request if the file is currently in use, using ReaderWriterLock for this. Then when the file isn't locked, I want to write the stacked logs.
I have come up with this in the hopes that it would satisfy the requirements but I think it will still cause a wait.
var wid = WindowsIdentity.GetCurrent().Token;
//add new log items
logs.Enqueue(helpers.createNewLog(requests));
string op;
while (logs.TryDequeue(out op))
{
using (WindowsIdentity.Impersonate(wid))
{
//write to text file, location on shared drive
var wrote = writers.WriteLog(op);
//item cannot be written since file locked, add back to queue to try again
if (!wrote)
{
logs.Enqueue(op);
}
}
}
Logs is a global like so
private static ConcurrentQueue<string> logs = new ConcurrentQueue<string>();
I feel like something isn't right but I'm struggling with what it is and which would be the best way in order for the requirements to be meet and still work in a web farm.
In my opinion, you should use a BlockingCollection instead of the ConcurrentQueue, here is an example of how you can use it as a Producer-Consumer is the same thing you are trying to do.
Now with ASP.Net you can insert modules to intercept every request, if you want to save a log, I suggest you register a module instead of going with your approach. On your Global.asax.cs you have a Register method
public class MvcApplication : System.Web.HttpApplication
{
public static void Register()
{
//registering an HttpModule
HttpApplication.RegisterModule(typeof(LogModule));
}
....
}
public class LogModule: IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.LogRequest += LogEvent;
}
private void LogEvent(object src, EventArgs args)
{
if (HttpContext.Current.CurrentNotification == RequestNotification.LogRequest)
{
if ((MvcHandler)HttpContext.Current.Handler != null)
{
Debug.WriteLine("This was logged!");
//Save the information to your file
}
}
}
}
Hope this helps
I am currently facing an issue related to logging messages in my WPF application.
I am keeping a static class for logging messages throughout my application which contains a function
private SomeService service = new SomeService();
private void LogMessage(string message)
{
service.Log(message);
}
My issue is in my screens where I require logging, I append strings from different places in the screen and pass it to the LogMessage function. I have very large data to be logged from different places within the screen.
Now the issue I am facing is that a new member has been introduced ie
public bool IsLoggingEnabled = false;
Now I need to check this condition each time before appending the string like this
if(ClassName.IsLoggingEnabled)
{
var msg = string.Format("Log 1 : {0}, Log 2 : {1}, Log 3 : {2} .... ", 0,1,2);
}
if(ClassName.IsLoggingEnabled)
{
msg += string.Format("Log 4 : {0}, Log 5 : {1}, Log 6 : {2} .... ", 4,5,6);
}
...............
ClassName.LogMessage(msg);
Could you please suggest a solution for handling this scenario?
Is it good to append all the messages and finally check the condition. Or check the condition within the LogMessage function?
But I felt these as wrong ways. Any suggestions would be appreciated.
You can instead check this parameter in your login class and keep it transparent to the other places you use it:
private void LogMessage(string message)
{
if(ClassName.IsLoggingEnabled)
{
service.Log(message);
}
}
About the string concatenation why not to just write it in separate logs - each log in it's own call. Makes code clearer and with less state.
Last, I think a better implementation is to have your class dependent on an ILogger instance and to just use it. Somewhere it'll be initialized and passed to your class. This will make it easier for you for change the logging class and to test your other classes.
With your current implementation, the IsLoggingEnabled property can be moved to the static LogMessage and the property can be set once when the project is loaded or through code or from external config file.
Using the Microsoft.Diagnostics.Tracing EventSource library (not to be mistaken for the System.Diagnostics.Tracing), it is possible to log certain messages to the event viewer by adding an Attribute to the Event annotation called 'Channel'. However this dumps the output to the 'Windows Logs\Application' area. How can I get this to log to 'Applications and Service Logs\MyApp\MyFeature' ?
Example code:
[EventSource(Name = "MyDemoApp")]
public sealed class MyDemoEventSource : EventSource
{
private MyDemoEventSource () { }
...
public const EventTask MyDemoTask = (EventTask) 12345;
...
[Event(12345,
Message = "My Demo Error: {0}",
Level = EventLevel.Warning,
Channel = EventChannel.Admin,
Task = Tasks.MyDemoTask,
Keywords = Keywords.Rule,
Opcode = Opcodes.Fail)]
private void SomethingWentWrong(string ErrorMessage)
{
WriteEvent(12345, ErrorMessage);
}
With thanks to Matthew Watson for pointing me in the direction of this article, the solution to the problem is contained within:
https://blogs.msdn.microsoft.com/dotnet/2014/01/30/microsoft-diagnostics-tracing-eventsource-is-now-stable/
*Remember to register your EventSource as this is the step that actually creates the entries in the Event Viewer, a unique name is required (if your company/product already has an entry in the Event Viewer for other purposes make sure you use a new name).
Before tracing to a TraceSource, should the "Trace Level" be checked prior to issuing the trace itself?
var ts = new TraceSource("foo");
ts.Switch.Level = SourceLevels.Warning;
if (/* should there be a guard here? and if so, what? */) {
ts.TraceEvent(TraceEventType.Warning, 0, "bar");
}
While there is SourceSwitch.ShouldTrace(TraceEventType), the documentation indicates
Application code should not call this method; it is intended to be called only by methods in the TraceSource class.
It appears that pre-TraceSource model employed the TraceSwitch (not SourceSwitch) class which had various TraceXYZ methods (for this purpose?), but such appears to be not needed/used/mentioned with the TraceSource model.
(Having the guard outside the trace method affects evaluation of expressions used in/for the call - of course side-effects or computationally expensive operations in such are "bad" and "ill-advised", but I'd still like focus on the primary question.)
As per expensive trace parameters computation I came up with the following:
internal sealed class LazyToString
{
private readonly Func<object> valueGetter;
public LazyToString(Func<object> valueGetter)
{
this.valueGetter = valueGetter;
}
public override string ToString()
{
return this.valueGetter().ToString();
}
}
The usage would be
traceSource.TraceEvent(TraceEventType.Verbose, 0, "output: {0}", new LazyToString(() =>
{
// code here would be executed only when needed by TraceSource
// so it can contain some expensive computations
return "1";
}));
Any better idea?
I know that in NLog you generally just do the trace at whatever level you want and it will take care of whether or not the log level should be traced or not.
To me it looks like TraceSource works the same way.
So I would say "No" you probably shouldn't check.
Test it out by setting different trace levels and tracing messages at different levels and see what gets traced.
I think in terms of performance you are generally ok if you use the methods defined on the class:
Based on an example from: http://msdn.microsoft.com/en-us/library/sdzz33s6.aspx
This is good:
ts.TraceEvent(TraceEventType.Verbose, 3, "File {0} not found.", "test");
This would be bad:
string potentialErrorMessageToDisplay = string.Format( "File {0} not found.", "test" );
ts.TraceEvent(TraceEventType.Verbose, 3, potentialErrorMessageToDisplay );
In the first case the library probably avoids the call to string.Format if the error level won't be logged anyway. In the second case, string.Format is always called.
Are strings you provide to the message argument expensive? A constant or literal is pretty cheap. If that is the case, don't worry about it, use the trace switch/trace listener filters, etc to reduce the amoount of trace processed (and the perf cost of trace) (BTW, the default trace listener is very expensive, always clear the trace listeners before adding the ones you want)
System.Diagnostics doesn't have anything to make a inactive TraceSource invocation costless. Even if you use the listener filters, or set the trace switch to zero (turn it off) the TraceEvent will be invoked and the message string will be constructed.
Imagine that the trace string is expensive to calculate, for example, it iterates across all the rows in a dataset and dumps them to a string. That could take a not trivial number of milliseconds.
To get around this you can make the string building part wrapped in a function that has a conditional attribute to turn it off in release mode, or use wrapper method that takes a lambda expression or a Func that creates the string (and isn't executed when not needed)
Like #nexuzzz suggests, there could be situations where calculation of event parameter is expensive. Here is what I could think of.
Suggestions to developers would be: "If you don't have string argument readily available, use the lambda version of TraceInformation or TraceWarning.
public class TraceSourceLogger : ILogger
{
private TraceSource _traceSource;
public TraceSourceLogger(object that)
{
_traceSource = new TraceSource(that.GetType().Namespace);
}
public void TraceInformation(string message)
{
_traceSource.TraceInformation(message);
}
public void TraceWarning(string message)
{
_traceSource.TraceEvent(TraceEventType.Warning, 1, message);
}
public void TraceError(Exception ex)
{
_traceSource.TraceEvent(TraceEventType.Error, 2, ex.Message);
_traceSource.TraceData(TraceEventType.Error, 2, ex);
}
public void TraceInformation(Func<string> messageProvider)
{
if (_traceSource.Switch.ShouldTrace(TraceEventType.Information))
{
TraceInformation(messageProvider());
}
}
public void TraceWarning(Func<string> messageProvider)
{
if (_traceSource.Switch.ShouldTrace(TraceEventType.Warning))
{
TraceWarning(messageProvider());
}
}
}
Currently I have a custom built static logging class in C# that can be called with the following code:
EventLogger.Log(EventLogger.EventType.Application, string.Format("AddData request from {0}", ipAddress));
When this is called it simply writes to a defined log file specified in a configuration file.
However, being that I have to log many, many events, my code is starting to become hard to read because all of the logging messages.
Is there an established way to more or less separate logging code from objects and methods in a C# class so code doesn't become unruly?
Thank you all in advance for your help as this is something I have been struggling with lately.
I like the AOP Features, that PostSharp offers. In my opinion Loggin is an aspect of any kind of software. Logging isn't the main value an application should provide.
So in my case, PostSharp always was fine. Spring.NET has also an AOP module which could be used to achieve this.
The most commonly used technique I have seen employs AOP in one form or another.
PostSharp is one product that does IL weaving as a form of AOP, though not the only way to do AOP in .NET.
A solution to this is to use Aspect-oriented programming in which you can separate these concerns. This is a pretty complex/invasive change though, so I'm not sure if it's feasible in your situation.
I used to have a custom built logger but recently changed to TracerX. This provides a simple way to instrument the code with different levels of severity. Loggers can be created with names closely related to the class etc that you are working with
It has a separate Viewer with a lot of filtering capabilities including logger, severity and so on.
http://tracerx.codeplex.com/
There is an article on it here: http://www.codeproject.com/KB/dotnet/TracerX.aspx
If your primary goal is to log function entry/exit points and occasional information in between, I've had good results with an Disposable logging object where the constructor traces the function entry, and Dispose() traces the exit. This allows calling code to simply wrap each method's code inside a single using statement. Methods are also provided for arbitrary logs in between. Here is a complete C# ETW event tracing class along with a function entry/exit wrapper:
using System;
using System.Diagnostics;
using System.Diagnostics.Tracing;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace MyExample
{
// This class traces function entry/exit
// Constructor is used to automatically log function entry.
// Dispose is used to automatically log function exit.
// use "using(FnTraceWrap x = new FnTraceWrap()){ function code }" pattern for function entry/exit tracing
public class FnTraceWrap : IDisposable
{
string methodName;
string className;
private bool _disposed = false;
public FnTraceWrap()
{
StackFrame frame;
MethodBase method;
frame = new StackFrame(1);
method = frame.GetMethod();
this.methodName = method.Name;
this.className = method.DeclaringType.Name;
MyEventSourceClass.Log.TraceEnter(this.className, this.methodName);
}
public void TraceMessage(string format, params object[] args)
{
string message = String.Format(format, args);
MyEventSourceClass.Log.TraceMessage(message);
}
public void Dispose()
{
if (!this._disposed)
{
this._disposed = true;
MyEventSourceClass.Log.TraceExit(this.className, this.methodName);
}
}
}
[EventSource(Name = "MyEventSource")]
sealed class MyEventSourceClass : EventSource
{
// Global singleton instance
public static MyEventSourceClass Log = new MyEventSourceClass();
private MyEventSourceClass()
{
}
[Event(1, Opcode = EventOpcode.Info, Level = EventLevel.Informational)]
public void TraceMessage(string message)
{
WriteEvent(1, message);
}
[Event(2, Message = "{0}({1}) - {2}: {3}", Opcode = EventOpcode.Info, Level = EventLevel.Informational)]
public void TraceCodeLine([CallerFilePath] string filePath = "",
[CallerLineNumber] int line = 0,
[CallerMemberName] string memberName = "", string message = "")
{
WriteEvent(2, filePath, line, memberName, message);
}
// Function-level entry and exit tracing
[Event(3, Message = "Entering {0}.{1}", Opcode = EventOpcode.Start, Level = EventLevel.Informational)]
public void TraceEnter(string className, string methodName)
{
WriteEvent(3, className, methodName);
}
[Event(4, Message = "Exiting {0}.{1}", Opcode = EventOpcode.Stop, Level = EventLevel.Informational)]
public void TraceExit(string className, string methodName)
{
WriteEvent(4, className, methodName);
}
}
}
Code that uses it will look something like this:
public void DoWork(string foo)
{
using (FnTraceWrap fnTrace = new FnTraceWrap())
{
fnTrace.TraceMessage("Doing work on {0}.", foo);
/*
code ...
*/
}
}
To make the code readable, only log what you really need to (info/warning/error). Log debug messages during development, but remove most when you are finished. For trace logging, use
AOP to log simple things like method entry/exit (if you feel you need that kind of granularity).
Example:
public int SomeMethod(int arg)
{
Log.Trace("SomeClass.SomeMethod({0}), entering",arg); // A
if (arg < 0)
{
arg = -arg;
Log.Warn("Negative arg {0} was corrected", arg); // B
}
Log.Trace("SomeClass.SomeMethod({0}), returning.",arg); // C
return 2*arg;
}
In this example, the only necessary log statement is B. The log statements A and C are boilerplate, logging that you can leave to PostSharp to insert for you instead.
Also: in your example you can see that there is some form of "Action X invoked by Y", which suggests that a lot of your code could in fact be moved up to a higher level (e.g. Command/Filter).
Your proliferation of logging statements could be telling you something: that some form of design pattern could be used, which could also centralize a lot of the logging.
void DoSomething(Command command, User user)
{
Log.Info("Command {0} invoked by {1}", command, user);
command.Process(user);
}
I think it is a good option to implement something similar to filters in ASP.NET MVC. This is implement with the help of attributes and reflection. You mark every method you want to log in a certain way and enjoy. I suppose there might be a better way to do it, may be with the help of Observer pattern or something but as long as I thought about it I couldn't think of something better.
Basically such problems are called cross-cutting concerns and can be tackled with the help of AOP.
I also think that some interesting inheritance schema can be applied with log entities at the base but I would go for filters