Logging
This page describes FigNet's logging model: how to emit and configure logs from your own code, and the tag/format conventions used for FigNet low-level runtime logs and Entangle app-level logs.
Basic Usage
FigNet logs through a pluggable ILogger interface, exposed as the static FN.Logger property.
FN.Logger.Info("Hello FigNet");
To use your own logger, implement ILogger and assign it to FN.Logger. Prefer FN.EnsureLogger(...) over
assigning FN.Logger directly - it only takes effect if no logger is set yet, which avoids re-subscribing to
FN.LogMessageReceived and producing duplicate log lines.
The shipped default logger writes to the console, or to a file, depending on the LoggingMethod server config field
(see Configuration):
CONSOLE- logs to standard output.FILE- logs to a rolling daily file underlogs/<name>.txtat the root of the application.NONE- disables logging (no-op logger).
In Unity, the default logger wraps Unity's Debug.Log (Debug.Log / Debug.LogWarning / Debug.LogError /
Debug.LogException depending on level).
Goals
- Keep logs compact and easy to scan.
- Use one predictable tag format on native and Unity.
- Separate low-level transport/framework logs from app-level gameplay logs.
- Keep the
sourceargument ofFN.LogMessageReceivedas a real source only. - Avoid pushing stack traces or exception metadata into the
sourceslot.
Ownership
Two log families exist:
- FigNet low-level logs: framework, provider, socket, packet, security, dispatch.
- Entangle app-level logs: room, entity, ownership, gameplay payload, state changes.
Use the correct family for the correct layer:
- Use
[Fn][...]for transport/framework concerns. - Use
[En][...]for Entangle behavior and game-facing flows.
Tag Format
Logs use compact segmented tags.
FigNet
Format:
[Fn][<Provider|Core>][<Area>] Message...
Examples:
[Fn][Core][Mod] Built-in module loaded.
[Fn][Enet][Life] Listening side=server port=5559 multithreaded=true packetMagic=PlaintextDatagramOnly.
[Fn][Enet][Conn] Connected side=client remote=127.0.0.1.
[Fn][Enet][Sec] Secure session established side=server peerId=42.
[Fn][Tcp][Drop] Reserved messageId=49374 cannot be sent side=server.
Provider tags:
CoreEnetLnlfor LiteNetLibTcpWsWsn
Entangle
Format:
[En][<Area>] Message...
[En][<Area>][<SubArea>] Message...
Examples:
[En][Conn] Network status changed status=Connected.
[En][Auth] RegisterAppId completed success=true.
[En][Room] JoinRoom completed status=Success selfId=4 roomId=10 roomName=Lobby.
[En][Entity] InstantiateEntity roomId=10 networkId=25 type=Agent entityId=3 ownerId=4.
[En][Payload] JoinRoom response payload was null.
Use sub-areas only when they add real value. Do not add extra tag segments just to mirror class names.
Fixed Area Vocabulary
FigNet Low-Level Areas
Use these area tags:
LifeConnAuthSecRxTxDropCfgModInt
Meaning:
Life: startup, shutdown, listen, connect start.Conn: peer connect, disconnect, timeout, reconnect skip.Auth: registration, built-in identity/auth flow.Sec: handshake, packet auth failure, secure session state.Rx: receive-path packet processing.Tx: send-path packet processing.Drop: reserved, unsupported, rejected, discarded traffic.Cfg: configuration or registration issues.Mod: module load/unload behavior.Int: internal transport/runtime exceptions or diagnostics.
Entangle Areas
Use these area tags:
ConnAuthLobbyRoomEntityStateOwnEventPayloadCfg
Meaning:
Conn: connection availability or connectivity-dependent actions.Auth: app registration or identity/auth outcomes.Lobby: room creation/list queries/join entry flow.Room: room membership or room-level state changes.Entity: entity spawn/delete/presence behavior.State: state delta/state apply/state snapshots.Own: ownership requests and ownership changes.Event: room/game event emission or receipt.Payload: null payloads, invalid payloads, serialization problems.Cfg: prefab/configuration/setup problems.
Message Style Rules
Write message bodies as short facts.
Prefer:
Peer connected peerId=42 remote=127.0.0.1.
Avoid:
SERVER::Client connected 42 || 127.0.0.1
Rules:
- Use sentence-style facts, not shouty phrases.
- Put classification in tags, not in the message body.
- Prefer
key=valuepairs for searchable details. - End normal messages with a period.
- Use the message body for exception text, never the
sourceparameter.
Exceptions
Use Internals.FormatExceptionMessage(...) when logging exceptions through the shared helpers.
Example:
Internals.EmitCoreLog(
LogType.Error,
"Int",
Internals.FormatExceptionMessage("Server application processing failed.", ex));
Do not do this:
FN.LogMessageReceived?.Invoke(ex.Message, ex.StackTrace, LogType.Error);
Helper Usage
FigNet
Use the shared helper methods from Internals:
EmitCoreLogEmitProviderLogEmitAppLogCreateCoreLogSourceCreateProviderLogSourceFormatLogLineFormatExceptionMessage
Provider files should usually wrap these with local helpers such as:
private void LogServer(LogType level, string area, string message)
{
if (Internals.ShouldLog(level, LoggingLevel))
{
Internals.EmitProviderLog(level, "En", true, area, message);
}
}
Entangle
Use the shared Entangle wrapper:
EN_Internals.ShouldLog(...)EN_Internals.Log(level, area, message, subArea = null)
Example:
EN_Internals.Log(LogType.Info, "Room", $"LeaveRoom completed.");
EN_Internals.Log(LogType.Warn, "Payload", "JoinRoom response payload was null.");
Runtime Override
FN.SetLogLevel(...)installs a process-wide runtime override.- When the override is active, it becomes the effective threshold for core logs, provider logs, and admin HTTP / ASP.NET logs.
- When no override is active, provider logs fall back to their configured
LoggingLeveland admin HTTP logs use their default category noise floors.
Runtime Guidance
- Use
Verbosefor packet content dumps. - Use
Debugfor packet metadata without payload dumps. - Use
Infofor expected lifecycle and state transitions. - Use
Warnfor dropped packets or recoverable misuse. - Use
Errorfor failed operations or invalid runtime states. - Use
Fatalsparingly for unrecoverable process-level failures.
Adding New Logs
When adding a new log:
- Decide whether it belongs to FigNet or Entangle.
- Choose the smallest valid area tag from the fixed vocabulary.
- Use the shared helper, not a raw
FN.LogMessageReceived?.Invoke(...). - Keep the message body factual and compact.
- Put stack traces in the message, not the source.
Examples
Low-level receive/drop:
[Fn][Enet][Rx] Received side=server messageId=18 encrypted=true callbackId=0 senderId=42 channelId=0 size=96.
[Fn][Enet][Drop] Dropped side=server messageId=18 senderId=42 before secure session establishment.
Low-level security:
[Fn][Enet][Sec] Secure session established side=client.
[Fn][Enet][Sec] Secure packet authentication failed side=server senderId=42.
Entangle room/entity:
[En][Room] JoinRoom completed status=Success selfId=4 roomId=10 roomName=Lobby.
[En][Entity] DeleteEntity roomId=10 networkId=25 type=Agent entityId=3.
[En][Payload] InstantiateEntity payload was null op=InstantiateEntity.