PERF.LOG001

Debug.Log calls still cost time in a release build

Warning Performance Report only — manual fix

Debug.Log survives into release builds. Both halves cost you: the log call itself goes through Unity’s logging pipeline (and writes to the player log), and — more often the real cost — the arguments are evaluated and the string is built before the call, every time, whether or not anything consumes the output.

// This allocates and formats on every frame, in your shipped build:
Debug.Log("Player at " + transform.position + " health " + health);

What the scan looks at

Runtime .cs files under Assets/ (anything inside an Editor/ folder is excluded — it isn’t in the build) and counts Debug.Log/Debug.LogFormat calls per file. Ten or more in one file is reported as a Warning; fewer is Info. Comments and string literals are excluded, but this is a text heuristic, not a compile-level analysis, so treat the count as close rather than exact.

Why it costs you

  • String construction and boxing happen at the call site, before any log filtering. Debug.unityLogger.logEnabled = false stops the write, not the concatenation.
  • The write itself hits the player log file. On mobile that’s slower than people expect, and inside a per-frame loop it shows up in a profile.
  • The allocations feed the GC, which is how “harmless logging” turns into a periodic frame spike.

How to fix it by hand

Wrap logging in your own class and mark it [Conditional], so the compiler removes the call and its arguments in builds where the symbol isn’t defined:

public static class Log
{
    [System.Diagnostics.Conditional("ENABLE_LOGS")]
    public static void Info(string message) => Debug.Log(message);
}

// Call sites stay readable, and compile to nothing without ENABLE_LOGS:
Log.Info($"Player at {transform.position}");

[Conditional] is the important detail — an if (enableLogs) guard still evaluates the string. Define ENABLE_LOGS in your development player settings and leave it out of release.

Alternatives: #if UNITY_EDITOR around editor-only diagnostics, and Player Settings ▸ Stack Trace set to None for Log, which cuts the per-call stack capture if you keep logging on in a shipping build deliberately.

What PerfLint does about it

Report-only, and deliberately not AI-fixable. Replacing log calls project-wide is a refactor with a design decision in it — which wrapper, which symbol, which calls are actually diagnostics you want in a release build. The finding gives you the file, the count, and a jump to the first occurrence, so you can decide where a wrapper is worth introducing.

The related build-size lever is IL2CPP managed stripping: see PROJ002.

Check your own project. The scan is free, runs entirely on your machine, and reports this rule with the exact assets that trip it — nothing is uploaded.

Install the free scanner See a sample report


Last reviewed · All rules