Debug.Log() in build

I was assuming writing debug.log() would have no effect on the performance in the build.

I noticed that my menu runned at about 4 fps in the editor, which turned to 500 fps after removing all the debug.log there.
However, it seems that my menu also runs very slowly (presumably also around 4 fps) in the build when I still have these debug.log there.

This leads me to believe that debug.log is still executed (but fails), rather than removed altogether.

Is this the case ?
because that would be quite annoying, as I’d have to remove all the debug stuff if I want to make a smooth build.

EDIT:

Apparently this is the case and intentional.
Thanks for the answers guys.

I think I’m gonna write a wrapper that’s something like:

static function DebugLog(text:String)
{ 
    if (Debug.isDebugBuild) 
        Debug.Log(text);
}

I have another alternative:

Create a custom “Debug” class in global space, that get’s used in release builds only and make its Log methods conditional:

#if DEBUG
#define VERBOSE
#endif

#if !UNITY_EDITOR && !VERBOSE
using UnityEngine;
using System.Diagnostics;
using System.Runtime.InteropServices;

public static class Debug {

	[Conditional("VERBOSE_EXTRA")]
	public static void LogInfo(string message, UnityEngine.Object obj = null) {
		UnityEngine.Debug.Log(message, obj);
	}

	[Conditional("VERBOSE")]
	public static void Log(string message, UnityEngine.Object obj = null) {
		UnityEngine.Debug.Log(message, obj);
	}

	public static void LogWarning(string message, UnityEngine.Object obj = null) {
		UnityEngine.Debug.LogWarning(message, obj);
	}

	public static void LogError(string message, UnityEngine.Object obj = null) {
		UnityEngine.Debug.LogError(message, obj);
	}

	public static void LogException(System.Exception e) {
		UnityEngine.Debug.LogError(e.Message);
	}
}
#endif

The main advantage is, that the log usage doesn’t differ at all, so it’s easy to introduce it anytime:

Debug.Log("Somethings going on here");

Note:
I still want Warnings and Errors to be logged, so I didn’t make them conditional.
Starting with Unity 5.1, DEBUG gets defined automatically as soon as you create a development build.

Downside:
UnityEngine.Debug methods other then Log, LogInfo, LogWarning and LogError have to be issued with the complete namespace. For example:

UnityEngine.Debug.DrawLine(...);

This can easily be resolved by wrapping them all in our own Debug class. Feel free to do that, I simply was too lazy :slight_smile:


My thoughts on how I got to this solution:

The solutions presented so far have one thing in common, they utilize an if statement. Downsides:

  • you actually have to write it out on every log occasion.
  • It generates an unnecessary evaluation at runtime.

You could argue that the impact of the if statement is minimal, but that didn’t keep me from optimizing.

One way would be to use preprocessor directives, which totally work, but you’d still have to wrap every log statement with ugly code:

#if DEBUG
	Debug.Log("Somethings going on here");
#endif

To get rid of this I wrote my own class, which wrapped the Log calls with conditional methods. I assume the calls don’t even exist in runtime assemblies. Something like that:

public class Logging {
	[Conditional("DEBUG")]
	public static void Log(string message) {
		Debug.Log(message);
	}
}

This works, but has these flaws:

  • You have to change every “Debug.Log” call to “Logging.Log”
  • In the Editor, you lose the feature of double clicking logs and jumping directly to the original place where the Log was issued, since you’ll now end up in our new Logging class all the time. This is a major time waste.

Next step: rename the Logging class to “Debug”. Since this new Debug class is in global namespace it automatically gets used instead of Unity’s UnityEngine.Debug if you use it without the complete namespace when calling it. You now don’t need to change Debug.Log calls at all, though the Editor click redirection still won’t work.

Our Debug class now prevents Logs in non DEBUG environments. As the last step I put the whole class into preprocessor statements that enable it only outside the Editor in non development builds or if you add the scripting define symbol “VERBOSE”.

I liked @atti 's solution, and decided to finish it off. Also added a few extra methods that auto concat args.

#if DEBUG || UNITY_EDITOR
#define VERBOSE
#endif

#if UNITY_EDITOR
#define VERBOSE_EXTRA
#endif

using UnityEngine;
using System.Diagnostics;
using UnityEngine.Internal;
using System;

public static class Debug
{
    //
    // Summary:
    //     Opens or closes developer console.
    public static bool developerConsoleVisible { get { return UnityEngine.Debug.developerConsoleVisible; } set { UnityEngine.Debug.developerConsoleVisible = value; } }
    //
    // Summary:
    //     In the Build Settings dialog there is a check box called "Development Build".
    public static bool isDebugBuild { get { return UnityEngine.Debug.isDebugBuild; } }

    //
    // Summary:
    //     Assert the condition.
    [Conditional("UNITY_ASSERTIONS")]
    public static void Assert(bool condition)
    {
        UnityEngine.Debug.Assert(condition);
    }
    //
    // Summary:
    //     Assert the condition.
    [Conditional("UNITY_ASSERTIONS")]
    public static void Assert(bool condition, string message)
    {
        UnityEngine.Debug.Assert(condition, message);
    }
    //
    // Summary:
    //     Assert the condition.
    [Conditional("UNITY_ASSERTIONS")]
    public static void Assert(bool condition, string format, params object[] args)
    {
        UnityEngine.Debug.Assert(condition, format, args);
    }
    public static void Break()
    {
        UnityEngine.Debug.Break();
    }
    public static void ClearDeveloperConsole()
    {
        UnityEngine.Debug.ClearDeveloperConsole();
    }
    public static void DebugBreak()
    {
        UnityEngine.Debug.DebugBreak();
    }
    //
    // Summary:
    //     Draws a line between specified start and end points.
    public static void DrawLine(Vector3 start, Vector3 end)
    {
        UnityEngine.Debug.DrawLine(start, end);
    }
    //
    // Summary:
    //     Draws a line between specified start and end points.
    public static void DrawLine(Vector3 start, Vector3 end, Color color)
    {
        UnityEngine.Debug.DrawLine(start, end, color);
    }
    //
    // Summary:
    //     Draws a line between specified start and end points.
    public static void DrawLine(Vector3 start, Vector3 end, Color color, float duration)
    {
        UnityEngine.Debug.DrawLine(start, end, color, duration);
    }
    //
    // Summary:
    //     Draws a line between specified start and end points.
    public static void DrawLine(Vector3 start, Vector3 end, [DefaultValue("Color.white")] Color color, [DefaultValue("0.0f")] float duration, [DefaultValue("true")] bool depthTest)
    {
        UnityEngine.Debug.DrawLine(start, end, color, duration, depthTest);
    }
    //
    // Summary:
    //     Draws a line from start to start + dir in world coordinates.
    public static void DrawRay(Vector3 start, Vector3 dir)
    {
        UnityEngine.Debug.DrawRay(start, dir);
    }
    //
    // Summary:
    //     Draws a line from start to start + dir in world coordinates.
    public static void DrawRay(Vector3 start, Vector3 dir, Color color)
    {
        UnityEngine.Debug.DrawRay(start, dir, color);
    }
    //
    // Summary:
    //     Draws a line from start to start + dir in world coordinates.
    public static void DrawRay(Vector3 start, Vector3 dir, Color color, float duration)
    {
        UnityEngine.Debug.DrawRay(start, dir, color, duration);
    }
    //
    // Summary:
    //     Draws a line from start to start + dir in world coordinates.
    public static void DrawRay(Vector3 start, Vector3 dir, [DefaultValue("Color.white")] Color color, [DefaultValue("0.0f")] float duration, [DefaultValue("true")] bool depthTest)
    {
        UnityEngine.Debug.DrawRay(start, dir, color, duration, depthTest);
    }

    [Conditional("VERBOSE_EXTRA")]
    public static void LogInfo(object message, UnityEngine.Object context = null)
    {
        UnityEngine.Debug.Log(message, context);
    }
    [Conditional("VERBOSE_EXTRA")]
    public static void LogInfoCat(params object[] args)
    {
        UnityEngine.Debug.Log(string.Concat(args));
    }
    //
    // Summary:
    //     Logs message to the Unity Console.
    [Conditional("VERBOSE")]
    public static void Log(object message, UnityEngine.Object context = null)
    {
        UnityEngine.Debug.Log(message, context);
    }
    //
    // Summary:
    //     Logs message to the Unity Console.
    [Conditional("VERBOSE")]
    public static void LogCat(params object[] args)
    {
        UnityEngine.Debug.Log(string.Concat(args));
    }
    //
    // Summary:
    //     A variant of Debug.Log that logs an error message to the console.
    public static void LogError(object message, UnityEngine.Object context = null)
    {
        UnityEngine.Debug.LogError(message, context);
    }
    //
    // Summary:
    //     A variant of Debug.Log that logs an error message to the console.
    public static void LogErrorCat(params object[] args)
    {
        UnityEngine.Debug.LogError(string.Concat(args));
    }
    //
    // Summary:
    //     Logs a formatted error message to the Unity console.
    public static void LogErrorFormat(string format, params object[] args)
    {
        UnityEngine.Debug.LogErrorFormat(format, args);
    }
    //
    // Summary:
    //     Logs a formatted error message to the Unity console.
    public static void LogErrorFormat(UnityEngine.Object context, string format, params object[] args)
    {
        UnityEngine.Debug.LogErrorFormat(context, format, args);
    }
    //
    // Summary:
    //     A variant of Debug.Log that logs an error message to the console.
    public static void LogException(Exception exception)
    {
        UnityEngine.Debug.LogException(exception);
    }
    //
    // Summary:
    //     A variant of Debug.Log that logs an error message to the console.
    public static void LogException(Exception exception, UnityEngine.Object context)
    {
        UnityEngine.Debug.LogException(exception, context);
    }
    //
    // Summary:
    //     Logs a formatted message to the Unity Console.
    [Conditional("VERBOSE")]
    public static void LogFormat(string format, params object[] args)
    {
        UnityEngine.Debug.LogFormat(format, args);
    }
    //
    // Summary:
    //     Logs a formatted message to the Unity Console.
    [Conditional("VERBOSE")]
    public static void LogFormat(UnityEngine.Object context, string format, params object[] args)
    {
        UnityEngine.Debug.LogFormat(context, format, args);
    }
    //
    // Summary:
    //     A variant of Debug.Log that logs a warning message to the console.
    public static void LogWarning(object message, UnityEngine.Object context = null)
    {
        UnityEngine.Debug.LogWarning(message, context);
    }
    //
    // Summary:
    //     A variant of Debug.Log that logs a warning message to the console.
    public static void LogWarningCat(params object[] args)
    {
        UnityEngine.Debug.LogWarning(string.Concat(args));
    }
    //
    // Summary:
    //     Logs a formatted warning message to the Unity Console.
    public static void LogWarningFormat(string format, params object[] args)
    {
        UnityEngine.Debug.LogWarningFormat(format, args);
    }
    //
    // Summary:
    //     Logs a formatted warning message to the Unity Console.
    public static void LogWarningFormat(UnityEngine.Object context, string format, params object[] args)
    {
        UnityEngine.Debug.LogWarningFormat(context, format, args);
    }
}

can’t think of debug.log to cause such performance loss other than due to exceptions, but you may want to add a static variable that defines whether you wan’t to log or not.
this way you don’t have to delete every debug.log within the code.

static var DEBUG : boolean = true;
...
if (DEBUG) Debug.Log("logging");

Debug.Log() is still called when you are in a build so it could have an effect on performance depending on how much you call it. On iOS, it will actually log your information into the internal profiler if you are connected to xCode.

Removing them all is one option. I would just comment them out, or you can do this like the scripting ref suggests:

// Log some debug information only if this is a debug build
if (Debug.isDebugBuild) {
    Debug.Log ("This is a debug build!");
}

I have definitely seen Debug.Log() be a performance problem. Even one can cause a little hiccup on a smallish platform if you have enough going on.

One thing I should mention that took me a little while to realize when I did a similar solution to your DebugLog() function is that often I would end up doing something like:

DebugLog("Here in Func() " + var1 + " / " + var2 + " / " + var3);

The string argument is evaluated whether or not you eventually log them, and they tend to be slow too - especially with concatenation. String.Format() is better, but still, I’ve come around to commenting these things out when not needed, and using #if UNITY_EDITOR for those I heavily rely on.

Suggestion to flaw above:

  • In the Editor, you lose the feature of double clicking logs and jumping directly to the original place where the Log was issued, since you’ll now end up in our new Logging class all the time. This is a major time waste.

Solution: If you compile your Logging class to a dll and include it in your project this problem goes away.

And now to disable it entirely from Unity 5.3 + you can use

Debug.logger.logEnabled = false;

All thanks to this thread I got to know about this new feature:
http://forum.unity3d.com/threads/is-it-possible-to-disable-all-debug-logs-in-builds.361553/

@atti @xzodia FYI I added another variant, Debug.log( msg, mask ) where the log only gets printed when int Debug.logMask matches the given mask (binary &). This is useful when debugging several paths through the code at the same time, you can leave the Debug.log calls in but toggle them on/off as needed in context.

public static int logMask = -1; // all masks are printed

//
// Summary:
//    Log with masking
//      give a binary mask (eg power of 2) will only get logged when Debug.debugMask matches it
//    Example
//      Debug.logMask = 4; 
//      Debug.Log( "printed", 4 );
//      Debug.Log( "not printed", 1);
//      Debug.logMask = 5; 
//      Debug.Log( "printed", 4 );
//      Debug.Log( "printed", 1);
//
[Conditional("VERBOSE_EXTRA")]
public static void Log(object message, int mask)
{
    if ((Debug.logMask & mask) == mask)
    {
        UnityEngine.Debug.Log(message);
    }
}

If you don’t want to use a whole new class but you already have a huge project with many print()/Debug.Log() :
CTRL + F and in the first slot you put :

print(

OR if you use Debug.Log :

Debug.Log(

and second slot , you put : (in visual studio you press the arrow that points down to open it)

if (Debug.isDebugBuild) print(

OR if you use Debug.Log :

if (Debug.isDebugBuild) Debug.Log(

Select “Complete Solution” or “Actif project” as your target in the dropdown

Then press Replace All.

**This will just “Add” ** :

if (Debug.isDebugBuild)
before every Debug.Log() or before every print()

after that press File → “Save All” and your project should work just as before but you’re protected from the debug performance issues.

I replaced 1200 occurences of print( , saved me a lot of time and everything works