I've added a conditional breakpoint in a C# project along with an "Action" that writes a message to the console. Basically, when you check "Actions", you are only provided an option to "Log a message to the Output Window" (this is VS 2015).
What if I wanted to also log that message to a text file? I've been reading about trace listeners but can't figure out how to hook one up to my tracepoint.
Tracepoints can only be used while debugging - since they are kept track of by the Visual Studio IDE debugger. I actually tried to set up a listener to write out the trace to a log file, but it looks like this functionality is not supported for tracepoints. But, it does work for the Trace class.
So, it looks like you are stuck with the output window while debugging. You can always copy and paste the contents of the output window to a file while debugging. If your intent was to use it for release code, then you should either use custom logging or the Trace class.
By default, the trace class writes to the output window. But, the default listener may be modified to also log Trace.WriteLine statements to a log file as well. For example:
using System.Diagnostics;
// Set up the log file to be the folder where the program is run from, with the name Trace.log.
DefaultTraceListener DefListener = (DefaultTraceListener)Trace.Listeners[0];
DefListener.LogFileName = AppDomain.CurrentDomain.BaseDirectory + "Trace.log";
// Write out the value of Count within the loop to the log file.
for (int Loop = 0; Loop < 5; Loop++)
{
Count++;
Trace.WriteLine($"Count = {Count}");
}
DefListener.Flush();
The contents of the log file will then contain:
Count = 1
Count = 2
Count = 3
Count = 4
Count = 5
The above code works for both release and debug builds.
Related
I have a c# project and a log file with errors. I want to give all errors on a new log file out with a counter if there are some errors twice or more. I used the command:
bool alreadyExist = fails.Contains(line);
This works really good, but I want also a counter, to show how many times I have the same line in a log file.
Using Regex:
Regex.Matches(fails, line).Count
Assuming fails is an IEnumerable<string> where each element is a log file line, this should work:
int count = fails.Count((x) => x.Equals(line));
I have been fighting with the Windows Event log for lots of hours with inconsistent behaviour during test of the log4net EventLogAppender and I realized, that the log4net code worked, but my windows event log was the one being unreasonable.
System
OS: Windows 8.1
C#: .Net 4.5, built to x64
Creating the error case
C#: Create Source1 in TestLog1
C#: Write to the log (Works)
Powershell: Removing the log using powershell
C# Create Source1 in TestLog2 (Different log)
C# Write to the log <= This shows no log entries in TestLog2!
I have made a complete step-by-step guide to recreate the problem:
1: Create a new source in a new log and write to it
Code executed:
EventLog.CreateEventSource(source: "TestSource1", logName: "TestLog1");
EventLog myLog = new EventLog();
myLog.Source = "TestSource1";
myLog.WriteEntry("This is a message");
List logs using powershell-command:
Get-EventLog -LogName *
This will correctly list all logs, including TestLog1 containing 1 log entry.
I can also get the log entries by using this powershell command:
GetEventLog -LogName "TestLog1"
This shows me the single log message in the log.
2: Delete the event log using powershell
Powershell command:
Remove-EventLog -LogName "TestLog1"
Listing all logs now shows, that the log has actually been deleted. Powershell command again:
Get-EventLog -LogName *
3: Create the source again, but in another log this time
Code executed:
EventLog.CreateEventSource(source: "TestSource1", logName: "TestLog2"); // New log name
EventLog myLog = new EventLog();
myLog.Source = "TestSource1";
myLog.WriteEntry("This is a message");
Result:
The log appears in powershell when listing all logs
The log does not contain any entry
Using Get-EventLog "TestLog2" throws and exception even though it appears in the log-list
Deleting the log in powershell using remove-eventlog -logName "TestLog2" somehow still works.
It seems that in some cases, the logs seems to exist, but in others it doesnt.
A: Is this a known bug or what is wrong with my scenario?
B: How can I clean up my existing mess if sources somehow still exist pointing at the old log? (If thats the case, that is)
EDIT: I even tried the following C# code to delete the source first and then the log, but the result is the same:
var source = "TestSource6";
var logName1 = "Testlog5";
var logName2 = "Testlog6";
EventLog.CreateEventSource(source: source, logName: logName1);
new EventLog() { Source = source }.WriteEntry("This is a message in log " + logName1);
EventLog.DeleteEventSource(source:source);
EventLog.Delete(logName:logName1);
EventLog.CreateEventSource(source: source, logName: logName2);
new EventLog() { Source = source }.WriteEntry("This is a message" + logName2);
Unfortunately you can't re-register an event source "back to back". It's one of the (many) reasons installers often ask to restart the computer.
From MSDN:
If a source has already been mapped to a log and you remap it to a new log, you must restart the computer for the changes to take effect.
EventLog.CreateEventSource Method (String, String)
For fixing the issue, I would recommend not deleting the event source unless the product is uninstalled. Just stop using Log1 and start using Log2, without deleting and recreating. When you go to use any log, you could use something similar to this:
if (!EventLog.SourceExists(source, log))
{
EventLog.CreateSource(source, log)
}
And simply leave the source where it is, until you uninstall the product. If you're using InstallShield, it should automatically detect a restart is required and ask the user to do so.
I have some problem filter tracing events. Here's my code:
PresentationTraceSources.Refresh();
Stream myFile = File.Create("trace.txt");
listener = new TextWriterTraceListener(myFile);
PresentationTraceSources.RoutedEventSource.Listeners.Add(listener);
PresentationTraceSources.RoutedEventSource.Switch.Level = SourceLevels.Warning;
PresentationTraceSources.RoutedEventSource.TraceEvent(TraceEventType.Warning, 0, "Test my warning");
Then i run my app and expect that file trace.txt will contain "Test my warning" string, however this file is empty. But if I change one string in code to
PresentationTraceSources.RoutedEventSource.Switch.Level = SourceLevels.All;
I can see string "Test my warning" in file called "trace.txt". But this is always traces all event types, not only warnings. But I want to trace only warnings. Can you help me to solve this issue?
Just add :
PresentationTraceSources.RoutedEventSource.Flush();
At the end and it will works, for any source level.
Actually as soon as you have another level than SourceLevels.All, you have to flush your TraceSource to write it in your listeners.
http://i.minus.com/ibsHfIOAy7lBCj.png
I want to write some stuff to VS's output window so I can see what's going on, but it just gets flooded with all this other stuff. Is there some way I can write to a different "channel"? It's got that dropdown there, which I see AnkhSVN has added itself too...can I add another one with only my stuff in there maybe?
Use Trace for this. You will either have an App.config file or a Web.config file in the project that is running. In this file add a trace listener.
When you call trace, which is very similar to Debug, you can specify the level (Info, Warning, Debug, Error). Based on this level you can decide where and how that information is saved.
How to Trace and Debug in Visual Studio
You can use the "Redirect all Output Window text to the Immediate Window" option:
Although it says all, it will only redirect Debug.WriteLine, etc.
Alternatively you can suppress the noisy messages from the output window itself:
If you create a visual studio addin (in default) you will have a connect.cs with a public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
You can use this application object to do what you want to do.
DTE2 app = (DTE2)application;
OutputWindowPane XXX = app.ToolWindows.OutputWindow.OutputWindowPanes.Add("XXX");
Now you can use :
XXX.OutputString("some text" + Environment.NewLine);
And this text will appear in the "channel" called "XXX"
I've read several articles that tell you how to add text to the output window in visual studio from within an Add-On (specifically, a visual studio 2008 integration package, via the visual studio 2008 SDK 1.1), but no examples of how to read text from the output window. My goal is to parse text from the debug output window while debugging a certain application (TRACE output and possibly stdin/stdout). The IVsOutputWindowPane interface has no methods for reading in text from the output window. The documentation seems to imply that it is possible, but it doesn't provide an example:
http://msdn.microsoft.com/en-us/library/bb166236(VS.80).aspx
Quote: In addition, the OutputWindow and OutputWindowPane objects add some higher-level functionality to make it easier to enumerate the Output window panes and to retrieve text from the panes.
Preferably I'd like to be able to subscribe to an event that fires when a new line of text arrives, similar to a StreamReader's asynchronous reads.
It is possible, it is just a long winding path to get to it:
ServiceProvider -> IVsOutputWindow -> GetPane( debugwindow ) -> IVsUserData -> GetData( wpftextviewhost ) -> IWpfTextViewHost -> IWpfTextView -> TextBuffer -> Changed event.
Presuming you have a VS IServiceProvider from somewhere else (vsix extension/whatever, global service provider), and without any error checking, it looks like this:
IVsOutputWindow outWindow = ServiceProvider.GetService(typeof(SVsOutputWindow)) as IVsOutputWindow;
Guid debugPaneGuid = VSConstants.GUID_OutWindowDebugPane;
IVsOutputWindowPane pane;
outWindow.GetPane(ref debugPaneGuid, out pane);
// from here up you'll find in lots of other stackoverflow answers,
// the stuff from here down is interesting to this question
IVsUserData userData = (IVsUserData)pane;
object o;
Guid guidViewHost = DefGuidList.guidIWpfTextViewHost;
userData.GetData(ref guidViewHost, out o);
IWpfTextViewHost viewHost = (IWpfTextViewHost)o;
IWpfTextView textView = viewHost.TextView;
textView.TextBuffer.Changed += YourTextChangedHandlerHere;
Your text changed handler will then get called every time the output window gets more data. you won't necessarily get it line by line, but you'll probably more likely than not get big chunks you'll need to deal with on your own.
It is highly likely that some of the above did not even exist in VS in 2010. But it exists now!
The default behavior (when you don’t set the listener explicitly) of VS is to display trace massages in the debugger output window, which you appreciate if you want a simple solution and do no other actions with the massages.
Unfortunately this is not your case. So you have to define a trace listener to send (and store) your trace massages where you then will be able to read them. The trace listener could be a file (for example XML) or you can create a custom listener by deriving a class from the base class TraceListener if you don't want to bother yourself with an additional file.
I don't know that what you ask is possible. But, you can register your add-in as a debugger for your application so that you get the output the trace messages. These are typically routed to OutputDebugString, and can be captured as described in this article: http://www.drdobbs.com/showArticle.jhtml?articleID=184410719. It does not give you the normal output, only debug, but it does not depend on the technology of the debugged application.
The solution on this page selects the text in order to read it. I'm hoping there's a better way.
Automatically stop Visual C++ 2008 build at first compile error?
Private Sub OutputWindowEvents_OnPaneUpdated(ByVal pPane As OutputWindowPane) Handles OutputWindowEvents.PaneUpdated
pPane.TextDocument.Selection.SelectAll()
Dim Context As String = pPane.TextDocument.Selection.Text
pPane.TextDocument.Selection.EndOfDocument()
End Sub