godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.12k stars 69 forks source link

Add support for viewing GD.Print logs in Visual Studio Output tab #8648

Open abelbascu opened 9 months ago

abelbascu commented 9 months ago

Describe the project you are working on

Learning Godot under C#/Visual Studio.

Describe the problem or limitation you are having in your project

Currently, if you debug under Visual Studio, you can add breakpoints and can have hotreload, but no GD.Print logs are displayed under the Output tab. To see them, you need to run the project in Godot editor, which adds to a constant and consuming task switching.

Please see this thread on reddit for more info: https://www.reddit.com/r/godot/comments/16q9c4u/gdprint_in_visual_studio/

Describe the feature / enhancement and how it helps to overcome the problem or limitation

It would be really helpful to see the GD.Print logs by default in the Output tab in Visual Studio, to help on a better proper debugging, and reducing the amount of back and forth between the IDE and Godot Editor.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

I don't have the knowledge to do this. The feature should just display the logs in the Output tab windows in VS.

If this enhancement will not be used often, can it be worked around with a few lines of script?

This enhancement would be used often by most beginner devs working under C#/Visual Studio. I don't have enough knowledge to tell if this could be solved easily with a few lines of code.

Is there a reason why this should be core and not an add-on in the asset library?

This is basic debug info that would help beginners to track down their code output without having to resort to creating their own log classes when they still probably don't have the knowledge for implementing them, difficulting their debug job and adding UX friction when working on other IDEs outside the Godot Editor.

Instead, I checked on VS Studio Code and this IDE shows GD.Print lines correctly. Please see image attached.

GDPrint works well on VSCode not VisualStudio

raulsntos commented 9 months ago

As far as I know, GD.Print is just printing to stdout. If that works in VSCode, it sounds to me like the issue may be on the Visual Studio IDE side and not Godot.

How are you launching the game from Visual Studio? Does it print stdout for other non-Godot applications? There may be some configuration that you need to do and I'm not familiar with Visual Studio myself, so consider asking in community channels (like the Discord). There's a chance you'll find someone else using Visual Studio that knows how to configure things properly.

abelbascu commented 9 months ago

@raulsntos I will ask on Discord thanks.

To answer your questions:

How are you launching the game from Visual Studio?

I linked Godot with VS by setting up the proper option in Editor settings: image

Then I launch the game using a debug profile image image

Does it print stdout for other non-Godot applications?

Trying to isolate the issue, this code show the message in the Output tab (no Godot involved)

using System;
using System.Diagnostics;

namespace TestingStdout
{
    class Program
    {
        static void Main()
        {
            Debug.WriteLine("Hello, this message should appear in the Output window!");
            ...
            ...

But If i copy the same debug line in my Godot script, I can see no message in the VS tab:

Here the output log on VS for if it could help:

'Godot_v4.2-stable_mono_win64.exe' (CoreCLR: DefaultDomain): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.0\System.Private.CoreLib.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Godot_v4.2-stable_mono_win64.exe' (CoreCLR: clr_libhost): Loaded 'C:\Users\camin\Desktop\Godot_v4.2-stable_mono_win64\GodotSharp\Api\Debug\GodotPlugins.dll'. Symbols loaded.
'Godot_v4.2-stable_mono_win64.exe' (CoreCLR: clr_libhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.0\System.Runtime.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Godot_v4.2-stable_mono_win64.exe' (CoreCLR: clr_libhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.0\System.Runtime.InteropServices.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Godot_v4.2-stable_mono_win64.exe' (CoreCLR: clr_libhost): Loaded 'C:\Users\camin\Desktop\Godot_v4.2-stable_mono_win64\GodotSharp\Api\Debug\GodotSharp.dll'. Symbols loaded.
'Godot_v4.2-stable_mono_win64.exe' (CoreCLR: clr_libhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.0\System.Collections.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Godot_v4.2-stable_mono_win64.exe' (CoreCLR: clr_libhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.0\System.Console.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Godot_v4.2-stable_mono_win64.exe' (CoreCLR: clr_libhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.0\System.Runtime.Loader.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Godot_v4.2-stable_mono_win64.exe' (CoreCLR: clr_libhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.0\System.Runtime.CompilerServices.Unsafe.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Godot_v4.2-stable_mono_win64.exe' (CoreCLR: clr_libhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.0\System.Threading.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Godot_v4.2-stable_mono_win64.exe' (CoreCLR: clr_libhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.0\System.Collections.Concurrent.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Godot_v4.2-stable_mono_win64.exe' (CoreCLR: clr_libhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.0\System.Diagnostics.TraceSource.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Godot_v4.2-stable_mono_win64.exe' (CoreCLR: clr_libhost): Loaded 'Testing Godot features'. Symbols loaded.
'Godot_v4.2-stable_mono_win64.exe' (CoreCLR: clr_libhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.0\System.Linq.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Godot_v4.2-stable_mono_win64.exe' (CoreCLR: clr_libhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.0\System.Runtime.Serialization.Formatters.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
atil commented 8 months ago

I have the same problem and can add something here. Sometimes when a GD.Print() or Console.WriteLine() executes, I see one more those "loading symbols" dlls with another dll name. I disabled the "Just My Code" optimization and nothing changed. Instead of "skipped", I see: 'godot_4_2_1_net.exe' (CoreCLR: clr_libhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\7.0.7\System.Memory.dll'. Symbols loaded.

whiletrue111 commented 8 months ago

i think same problem not sure attached example project https://github.com/godotengine/godot/issues/86519

thedemons commented 6 months ago

I have found a workaround, you need to start debugging from a C++ project debugger, here's how:

  1. You need to install C++ development, in VS Installer, check the "Desktop development with C++".
  2. In Solution Explorer, right-click on the Solution, then Add -> New Project, and select the "Empty Project" template, the C++ one, not .NET. This will be the dummy project that launches the game.
  3. In Solution Explorer, right-click on the project you just created and click Properties.
  4. Go to the Debugging tab, and enter the executable path, arguments, and working directory as you would with a .NET project.
  5. For "Debugger Type", select "Managed Only (.NET Core)", or "Mixed (.NET Core)" works too but doesn't allow for Hot Reload, then click Apply. Example image below.
  6. Right-click on the newly created project in the Solution Explorer, and click on "Set as Startup Project"
  7. Optionally, right-click on the project -> Build Dependencies -> Project Dependencies and check your main project. This makes sure it builds your scripts when hitting F5.

You should be able to launch the game with the console opened and working breakpoints by now. Why does this work? I have no idea.

image

You can also add multiple dummy projects to launch multiple instances of the game, just go to your Solution Properties then config the Multiple startup projects.

joshuaandrewhoffman commented 6 months ago

I have found a workaround, you need to start debugging from a C++ project debugger, here's how: ...

Thanks a ton for sharing this @thedemons ! This worked like a charm for me; really glad to finally have this functionality.

Out of curiosity, do you have "Build and Run" behavior working with this setup? I have the box ticked for it, and it worked as I'd expect prior to implementing this workaround, so I suspect there's some side effect I'm missing with the secondary Project.

thedemons commented 6 months ago

Out of curiosity, do you have "Build and Run" behavior working with this setup?

What specific option isn't working for you? I think mine is working correctly

joshuaandrewhoffman commented 6 months ago

Out of curiosity, do you have "Build and Run" behavior working with this setup?

What specific option isn't working for you? I think mine is working correctly

Ugh, solved this on my second look just now as I was replying to you. Hopefully I can save the next person the lost sanity... The answer was this checkbox: "Only build startup projects and dependencies on Run" needing to be unchecked image

Prior to that change, I was having to manually invoke a build before every run. Just hitting F5 or clicking the run button results in the project running the previous build, so you get things like mismatched line numbers in my output, or breakpoints not being recognized.

In the past when I've seen this, it was just a matter of needing to enable "Always Build" (because I've never had the second startup project in the mix). This was a classic case of just moving too fast and only seeing what I expected to see. Thanks for taking the time to ping me back!

thedemons commented 6 months ago

I just found another workaround that requires less setup but is not as comfortable to use. Just setup the debug profile as usual but select the Godot_xxxx_mono_win64_console.exe and add this to _Ready or the constructor of your entry scene:

if (!Debugger.IsAttached) Debugger.Launch();

Then "Start without Debugging" Ctrl+F5, a window will open and ask for the instance of VS you want to launch the debugger. Maybe do this if you don't want a dummy project/folder just lying around in your solution/repo but it is less convenient to use than the other method.

More info: The reason why breakpoints don't work when you launch Godot_xxxx_mono_win64_console.exe is because it spawns your actual game as a child process which Visual Studio doesn't attach its debugger to, I have tried the Child Process Debugging Power Tool plugin but it doesn't seem to work for me.

EniacMlezi commented 4 months ago

Found another workaround by wrapping GD.Print and also writing to the attached Debuggger:

public static void Print(string format, params object?[] args)
{ 
    var formatted = string.Format(format, args);
    GD.Print(formatted);
    Debugger.Log(2, "inf", formatted);
}
phildoesdev commented 4 months ago

Another work-around is using

GD.PushError("Uhhh");

Taking this idea from the method summary for GD.Print:

//
 // Summary:
 //     Prints a message to the console. Note: Consider using Godot.GD.PushError(System.String)
 //     and Godot.GD.PushWarning(System.String) to print error and warning messages instead
 //     of Godot.GD.Print(System.String). This distinguishes them from print messages
 //     used for debugging purposes, while also displaying a stack trace when an error
 //     or warning is printed.
 //
 // Parameters:
 //   what:
 //     Message that will be printed.

    public static void Print(string what)
    {
        ....
    }
Neutrino-Sunset commented 1 month ago

As far as I know, GD.Print is just printing to stdout. If that works in VSCode, it sounds to me like the issue may be on the Visual Studio IDE side and not Godot.

I strongly disagree.

When you have selected Visual Studio as your external editor, and you attach a script to a node in Godot and select a C# script, Godot creates a Visual Studio project with a class for your script.

In that project all logging appears to be broken.

      Debug.WriteLine("*** Hi from my script - Debug.WriteLine ***"); // Does not work.
      Trace.WriteLine("*** Hi from my script - Trace.WriteLine ***"); // Does not work.
      Console.WriteLine("Writing to the console"); // Does not work.
      GD.Print("Hello World!"); // Does not work.

Examining Trace.Listeners it appears Godot has added it's own custom listener, but in the process removed the default listeners.

Adding the following line in a static constructor in one of your script classes will get Trace and Debug logging working again.

   Trace.Listeners.Add(new DefaultTraceListener());

However, when starting your project from Visual Studio, the GD.Print logging, which is presumably where the engine will log any errors it detects (so it's quite important to get that working) does not appear anywhere. Not even in the Gotdot editor itself.

If (as you say) GD.Print just logs to standard output, then I think the problem is in the Gotdot editor. The Gotdot editor is a desktop application not a console application, if in a desktop application GD.Print is writing to standard output then the Gotdot editor must be doing something a bit non-standard in order to redirect that output back to its own output window in its UI.

Visual Studio, when debugging a desktop application, has no way of knowing whether Godot is doing something unconventional with console output.

The script project uses a custom SDK <Project Sdk="Godot.NET.Sdk/4.2.2"> so it's difficult to know whether fixing this is something that can even be done from within the script library project.

The first script tutorial for Godot is outputting a simple Hello World log message. I sat down hoping to have a fun afternoon doing some Godot tutorials, and instead I've spent 6 hours just trying to get some sort of basic logging to work when running my application from Visual Studio.

The workarounds described in this thread are pretty grim. Having to create a dummy project, of a type I might not even have the tooling installed for, which works for a reason no one understands.

This is a terrible experience for new users trying to complete the very first Hello World tutorial. This issue has been reported for 8 months now. I suggest that fixing this should be considered a higher priority than it seems to have been.

Neutrino-Sunset commented 1 month ago

My PR doesn't actually output the log in the Visual Studio output pane, as best I can tell that doesn't seem to be possible for a process that is created as a windows process instead of a console process. Instead it just forces the spawning of a console window and outputs to that instead.

Opinions on this approach may vary, but personally I think it's ok. The output is better formatted and less cluttered than it would be in the VS output pane (although that can be filtered somewhat), and this "program output in a separate console" experience is the same as the Visual Studio out-of-the-box experience when debugging an ASP web service, so is pretty familiar.