Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ private void DisplayNetworkManagerProperties()
#else
string path = Path.Combine(directory, $"NetworkPrefabs-{m_NetworkManager.GetInstanceID()}.asset");
#endif
Debug.Log("Saving migrated Network Prefabs List to " + path);
m_NetworkManager.Log.Info(new Context(LogLevel.Normal, "Saving migrated Network Prefabs List").With("Path", path));
AssetDatabase.CreateAsset(networkPrefabs, path);
EditorUtility.SetDirty(m_NetworkManager);
}
Expand Down
12 changes: 5 additions & 7 deletions com.unity.netcode.gameobjects/Editor/NetworkManagerHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,19 +162,17 @@ public void CheckAndNotifyUserNetworkObjectRemoved(NetworkManager networkManager

if (!EditorApplication.isPlaying && !editorTest)
{
EditorUtility.DisplayDialog($"Removing {nameof(NetworkObject)}", NetworkManagerAndNetworkObjectNotAllowedMessage(), "OK");
EditorUtility.DisplayDialog($"Removing {nameof(NetworkObject)}", k_NetworkManagerAndNetworkObjectNotAllowedMessage, "OK");
}
else
{
Debug.LogError(NetworkManagerAndNetworkObjectNotAllowedMessage());
networkManager.Log.Error(new Context(LogLevel.Error, k_NetworkManagerAndNetworkObjectNotAllowedMessage));
}
}
}

public string NetworkManagerAndNetworkObjectNotAllowedMessage()
{
return $"A {nameof(GameObject)} cannot have both a {nameof(NetworkManager)} and {nameof(NetworkObject)} assigned to it or any children under it.";
}
private static readonly string k_NetworkManagerAndNetworkObjectNotAllowedMessage = $"A {nameof(GameObject)} cannot have both a {nameof(NetworkManager)} and {nameof(NetworkObject)} assigned to it or any children under it.";
public string NetworkManagerAndNetworkObjectNotAllowedMessage() => k_NetworkManagerAndNetworkObjectNotAllowedMessage;

/// <summary>
/// Handles notifying the user, via display dialog window, that they have nested a NetworkManager.
Expand Down Expand Up @@ -215,7 +213,7 @@ public bool NotifyUserOfNestedNetworkManager(NetworkManager networkManager, bool
}
else
{
Debug.LogError(message);
networkManager.Log.Error(new Context(LogLevel.Error, message));
}

if (!s_LastKnownNetworkManagerParents.ContainsKey(networkManager) && isParented)
Expand Down
149 changes: 65 additions & 84 deletions com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs

Large diffs are not rendered by default.

184 changes: 184 additions & 0 deletions com.unity.netcode.gameobjects/Runtime/Logging/ContextualLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Text;
using UnityEngine;
using Debug = UnityEngine.Debug;
using LogType = UnityEngine.LogType;

namespace Unity.Netcode
{
internal class ContextualLogger
{
private const string k_NetcodeHeader = "[Netcode] ";
private bool m_UseCompatibilityMode;
private readonly GameObject m_GameObject;
private readonly ContextBuilder m_Builder = new();

private LogContextNetworkManager m_ManagerContext;
private readonly GenericContext m_LoggerContext;

private const string k_CompilationCondition = "UNITY_ASSERTIONS";

public ContextualLogger(bool useCompatibilityMode = false)
{
m_UseCompatibilityMode = useCompatibilityMode;
m_ManagerContext = new LogContextNetworkManager(true);
m_GameObject = null;
m_LoggerContext = GenericContext.Create();
}

public ContextualLogger([NotNull] NetworkManager networkManager, GameObject gameObject)
{
m_ManagerContext = new LogContextNetworkManager(networkManager);
m_GameObject = gameObject;
m_LoggerContext = GenericContext.Create();
}

[Conditional(k_CompilationCondition)]
internal void UpdateNetworkManagerContext(NetworkManager manager)
{
m_ManagerContext.Dispose();
m_ManagerContext = new LogContextNetworkManager(manager);
}

[Conditional(k_CompilationCondition)]
internal void PushContext(string key, object value)
{
m_LoggerContext.StoreInfo(key, value);
}

[Conditional(k_CompilationCondition)]
internal void PushContext(string key)
{
m_LoggerContext.StoreContext(key);
}

[Conditional(k_CompilationCondition)]
internal void PopContext(string key)
{
m_LoggerContext.ClearInfo(key);
}


[HideInCallstack]
[Conditional(k_CompilationCondition)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CaptureFunctionCall([CallerMemberName] string memberName = "")
{
Log(LogType.Log, new Context(LogLevel.Developer, memberName, true));
}

[HideInCallstack]
[Conditional(k_CompilationCondition)]
public void Info(Context context) => Log(LogType.Log, context);
[HideInCallstack]
[Conditional(k_CompilationCondition)]
public void Warning(Context context) => Log(LogType.Warning, context);
[HideInCallstack]
[Conditional(k_CompilationCondition)]
public void Error(Context context) => Log(LogType.Error, context);

[HideInCallstack]
[Conditional(k_CompilationCondition)]
public void InfoServer(Context context) => LogServer(LogType.Log, context);
[HideInCallstack]
[Conditional(k_CompilationCondition)]
public void WarningServer(Context context) => LogServer(LogType.Warning, context);
[HideInCallstack]
[Conditional(k_CompilationCondition)]
public void ErrorServer(Context context) => LogServer(LogType.Error, context);

[HideInCallstack]
public void Exception(Exception exception)
{
Debug.unityLogger.LogException(exception, m_GameObject);
}

[HideInCallstack]
private void Log(LogType logType, Context context)
{
// Don't act if the LogLevel is higher than the level of this log
if (m_ManagerContext.LogLevel > context.Level)
{
return;
}

var message = BuildLog(context);
Debug.unityLogger.Log(logType, (object)message, context.GameObjectOverride ?? m_GameObject);
}

[HideInCallstack]
private void LogServer(LogType logType, Context context)
{
// Don't act if the configured logging level is higher than the level of this log
if (m_ManagerContext.LogLevel <= context.Level)
{
return;
}

var message = BuildLog(context);
Debug.unityLogger.Log(logType, (object)message, context.GameObjectOverride ?? m_GameObject);

m_ManagerContext.TrySendMessage(logType, message);
}

private string BuildLog(Context context)
{
m_Builder.Reset();

// Add the Netcode prefix
m_Builder.Append(k_NetcodeHeader);

if (m_UseCompatibilityMode)
{
m_Builder.Append(context.Message);
}
else
{
// Add the system context
m_ManagerContext.AppendTo(m_Builder);
m_LoggerContext.AppendTo(m_Builder);

// Add the context for this log
context.AppendTo(m_Builder);
}

return m_Builder.Build();
}
}

internal class ContextBuilder
{
private readonly StringBuilder m_Builder = new();
private const string k_OpenBracket = "[";
private const string k_CloseBracket = "]";
private const string k_Separator = ":";

public void Reset()
{
m_Builder.Clear();
}

public void AppendContext(string context)
{
m_Builder.Append(k_OpenBracket);
m_Builder.Append(context);
m_Builder.Append(k_CloseBracket);
}

public void AppendContext(object key, object value)
{
m_Builder.Append(k_OpenBracket);
m_Builder.Append(key);
m_Builder.Append(k_Separator);
m_Builder.Append(value);
m_Builder.Append(k_CloseBracket);
}

public void Append(string value) => m_Builder.Append(value);

public string Build() => m_Builder.ToString();
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 86 additions & 0 deletions com.unity.netcode.gameobjects/Runtime/Logging/GenericContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;

namespace Unity.Netcode
{
internal readonly struct GenericContext : ILogContext, IDisposable
{
private readonly List<string> m_Contexts;
private readonly Dictionary<object, object> m_Info;

private GenericContext(List<string> contexts, Dictionary<object, object> info)
{
m_Contexts = contexts;
m_Info = info;
}

public readonly void AppendTo(ContextBuilder builder)
{
if (m_Contexts != null)
{
foreach (var ctx in m_Contexts)
{
builder.AppendContext(ctx);
}
}

if (m_Info != null)
{
foreach (var (key, value) in m_Info)
{
builder.AppendContext(key, value);
}
}
}

public void StoreContext(string msg)
{
m_Contexts.Add(msg);
}

public void StoreInfo(object key, object value)
{
m_Info.Add(key, value);
}

public void ClearInfo(object key)
{
m_Info?.Remove(key);
}

public void Dispose()
{
PreallocatedStore.Free(this);
}

public static GenericContext Create()
{
return PreallocatedStore.GetPreallocated();
}

private static class PreallocatedStore
{
private static readonly Queue<GenericContext> k_Preallocated = new();

internal static GenericContext GetPreallocated()
{
if (k_Preallocated.Count > 0)
{
k_Preallocated.Dequeue();
}

var contexts = new List<string>();
var info = new Dictionary<object, object>();
return new GenericContext(contexts, info);
}

internal static void Free(GenericContext ctx)
{
ctx.m_Contexts.Clear();
ctx.m_Info.Clear();
k_Preallocated.Enqueue(ctx);
}
}
}

}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading