I'm using a 3rd party library which makes several calls to the function:
Trace.WriteLine(string message);
This clutters up the visual studio output window and makes debugging my application difficult (for instance; XAML binding warnings).
I'm trying to find a way to stop all trace messages from a specific dll from dumping to the visual studio output window - is writing my own TraceListener the only path forward?
I can't make a TraceFilter / EventTypeFilter work for a string message without category -- although I can't find the documentation to back this up -- empirically:
TraceFilter.ShouldTrace(...)
is called by the following functions (not a complete set):
Trace.WriteLine(string message, string category);
Trace.TraceError(string message);
Trace.WriteLine(object o);
but isn't called by:
Trace.WriteLine(string message);
Does anyone know why this call avoids the ShouldTrace filter?
If you don't want to create your own TraceListener, the only way to suppress Trace messages from a problematic dll is to stop all Trace messages by using Trace.Listeners.Clear().
Note that this will stop your own Trace calls as well. I am mentioning this because I know of a few applications that never used Trace.WriteLine and were getting a severe performance hit from a very noisy library constantly writing to the output window.
I would recommend creating a TraceListener that uses reflection to look for the dll you want to ignore in the call stack.
It's not possible to override Trace.WriteLine, but it is possible to override some calls in the default TraceListener to achieve the same effect.
Using a TraceListener like the one below can help you clean up your output window in Visual Studio so you can focus on the events you are interested in, rather than getting bombarded by messages from a third party library.
See sample code below:
using System;
using System.Diagnostics;
using System.Reflection;
// The library that calls Trace, causing the messages you want to suppress.
using NoisyLibrary;
namespace TraceSuppress
{
/// <summary>
/// Trace listener that ignores trace messages from a specific assembly.
/// </summary>
public class AssemblyFilteredListener : DefaultTraceListener
{
private Assembly assemblyToIgnore;
public AssemblyFilteredListener(Assembly assemblyToIgnoreTracesFrom)
{
this.assemblyToIgnore = assemblyToIgnoreTracesFrom;
}
public bool TraceIsFromAssemblyToIgnore()
{
StackTrace traceCallStack = new StackTrace();
StackFrame[] traceStackFrames = traceCallStack.GetFrames();
// Look for the assembly to ignore in the call stack.
//
// This may be rather slow for very large call stacks. If you find that this is a bottleneck
// there are optimizations available.
foreach (StackFrame traceStackFrame in traceStackFrames)
{
MethodBase callStackMethod = traceStackFrame.GetMethod();
bool methodIsFromAssemblyToIgnore = (callStackMethod.Module.Assembly == this.assemblyToIgnore);
if (methodIsFromAssemblyToIgnore)
{
return true;
}
}
// The assembly to ignore was not found in the call stack.
return false;
}
public override void WriteLine(string message)
{
if (!this.TraceIsFromAssemblyToIgnore())
{
base.WriteLine(message);
}
}
public override void Write(string message)
{
if (!this.TraceIsFromAssemblyToIgnore())
{
base.Write(message);
}
}
}
class Program
{
static void SetupListeners()
{
// Clear out the default trace listener
Trace.Listeners.Clear();
// Grab the asssembly of the library, using any class from the library.
Assembly assemblyToIgnore = typeof(NoisyLibrary.LibraryClass).Assembly;
// Create a TraceListener that will ignore trace messages from that library
TraceListener thisApplicationOnlyListener = new AssemblyFilteredListener(assemblyToIgnore);
Trace.Listeners.Add(thisApplicationOnlyListener);
// Now the custom trace listener is the only listener in Trace.Listeners.
}
static void Main(string[] args)
{
SetupListeners();
// Testing
//-------------------------------------------------------------------------
// This still shows up in the output window in VS...
Trace.WriteLine("This is a trace from the application, we want to see this.");
// ...but the library function that calls trace no longer shows up.
LibraryClass.MethodThatCallsTrace();
// Now check the output window, the trace calls from that library will not be present.
}
}
}
According to ILSpy, the Trace.WriteLine(string message) is declared as abstract and needs to be overridden by derived classes:
public abstract void WriteLine(string message);
All other methods you mention check the ShouldTrace and ultimately call the Trace.WriteLine(string message) message.
E.g.:
public virtual void WriteLine(string message, string category)
{
if (Filter != null &&
!Filter.ShouldTrace(null, "", TraceEventType.Verbose, 0, message))
{
return;
}
if (category == null)
{
WriteLine(message);
return;
}
WriteLine(category + ": " + ((message == null) ? string.Empty : message));
}
So the real reason is in my opinion, a decision of the designer of the Trace class.
He could have made that Trace.WriteLine(string message) protected to incidate that it is not intended to be called directly, e.g.:
protected abstract void WriteLine(string message);
Related
I was wondering what Debug.WriteLine() does. I see it all the time in many different codes, but I don't get what it's supposed to do.
What I found out so far:
"Writes information about the debug to the trace listeners in the
Listeners collection."
It will show the message/text in your output window at the bottom of Visual Studio, you can log with it some actions like "Constructor just started" then it is easier to find where error appeared. Another thing is that you can add variables to your debug output like:
Debug.WriteLine("Debug message:Shop.Add.Product({0})", Product);
Check it here: Debug.WriteLine Method
This can be used to trace or log messages in debug versions. It is only executed if your program is compiled as debug version (with the DEBUG symbol defined).
You can create own TraceListeners to catch the messages and log them as you need. In order to do that, you have to inherit from the abstract TraceListener class:
public class MyListener : TraceListener
{
public override void Write(string message)
{
// log to file or db or whatever you need
}
public override void WriteLine(string message)
{
// log to file or db or whatever you need
}
}
Then you have to register an instance of your listener:
public static void Main()
{
MyListener listener = new MyListener();
Debug.Listeners.Add(listener);
// this ends up in MyListener.WriteLine, but only in a debug version
Debug.WriteLine("This is a debug log message");
Debug.Listeners.Remove(listener);
}
Further reading: How to: Create and Initialize Trace Listeners
Visual Studio always adds its own TraceListener when debugging and outputs the messages to the output window's debug pane.
Yes, it works exactly according to what you stated in the question, source for this method looks something like (simplified):
public static void WriteLine(string message)
{
foreach (TraceListener listener in Listeners)
{
listener.WriteLine(message);
if (AutoFlush)
{
listener.Flush();
}
}
}
So it simply calls the TraceListener.WriteLine method for each registered trace listener, just like Trace.WriteLine does. You can register trace listeners through config files or code.
The only difference between Trace.WriteLine and Debug.WriteLine is that they are compiled based on different conditionals:
public class Debug
{
// this will be optimized away if "DEBUG" symbol is not defined
// in project build properties
[System.Diagnostics.Conditional("DEBUG")]
public static void WriteLine(string message) { ... }
}
public class Trace
{
// this will be optimized away if "TRACE" symbol is not defined
// in project build properties
[System.Diagnostics.Conditional("TRACE")]
public static void WriteLine(string message) { ... }
}
I have a .NET winforms application and i am trying to avoid the cumbersome of a debug mode.
As it is the user selects to Enable Debug and by that some operations will take place like writing a log,displaying messages and so on..
I would like to avoid the repeating of
If me.DebugMode then
Write a log
Display A Message on the textBox
.....
There are several / alot of methods that i use and i don't like the idea of polluting the code with the above code
Any recommendations more than welcome
P.S because i have some "complaints" about the "wrong" tag here is the same pseudocode in C# with some extra
if(DebugMode.Checked ==true)
{
Write A log
Display A messagge on the textbox
Dump data as CSV
Activate Tab for Comparing data Before/After
}
Here's an approach.
Let's say I have this code:
void Main()
{
var dc = new DistanceConversion();
var miles = 4.5;
Console.WriteLine("{0} miles is {1} kilometres", miles, dc.MilesToKilometres(miles));
}
public class DistanceConversion
{
public double MilesToKilometres(double miles)
{
return miles * 8.0 / 5.0;
}
}
When I run this I get:
4.5 miles is 7.2 kilometres
I can use a dependency injection library to allow me to create an instance of an interface.
void Main()
{
// Somewhere in my configuration
var injectivity = Injectivity.Context.CreateRoot();
injectivity.SetFactory<IDistanceConversion, DistanceConversion>();
// Here's the previous example using dependency injection.
var dc = injectivity.Resolve<IDistanceConversion>();
var miles = 4.5;
Console.WriteLine("{0} miles is {1} kilometres", miles, dc.MilesToKilometres(miles));
}
public interface IDistanceConversion
{
double MilesToKilometres(double miles);
}
public class DistanceConversion : IDistanceConversion
{
public double MilesToKilometres(double miles)
{
return miles * 8.0 / 5.0;
}
}
When I run this I get:
4.5 miles is 7.2 kilometres
Now I can introduce a logging decorator:
public class DistanceConversionLoggingDecorator
: Injectivity.DecoratorBase<IDistanceConversion>, IDistanceConversion
{
public double MilesToKilometres(double miles)
{
Console.WriteLine("CONVERTING " + miles);
return this.Inner.MilesToKilometres(miles);
}
}
And imply put one line in the configuration section:
injectivity.SetDecorator<IDistanceConversion, DistanceConversionLoggingDecorator>();
When I run this I get:
CONVERTING 4.5
4.5 miles is 7.2 kilometres
So, without changing my code I can inject logging into my code at config.
I can also go ahead and apply attributes to my classes:
[Injectivity.Attributes.Decorator(typeof(IDistanceConversion))]
public class DistanceConversionLoggingDecorator
: Injectivity.DecoratorBase<IDistanceConversion>, IDistanceConversion
{ ... }
[Injectivity.Attributes.Factory(typeof(IDistanceConversion))]
public class DistanceConversion : IDistanceConversion
{ ... }
Now instead of using my SetFactory and SetDecorator methods I can use this instead:
injectivity.Register(this.GetType().Assembly);
Finally, if I wish I can avoid attributes and define an XML file for configuration, then I just do this:
var injectivity = Injectivity.Context.LoadRoot("config.xml");
Now simply by changing my config file I can turn on or turn off logging without changing my code and with cluttering it with loads of if statements and logging commands.
Create a class derived from the Form class and implement the desired behaviour in that. Then derive all your forms from this new class.
You could write a helper class that takes a flag and a delegate to be executed only if the flag is true. In this example, the delegate also returns a string which is added to the written to the console output (it could just as easily write to a log file).
static class DebugLog
{
static public void Write(bool flag, Func<string> f)
{
if (flag) Console.WriteLine(f);
}
}
You would call it like this:
DebugLog.Write(this.DebugMode, () => "This is a string I wish to log");
If you want to include some additional processing, you can enclose the delegate body in {} and add additional statements:
DebugLog.Write(this.DebugMode, () => {
this.DisplayMessage("You're debugging!");
return "This is a string I wish to log");
});
P.S. You used me in your example but you tagged this post c#, so my example is in c#.
If the debug flag is part of global state, you can simplify the individual calls.
static class DebugLog
{
static public bool DebugMode = true;
static public void Write(Func<string> f)
{
if (DebugMode) Console.WriteLine(f);
}
}
which makes it simpler to call, like this:
DebugLog.Write(() => "This is a string I wish to log");
Read about postsharp https://www.postsharp.net/diagnostics/net-logging
It's the more elegant way that I can imagine
You could use a logging framework like log4net with properly planed invocation of different logging levels like debug, info, warning, error or fatal.
You then manage activation and deactivation of logging either generally or fine grainer with restriction to minimal level and target (console, file, eventlog, database etc.).
In general a proper logging should be an obligatory part of the source code.
I wrote such a thing for WPF and posted on codeproject quite some time ago.
It basically consists of three parts:
A class that inherits from TraceListener that routes trace messages
to a UI component
A UI component that listens for trace output and displays
A binder (ITraceTextSink) that the TraceListener uses to send output to the UI
The same concept can easily be applied to WinForms by replacing the UI and binding code.
This allows you to sprinkle Trace.WriteLine like you normally would wherever you want without worrying if "debug" mode is on or not. "Debug" mode consists of attaching the TraceListener and displaying the UI.
If you poke around the code in the linked codeproject example it should make some sense.
The part that would work without change in WinForms is the TraceListener which looks like this (you'd have to implement an ITraceTextSink to proxy the message to a Winforms UI component. This is done with a FlowDocument in this WPF version but text could be pumped into a RichTextBox control as it arrives pretty easily).
sealed class TraceTextSource : TraceListener
{
public ITraceTextSink Sink { get; private set; }
private bool _fail;
private TraceEventType _eventType = TraceEventType.Information;
public TraceTextSource(ITraceTextSink sink)
{
Debug.Assert(sink != null);
Sink = sink;
}
public override void Fail(string message)
{
_fail = true;
base.Fail(message);
}
public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message)
{
_eventType = eventType;
base.TraceEvent(eventCache, source, eventType, id, message);
}
public override void Write(string message)
{
if (IndentLevel > 0)
message = message.PadLeft(IndentLevel + message.Length, '\t');
if (_fail)
Sink.Fail(message);
else
Sink.Event(message, _eventType);
_fail = false;
_eventType = TraceEventType.Information;
}
public override void WriteLine(string message)
{
Write(message + "\n");
}
}
Once you implement the ITraceTextSource turning on "debug" entails adding it to the collection of trace listeners.
Trace.Listeners.Add(new TraceTextSource(new YourTraceSink()));
I have built a c# .net 4.0 library.
all of the methods are public and static.
i want to add an aspect using an aspect programming library that does something like this:
try block
1. call method (if method throws exception)
catch block
2. log the exception and massage the exception
it is a dll (class library project)
can you please advice if there is a way to add try/catch routines in one class instead of wrapping around all methods one by one?
Because you had mentioned word static neither ninject nor castle-windsor nor anything else based upon castle-dynamicproxy would help you, because they able to add aspects around regular method. So you have two options:
Handwritten tracing decorator
Add separate handwritten tracing decorator that will add required functionality without altering of existing code
Benefits
Simple and easy to write yourself
Drawbacks
Almost no call context. This is important for tracing, if you like to know what method actually has been called and what parameters had been passed, etc.
New layer of abstraction around existed code. Instead of calling your static methods, you have to call Decorator that will call your static methods inside
Example
// Decorated calls
TraceDecorator.Aspect(() => StaticLogic.SuccessfulCall());
TraceDecorator.Aspect(() => StaticLogic.ExceptionCall());
TraceDecorator.Aspect(() => StaticLogic.SuccessfulCallWithReturn(42));
TraceDecorator.Aspect(() => StaticLogic.ExceptionCallWithReturn(42));
// Decorator itself
public static class TraceDecorator
{
public static T Aspect<T>(Func<T> func)
{
try
{
return func();
}
catch(Exception ex)
{
LogException(ex);
return default(T);
}
}
public static void Aspect(Action func)
{
try
{
func();
}
catch(Exception ex)
{
LogException(ex);
}
}
private static void LogException(Exception ex)
{
Console.WriteLine("Traced by TraceDecorator: {0}", ex);
}
}
Full sample available here
PostSharp
Take a look at Non-Invasive Tracing & Logging with postsharp
Benefits
Broadcast your aspect without altering existing code or adding attributes by yourself, whatever you found suitable
Separation of concerns: tracing/logging are separated from your logic
and alot more …
Drawbacks
Nothing come for free. But there is a free PostSharp edition available with limited functionality
Sometimes integration with other tools because of post-compilation
See NConcern .NET AOP Framework, an open source project.
Example
Your static class
static public class Calculator
{
static public int Add(int a, int b)
{
return a + b;
}
}
Logger
static public class Logger
{
static public void Log(MethodInfo method, object[] arguments, Exception exception)
{
Console.WriteLine("{0}({1}) exception = {2}", method.Name, string.Join(", ", arguments), exception.Message);
}
}
Aspect : log on exception
public class Logging : IAspect
{
public IEnumerable<IAdvice> Advise(MethodInfo method)
{
yield return Advice.Basic.After.Throwing((instance, arguments, exception) =>
{
Logger.Log(method, arguments, exception);
});
}
}
Joinpoint : methods of Calculator
var calculatorMethods = new Func<MethodInfo, bool>(method => method.ReflectedType == typeof(Calculator));
Activate the logging aspect for joinpoint
Aspect.Weave<Logging>(calculatorMethods);
I have a multicast OnExceptionAspect from Postsharp which is applied on the assembly level. This naturally means that all methods, upon throwing an exception, will invoke the Aspect.
Within the Aspect I'm logging the exception details including the values of the parameters passed when the exception occured, this is working properly.
However because this is applied to all methods in the assembly a log entry is created for each method in the stack as the exception bubbles up through each.
I'm out of ideas on how to prevent this, initially I was going to compare the exception (to see if it's the same one) but this just seems messy. Someone must have had this problem before, any ideas?
There are two solutions to this problem.
A. Use a thread-static field to store any exception that has already been logged.
[Serializable]
public class MyAspect : OnExceptionAspect
{
[ThreadStatic]
private static Exception lastException;
public override void OnException(MethodExecutionArgs args)
{
if(args.Exception != lastException)
{
string msg = string.Format("{0} had an error # {1}: {2}\n{3}",
args.Method.Name, DateTime.Now,
args.Exception.Message, args.Exception.StackTrace);
Trace.WriteLine(msg);
lastException = args.Exception;
}
}
}
B. Add a tag to the Exception object.
[Serializable]
public class MyAspect : OnExceptionAspect
{
private static object marker = new object();
public override void OnException(MethodExecutionArgs args)
{
if(!args.Exception.Data.Contains(marker))
{
string msg = string.Format("{0} had an error # {1}: {2}\n{3}",
args.Method.Name, DateTime.Now,
args.Exception.Message, args.Exception.StackTrace);
Trace.WriteLine(msg);
args.Exception.Data.Add(marker, marker);
}
}
}
FYI--Gael is a PostSharp guru because he is employed there...just so you are aware.
For what it is worth you can always tell where the exception originated by examining the StackTrace. The StackTrace is made available via args.Exception.StackTrace. You may try what Dustin Davis (another PostSharp employee) recommends here: PostSharp - OnExceptionAspect - Get line number of exception
Parse the StackTrace (via the method outlined here: How to split a stacktrace line into namespace, class, method file and line number?) then compare the args.Method.Name with the parsed results. If your args.Method.Name is the same as the originating method (found via parsing the StackTrace) then you know you should log it otherwise ignore.
Here is some code to make my solution more concrete (building on the prior two solutions cited):
[Serializable]
public class ExceptionWrapper : OnExceptionAspect
{
public override void OnException(MethodExecutionArgs args)
{
var st = new StackTrace(args.Exception, true);
var frame = st.GetFrame(0);
var lineNumber = frame.GetFileLineNumber();
var methodName = frame.GetMethod().Name;
if(methodName.Equals(args.Method.Name))
{
string msg = string.Format("{0} had an error # {1}: {2}\n{3}",
args.Method.Name, DateTime.Now,
args.Exception.Message, args.Exception.StackTrace);
Trace.WriteLine(msg);
}
}
}
(Or, honestly, you could just use one of Gael's recommended solutions.)
One way i could see this being done would be to define a custom exception and just throw that one in your aspect. then also in your aspect check the exception before loggin, if it's not your custom exception log it, otherwise don't log it and (re-throw?).
That's what the example code would look like:
[Serializable]
public class DatabaseExceptionWrapper : OnExceptionAspect
{
public override void OnException(MethodExecutionArgs args)
{
if(!(args.Exception is CustomException))
{
string msg = string.Format("{0} had an error # {1}: {2}\n{3}",
args.Method.Name, DateTime.Now,
args.Exception.Message, args.Exception.StackTrace);
Trace.WriteLine(msg);
}
throw new CustomException("There was a problem");
}
}
Of course you'd still have to define that exception and everything. :)
I want to implement a custom trace listener like follows:
public class TraceListener : System.Diagnostics.TraceListener
{
public override void Write(string message)
{
LogToDatabase(message);
}
public override void WriteLine(string message)
{
LogToDatabase(message);
}
}
Now suppose an error occurs somewhere in the code. In catch block I want to do
Trace.TraceError(ex.ToString())
where ex is caught exception.
Now the problem is that in my MyTraceListener the message parameters of Write method and WriteLine method are different. And even more interesting the string generated by ex.ToString() is passed as parameter in WriteLine method but not in Write.
In fact Trace.TraceError() method invokes two methods: First it will execute Write() to print/write the source of an error along with error code and method WriteLine() to print/write error description.
PS: Before adding an instance of Custom TraceListener, Use Clear() method to remove default instance of trace listener.