How to use Debug Log in Unity (without affecting performance)

In Unity by John French12 Comments

Debugging in Unity can be a very simple thing to do.

In fact, even if you’re still new to Unity, you’ve probably already used Debug Log to send basic messages to the Console.

Which is useful, as being able to trigger messages from your scripts can be a great way to understand what’s happening behind the scenes.

However…

While using Debug Log to display a single message in the Console can be very straightforward, knowing how to use Unity’s debugging tools to manage an entire project can be much more challenging.

For example, how can you tell the difference between good log messages, that confirm that things are working properly, from bad ones, that can tell you that something’s gone wrong?

How can you manage different categories of debug messages, and avoid cluttering your Console with information about old work that you’ve already finished?

And when your game is done, how can you easily turn off some or all of your debug messages, to prevent them from negatively impacting your game’s performance?

There’s a lot to consider, but don’t worry, because in this article you’ll learn the basics of debugging in Unity, how you can use Unity’s debugging tools to your advantage and how to easily manage your debug messages as you go.

Here’s what you’ll find on this page:

Let’s get started.

How to use Debug Log in Unity

The simplest way to print a message in the console in Unity is by using the Debug Log function, which takes a string value and displays it in the Console window.

Like this:

void Start()
    {
        Debug.Log("Hello World");
    }

Which, in the Console, looks like this:

Example of Debug Log in Unity

In its most basic form, Debug Log prints a single message, that will be shown in the Console when that line of code gets executed.

However, while what you see in the Console is a simple string, you can pass in just about anything you like.

For example, a float value:

float health = 100;
void Start()
{
    Debug.Log(health);
}

Which can be useful for checking the value of a variable at a specific time.

Like this:

Debug a float variable in Unity

An object or property reference:

void Start()
{
    Debug.Log(gameObject.name);
}

Which, in this case, gets the name of the object that the script is attached to.

Which, in the Console, looks like this:

Debug Game Object example Unity

A conditional value:

void Start()
{
    Debug.Log(1 + 1 == 2);
}

Which, in the Console, returns a true or false statement depending on the result of the conditional check.

Like this:

Debug Boolean condition example in Unity

Or a mixture of text and variables:

float health = 100;
void Start()
{
    Debug.Log("Player Health: " + health);
}

Which allows you to add any combination of text and variable data to a Console message.

And looks like this:

Debug Log string and variables example

How to connect a Debug Log message with a specific object

While the basic method of using Debug Log displays a message in the Console, it’s also possible to provide a reference to an Object that the message may relate to.

For example, you could pass in a reference to the game object that the script is attached to.

Like this:

float health = 100;
void Start()
{
    // Logs the player's health, with a reference to this game object.
    Debug.Log("Player Health: " + health, gameObject);
}

Then, in the Unity Editor, clicking on the message in the Console will show you exactly which object it relates to.

Like this:

Debug Log Context

Providing an object reference will show you, in the Editor, which object relates to a specific Console message.

This can be useful for working out which object is associated with a specific message or error, particularly if it could have been generated from any one of a number of duplicated objects.

Debug Log vs Print to Console

Print is a built-in method that prints a message to the Console in Unity in almost the exact same way as Debug Log does.

Like this:

print("This is a print message");

The only real difference is that print is a little easier to write however it doesn’t support an object context in the same way as Debug Log does.

Print is also a method of the Monobehaviour Class meaning that, if your script doesn’t inherit from Monobehaviour, for example, because it’s static, then you won’t be able to use Print, and you’ll need to use Debug Log instead.

How to use Debug Warning and Debug Error

While Debug Log can be useful for displaying information about what’s happening in your game, it’s also possible to use the Debug Console to display your own warnings and errors as well.

This works by using the Log Warning and Log Error functions.

Like this:

void Start()
    {
        Debug.Log("This is a basic log message");
        Debug.LogWarning("This is a basic warning message");
        Debug.LogError("This is a basic error message");
    }

Which, in the Console, will appear as errors and warnings, just like the ones that are generated by Unity.

Like this:

Console Log Messages in Unity

Debug Log, Warning and Error will each display a message of that category in the Console.

This can be useful for raising different types of notification, instead of just basic messages, and can be particularly helpful when you want to distinguish between informational logs and an alert that something is not working in the way that it’s supposed to.

For example, you could use a warning to remind yourself that a particular script hasn’t been set up properly, or an error to catch a mistake that you know will cause a problem.

Log Messages, Warnings and Errors can each be shown or hidden by using the filtering tools available in the top right-hand corner of the Console.

Filter notifications in Debug Console Unity

You can use the filter buttons in the Console to hide certain types of log messages. Be careful though, it can be very easy to forget that certain messages are being hidden.

Using different categories of messages can help you to find problems in your game more easily.

But, that can sometimes be difficult to do when you’re not sure when an error has occurred and what else was happening at the time.

So how can you debug your game in a way that makes catching problems easier to do.

How to use debug messages to check for problems

One basic method of catching issues as they happen is to enable Error Pause in the Console.

Error Pause in Unity

Enabling Error Pause will stop the game when something goes wrong.

This will pause the Unity Editor when an error occurs which can make it significantly easier to work out what the cause was.

However, that’s not the only way you can pause the Editor using debug messages.

Debug Break, for example, allows you to deliberately pause the Unity Editor at a specific moment in time:

Debug.Break();

This can be useful for diagnosing problems or checking data that would be difficult to see while the game runs at full speed.

Lastly, Debug Assert can be used to double-check if what you expected to happen in a script actually did.

This works by passing in a conditional value to the Assert function, that will either be true or false, along with a message, that can be used to describe the problem.

For example:

public int one = 1;
public int two = 2;
public int three = 3;
void Start()
{
    Debug.Assert(one + two == three, "1 plus 2 did not equal 3");
}

The Debug Assert function expects the conditional value to be true and, if it’s not, an error will be raised, using the message that’s passed in.

This can be useful for double-checking what you think you know, or testing to see if variable data is what you thought it was going to be.

By default, Debug Assert assumes that the conditional value that you pass in is meant to be true.

However, there may be times when you want to check that something is false, that two things are not the same or that two float-based values, which can be difficult to directly compare, are roughly equal or not.

Luckily, the Assert Class provides a number of additional comparison functions that allows you to do exactly that and to check that a value or a method is doing what it’s meant to do.

Visual debugging in Unity

While Debug Log can be useful for understanding what’s happing to the data in your scripts, it can sometimes be easier to see what’s going on behind the scenes.

In Unity, there are a few different ways to do this.

For example, the Inspector has a debug mode, that allows you to see normally hidden information about a component, such as the values of private variables.

Debug Inspector example in Unity

Enabling the Debug Inspector will show you additional information about an object’s components, including the values of private variables.

The Debug Class also provides two methods for displaying visual lines in the Unity Editor as the game runs, which can be useful for visually identifying direction vectors and even connections between objects. 

Debug Draw Line, for example, draws a line between two points, such as two object positions, and can be useful for showing a link between objects in the Scene.

Like this:

public class VisualDebugging : MonoBehaviour
{
    public Transform otherCube;
    void Update()
    {
        // Draws a line between the object and the other cube
        Debug.DrawLine(transform.position, otherCube.transform.position);
    }
}

While Debug Draw Ray, allows you to draw a direction vector in the scene, which can help to debug detection zones, weapon trajectories and mouse to world input:

Like this:

public class VisualDebugging : MonoBehaviour
{
    void Update()
    {
        // Draws a 10 unit long line in the Scene view going up
        Debug.DrawRay(transform.position, Vector3.up * 10);
    }
}

How to format Debug Log messages in Unity

Once you’re familiar with how to print a message to the Console in Unity, you might want to format how that message is displayed.

The dotted menu icon at the top right of the Console, allows you to hide some of the additional information that you may not always need but that is provided by default.

It also allows you to change the number of lines used to display each entry.

Console Formatting Options in Unity

Which can make reading the Console much easier to do at a glance:

Debug Console - 1 line per entry

But that’s not all.

While Unity provides a number of filtering and display options in the Console window, it’s possible to format the actual text that is displayed in the message, using Rich Text Formatting.

Which can be used to change the size, emphasis and even the colour of text in the Debug Console window.

How to change the colour of Debug Log messages in the Console

To change the colour of the text in a Debug Log message, simply wrap the text you’d like to highlight with a Color Tag.

Like this:

Debug.Log("<color=red>This is a red message</color>");
Debug.Log("<color=blue>This is a blue message</color>");
Debug.Log("This is <color=red>red</color> & <color=blue>blue</color>");
Debug.Log("<color=#cd542a>This is my favourite shade of orange</color>");

The Color Tag accepts colours defined by specific names, such as red, blue or magenta as well as hex values.

It’s also possible to make the text in a Debug Log message bold, italic or even change its size.

How to make Debug Log text bold, italic or create new lines

To change the formatting of the Debug Console text, simply add tags before and after whatever text you’d like to format.

Like this:

Debug.Log("<b>This is bold.</b>");
Debug.Log("<i>This is italic</i>");
Debug.Log("<size=25>This Text is BIG</size>");
Debug.Log("<size=5>This Text isn't</size>");

It’s even possible to create new lines using the new line character. 

Like this:

Debug.Log("This is a \n new line.");

For more information on how to format Console messages in Unity, see the official documentation here.

How to use Debug Log Format

Debug Log, Debug Warning and Debug Error each allow you to send a message to the Console.

And, by using string concatenation, which typically involves adding variables and sections of text together to form a single string, it’s possible to record information to the Console in pretty much any way that you would like.

However, combining multiple parameters and sections of text in this way can lead to lines of code that are long and tricky to write.

Instead, formatting a string with defined parameters can be an easier way to insert data into the text without splitting it up.

To use string formatting with debug messages in Unity, simply choose the Format version of the Log, Warning or Error functions: Log Format, Warning Format or Error Format, which will allow you to insert parameters into the string of the message without breaking it up.

Like this:

string playerName = "Keith";
float health = 100;
void Start()
{
    Debug.LogFormat("{0}'s Health is {1}", playerName, health);
}

This works by marking a numbered position in your text with brackets for each of the arguments that you pass in to the Format method.

In this case, the player’s name is the first argument, marked with a 0, while their health value is the second, marked with a 1.

Which, in the Console, looks like this:

Debug Log Format example in Unity

Log Format also makes it possible to display data in a specific format.

This can be useful when numbers, for example, need to be displayed to a specific number of digits. Such as for a timer that shows a minutes and seconds display

Like this:

void WhatsTheTime()
{
    float minutes = Mathf.FloorToInt(Time.realtimeSinceStartup / 60);
    float seconds = Mathf.FloorToInt(Time.realtimeSinceStartup % 60);
    Debug.LogFormat("The game has been running for {0:00}:{1:00}", minutes, seconds);
}

In this case, each of the placeholders also specifies that the number passed in should be displayed as a 2 digit value.

The best way to use Debug Log

Debug Log is an extremely useful feature of Unity that allows you to understand what’s happening behind the scenes of your game in an easy and simple way.

However…

While the Debug Log function might appear to be simple and lightweight, it can actually be very slow and, depending on how you’re using Debug Log in your game, can cause significant performance issues.

This happens because Debug Log writes every message to an actual file, on your computer’s hard disk, which can be a slow operation to perform.

What’s more, the Debug Log function creates garbage which, if used frequently or excessively, can lead to stuttering and hitches in gameplay as it’s collected.

While this isn’t necessarily a problem when you’re working on your game, it might surprise you to know that debug messages will be included, and called, in your finished build by default.

Meaning that every Debug Log, Warning and Error function that you use while you’re building your game will be also be called, and logged, in your finished game too.

In some cases, this might be exactly what you want. 

After all, the purpose of logging information is so that you can use it to identify problems.

However, if you’re using Debug Log excessively in your project, it can cause a noticeable drop in performance.

For this reason, it can be a good idea to use Debug Log sparingly and to avoid calling it frequently in Update.

However, depending on how much you’ve used Debug Log, you might want to completely disable log messages in your finished game.

So how can you turn Debug Log off? 

How to disable Debug Log messages in Unity

Because of the potential performance impact of using Debug Log in your game, you may wish to turn off some or all debugging in your finished project.

There are a number of ways you could do this.

For example, it’s possible to exclude certain code from being used in built games with Platform Dependent Compilation.

Like this:

#if UNITY_EDITOR
     Debug.Log("This will only be included in the Editor");
 #endif

This will mean that code inside of the conditional statement simply won’t be compiled if the platform doesn’t match, which can be useful for running platform-specific debugging or for turning it off altogether.

However,

While checking if the game is running in the Editor or in a standalone build will work, it’s not a convenient option and, if you’re using multiple Debug Log messages throughout your code, wrapping each one with a conditional statement can be time-consuming and can clutter up your scripts.

So what are the alternatives?

How can you turn off some or all of the debugging in your game, without adding conditional checks to every Debug Log call in every script?

Option 1: Disable the Player Log

In Project Settings, under the Player Tab, you’ll find an option to disable the Player Log, which is the file that Debug Log writes to when it’s called.

Use Player Log Option

Disabling the Player Log prevents Unity from writing a log file when the game runs. However this won’t stop Debug Log from being called.

This can dramatically improve performance as, writing to a file, compared to most game functions, can be an extremely slow process.

However, while this will improve performance dramatically, by removing the need to write each log entry to disk, Debug Log will still be called and, as a result, will still generate garbage, which can cause performance issues.

If you’re only occasionally calling Debug Log, this might not be a problem for you.

But, if you’re using Debug Log frequently, from many different objects, you may start to notice stuttering and hitches as garbage is collected.

In which case, turning off the Player Log doesn’t make a lot of sense, as you’d still be sacrificing part of your game’s performance with no real benefit.

So what else can you do?

Option 2: Use a custom Debug function

One option for disabling log messages in your finished project is to create a custom debug function inside a static class and then wrap that in a conditional check.

Like this:

public static class GameLog
{
    public static void LogMessage(string message)
    {
        #if UNITY_EDITOR
        Debug.Log(message);
        #endif
    }
    public static void LogWarning(string message)
    {
        #if UNITY_EDITOR
        Debug.LogWarning(message);
        #endif
    }
    public static void LogError(string message)
    {
        #if UNITY_EDITOR
        Debug.LogWarning(message);
        #endif
    }
}

Then whenever you want to use Debug Log, simply call your custom function instead of the standard Debug method.

Like this:

GameLog.LogMessage("This is a custom Log Message!");

This makes it possible to exclude debug messages from your finished game, but without needing to wrap every debug method in its own compilation check.

This works, and can be a useful way to manage excessive logging in your game so that it doesn’t hurt performance.

However, this method can still cause performance problems in your game, depending on how you’re using log messages.

This is because, while the content of the function is wrapped in a conditional check, the function itself can still be called.

Which, while this prevents the large performance overhead of using Debug Log, doesn’t avoid the potential to create garbage when defining its contents.

If you’re just using simple strings in your log messages, then this may not be a problem for you as, even though the function is still being called, surprisingly, no garbage is generated.

Unity Profiler showing no garbage

However, if you combine two strings together, as you’re likely to do when introducing game data to a debug message, the string concatenation process will create garbage, even though the function is, essentially, empty.

To avoid this, it’s possible to make the method itself conditional, meaning that it, and any calls to it, will not be compiled unless a define symbol exists, such as the UNITY_EDITOR symbol.

Like this:

[System.Diagnostics.Conditional("UNITY_EDITOR")]
    public static void LogMessage(string message)
    {
        Debug.Log(message);
    }

Or you can use a custom symbol, in which case you’ll need to enable it by adding the define preprocessor directive to the top of the script.

Like this:

#define MYSYMBOL
using UnityEngine;
public class MyClass : MonoBehaviour
{
    void Start()
    {
        GameLog.LogMessage("This will only appear if the define symbol is set!");
    }
}

This is one of the best methods for removing debug messages from a finished game because it excludes the message function and the call to it, avoiding garbage*.

What’s more, it allows you to easily enable or disable messages globally.

However, this may not be as useful to you if you’ve already added a large number of log messages to your game using Unity’s existing Debug Log function.

So how can you turn off debug messages, without using custom functions?

Option 3: Disable the Unity Logger

An easy way to disable all Debug Log functions in Unity is to simply turn off the Unity Logger.

This works by setting the Log Enabled property of the Logger to false.

Debug.unityLogger.logEnabled = false;

This works in the Editor and in standalone builds of the project and prevents all debug messages from being called, saving performance and avoiding garbage.

Typically, however,  you might only want to disable debug messages in your finished project, in which case it’s possible to enable or disable the Logger depending on if the project is a Debug Build or not.

Like this:

private void Awake()
{
    Debug.unityLogger.logEnabled = Debug.isDebugBuild;
}

This means that log messages will only be called in the Editor and in a build of the game if it’s marked as a development build.

Debug Build in Unity

Using isDebugBuild, it’s possible to enable log messages in the Editor and in Development Builds only.

However, what if you only want to disable some, but not all, log messages.

For example, you might want to keep certain messages, such as warnings and errors, in the log, so that you know if something went wrong in the build of your game.

Or you might want to disable messages relating to a particular feature that were useful while you were working on it, but are, now, just cluttering up the Console.

How can you categorise different messages into groups so that you can turn some of them off but leave others on?

How to turn off some, but not all, Debug Log messages in Unity

In the same way that it’s possible to disable the default Unity Logger, it’s possible to create new Logger instances, that can be used to categorise log messages into different groups, and then turn them on or off as you like.

This is useful, as it allows you to separate the messages that you use during development from the errors and the warnings that you might need to be able to check for in a build.

Here’s how it works.

To make a new Logger, create a new Logger instance that is public and static so that any script can access it.

Like this:

public static class Logging
{
    public static Logger myLogger = new Logger(Debug.unityLogger.logHandler);
}

To initialise the Logger instance, you’ll need to pass in a Log Handler, which manages saving log messages to a file on your computer’s hard drive.

In this example, I’m using the same Log Handler as the default Logger, meaning that, even though the log messages can be enabled or disabled separately, they’ll still be written to the same log file.

Once you’ve created a new Logger, you can use it to create debug messages with the Logger’s Log function, which works in the same way as Debug Log does.

Like this:

Logging.myLogger.Log("This message uses my custom Logger");

Setting up your own Loggers in this way allows you to enable or disable specific logging functions in your finished game and in the Editor.

For example, you could create different logging categories for combat, for your player, or for any other feature that might require extensive logging but that you’d like to have the option of turning off later on.

For this to work, create new Loggers for any categories of logging that you want to be able to separate and create a static function, in the same class (so that it’s easy to find and modify), that will specify if they are enabled or disabled.

public static class Logging
{
    public static Logger combatLogger = new Logger(Debug.unityLogger.logHandler);
    public static Logger playerLogger = new Logger(Debug.unityLogger.logHandler);
    public static void LoadLoggers()
    {
        // Call this function when the game starts
        combatLogger.logEnabled = true;
        playerLogger.logEnabled = true;
    }
}

Then, to set your debugging preferences, call the Load Loggers function when the first Scene loads.

Like this:

public class LoadLoggers : MonoBehaviour
{
    private void Awake()
    {
        Logging.LoadLoggers();
    }
}

Enabling or disabling groups of log messages in this way can be an efficient method for managing debug functions in your game.

However, while this method prevents the processing and garbage overheads of using the Debug Log function, just like when using conditional statements inside of a function, it doesn’t prevent garbage from being created when it’s called.

Meaning that, if you’re passing concatenated strings to the Debug Log function, it will still create some garbage.

As a result, if it’s an option for you, the best method for managing debug messages inside of a finished game is to exclude them from compilation entirely, by calling a custom function with a conditional attribute.

Now it’s your turn

Now I want to hear from you.

How are you debugging your project?

Are you using a custom Logger?

Or have you created your own debug functions?

And what have you learned about debugging in Unity that you know other people will find useful?

Whatever it is, let me know by leaving a comment below.

by John Leonard French

Game audio professional and a keen amateur developer.

Get Game Development Tips, Straight to Your inbox

Get helpful tips & tricks and master game development basics the easy way, with deep-dive tutorials and guides.

My favourite time-saving Unity assets

Rewired (the best input management system)

Rewired is an input management asset that extends Unity's default input system, the Input Manager, adding much needed improvements and support for modern devices. Put simply, it's much more advanced than the default Input Manager and more reliable than Unity's new Input System. When I tested both systems, I found Rewired to be surprisingly easy to use and fully featured, so I can understand why everyone loves it.

DOTween Pro (should be built into Unity)

An asset so useful, it should already be built into Unity. Except it's not. DOTween Pro is an animation and timing tool that allows you to animate anything in Unity. You can move, fade, scale, rotate without writing Coroutines or Lerp functions.

Easy Save (there's no reason not to use it)

Easy Save makes managing game saves and file serialization extremely easy in Unity. So much so that, for the time it would take to build a save system, vs the cost of buying Easy Save, I don't recommend making your own save system since Easy Save already exists.

Additional Credits

  • Many thanks to Daniel in the comments, who pointed out that calls to a disabled logger / custom functions can still cause garbage.

Comments

  1. Very comprehensive overview. I’ve only just started with Unity, so this is very useful to me. Thanks!

  2. Great article, have been using Unity for over a decade and still learned some good stuff!

  3. Very nice and comprehensive blog post.

    While it’s outside of the scope of this article, I’d like to mention that using breakpoints in Visual Studio is often a much better way to debug your code. It automatically pauses where you want it to, and lets you inspect all the variables by hovering the mouse over them right in VS.

    I only recently started using breakpoints, and it’s made debugging much more efficient for me – so hopefully someone else sees this comment and becomes enlightened like I did.

    1. Author

      Absolutely! while I didn’t look into them in-depth for this article, they can be amazing. If you’ve ever found yourself setting everything to public, because you don’t know what’s going on in the script… Breakpoints!

  4. Awesome stuff man !
    I have more than 5y struggling to learn many aspects of how to build a complete game, but in terms of programming the resources are scattered and the yt videos outthere are scattered and not very cocnise.
    I find your blog posts to be very concise and very very helpful !

    I implemented the above by making some bools serialized in inspector in the MB script and is great !

    Q1: how to have separate files to save the logs ?
    “Debug.unityLogger.logHandler” how to change the logHandler here ?

    Q2: the files gets erased on stop playing in Unity editor ?
    if not, can I erase the logs ?

    Thanks

    1. Author

      Thanks, I assume it’s possible to make a new Log Handler, instead of using the existing Unity one, but that’s not something I tested as part of this article. Regarding the files, I believe that the same files get reused. Hope that helps!

  5. Hi, I tested this and profiled the result. Unfortunately this does not address the problem of garbage generation.

    Since the string is in the method call, it is allocated even though it is not written to the log. This will cause garbage collection eventually.

    A way to avoid all allocations is to use:

    [System.Diagnostics.Conditional(“LOG_ENABLED”)]
    public static void Log(object message, UnityEngine.Object context = null)
    {
    Debug.Log(message, context);
    }

    Enable it via: #define LOG_ENABLED

  6. This is a very comprehensive and helpful article.

    However, a word of warning when using:

    Debug.unityLogger.logEnabled = false;

    in a production build because this may prevent proper symbolication of crash reports.

    With this line in my code I was getting no symbolication in stack traces from Crashlytics, Unity Crash & Exception Reporting or crash reports from the Play Console. Once I removed this line, symbolication appeared.

Leave a Comment