Diagnostics¶
DxMessaging emphasizes visibility. You can enable diagnostics globally or per token, inspect recent emissions, page through registrations, and even view contexts (targets/sources) — all from the MessagingComponent inspector.
DiagnosticsTarget Enum¶
The DiagnosticsTarget enum is a flags enum that controls when diagnostics are enabled. It allows fine-grained control over which execution environments collect diagnostic data.
| Value | Description |
|---|---|
Off | Diagnostics are disabled in all environments. |
Editor | Diagnostics run only while in the Unity Editor. |
Runtime | Diagnostics run only in player/runtime builds (not the Editor). |
All | Diagnostics run in both Editor and runtime environments. |
Because DiagnosticsTarget is a flags enum, you can combine values:
using DxMessaging.Core.MessageBus;
// Enable diagnostics only in the Unity Editor
IMessageBus.GlobalDiagnosticsTargets = DiagnosticsTarget.Editor;
// Enable diagnostics only in runtime builds
IMessageBus.GlobalDiagnosticsTargets = DiagnosticsTarget.Runtime;
// Enable diagnostics everywhere
IMessageBus.GlobalDiagnosticsTargets = DiagnosticsTarget.All;
// Disable diagnostics completely
IMessageBus.GlobalDiagnosticsTargets = DiagnosticsTarget.Off;
Configuration Toggles¶
DxMessaging provides multiple levels of diagnostics control:
Global Defaults¶
IMessageBus.GlobalDiagnosticsTargets— Sets the default diagnostics mode for newly created buses and tokens. Uses theDiagnosticsTargetflags enum.IMessageBus.GlobalMessageBufferSize— Sets the default ring buffer size for emission history (default: 100).
Per-Bus and Per-Token¶
IMessageBus.DiagnosticsMode— Read-only property indicating whether diagnostics are active for a specific bus instance.MessageRegistrationToken.DiagnosticMode— Controls diagnostics for an individual registration token.
using DxMessaging.Core;
using DxMessaging.Core.MessageBus;
// Configure global defaults before creating buses/tokens
IMessageBus.GlobalDiagnosticsTargets = DiagnosticsTarget.Editor;
IMessageBus.GlobalMessageBufferSize = 200;
// Check if diagnostics are enabled for a specific bus
IMessageBus bus = MessageHandler.MessageBus;
if (bus.DiagnosticsMode)
{
Debug.Log("Diagnostics are active on this bus.");
}
RegistrationLog API¶
The RegistrationLog class tracks all messaging registrations and deregistrations for a message bus. This is invaluable for debugging subscription issues and understanding message flow.
Properties¶
| Property | Type | Description |
|---|---|---|
Enabled | bool | Get/set whether logging is active. Disabled by default for performance. |
Registrations | IReadOnlyList<MessagingRegistration> | Read-only access to all logged registrations. |
Methods¶
Log(MessagingRegistration registration)¶
Records a registration event. Called automatically by the message bus when Enabled is true.
GetRegistrations(InstanceId instanceId)¶
Returns all registrations for a specific instance. Useful for inspecting what a particular component has registered for.
using DxMessaging.Core;
using DxMessaging.Core.MessageBus;
IMessageBus bus = MessageHandler.MessageBus;
bus.Log.Enabled = true;
// After some registrations occur...
InstanceId myComponent = GetComponent<MonoBehaviour>();
foreach (MessagingRegistration reg in bus.Log.GetRegistrations(myComponent))
{
Debug.Log($"Registered for {reg.type.Name} via {reg.registrationMethod}");
}
ToString() and ToString(Func<MessagingRegistration, string> serializer)¶
Returns a string representation of all logged registrations. You can provide a custom serializer for formatted output.
using DxMessaging.Core;
using DxMessaging.Core.MessageBus;
IMessageBus bus = MessageHandler.MessageBus;
bus.Log.Enabled = true;
// ... after some registrations/deregistrations
Debug.Log(bus.Log.ToString());
// Custom formatting
string formatted = bus.Log.ToString(reg =>
$"[{reg.registrationType}] {reg.type.Name} @ {reg.time:F2}s"
);
Debug.Log(formatted);
Clear(Predicate<MessagingRegistration> shouldRemove = null)¶
Removes registrations from the log. Pass null to clear all, or provide a predicate to selectively remove entries.
using DxMessaging.Core;
using DxMessaging.Core.MessageBus;
IMessageBus bus = MessageHandler.MessageBus;
// Clear all registrations
int cleared = bus.Log.Clear();
// Clear only deregistrations
int deregistrationsCleared = bus.Log.Clear(
reg => reg.registrationType == RegistrationType.Deregister
);
MessagingRegistration Struct¶
Each logged registration is stored as a MessagingRegistration struct containing:
| Field | Type | Description |
|---|---|---|
id | InstanceId | The handler's unique identifier. |
type | Type | The message type being registered for. |
registrationType | RegistrationType | Whether this was a Register or Deregister event. |
registrationMethod | RegistrationMethod | The exact registration category (Targeted, Broadcast, etc.). |
time | float | Unity time when the registration occurred (Unity only). |
RegistrationMethod Values¶
The RegistrationMethod enum captures how the handler was wired up:
Targeted— Bound to a specific recipientUntargeted— Global untargeted handlerBroadcast— Bound to a specific sourceBroadcastWithoutSource— Broadcast handler without explicit sourceTargetedWithoutTargeting— Targeted handler ignoring runtime targetGlobalAcceptAll— Catch-all handlerInterceptor— Message interceptorUntargetedPostProcessor,TargetedPostProcessor,BroadcastPostProcessor— Post-processorsTargetedWithoutTargetingPostProcessor— Post-processor for targeted messages ignoring runtime targetBroadcastWithoutSourcePostProcessor— Post-processor for broadcasts without explicit source
Emission History¶
When diagnostics are enabled, buses and tokens record message emissions in a ring buffer:
- Buffer size is controlled by
IMessageBus.GlobalMessageBufferSize(default: 100). - Setting buffer size to 0 disables history retention (emissions are silently discarded).
- Inspect recent emissions per token via built-in diagnostics or build custom tools using post-processors.
using DxMessaging.Core.MessageBus;
// Increase buffer size for more history
IMessageBus.GlobalMessageBufferSize = 500;
Logging Integration¶
Integrate DxMessaging with your logging framework:
using DxMessaging.Core;
MessagingDebug.enabled = true;
MessagingDebug.LogFunction = (level, msg) =>
UnityEngine.Debug.Log($"[DxMessaging:{level}] {msg}");
Per-Environment Configuration¶
A common pattern is enabling diagnostics only in the Editor for development visibility while keeping runtime builds lean.
Editor-Only Diagnostics¶
using DxMessaging.Core.MessageBus;
// Enable diagnostics only when running in the Unity Editor
IMessageBus.GlobalDiagnosticsTargets = DiagnosticsTarget.Editor;
This is the recommended default for most projects. You get full visibility during development without any performance cost in production builds.
Runtime Diagnostics for QA Builds¶
For QA or debug builds where you need diagnostics in the player:
using DxMessaging.Core.MessageBus;
#if DEVELOPMENT_BUILD || UNITY_EDITOR
IMessageBus.GlobalDiagnosticsTargets = DiagnosticsTarget.All;
#else
IMessageBus.GlobalDiagnosticsTargets = DiagnosticsTarget.Off;
#endif
Conditional Logging Based on Build Type¶
using DxMessaging.Core;
using DxMessaging.Core.MessageBus;
public static class DiagnosticsBootstrap
{
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void Initialize()
{
#if UNITY_EDITOR
IMessageBus.GlobalDiagnosticsTargets = DiagnosticsTarget.Editor;
IMessageBus.GlobalMessageBufferSize = 200;
MessageHandler.MessageBus.Log.Enabled = true;
#elif DEVELOPMENT_BUILD
IMessageBus.GlobalDiagnosticsTargets = DiagnosticsTarget.Runtime;
IMessageBus.GlobalMessageBufferSize = 50;
#else
IMessageBus.GlobalDiagnosticsTargets = DiagnosticsTarget.Off;
#endif
}
}
Performance Considerations¶
Diagnostics add overhead. Consider these factors when enabling them:
Memory Impact¶
- Each
MessagingRegistrationstruct consumes memory for the registration log. - The emission ring buffer stores
MessageEmissionDatarecords (controlled byGlobalMessageBufferSize). - Larger buffer sizes consume more memory but provide more history.
CPU Impact¶
- Registration logging adds overhead to every
RegisterandDeregistercall. - Emission recording adds overhead to every message broadcast.
- Post-processor chains for diagnostics run after each message dispatch.
Recommendations¶
| Environment | Recommended Setting | Buffer Size |
|---|---|---|
| Development/Editor | DiagnosticsTarget.Editor | 100-200 |
| QA/Debug Builds | DiagnosticsTarget.All | 50-100 |
| Release Builds | DiagnosticsTarget.Off | N/A |
| Automated Tests | DiagnosticsTarget.All + Log.Enabled | 100 |
using DxMessaging.Core.MessageBus;
// Production-safe defaults
IMessageBus.GlobalDiagnosticsTargets = DiagnosticsTarget.Off;
IMessageBus.GlobalMessageBufferSize = 0; // No history retention
Editor Integration (Inspector)¶
Attach MessagingComponent to a GameObject. In the Unity Inspector:
- Enable/Disable Global Diagnostics: Toggles bus-wide recording.
- Global Buffer: Paged view of recent emissions (type and context). Matching listeners are highlighted.
- Local Buffer: Per-listener ring buffer; enable per-token diagnostics to populate.
- Registrations: Paged list of what each listener registered for (type, priority, context).
Tips¶
- Turn on diagnostics while developing; turn off for release builds if you don't need runtime recording.
- Use
RegisterTargetedWithoutTargetingorRegisterBroadcastWithoutSourcefor custom monitoring dashboards. - Set
Log.Enabled = truein tests to verify registration behavior. - Use
Log.Clear()between test cases to isolate registration tracking.