In my application I have a lot of Console#WriteLine or Console#Write calls. This are so many, that the application is really slower than necessary.
So I'm looking for an easy way to remove or at least disable all Console#WriteLine and Console#Write calls.
What's the easiest way to achieve that?
Here's a even quicker quick fix I implemented.
...
static int Main(String[] args)
{
...
#if !DEBUG
Console.SetOut(TextWriter.Null);
Console.SetError(TextWriter.Null);
#endif
...
}
HTH
Maybe Find&Replace function in any code editor?
For example find all
Console.WriteLine
and replace with
//Console.WriteLine
To switch off Console.WriteLine() output in runtime temporarily use
// backup the previous output handler connected to Console
TextWriter backupOut = Console.Out;
// activate a null handle
Console.SetOut(TextWriter.Null);
// this console output will be invisible
Console.WriteLine("Hidden output on Console.");
// restore the previous handle
Console.SetOut(backupOut);
// this console output will be visible
Console.WriteLine("Showing output on Console.");
Similarly, you can disable program Debug.WriteLine() output in runtime, also while compiling in Debug mode, by using a dummy TextWriterTraceListener, like so
using System.Diagnostics;
using System.IO;
//...
public class MyDummyListener: TextWriterTraceListener
{ }
// ......
[STAThread]
static void Main()
{
// Back up the old one
DefaultTraceListener[] debuglisteners = {(DefaultTraceListener) Debug.Listeners[0]};
// Plug in dummy listener
TextWriterTraceListener[] dummylisteners = {new MyDummyListener()};
Debug.Listeners.Clear();
Debug.Listeners.AddRange(dummylisteners);
// this is an invisible debug message
Debug.WriteLine("This one is invisible");
// ..
// to activate output again, plug in the previous listener
Debug.Listeners.Clear();
Debug.Listeners.AddRange(debuglisteners);
Debug.WriteLine("This one is visible again");
// ....
}
Note: I tested above code in .NET Framework 4.7.2 in Debug mode, using the Winforms platform.
If they are non-essential (logging) then you should have used System.Diagnostics.Debug.Print() to start with.
Luckily WriteLine() is compatible with Debug.Print() so that's an easy S&R. And fix some usings maybe.
Replacing Console.Write() might be a little trickier.
To be complete: The Debug.Print() statements can be turned on/off with a checkbox in project|Properties.
Use a simple, non regex, Find/Replace dialog, and replace every Console.WriteLine( by Debug.WriteLine(.
You can then keep the possibility to track what was previously outputted directly to the console window, still optimizing performance in release mode.
In Visual Studio, use the Tools|Macros|Record temporary macro option to record a macro that does a Find of "Console.Write", and deletes the line. That is:
Ctrl+F to find "Console.Write"
then Ctrl+L to delete the line.
Save the macro and then run it against every file in the project that has the offending lines.
Should take about two minutes.
I would suggest, however, that you back up your source first. Just in case.
Related
I'm trying to set the Text value of the Clipboard to the value of a string variable in a WPF application on .NET 4.7.2. If I debug the application and stop the execution right after the clipboard value has been saved then the value is there in clipboard and I can paste it as expected. If I continue execution then the value is wiped of sorts. For example, this is code that I can use to test with:
public void CopyToClipboard()
{
string temp = "test\ntest\ntest";
System.Windows.Clipboard.SetText(temp);
}
As you can see there are three lines that should be pasted. When I stop execution right after saving to the clipboard I will see an output like so:
test
test
test
If I continue execution (by hitting F5 or the "Continue" button in Visual Studio) then when I paste I get three lines of '\t' tabs. So, my three lines still exist, but the text has been erased.
Can anyone help me to get this resolved. What is causing me to loose the data in the clipboard?
I wrote a quick Linqpad script that just consists of the following line:
System.Windows.Clipboard.SetText("Hello");
And my clipboard is successfully set to "Hello" and stays that way after the program exits. Is there something else in your application that is modifying the clipboard?
Check this
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.clipboard.settext?redirectedfrom=MSDN&view=netframework-4.8#System_Windows_Forms_Clipboard_SetText_System_String_
public String SwapClipboardHtmlText(String replacementHtmlText)
{
String returnHtmlText = null;
if (Clipboard.ContainsText(TextDataFormat.Html))
{
returnHtmlText = Clipboard.GetText(TextDataFormat.Html);
Clipboard.SetText(replacementHtmlText, TextDataFormat.Html);
}
return returnHtmlText;
}
The Clipboard class can only be used in threads set to single thread
apartment (STA) mode. To use this class, ensure that your Main method
is marked with the STAThreadAttribute attribute.
Is there a way to write to console / command prompt / powershell (like Console.WriteLine()) or anything similar in UWP apps?
If console is unavailable is there a proper alternative that I can use instead to write to the screen large amounts of text?
I, of course, can make a XAML control and output to it, but it doesn't seem to be convenient in comparison to simple Console.WriteLine().
There is also very old discussion on WPF console, but nothing seems to work from there (at least, I couldn't find Project-Properties-Application tab-Output Type-Console Application and Trace.WriteLine("text") is unavailable).
You can use Debug.WriteLine method from System.Diagnostics namespace
MSDN Link
When you start debugging your application those messages will be displayed in the Output Window (Standard VS shortcut is Ctrl+Alt+O, ReSharper shortcut is Ctrl+W, O)
Starting with RS4 (the release coming out mid-2018) you can build command - line apps with UWP or output info to the command line. The pre-release SDK is already available and you can watch a Channel 9 video.
You can use the LoggingChannel class. to create ETW trace events.
The cool thing with LoggingChannel is you can do sophisticated traces (and use advanced tools like PerfView, etc.), but you can also have a simple equivalent of Debug.WriteLine in terms of simplicity with the LoggingChannel.LogMessage Method
public void LogMessage(String eventString)
or
public void LogMessage(String eventString, LoggingLevel level)
This has numerous advantages over Debug.WriteLine:
it's much faster, you can log millions of messages easily, while Debug.WriteLine is dog slow (based on the archaic Windows' OutputDebugString function).
it doesn't block the sender nor the receiver.
each channel is identified by its own guid, while with Debug.WriteLine you get all traces from everywhere, everyone, it's a bit messy to find your own ones.
you can use a trace level (Critical, Error, Information, Verbose, Warning)
you can use PerfView (if you really want to) or Device Portal or any other ETW tool.
So, to send some traces, just add this:
// somewhere in your initialization code, like in `App` constructor
private readonly static LoggingChannel _channel = new LoggingChannel("MyApp",
new LoggingChannelOptions(),
new Guid("01234567-01234-01234-01234-012345678901")); // change this guid, it's yours!
....
// everywhere in your code. add simple string traces like this
_channel.LogMessage("hello from UWP!");
....
Now, if you want a simple way to display those traces on your local machine, beyond using PerfView or other ETW tools, you can use a free open source GUI tool I write called WpfTraceSpy available here: https://github.com/smourier/TraceSpy#wpftracespy or here is a sample .NET Framework Console app that will output all traces and their level to the console:
using System;
using System.Runtime.InteropServices;
using Microsoft.Diagnostics.Tracing; // you need to add the Microsoft.Diagnostics.Tracing.TraceEvent nuget package
using Microsoft.Diagnostics.Tracing.Session;
namespace TraceTest
{
class Program
{
static void Main()
{
// create a real time user mode session
using (var session = new TraceEventSession("MySession"))
{
// use UWP logging channel provider
session.EnableProvider(new Guid("01234567-01234-01234-01234-012345678901")); // use the same guid as for your LoggingChannel
session.Source.AllEvents += Source_AllEvents;
// Set up Ctrl-C to stop the session
Console.CancelKeyPress += (object s, ConsoleCancelEventArgs a) => session.Stop();
session.Source.Process(); // Listen (forever) for events
}
}
private static void Source_AllEvents(TraceEvent obj)
{
// note: this is for the LoggingChannel.LogMessage Method only! you may crash with other providers or methods
var len = (int)(ushort)Marshal.ReadInt16(obj.DataStart);
var stringMessage = Marshal.PtrToStringUni(obj.DataStart + 2, len / 2);
// Output the event text message. You could filter using level.
// TraceEvent also contains a lot of useful informations (timing, process, etc.)
Console.WriteLine(obj.Level + ":" + stringMessage);
}
}
}
I just want to also add that debug.writeline seems to best work on the main thread so if async/await is used use something like Device.BeginInvokeOnMainThread(() => Debug.WriteLine(response)); to print to the console
Is there a way to write to console / command prompt / powershell (like Console.WriteLine()) or anything similar in UWP apps?
If console is unavailable is there a proper alternative that I can use instead to write to the screen large amounts of text?
I, of course, can make a XAML control and output to it, but it doesn't seem to be convenient in comparison to simple Console.WriteLine().
There is also very old discussion on WPF console, but nothing seems to work from there (at least, I couldn't find Project-Properties-Application tab-Output Type-Console Application and Trace.WriteLine("text") is unavailable).
You can use Debug.WriteLine method from System.Diagnostics namespace
MSDN Link
When you start debugging your application those messages will be displayed in the Output Window (Standard VS shortcut is Ctrl+Alt+O, ReSharper shortcut is Ctrl+W, O)
Starting with RS4 (the release coming out mid-2018) you can build command - line apps with UWP or output info to the command line. The pre-release SDK is already available and you can watch a Channel 9 video.
You can use the LoggingChannel class. to create ETW trace events.
The cool thing with LoggingChannel is you can do sophisticated traces (and use advanced tools like PerfView, etc.), but you can also have a simple equivalent of Debug.WriteLine in terms of simplicity with the LoggingChannel.LogMessage Method
public void LogMessage(String eventString)
or
public void LogMessage(String eventString, LoggingLevel level)
This has numerous advantages over Debug.WriteLine:
it's much faster, you can log millions of messages easily, while Debug.WriteLine is dog slow (based on the archaic Windows' OutputDebugString function).
it doesn't block the sender nor the receiver.
each channel is identified by its own guid, while with Debug.WriteLine you get all traces from everywhere, everyone, it's a bit messy to find your own ones.
you can use a trace level (Critical, Error, Information, Verbose, Warning)
you can use PerfView (if you really want to) or Device Portal or any other ETW tool.
So, to send some traces, just add this:
// somewhere in your initialization code, like in `App` constructor
private readonly static LoggingChannel _channel = new LoggingChannel("MyApp",
new LoggingChannelOptions(),
new Guid("01234567-01234-01234-01234-012345678901")); // change this guid, it's yours!
....
// everywhere in your code. add simple string traces like this
_channel.LogMessage("hello from UWP!");
....
Now, if you want a simple way to display those traces on your local machine, beyond using PerfView or other ETW tools, you can use a free open source GUI tool I write called WpfTraceSpy available here: https://github.com/smourier/TraceSpy#wpftracespy or here is a sample .NET Framework Console app that will output all traces and their level to the console:
using System;
using System.Runtime.InteropServices;
using Microsoft.Diagnostics.Tracing; // you need to add the Microsoft.Diagnostics.Tracing.TraceEvent nuget package
using Microsoft.Diagnostics.Tracing.Session;
namespace TraceTest
{
class Program
{
static void Main()
{
// create a real time user mode session
using (var session = new TraceEventSession("MySession"))
{
// use UWP logging channel provider
session.EnableProvider(new Guid("01234567-01234-01234-01234-012345678901")); // use the same guid as for your LoggingChannel
session.Source.AllEvents += Source_AllEvents;
// Set up Ctrl-C to stop the session
Console.CancelKeyPress += (object s, ConsoleCancelEventArgs a) => session.Stop();
session.Source.Process(); // Listen (forever) for events
}
}
private static void Source_AllEvents(TraceEvent obj)
{
// note: this is for the LoggingChannel.LogMessage Method only! you may crash with other providers or methods
var len = (int)(ushort)Marshal.ReadInt16(obj.DataStart);
var stringMessage = Marshal.PtrToStringUni(obj.DataStart + 2, len / 2);
// Output the event text message. You could filter using level.
// TraceEvent also contains a lot of useful informations (timing, process, etc.)
Console.WriteLine(obj.Level + ":" + stringMessage);
}
}
}
I just want to also add that debug.writeline seems to best work on the main thread so if async/await is used use something like Device.BeginInvokeOnMainThread(() => Debug.WriteLine(response)); to print to the console
If I have these sprinkled throughout my code:
MessageBox.Show("See a format exception yet? #1");//todo: remove
(there are 7 of these, numbered from 1..7, most of which display (1,2,5,6,7))
I end up with one err msg ("Exception: Cannot find table 0 Location: frmFunction.SetPlatypus")
If I comment out all of those, I end up with a different err msg ("Exception: FormatException Location frmFunction.getDuckbillRecord")
How could this be? Shouldn't the existence/display of such an information msg have no effect on the way the code executes/the path it takes, etc.?
Note: getDuckbillRecord() is where all of the MessageBoxes are.
UPDATE
Using RT's suggestions as motivation, I came up with this:
public static StringBuilder LogMsgs = new StringBuilder();
public static void ExceptionHandler(Exception ex, string location)
{
try
{
LogMsgs.Append(string.Format("{0}\r\n", ex.Message)); //TODO: Comment out before deploying?
DateTime dt = DateTime.Now;
string timeAsStr = string.Format("{0}_{1}_{2}_{3}.txt", dt.Hour, dt.Minute, dt.Second, dt.Millisecond);
using (StreamWriter file = new StreamWriter(timeAsStr))
{
file.WriteLine(LogMsgs.ToString());
}
. . .
//in the problematic code, replacing the MessageBox.Show() calls:
TTBT.LogMsgs.Append("Made it to location 1 in frmOverFunction.GetDuckbillRecord()\r\n");
...and it did help - the exception is reached right after the first of 7 "code waypoints," so there's something rotten in that particular Denmark, apparently.
UPDATE 2
After the rare experience of being able to run the app without crashing somewhere, I realized I also need that file-writing code in the main form's OnClosing() event - being in the global exception handler had worked for awhile - I wasn't expecting a clean termination of the app to ever occur again, I guess.
I'd strongly encourage you NOT to use MessageBox.Show(...) to log/trace/debug errors, because popping-up a dialog can introduce many subtle bugs and changes in behavior, focus, etc., especially if your UI flow/state is important.
Instead, use System.Diagnostics.Trace for writing tracing code (which you can optionally compile into your production/release code) or System.Diagnostics.Debug to write debug messages which get removed when you build your release version.
For example:
public void DoSomething(int a, int b)
{
Trace.TraceInformation("Starting to do something: a = {0}, b = {1}",
a, b);
try
{
int c = a / b;
}
catch (DivideByZeroException e)
{
Debug.WriteLine("OH NO ... 'b' WAS ZERO!!!! RUN AWAY!!!!");
throw e;
}
Trace.TraceInformation("Done doing something");
}
In the example above, the debug output will be available in debug builds, but will be removed in release builds. Trace output will be available in debug and retail bugs (unless you turn off the TRACE build parameter) but introduces no measurable perf impact unless you hook-up a listener and start writing trace output to a slow medium like spinning disks, ticker-tape printers, etc. ;)
When you run code with Trace and/or Debug builds with Debug messages in Visual Studio, the messages are written to the Output pane so you can watch what's going on inside your app as it runs.
If you want to, you can also write a stand-alone trace listener that listens for Trace and/or Debug messages and log them to a file/database or display them in a console window (or GUI if you want to get fancy).
You can also use tools like log4net which enables you to write log/trace messages to a variety of file formats, databases, etc.
i have a bunch of Console.WriteLines in my code that I can observe at runtime. I communicate with a native library that I also wrote.
I'd like to stick some printf's in the native library and observe them too. I don't see them at runtime however.
I've created a convoluted hello world app to demonstrate my problem. When the app runs, I can debug into the native library and see that the hello world is called. The output never lands in the textwriter though. Note that if the same code is run as a console app then everything works fine.
C#:
[DllImport("native.dll")]
static extern void Test();
StreamWriter writer;
public Form1()
{
InitializeComponent();
writer = new StreamWriter(#"c:\output.txt");
writer.AutoFlush = true;
System.Console.SetOut(writer);
}
private void button1_Click(object sender, EventArgs e)
{
Test();
}
and the native part:
__declspec(dllexport) void Test()
{
printf("Hello World");
}
Update:
hamishmcn below started talking about debug/release builds. I removed the native call in the above button1_click method and just replaced it with a standard Console.WriteLine .net call. When I compiled and ran this in debug mode the messages were redirected to the output file. When I switched to release mode however the calls weren't redirected. Console redirection only seems to work in debug mode. How do I get around this?
Perhaps your native library, for some reason, doesn't know about the console.
You could try calling GetConsole an see if a handle is returned. If not you could try allocating your own console to see if that works.
Good luck! :-)
Update:
I wrote a sample app too (console C# app calling native C++ dll) and both the C# Console.WriteLine and the native printf appear on the console... So what are we missing?
Do you always run it in debug mode - do you see a console window at all if you run it in release mode?
Update 2:
Sorry, I should say I see the text on the console, but if I set the Console output to a StreamWriter, like you have in your example, then only the WriteConsole text goes to the output file, the printfs still go to the screen
I don't currently have any project I could try this on but I would definitely suspect buffering. stdout is buffered if my memory serves me right. It flushes buffer every time it hits the end of line:
printf("Should be flushed immediatelly\n");
Or you can use fflush to flush the stdout:
printf("Will be buffered and then flushed");
fflush(stdout);
You can also turn buffering off by using setbuf:
setbuf(stdout, NULL);
Console redirection only works in debug mode.
Implement your own printf (on top of vsnprintf to take care of the dirty details) that writes to the console:
#include <stdarg.h>
int printf(const char *fmt, ...)
{
char buffer[LARGESIZE];
int rv;
va_list ap;
va_start(ap, fmt);
rv = vsnprintf(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
Console.WriteLine(buffer);
return rv;
}