At least by default, ConsoleTraceListener starts its trace messages with the name of the executable and the mode. E.g.:
myExecutable.exe Information: 0 : Saving 3602 row(s)...
It's a bit of an eyesore. Is there a way to get rid of the prefix and only output the message itself except inheriting and overriding the class?
Sorry of it's too much of a first world problem.
Yes, you can customize the format of the trace messages that are output by the ConsoleTraceListener but you'll have to override it as far as I know.
To do this, you need to create a new class that derives from ConsoleTraceListener and override the TraceEvent method.
In the overridden method, you can use the base implementation of the method to get the default formatting for the trace message, and then modify it to remove the prefix.
Here is an example of how to create a custom ConsoleTraceListener that removes the prefix from trace messages:
public class CustomConsoleTraceListener : ConsoleTraceListener
{
public CustomConsoleTraceListener()
{
}
public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message)
{
// Call the base implementation to get the default formatting for the trace message
string formattedMessage = base.FormatMessage(eventCache, source, eventType, id, message);
// Remove the prefix from the formatted message
int index = formattedMessage.IndexOf(" : ");
if (index >= 0)
{
formattedMessage = formattedMessage.Substring(index + 3);
}
// Output the formatted message to the console
Console.WriteLine(formattedMessage);
}
}
To use the custom ConsoleTraceListener, you simply create an instance of the CustomConsoleTraceListener class and add it to the Trace.Listeners collection:
CustomConsoleTraceListener listener = new CustomConsoleTraceListener();
Trace.Listeners.Add(listener);
It's a bit of a pain in the code but hope this helps!
I'll try achieving this without overriding the method, I'll edit my answer if I manage to do it properly.
Related
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);
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()));
It seems that CodeContract from DevLab is a nice tool, but I had two errors in with code:
public class SomeClass
{
private DataTable _dataTable
// I don't want to write the same condition more then ones, so incapsulate it
private void CheckRowIndex(int rowIndex)
{
//Error1 in next line: User message to contract call can only be string literal, or a static
// field, or static property that is at least internally visible.
Contract.Requires<IndexOutOfRangeException>(_dataTable.Rows.Count >= rowIndex + 1,
String.Format("There is no row with index {0} in table.", rowIndex));
}
public object GetObject(int rowIndex, int colIndex)
{
// Error2 in next line: malformed contract
CheckRowIndex();
return _dataTable.Rows[rowIndex][colIndex];
}
public object GetObject(int rowIndex, string colName)
{
CheckRowIndex();
return _dataTable.Rows[rowIndex][colName];
}
}
Are there any techniques how to avoid it?
For point #1 have a look here
Contract overloads taking a userMessage such as Requires(bool condition, string userMessage) require that the userMessage message be a literal, or static (e.g. static readonly), or const, as per the error message.
Since the user message is for you, the developer, not for users why not just make it generic:
String.Format("There is no row with this index in the table");
There's more of a discussion on what to put in the (IMO badly named) userMessage parameter here
I posted this question on the StoryQ discussion boards, but by looking at the (lack of) responses to other questions, activity there seems sparse at best. I thought I'd let everyone here have a go.
Is there a way to modify or configure the output (both output window and file) to include custom strings? For example, one of my stories requires that a specific exception is thrown. To do this, I catch the exception and save it, then in a separate method test that it's non-null and of the required type. I'd like to be able to append the type of the exception to the output (much like parameters are appended to method calls).
For example
.Then(ExceptionIsThrown<ArgumentNullException>)
would result in the following output
then exception is thrown (ArgumentNullException)
Thanks to Giorgio Minardi for guiding me to look into the StoryQ.Formatting namespace. There I discovered that I can override the method formatting using a simple attribute.
The API provides an OverrideMethodFormatAttribute (subclassed from the abstract class MethodFormatAttribute), which works if you want to use a specific string constant, but C# doesn't like the method's type parameters in attributes. This doesn't compile due to the T in the attribute:
[OverrideMethodFormat(string.Format("exception is thrown ({0})", typeof(T).Name))]
private void ExceptionIsThrown<T>() where T : Exception
{
...
}
The solution is to create another MethodFormatAttribute subclass that specifically searches the method for generic types and output them. This subclass is below:
public class GenericMethodFormatAttribute : MethodFormatAttribute
{
private readonly string _textFormat;
public GenericMethodFormatAttribute()
{
_textFormat = null;
}
public GenericMethodFormatAttribute(string textFormat)
{
_textFormat = textFormat;
}
public override string Format(MethodInfo method,
IEnumerable<string> parameters)
{
var generics = method.GetGenericArguments();
if (_textFormat == null)
{
var genericsList = string.Join<Type>(", ", generics);
return string.Format("{0} ({1})",
UnCamel(method.Name),
genericsList);
}
return string.Format(_textFormat, generics);
}
}
Usage is almost like the supplied attribute, except that you optionally supply a format string instead of a string constant. Omitting the format string un-camel-cases the method name just like the default behavior.
[GenericMethodFormatAttribute]
private void ExceptionIsThrown<T>() where T : Exception
{
...
}
This allows me to declare the attribute in my source, while not having to touch the StoryQ code. Ten points to StoryQ for extensibility!
Best thing is to look at the sources of StoryQ, in particular look at the StoryQ.Formatting namespace. To get a particular output you should follow the FluenInterface pattern used within the framework and wrote your own method, something like ThenExceptionIsThrown(Exception ex) and chain it like the other methods in the story.
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. :)