Debug.Log Extensions

Enhance the Debug class with numerous improvements that can greatly improve readability in the Console and save a lot of time by enabling more compact debugging code to be used.

This is a plug & play solution; all Debug commands in your classes will automatically switch to using the new and improved versions.

Asset Store - Buy Debug.Log Extensions
Webpage - Find the blog, contact information…
Online Documentation - Scripting reference

Features

Clean Console

Stack traces are no longer visible for every entry in the Console list. This greatly improves readability.

Syntax Highlighting

Your console messages are automatically augmented with colorful syntax highlighting, improving readability even more.

Automatic Context

The context Object is automatically determined for your messages whenever possible to help with locating message sources.

Channels

Organize messages into channels (like Audio, AI…) and make the Console window only display messages from the ones you care about.

Debug.Log(()=>field)

A new compact syntax can be used to log both the name and value of a field to the console.

Debug.LogChanges(()=>field)

Have messages be printed automatically whenever the value of a field changes.

Debug.LogState(target)

Easily print the full state of a target to the console.

Debug.DisplayOnScreen(()=>field)

Easily display the name and current value of any field on the screen.

Debug.LogToFile(message, path)

Easily output messages into text files instead of the console.

Dev.Log(message)

Just like Debug.Log except all calls are omitted from release builds.

Critical.Log(message)

Useful for important messages you don’t want getting lost in the shuffle; uses a larger font, full stack trace and always gets recorded in a log file, regardless of Project Settings.

Highly Customizable

Thorough customization options allow you to configure everything to fit your team as well as your personal preferences.

Console+

An augmented Console window with controls for filtering messages based on their channels, the ability to locate all instances of types references in stack traces, and more.

Usage

:cross_mark: Before:


 Debug.Log(nameof(target)+"="+(target == null ? "null" : target.name), this);

:check_mark: After:


 Debug.Log(()=>target);

:desktop_computer: Console:


 target="Player"

:cross_mark: Before:


 var message = "MyClass state:\n"
 + "speed=" + speed + "\n";
 + "target=" + (target == null ? "null" : target.name) + "\n";
 + "progress=" + progress;
 ...

 Debug.Log(message, this);

:check_mark: After:


 Debug.LogState(this);

:desktop_computer: Console:


 MyClass state:
 speed=5
 target=null
 progress=0.25

:cross_mark: Before:


 int lastValue;

 void Update()
 {
  if(myField != lastValue)
  {
   Debug.Log("myField="+(lastValue = myField)+"\n(was: "+lastValue+")", this);
   lastValue = myField;
  }
 }

:check_mark: After:


 Debug.LogChanges(()=>myField);

:desktop_computer: Console:

----------------------------------------------------------
 myField=5
 (was: 4)
----------------------------------------------------------
 myField=6
 (was: 5)
----------------------------------------------------------

Installation

When you import the Debug.Log Extensions package to a project, a dialog will appear asking you whether you’d like to replace all usages of the built-in Debug class with the extended Debug class, or if you’d prefer to opt-in to use it on a script-by-script basis.

You can change this choice later by going to Project Settings > Debug.Log Extensions.

Unique Namespace

If you choose to install the extended Debug class in a unique namespace, then all your existing classes will continue using the built-in UnityEngine.Debug class by default, and you can switch individual scripts to use the extended Debug class with a using alias:


 using UnityEngine;
 using Debug = Sisus.Debugging.Debug; // <- opt-in to use extended Debug class

 class Player : MonoBehaviour
 {
   void Awake()
   {
     var greeting = "Hello, World!";
     Debug.Log(()=> greeting);
  }

Global Namespace

If you install the extended Debug class in the global namespace, then all your classes will use the extended Debug class by default, and you won’t need to add any using aliases to them:


 using UnityEngine;

 class Player : MonoBehaviour
 {
   void Awake()
   {
     var greeting = "Hello, World!";
     Debug.Log(()=> greeting);
  }

Resolving Conflicts

There is an edge case in which the compile might not know if usages of Debug are supposed to refer to the extended class in the global namespace or the built-in one, and that is if a script has created a using alias with the identifier Debug:


 using UnityEngine;
 using Debug = UnityEngine.Debug; // <- problem

 class Player : MonoBehaviour
 {
   void Awake() => Debug.Log("Hello?"); // <- error CS0576: Namespace '<global namespace>' contains a definition conflicting with alias 'Debug'
 }

To fix this just remove the using alias from the script. It’s not necessary when you have Debug.Log Extensions installed in the global namespace.

Assembly References

To make your script assembly reference the Debug.Log Extensions assembly, do the following:

  1. Select the Assembly Definition Asset for the assembly (create it if it doesn’t exist yet).
  2. Tick the Override References checkbox.
  3. Add Debug-Log-Extensions.dll to the Assembly References list.
  4. Click Apply.

2 Likes

Update 1.1.1 is now out and adds the following improvements:

  • Extended Debug class with several new LogWarning and LogError methods.
  • Extended Dev class with several new methods.
  • Improved syntax formatting logic.
  • Improved UnityEngine.Object formatting in Log messages.
  • Improved automatic context Object fetching.

Hello! Thanks for this great tool, pretty much just what I was looking for.

I had a question though. Aside from Dev.Log is there a way of automatically disabling all logs from builds; debug/non-debug.

I know there are some risks/implications with this, but it’d be very helpful and would save a lot of time from rewriting all the logs when using your tool in large large projects.

Thanks!

Hi there @Jh2556 ! I’m glad to hear you’ve found the asset useful.

I actually have been considering adding an option that would allow omitting all Debug method calls from release builds. I’ve been thinking I could also enable this mode automatically whenever the Use Player Log setting is set to false, since all those method calls are just wasted resources in that context anyways.

Critical.Log should also work together well with this approach, since you could still use it to log a couple of very important errors into a custom Log file for end users, even if all normal Debug.Log calls have been omitted.

Are you in a hurry to get this functionality? I’m a bit busy with other things right now, but I could start implementing this functionality in about a week’s time I think.

It took a bit longer than I first anticipated, but version 1.1.2 of Debug.Log Extensions now introduces support for removing all logging done using the extended Debug class from release builds.

When this new option is enabled in the settings all Debug.Log calls will be completely omitted from release builds, including any evaluation done for their parameters. So the cost of any string concatenations, ToString operations etc. in your Debug.Log calls will also get eliminated.

As mentioned previously, you can still use the new Critical class to bypass this and log some messages in release builds to custom log files. This works even if you have disabled Use Player Log in Player Settings.

Additionally the syntax highlighting feature has been improved in the new update. When you log a color to the console the text representation will now be tinted using the color in question.

Full source code is now also bundled with the download inside a unity package, along with a DLL builder. This means that is now possible for users to extend the Debug class with their own code and then integrate those changes into the DLL. Do note though that doing this would also mean losing the ability to update Debug.Log Extensions to newer versions (at least without losing your own changes), so it is not recommended in most situations. But if I should for example die in a car crash tomorrow it might come in handy :smile:

1 Like

Woah!! Thanks for this great update!!! :smile: (sorry I forgot to reply earlier)

1 Like

Hi

I think there is a bug in the Console+ Tab. Channel filtering does not work. The disabled channels still show up in the console.
5918975--632360--Screen Shot 2020-05-30 at 9.08.56 pm.png
macOS version: 10.14.6
Unity version: 2020.1.0b10.3837
Debug.Log Extensions version: 1.1.2

Edit:
I also tried on Unity 2019.3.11f1 and the issue still insists.

Hi Ben!

The channel dropdown works a bit differently than some of the other controls found on the console window. It doesn’t actually filter which ones of existing messages are currently listed on the window. Instead it lets you completely disable all messages that are henceforth logged using certain channels.

Because messages from disabled channels are completely ignored, you don’t take the usual performance hit from them, and they don’t cause your log file to grow bigger. So you could have hundreds of messages being logged every minute on all sorts of channels like audio, pathfinding and combat, but only have the channels that you currently care about actually be active.

The downside is that you can’t retroactively recover messages from channels that were disabled when the log call was made.

1 Like

How can I remove a channel?

Anytime I create a channel either via code or via Project Settings, the channel is created permanently. Even if I remove it from the Project Settings or the code, it still shows up in the Console+ tab.

The Console+ window will catch it when you use any channels in your debugging code and automatically adds them to the channels popup. This list is currently serialized so that it doesn’t get cleared for an open Console+ window even if scripts are recompiled, you enter play mode or stuff like that. This ensures that your settings for enabled/disabled channels won’t get reset every time you toggle play mode, restart the editor etc.

It looks like this list is a bit too persistent as it stands right now - the only way to clear it is by first closing the Console+ window and then restarting the editor or entering / exiting play mode.

I’ll think of ways on how this could be improved in the future, maybe e.g. by allowing the user to manually clear the list.

1 Like

Hi @SisusCo . I’ve been getting this error in Unity 2019.4.1f1

Any thoughts? Thanks!!

Can I make a request for the Channel filtering to be actually showing/hiding all messages per channel (instead of just for future logs)? Should be more useful that way.

Also what does the runtime GUI do exactly? Pressing the Insert key in playmode only shows a small white text: “Dynamic” near the top left corner.

Pretty cool plugin btw. I just purchased!

Hi @Jh2556

It seems like this error can occur if your project contains assets with a bad .meta file containing no guid.

Here are instructions on how you can find any files with missing guids. You’ll need to open Windows PowerShell, change the directory to your project’s asset directory and run the command given in that link.

Hope this helps!

Hi @Singtaa , thanks for the purchase and the feedback :slight_smile:

Currently the Console+ is a very simple wrapper on top of the default Console window and does little more than adds that Channel popup menu to the top.

I wholly agree that having the popup menu actually filter the contents of the window would be really nice, however this would mean having to rewrite almost all the functionality of the default Console window from scratch. And every time Unity would add new updates to their console window I might also have to update my window to have feature parity. For these reasons I’ve been wary of going with this approach.

I have actually done some experimenting with this full rewrite approach, and was able to replicate most of the default console window’s features. But some features like maybe device attaching could be problematic to replicate. Perhaps I could still finish it up and offer it as an experimental alternative to the wrapper variant, even if it’s missing some features though…

You can press the Insert key multiple times to cycle through three different modes.

  • In Dynamic mode the GUI will remain hidden except when Debug.DisplayOnScreen or Debug.ShowFps has been used to display something on the screen.
  • In Always Visible mode the GUI will always remain visible and also becomes interactive, allowing you to enable and disable channels through it.
  • In Always Hidden mode the GUI will always remain hidden, even if debugging information is being displayed on screen.
1 Like

Great! Thanks for the clarification. Real tag filtering and regex support may be worth the effort for the standalone new console. :wink:

@Singtaa So, I had a pretty productive weekend and as a result version 1.1.3 is out now with an all-new experimental Console+ window :smile:

It can be opened using the menu item Window > Debugging > Console+ (Experimental).

Regex support didn’t quite make it to the first version, but I’ll keep that idea in mind for future updates :wink:

1 Like

I’ve made some good progress with the new Console+ window.
If I’m going to have to write it all from scratch I might as well add some improvements on top :smile:

(P.S. regex support for the search is now also included :sunglasses:)

1 Like

@SisusCo I tried adding this to a mostly empty project (just game objects) and get a lot of errors like:

Library\PackageCache\com.unity.quicksearch@2.0.2\Editor\DebugTimer.cs(60,17): error CS0576: Namespace ‘’ contains a definition conflicting with alias ‘Debug’

Library\PackageCache\com.unity.burst@1.4.1\Editor\BurstAotCompiler.cs(420,29): error CS0576: Namespace ‘’ contains a definition conflicting with alias ‘Debug’

I’m using Unity 2020.2 let me know if you need more info.

Hi @jasons-novaleaf

The feature in Debug.Log Extensions that allows replacing the default Debug class across the project unfortunately does not work if any classes in the project contain the statement “using Debug = UnityEngine.Debug”. Lately it seems more and more packages have been added to the package manager containing this statement and thus making it practically impossible to use this feature in many projects.

So if you run into this conflict the only option currently is to not replace the Debug class globally by placing the extended Debug class in the global namespace, but to have it exist in a different namespace and then manually specify whenever you want to use it in your classes.

You can move the Debug class back under a unique namespace by going to Edit > Project Settings… > Console and unticking the Replace Default Debug Class option.

6800549--788729--Replace Default Debug Class.png

Because the project doesn’t compile it is possible that the settings do not get applied automatically, in which case you can do it manually instead by double-clicking the package found at Assets > Sisus > Debug.Log Extensions > Installers > Install In Unique Namespace and selecting Import.

(If after completing these steps you are still experiencing any issues you should do a clean install of Debug.Log Extensions.)

After this change you will need to add “using Debug = Sisus.Debugging.Debug;” to any classes where you want to enable Debug.Log Extensions’ enhancements.

I hope this helps! I have done some experiments with alternative ways to replace the default debug class which could help resolve these compatibility issues. So maybe in a future update it can become possible to replace the Debug class globally in any project no matter what packages are being used.

@SisusCo thank you for the reply. Unfortunately I can’t do either workaround.

The gui “console” setting in Project Settings does not exist. Also, the "Assets > Sisus > Debug.Log Extensions > Installers" folder does not exist.

6802367--789086--upload_2021-2-4_14-43-51.png

curiously, I see that the installers folder is listed in the asset store “Package Contents” but for some reason it’s not put into my project folder when I import it.

PS: Thank you for explaining the problem.