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) { ... }
}
Related
I would like to list down the method call sequence from top to bottom in my .net project.
using System;
public class Program
{
public static void Main()
{
One();
}
public static void One(){
Two();
}
public static void Two(){
Three();
}
public static void Three(){
Four();
}
public static void Four(){
Console.WriteLine("Hello World!");
}
}
In the above sample class I required to get the log like
"Main()->One()->Two()->Three()->Four()"
you can use System.Diagnostics.StackTrace to get the current stackTrace and use it to log the required:
Demo as per your code:
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
One();
}
public static void One(){
Two();
}
public static void Two(){
Three();
}
public static void Three(){
Four();
}
public static void Four(){
Console.WriteLine("Hello World!");
var stackTrace = new System.Diagnostics.StackTrace();
List<string> methods = new List<string>();
for (int i = stackTrace.FrameCount - 1; i >= 0; i--)
{
methods.Add($"{stackTrace.GetFrame(i).GetMethod().Name}()");
}
Console.WriteLine(string.Join("->", methods));
}
}
The above code prints the output as
Main()->One()->Two()->Three()->Four()
Check the fiddle - https://dotnetfiddle.net/Ee8ni8
There is one non-ideal solution:
Prepare a set of test cases that will run your program methods in as many combinations as possible, and so provide good code coverage.
Manually add a stack trace logging functionality at the beginning of each method's body and adjust stack trace logging format to your needs (Main()->One()...). This could be done with System.Diagnostics.StackTrace, as user1672994 pointed out.
Filter your stack trace log so that it contains only stack traces which are not prefix of any other stack traces, thus leaving off incomplete paths.
You could also discover the call flow from Call Hiearchy window in Visual Studio, but it doesn't give you the data in requested format. It will however find call flows independently of your possibly imperfect test cases.
See also: Visual Studio Call Hierarchy View: call it programmatically
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'm Using C# with Unity, I'm attempting to organize my debugging. The way i have it done now runs into the problem of stacking up the more "Conditional"s i add. Is there a way i don't know of where debug messages can be cleanly separated or filtered away whenever unnecessary? I don't want to keep modifying the Project Settings, or the RSP file if they grow beyond possibility of just a mess of defines.
I've looked into Script defines, but unless loaded through the player settings each file will count by itself.
This is what i ended up with to keep things sane.
public class Cosmetics
{
[Conditional("COSMETICS_LOG")] static public void LogWarning(string message) => Debug.LogWarning(message);
[Conditional("COSMETICS_LOG")] static public void LogError(string message) => Debug.LogError(message);
[Conditional("COSMETICS_LOG")] static public void Log(string message) => Debug.Log(message);
}
public class Badge
{
[Conditional("BADGE_LOG")] static public void LogWarning(string message) => Debug.LogWarning(message);
[Conditional("BADGE_LOG")] static public void LogError(string message) => Debug.LogError(message);
}
public class Analytics ...
}
I'm able to properly see them if i put them in the player settings as global defines.
Files that have those definied in will also display them properly.
Adding them through rsp files, works as well.
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 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.