- Home /
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 just wanted to add a comment regarding making a static function to anyone considering it. By adding a static function, you are changing the call stack, specifically the top level of the call stack which is stored with the output message. As a result, you will no longer be able to double click on the editor output messages and be taken to the line of code from which the log originated, as you will ins$$anonymous$$d be taken to the new static function you created.
You can get around that by making the static function into a DLL, or you can not bother with that at all and just turn off "Use Player Log" in the player settings. (I don't think that option existed when this question was originally asked.)
its understandable to think this is a bug. stripping debug logging functionality from release builds is not uncommon and has certainly been a part of various certification requirements over the years... unity is the first engine i've worked with properly (including scratch built own engines) that doesn't include this functionality out of the box along with useful code-triggered breakpoint and assert functionality... however, given the enormous stack of technology involved i'm inclined to be a little forgiving. Unity is a strange environment compared to 'old school' native game development - performance considerations are very different - usual advice like not using RTTI and forbidding exceptions can not apply because these features are baked into the platform already... what was once an unacceptable performance cost is now acceptable as a trade off for ease of use by virtue of modern horsepower.
@semiessessi: it does have the option to remove debug log output out of the box; see my previous comment. Also it does breakpoints in code; see the section in the docs about the debugger.
Another reason why this may be useful is because you want to disable logging for plugins too.
Answer by zwacky · Jun 05, 2011 at 01:04 PM
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");
Thanks. It caused such performance loss because I call it about 50 times per frame in the menu. And yeah, a way so I don't have to this manually would be better than just deleting or commenting it out each time. I think I'm gonna write a wrapper that's something like: static function DebugLog(text:String) { if (Debug.isDebugBuild) Debug.Log(String); }
In a build, Unity's Debug.Log statement will do a bunch of stack trace parsing and then write to a file, so yes, it is that slow.
I'd recommend using preprocessor to do this if possible - it will save the compile time and potentially run-time checks (i have no idea how sufficiently smart the compiler is... they may or may not be removed - easier to not know imo). using custom preprocessor directives on a build is documented here: https://docs.unity3d.com/Documentation/$$anonymous$$anual/PlatformDependentCompilation.html
Answer by tteneder · Jul 16, 2015 at 12:36 PM
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 :)
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".
A downside with occupying the global Debug namespace however is that scripts using other Debug classes (like System.Diagnostics.Debug) start to complain about missing methods (like Assert).
hi meisi :) Your right, but since I didn't use Assert so far, I'm fine with it. There probably is no ideal solution atm.
$$anonymous$$aybe you've managed to find a solution for double click issue?
what issue do you mean? Double clicking log messages in Editor should work, since my custom Debug class is only compiled/used in non-editor and non-debug builds.
This does not work in current Unity versions anymore. You have to either add the define symbol in the unity player settings or add the define in all scripts that use our updated Debug class.
Just spend 2 hours trying to figure out why this was not working.
See: https://forum.unity.com/threads/conditionalattribute-not-working.469720/#post-3157609
This is brilliant! Similar to a global debug Trace class I created from Flash days:) So with this method you can leave ALL your Debug statements in your code and be assured they will NOT be called and impact performance in your release build, correct?
Correct! Been using it in production for years now. I just reassured by looking at the C++ code generated by IL2CPP. The log commands get stripped away completely!
It looks very useful but what should I do If I would like to see the debug messages on debug mode only? Something like this?
#if VERBOSE
#define DEBUG
#endif
Answer by xzodia · Sep 25, 2015 at 02:56 PM
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);
}
}
So do I put this script anywhere in a project or does it have to be on a specific folder? And btw, how could I test this with an Android app?
The location of the script file is not important, as long as it is within the Assets folder.
To view logs on Android devices (I asume connection and deploying via USB is already working), you can use adb ( http://developer.android.com/tools/help/logcat.html ).
I personally use/prefer the "monitor" tool (Comes with the Android SD$$anonymous$$ within the "tools" folder). It's a GUI to logcat that lets you create filters.
Answer by Peter G · Jun 05, 2011 at 01:12 PM
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!");
}
Right, see this page to see where the log output ends:
http://unity3d.com/support/documentation/$$anonymous$$anual/Log%20Files.html
Thanks, so it is as I assumed. If it's intentional, I find it strange that unity calls it "Debug", as I would expect anything by that name to do nothing in the build. And yes, I meant "commenting them out" when I said "remove". I guess I best just make a wrapper for it, so I don't have to do this manually all the time.
Debugging doesn't end with creating a build ;) If you have Debug.Logs that really should only work in the editor you can include it in a preprocesser if-statement #if UNITY_EDITOR #endif
Answer by ZowPac · Jun 19, 2012 at 11:22 PM
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.