NjLogger is a high-performance alternative to Debug.Log, designed to minimize overhead and integrate tightly with NjConsole. Compared to Debug.Log, which allocates memory and generates costly stack traces, NjLogger offers:
// These logs will appear in NjConsole with appropriate severity styling
NjLogger.Debug("This is a debug level text - they get auto excluded in release builds");
NjLogger.Info("This is an info level text");
NjLogger.Warn("This is a warning level text");
NjLogger.Error("This is an error level text - an alert shows when an error is logged.");
// Mixing types? No problem. This won't allocate.
NjLogger.Info("Mix argument types without allocation... integer:",123," float:", 123.45f," bool:", true);
// Link to objects for runtime inspection
var playerObj = GetTestPlayerObj();
NjLogger.Info("Here is a log with a link to ", playerObj.AsLogRef(), " - you can inspect it");
// Log object as plain string (no link)
NjLogger.Info("If you don't want a link, this is how... ", playerObj.AsString());
// Use named channels to group logs (recommended to keep as static readonly)
static readonly LogChannel channel = new LogChannel("myChannel");
channel.Info("A log in `myChannel`");
channel.Warn("A warning in `myChannel`");
NjLogger.Info(Color.cyan, "Passing a Unity Color as the first param will auto color the log to that color.");
// Unity's native logs still show up in NjConsole
Debug.Log("Logs from Unityβs Debug.Log() automatically appear in NjConsole");


NjConsole provides powerful filtering options to help you focus on the logs that matter:
And All conditions must matchOr At least one Or condition must matchNot Must not match to pass the filterπ Right-click any log to pin it. Pinned logs remain visible regardless of filters.
You can include object references directly in your logs.
When clicked, they open in the Object Inspector for quick inspection and editing.
var playerObj = GetTestPlayerObj();
NjLogger.Info("Here is a log with a link to ", playerObj);
NjLogger.Info("Here is a link to ", playerObj.AsLogRef(), " - mixed in multiple arguments");
When you click the log entry in the console, a button will appear for any linked object:
Clicking the button opens the object in the inspector:

β»οΈ Memory-Safe by Design
Object links are held via weak references, so they wonβt cause memory leaks. However, if the object is garbage collected, the link may expire.
To retain the object for the logβs lifetime (as long as it stays in the ring buffer), use a strong reference:
NjLogger.Info("A strong object link:", aTestObj.AsStrongLogRef());
β οΈ Limitations
While you can view and modify many fields and properties, not all data types are fully editable (yet).
// Optionally, add custom stack trace skipping logic so your wrapper code is ignored when going to the IDE source code. ConsoleEditorBridge.CustomStackTraceFrameSkip = (..) => { β¦ }
## π Sending Logs _From_ NjLogger to Your Own Logger
To forward logs from `NjLogger` into your own logging system, implement and register a custom `NjLogger.IHandler`.
// Register once during initialization NjLogger.AddHandler(new MyLoggerBridge());
public class MyLoggerBridge : NjLogger.IHandler { public void HandleLog(ref NjLogger.LogRow logRow){ var message = logRow.GetString(LoggerUtils.TempStringBuilder); var level = logRow.Level; // Forward to your logger } public void HandleException(Exception exception, ref LogRow logRow){ var message = logRow.GetString(LoggerUtils.TempStringBuilder); var level = logRow.Level; // Forward exception to your logger } }
> β οΈ Only register your handler once. Multiple registrations will result in duplicate logs.
## π§΅ Extracting Log Strings from NjLogger
`NjLogger` stores logs in a rotating ring buffer, with the size controlled by `MaxHistoryCount` (set in Project Settings for Editor/Player).
To export logs (from newest to oldest) as a single string:
var stringBuilder = new StringBuilder(); NjLogger.LogsHistory.GenerateHistoryNewestToOldest(stringBuilder); var logMessages = stringBuilder.ToString();
For finer control, you can iterate manually:
NjLogger.LogsHistory.ForEachLogNewestToOldest((log) => { var message = log.GetLineString(); var level = log.Level; var time = log.Time; var channelName = log.GetChannelName(); var channelTag = !string.IsNullOrEmpty(channelName) ? $β [{channelName}]β : ββ; var formattedLogString = $β[{time:HH:mm:ss}] [{level}]{channelTag} {message}β;
//Debug.Log(formattedLogString); }); ``` If you need the other direction, use `ForEachLogOldestToNewest`
IConsoleTimestampFormatter and IConsoleExtension.[Serializable] attribute.
[Serializable]
public class MyCustomTimestampFormatter : IConsoleTimestampFormatter, IConsoleExtension
{
public void AppendFormatted(LogLine log, StringBuilder stringBuilder)
{
var time = log.Time;
LoggerUtils.AppendNumWithZeroPadding(stringBuilder, time.Hour, 2);
stringBuilder.Append(":");
LoggerUtils.AppendNumWithZeroPadding(stringBuilder, time.Minute, 2);
stringBuilder.Append(":");
LoggerUtils.AppendNumWithZeroPadding(stringBuilder, time.Second, 2);
}
}
Project Settings > NjConsole > Extension Modules, add your new class to the list.Apply Extension Changes to reload.IConsoleTimestampFormatter modules added, it might not pick the right one.