14 Runtime Monitor: Production Observability
Stress-test the event system with four test units and read every Monitor tab: performance timings, firing frequency, listener counts, graph structure, and integrity warnings.
For developers profiling event performance and diagnosing frame drops, spam, or missing listeners.Overviewโ
In production, events fire thousands of times per second. Debug.Log() creates garbage, floods the console, and gives no structured view of system health. The Game Event Monitor provides real-time performance profiling, listener tracking, frequency analysis, and integrity warnings.
The Game Event Monitor is a specialized debugging window that answers critical questions:
- "Which event is causing that frame drop?"
- "Is this event firing too often?"
- "Who is actually listening to this event right now?"
- "Why did my chain sequence break?"
This demo simulates a high-load stress test facility with four specialized test units, each designed to populate specific Monitor tabs with diagnostic data.
- How to open and navigate the Runtime Monitor window
- Reading performance metrics (avg/min/max execution time)
- Analyzing event frequency and detecting spam
- Inspecting listener counts (Inspector vs API bindings)
- Visualizing programmatic Flow Graphs
- Detecting integrity issues (ghost events, broken chains)
- Interpreting warnings and health indicators
Demo Sceneโ
Assets/TinyGiants/GameEventSystem/Demo/14_RuntimeMonitor/14_RuntimeMonitor.unity
Scene Compositionโ
Visual Elements:
- ๐ฏ Test Console - Information panel describing 4 test units
- ๐ง Simple Geometry - Plane and Cube (minimal scene)
UI Layer (Canvas):
- ๐ฎ Four Control Buttons - Bottom of screen
- "Toggle Spammer (Unit A)" โ Starts/stops high-frequency spam
- "Trigger Heavy Load (Unit B)" โ Fires expensive operation
- "Fire Chain Reaction (Unit C)" โ Executes programmatic chain
- "Fire Ghost Event (Unit D)" โ Raises event with no listeners
Game Logic Layer:
- ๐ค RuntimeMonitorRaiser - Test orchestrator
- ๐ฅ RuntimeMonitorReceiver - Test responder with instrumented listeners
The 4 Test Unitsโ
Each unit is designed to stress-test a specific Monitor subsystem:
Unit A: The Spammer (Frequency Test)โ
Purpose: Generate high-frequency event spam to test Statistics tab
Configuration:
- Events:
OnSpammer(void),OnSpammerPersistent(void) - Behavior: Fires >60 times/second in
Update()while active - Monitor Goal: Detect high-frequency warnings
Expected Results:
- ๐ Statistics Tab: Shows >60 fires/sec (RED warning)
- โ ๏ธ Warnings Tab: Flags
[High Frequency]issue
Unit B: The Heavy Lifter (Performance Test)โ
Purpose: Simulate expensive computation to test Performance tab
Configuration:
- Events:
OnHeavyLoad,OnHeavyLoadCondition(GameObject, DamageInfo) - Behavior: Listener calls
Thread.Sleep(6)to simulate 6ms+ lag - Monitor Goal: Trigger performance warnings
Expected Results:
- โก Performance Tab: Execution time shows 6-12ms (YELLOW/RED)
- ๐ Dashboard: Performance bar turns yellow/red
Code Mechanism:
public void OnHeavyExecution(GameObject sender, DamageInfo info)
{
// Simulate heavy computation (BAD in production, perfect for testing!)
Thread.Sleep(6); // โ Forces 6ms execution time
}
Unit C: The Chain Reactor (Automation Test)โ
Purpose: Demonstrate programmatic Flow Graph visualization
Configuration:
- Events:
OnChainStartโOnChainProcessโOnChainFinishโOnTriggerComplete - Behavior: Code-built sequential pipeline with delays and conditions
- Monitor Goal: Visualize dynamic automation in Automation tab
Graph Structure:
๐ [ START ] OnChainStart (DamageInfo)
โ โ Payload: { amount: 75.0, type: Physical, ... }
โ
โโ โฑ๏ธ [ STEP 1 ] โ Delay: 0.5s
โ โโโบ โ๏ธ OnChainProcess (DamageInfo) โ
Data Relayed
โ
โโ โ๏ธ [ STEP 2 ] โ Delay: 0.2s | Guard: `amount > 50`
โ โโโบ ๐ฏ OnChainFinish (DamageInfo) โ
Logic Passed (75 > 50)
โ
โโ ๐งน [ STEP 3 ] โ Trigger Mode | Block Args
โโโบ ๐ OnTriggerComplete (void) โ
Signal Purified
โ
๐ Result: Pipeline Completed | ๐ก๏ธ Data Safety: Argument Blocked at Exit
Expected Results:
- ๐ Automation Tab: Shows hierarchical tree with timing/condition badges
- ๐ Recent Events Tab: Sequential firing pattern visible
Unit D: The Ghost (Integrity Test)โ
Purpose: Detect events fired with no listeners
Configuration:
- Event:
OnGhost(void) - Behavior: Raises event with zero listeners bound
- Monitor Goal: Trigger integrity warning
Expected Results:
- โ ๏ธ Warnings Tab: Shows
[No Listeners]warning - ๐ Dashboard: Warning count increases
How to Test (Step-by-Step)โ
Phase 1: Preparationโ
Step 1: Open Monitor Window
-
Menu
The utility is located within the Game Event System, you can access through the following method:
From the System Dashboard:
Game Event System Window โ Click "Game Event Monitor" -
Window appears
dockable like any Unity Editor window
Step 2: Enter Play Mode
- Click Unity's Play button
- Monitor remains visible during play
Phase 2: Generate Test Dataโ
Step 3: Activate Unit A (Spammer)
- Click "Toggle Spammer (Unit A)" button
- Observe: Button stays active (toggled ON)
- Effect:
OnSpammerfires >60 times/second
Step 4: Activate Unit B (Heavy Load)
- Click "Trigger Heavy Load (Unit B)" button 3-5 times
- Effect: Each click triggers one expensive operation (6ms lag)
Step 5: Activate Unit C (Chain Reaction)
- Click "Fire Chain Reaction (Unit C)" button once
- Effect: Initiates 4-step sequential pipeline
Step 6: Activate Unit D (Ghost Event)
- Click "Fire Ghost Event (Unit D)" button once
- Effect: Raises event with no listeners (integrity violation)
After triggering all units, wait 5-10 seconds to accumulate data before analyzing Monitor tabs.
Monitor Window Analysisโ
Tab 1: ๐ Dashboard (System Health Overview)โ
The landing pageโaggregates metrics from all subsystems into a single health report.

Metric Cards (Top Row):
| Card | Meaning | Expected Value |
|---|---|---|
| Total Events | Loaded event count | 9 |
| Total Logs | Cumulative fires since play start | 500+ (climbing) |
| Monitored | Events with active performance tracking | 4-6 |
| Warnings | Current active issues | 2+ (Spam + Ghost) |
Active Databases Section:
- Lists all loaded database assets
- PRIMARY badge shows main database
- Click database name to filter views
Performance Overview (Traffic Light Bar):
- ๐ข Green: All events <1ms (healthy)
- ๐ก Yellow: Some events 1-5ms (caution)
- ๐ด Red: Events >5ms detected (critical)
- Shows percentage distribution
Recent Activity (Mini-Log):
- Last 15 event firings
- Format:
[Frame] EventName (args) - Click to jump to Details tab
Quick Warnings (Top 3):
- Most critical alerts surfaced
- Severity icons: ๐ต Info, ๐ก Warning, ๐ด Critical
- Click to jump to Warnings tab
Single-glance system health checkโlike a car's instrument panel. If this shows red/yellow, drill into specific tabs for diagnosis.
Tab 2: โก Performance (Execution Profiling)โ
Focus: Detect performance bottlenecks by execution time

Columns:
| Column | Meaning | Healthy Range |
|---|---|---|
| Event Name | Event identifier | - |
| Avg Time | Average execution ms | <1ms ๐ข |
| Min Time | Fastest execution | - |
| Max Time | Slowest execution | <5ms ๐ก, >5ms ๐ด |
| Listeners | Avg listener count per fire | - |
| GC Alloc | Garbage generated per fire | 0 KB ideal |
Color Coding:
- ๐ข Green: 0-1ms (excellent)
- ๐ก Yellow: 1-5ms (monitor)
- ๐ด Red: >5ms (investigate)
Test Results (Unit B):
- Locate
OnHeavyLoadevent in table - Avg Time: Shows ~6.00ms (๐ก Yellow)
- Max Time: May show ~12.00ms if clicked multiple times (๐ด Red)
- Cause:
Thread.Sleep(6)in listener code
Usage:
- Sort by "Avg Time" to find worst offenders
- Click event name to see Details tab
- Compare listener countsโmore listeners = higher risk
General rule: Keep avg execution time <1ms. Budget total frame time (16ms @ 60fps) across all systems.
Tab 3: ๐ Recent Events (Real-Time Event Log)โ
Focus: Chronological stream of all event firings

Columns:
| Column | Meaning | Example |
|---|---|---|
| Frame | Unity frame number | F:1450 |
| Time | Timestamp since play start | 12.45s |
| Event | Event name | OnHeavyLoad |
| Arguments | Payload preview | <DamageInfo: 100> |
| Caller | Method that called .Raise() | RuntimeMonitorRaiser.TriggerHeavyLoad |
Features:
- ๐ Search: Filter by event name
- ๐ Stack Trace: Toggle to see full call stack
- ๐ Details Link: Click event to see deep dive
Test Results (All Units):
- Unit A: Rapid succession of
OnSpammerentries (60+/sec) - Unit C: Sequential pattern:
OnChainStartโ (delay) โOnChainProcessโOnChainFinishโOnTriggerComplete - Unit D: Single
OnGhostentry
Usage:
- Verify event firing order (sequential vs parallel)
- Debug unexpected event triggers
- Investigate caller methods (who's raising this?)
Unlike Unity Console, this log is specialized for eventsโno noise from other Debug.Log calls, structured data preview, direct caller info.
Tab 4: ๐ Statistics (Frequency Analysis)โ
Focus: Long-term usage patterns and frequency tracking

Columns:
| Column | Meaning | Healthy Range |
|---|---|---|
| Event Name | Event identifier | - |
| Trigger Count | Total fires since play start | - |
| Freq/sec | Fires per second | <10 ๐ข, 10-30 ๐ก, >30 ๐ด |
| Avg Interval | Time between fires (ms) | >100ms ideal |
| Last Trigger | Time since last fire | - |
Test Results (Unit A):
- Locate
OnSpammerevent - Trigger Count: Rapidly climbing (1000+ after 10sec)
- Freq/sec: Shows >60/s (๐ด Red warning)
- Avg Interval: Shows ~16ms (every frame at 60fps)
Warning Triggers:
- ๐ก Yellow: 10-30 fires/sec
- ๐ด Red: >30 fires/sec (potential performance issue)
Usage:
- Identify event spam (too frequent)
- Detect idle events (never firing)
- Analyze firing patterns over time
- >60/sec: Likely firing every frameโconsider batching
- Irregular spikes: May indicate logic bug
- Zero frequency: Dead code or misconfigured event
Tab 5: โ ๏ธ Warnings (Integrity & Health Alerts)โ
Focus: Filter noise, surface critical issues

Severity Levels:
| Icon | Level | Meaning |
|---|---|---|
| ๐ต | Info | Advisory notice (FYI) |
| ๐ก | Warning | Non-critical issue (monitor) |
| ๐ด | Critical | Severe problem (fix immediately) |
Warning Types:
| Warning | Trigger | Severity |
|---|---|---|
[No Listeners] | Event raised but no listeners bound | ๐ต Info |
[High Frequency] | Fires >30 times/sec | ๐ก Warning |
[Performance] | Execution time >5ms | ๐ด Critical |
[GC Pressure] | Garbage allocation >1KB/fire | ๐ก Warning |
Test Results:
- Unit A:
OnSpammer - [High Frequency] Firing at 62/sec - Unit D:
OnGhost - [No Listeners] Event raised with zero subscribers
Usage:
- Check after major feature additions
- Monitor during stress tests
- Ignore expected warnings (e.g., debug events)
[No Listeners] warnings are usually bugsโeither:
- Listener registration failed (check
OnEnable) - Event asset reference is wrong
- Dead code (remove the
.Raise()call)
Tab 6: ๐ Listeners (Subscription Inspector)โ
Focus: Granular breakdown of WHO is listening

Select an event (e.g., OnHeavyLoad) to see detailed breakdown:
Listener Categories:
| Category | Meaning | Icon |
|---|---|---|
| Basic | Standard AddListener | ๐ |
| Priority | AddPriorityListener with priority value | ๐ข |
| Conditional | AddConditionalListener with predicate | โ |
| Persistent | AddPersistentListener (survives scenes) | ๐งฌ |
Breakdown Grid:
๐ Total Active Listeners: 5
โ
โโ ๐ Basic Listeners (1)
โ โโ ๐ฆ Inspector Bindings: 0
โ โโ ๐ป API Bindings: 1
โ โโ โ๏ธ RuntimeMonitorReceiver.OnHeavyExecution
โ
โโ โ๏ธ Priority Queue (3)
โ โโ ๐ฅ High Priority (100): 1
โ โ โโ โ๏ธ RuntimeMonitorReceiver.OnHeavyPreCheck
โ โโ ๐ฅ Normal Priority (0): 1
โ โ โโ โ๏ธ RuntimeMonitorReceiver.OnHeavyExecution
โ โโ ๐ฅ Low Priority (-100): 1
โ โโ โ๏ธ RuntimeMonitorReceiver.OnHeavyPostCheck
โ
โโ ๐ก๏ธ Conditional Guards (1)
โ โโ ๐ [Prio: 50] RuntimeMonitorReceiver.OnHeavyCriticalWarning
โ โโ ๐ Predicate: (sender, info) => info.isCritical
โ
โโ ๐ Persistent Registry (0)
โโ (No cross-scene listeners active)
Test Results (Unit B):
- Total: 4-5 listeners
- Priority Distribution: High (1), Normal (1), Low (1)
- Conditional: 1 (with predicate preview)
Usage:
- Verify code-based registrations worked
- Check listener execution order (priority values)
- Debug missing listeners (expected vs actual count)
- Audit persistent listeners (memory leak prevention)
- Inspector Bindings: Configured in Behavior window
- API Bindings: Registered via
AddListenerin code - Both show up hereโvalidates your hybrid approach
Tab 7: ๐ Automation (Programmatic Flow Visualization)โ
Focus: Visualize code-built Trigger/Chain graphs

Tree View Structure:
โผ OnChainStart (Root, <DamageInfo>)
โ
โโ ๐ Chain โ OnChainProcess
โ โโ โฑ๏ธ Delay: 0.5s
โ โโ โ
Pass Argument
โ โโ Type: <DamageInfo>
โ
โโ (OnChainProcess expanded)
โ
โโ ๐ Chain โ OnChainFinish
โ โโ โฑ๏ธ Delay: 0.2s
โ โโ ๐งฉ Condition: info.amount > 50
โ โโ โ
Pass Argument
โ โโ Type: <DamageInfo>
โ
โโ (OnChainFinish expanded)
โ
โโ ๐น๏ธ Trigger โ OnTriggerComplete
โโ โ Block Argument
โโ Type: (void)
Badge Legend:
| Badge | Meaning |
|---|---|
โฑ๏ธ 0.5s | Delay configured |
| ๐งฉ | Condition enabled |
| โ | Argument passing enabled |
| โ | Argument blocked |
| ๐ | Chain node (sequential) |
| ๐น๏ธ | Trigger node (parallel) |
Test Results (Unit C):
- Root:
OnChainStart - Depth: 3 levels (Start โ Process โ Finish โ Complete)
- Mixed Types: Chain (sequential) + Trigger (parallel) combined
Usage:
- Verify programmatic graphs built correctly
- Debug broken chains (missing nodes)
- Visualize complex automation without opening Flow Graph window
- Compare code-built vs visual-built graphs
- This tab: Shows code-built graphs (
AddChainEvent,AddTriggerEvent) - Flow Graph window: Shows visual-built graphs (created via UI)
- Both are valid, both are debuggable
Tab 8: ๐ Event Details (Deep Dive)โ
Focus: Single-event analysis and history

Click "Details" or "View" from any other tab to drill down.
Sections:
1. Metadata:
- GUID: Unique identifier (immutable)
- Type: Full generic signature
- Category: Organizational tag
- Database: Source asset file
2. Performance Summary:
- Avg/Min/Max Time: Same as Performance tab
- GC Allocation: Memory profile
- Listener Count: Current subscribers
3. Frequency Summary:
- Total Fires: Since play start
- Fires/Sec: Current rate
- Avg Interval: Between fires
- Last Fire: Time ago
4. Recent Activity (Filtered):
- Event-specific log stream
- Only shows this event's history
- Full stack traces available
5. Automation (If Applicable):
- Shows this event's place in Flow Graph
- Upstream/downstream connections
Usage:
- Comprehensive single-event analysis
- Compare before/after optimization
- Export data for team review
Scene Architectureโ
Event Organizationโ
Events organized by test unit in Game Event Editor:

| Category | Event Name | Type | Purpose |
|---|---|---|---|
| Unit A | OnSpammer | GameEvent | High-frequency spam |
| Unit A | OnSpammerPersistent | GameEvent | Persistent spam |
| Unit B | OnHeavyLoad | GameObjectDamageInfoGameEvent | Performance test |
| Unit B | OnHeavyLoadCondition | GameObjectDamageInfoGameEvent | Conditional test |
| Unit C | OnChainStart | DamageInfoGameEvent | Root (gold) |
| Unit C | OnChainProcess | DamageInfoGameEvent | Chain step 1 |
| Unit C | OnChainFinish | DamageInfoGameEvent | Chain step 2 |
| Unit C | OnTriggerComplete | GameEvent | Chain step 3 (trigger) |
| Unit D | OnGhost | GameEvent | Integrity test |
Flow Graph Configurationโ
Programmatic chain built in code:

Graph Structure:
- ๐ด OnChainStart (Root, Red) - Entry point
- ๐ข OnChainProcess (Chain, Green) - Step 1 (Delay: 0.5s)
- ๐ข OnChainFinish (Chain, Green) - Step 2 (Delay: 0.2s, Condition: amount > 50)
- ๐ก OnTriggerComplete (Trigger, Yellow) - Step 3 (Argument blocked)
Connection Types:
- ๐ข Green "CHAIN" lines - Sequential execution
- ๐ก Yellow "TRIGGER" line - Parallel execution
Raiser Setup (RuntimeMonitorRaiser)โ

Unit A: Frequency Test
On Spam Event: OnSpammerOn Spam Persistent Event: OnSpammerPersistent
Unit B: Performance Test
On Heavy Load Event: OnHeavyLoadOn Heavy Load Condition Event: OnHeavyLoadCondition
Unit C: Automation Test (Roots)
On Chain Start: OnChainStart
Unit C: Automation Test (Targets)
On Chain Process: OnChainProcessOn Chain Finish: OnChainFinishOn Trigger Complete: OnTriggerComplete
Unit D: Integrity Test
On Ghost Event: OnGhost
Receiver Setup (RuntimeMonitorReceiver)โ

Events (Asset References):
- Same events as Raiser
Chain Events (For Inspector Binding):
On Chain Process,On Chain Finish,On Trigger Complete- These have Inspector-based listeners (drag & drop in Behavior window)
- Complements code-based API listeners
Code Breakdownโ
Simulating Performance Issues (Unit B)โ
RuntimeMonitorReceiver.cs - Heavy Execution:
public void OnHeavyExecution(GameObject sender, DamageInfo info)
{
// โ ๏ธ INTENTIONAL LAG FOR TESTING
// In production, NEVER use Thread.Sleep in game logic!
// This forces execution time to >5ms to trigger Monitor warnings
Thread.Sleep(6); // โ Simulates expensive computation
Debug.Log($"[Receiver] Processed heavy data. Latency: 6ms (simulated)");
}
Why this works:
Thread.Sleep(6)blocks main thread for 6 milliseconds- Monitor's Performance tab tracks execution time per listener
- 6ms exceeds 5ms threshold โ triggers YELLOW warning
- Click button 2x with
Thread.Sleep(12)โ RED critical warning
Building Programmatic Automation (Unit C)โ
RuntimeMonitorRaiser.cs - Awake() Graph Construction:
private ChainHandle _chainProcessHandle;
private ChainHandle _chainFinishHandle;
private TriggerHandle _triggerCompleteHandle;
private void Awake()
{
// โ
BUILD CHAIN IN CODE (Not visual graph!)
// Step 1: Start โ (Delay 0.5s) โ Process
_chainProcessHandle = onChainStart.AddChainEvent(
targetEvent: onChainProcess,
delay: 0.5f, // โ Pause for half a second
passArgument: true // โ Forward DamageInfo
);
// Step 2: Process โ (Condition + Delay 0.2s) โ Finish
_chainFinishHandle = onChainProcess.AddChainEvent(
targetEvent: onChainFinish,
delay: 0.2f,
condition: (info) => info.amount > 50f, // โ Only high damage continues
passArgument: true
);
// Step 3: Finish โ (Trigger, Block Args) โ Complete
_triggerCompleteHandle = onChainFinish.AddTriggerEvent(
targetEvent: onTriggerComplete,
passArgument: false // โ Block arguments (type conversion void)
);
}
private void OnDestroy()
{
// โ
CLEANUP: MANDATORY for dynamic graphs
onChainStart.RemoveChainEvent(_chainProcessHandle);
onChainProcess.RemoveChainEvent(_chainFinishHandle);
onChainFinish.RemoveTriggerEvent(_triggerCompleteHandle);
}
Graph Execution Flow:
๐ฑ๏ธ User Interaction: Button Clicked
โ
๐ [ INITIATION ] โ onChainStart.Raise(DamageInfo)
โ ๐ฆ Payload: { amount: 100, isCritical: true }
โ
โณ [ SCHEDULING ] โ System Pauses for 0.5s
โ โโโบ โ๏ธ onChainProcess.Raise(DamageInfo)
โ
โ๏ธ [ EVALUATION ] โ Gate: `100 > 50` ?
โ โโโบ โ
Result: YES (Condition Passed)
โ
โณ [ SCHEDULING ] โ System Pauses for 0.2s
โ โโโบ ๐ฏ onChainFinish.Raise(DamageInfo)
โ
๐งช [ PURIFICATION ] โ Parameter Stripping: `DamageInfo` โ `void`
โ โโโบ ๐ onTriggerComplete.Raise()
โ
๐ Final Outcome: Pipeline Finalized | โก Timing: 0.7s Total Delay
Monitor Visibility:
- Automation Tab: Shows this exact tree structure
- Recent Events Tab: Shows sequential firing pattern with timing
- Performance Tab: Tracks each step's execution time
Registering Multi-Priority Listeners (Unit B)โ
RuntimeMonitorReceiver.cs - OnEnable():
private void OnEnable()
{
// โ
POPULATE LISTENERS TAB WITH VARIETY
// Basic listener (no priority)
onSpamEvent.AddListener(OnSpamReceived);
// Priority listeners (execution order)
onHeavyLoadEvent.AddPriorityListener(OnHeavyPreCheck, priority: 100); // Runs 1st
onHeavyLoadEvent.AddPriorityListener(OnHeavyExecution, priority: 0); // Runs 2nd (lag here)
onHeavyLoadEvent.AddPriorityListener(OnHeavyPostCheck, priority: -100); // Runs 3rd
// Conditional listener with priority
onHeavyLoadConditionEvent.AddConditionalListener(
OnHeavyCriticalWarning,
condition: (sender, info) => info.isCritical, // โ Only if critical
priority: 50
);
}
private void OnDisable()
{
// โ
CLEANUP
onSpamEvent.RemoveListener(OnSpamReceived);
onHeavyLoadEvent.RemovePriorityListener(OnHeavyPreCheck);
onHeavyLoadEvent.RemovePriorityListener(OnHeavyExecution);
onHeavyLoadEvent.RemovePriorityListener(OnHeavyPostCheck);
onHeavyLoadConditionEvent.RemoveConditionalListener(OnHeavyCriticalWarning);
}
Monitor Visibility:
- Listeners Tab: Shows 4 listeners for
OnHeavyLoad- Priority breakdown: High (1), Normal (1), Low (1)
- Conditional (1) with predicate preview
- Performance Tab: Tracks cumulative execution time (sum of all listeners)
Persistent Listener Management (Unit A)โ
RuntimeMonitorReceiver.cs - Awake/OnDestroy:
private void Awake()
{
// โ
PERSISTENT LISTENER (Survives scene reload)
// Registered in Awake, cleaned in OnDestroy
onSpamPersistentEvent.AddPersistentListener(OnSpamPersistentLog, priority: -10);
}
private void OnDestroy()
{
// โ
CLEANUP PERSISTENT
onSpamPersistentEvent.RemovePersistentListener(OnSpamPersistentLog);
}
public void OnSpamPersistentLog()
{
// Empty methodโexists only for Monitor to count
// Simulates background tracking (e.g., analytics, achievements)
}
Monitor Visibility:
- Listeners Tab: Shows "Persistent Listeners: 1" for
OnSpammerPersistent - Dashboard: Tracks persistent listener health
Production Debugging Workflowโ
Scenario 1: Frame Drops During Combatโ
Symptoms:
- FPS drops from 60 to 30 during combat
- No obvious Unity Profiler spikes
Debug Steps:
- Open Performance Tab
- Sort by "Avg Time" (descending)
- Look for events with >2ms execution
- Click event โ Details Tab โ See caller methods
- Optimize heavy listeners or reduce fire frequency
Scenario 2: Event Not Firingโ
Symptoms:
- UI button click does nothing
- Expected behavior doesn't occur
Debug Steps:
- Open Recent Events Tab
- Search for expected event name
- If found: Event firing but listeners not responding
- Go to Listeners Tab โ Check listener count
- Verify method names match
- If not found: Event not being raised
- Check raiser code's
.Raise()call - Verify event asset reference in Inspector
- Check raiser code's
Scenario 3: Memory Leak Suspectedโ
Symptoms:
- Memory usage grows over time
- GC spikes increase
Debug Steps:
- Open Performance Tab
- Check "GC Alloc" column
- Look for events allocating >0 KB per fire
- Click event โ Listeners Tab โ Check for closure allocations
- Refactor to avoid per-fire allocations
Scenario 4: Ghost Events (Dead Code)โ
Symptoms:
- Warning tab shows
[No Listeners]
Debug Steps:
- Open Warnings Tab
- Identify ghost events
- Option A: Event is debug-only โ Ignore warning
- Option B: Listener registration failed
- Check
OnEnableforAddListenercall - Verify event asset reference matches
- Check
- Option C: Dead code โ Remove
.Raise()call
Monitor Best Practicesโ
DOโ
During Development:
- Keep Monitor open in second display
- Check after adding new events
- Verify listener counts match expectations
- Profile before/after optimizations
During Stress Testing:
- Generate high load (like this demo)
- Monitor Performance tab for >1ms events
- Check Warnings tab for integrity issues
- Export metrics for team review
In Production Builds:
- Enable Monitor in Development Builds
- Test on target devices (mobile, console)
- Profile in realistic scenarios
- Document performance baselines
DON'Tโ
Performance Anti-Patterns:
- Fire events every frame (>60/sec) without batching
- Allocate memory in listeners (closures, LINQ)
- Call expensive operations synchronously
Debugging Anti-Patterns:
- Ignore yellow warnings ("it's just a warning")
- Rely solely on
Debug.Logfor event debugging - Skip listener cleanup (
OnDisablemissing) - Leave test events in production builds
Monitor vs Unity Profilerโ
| Feature | Game Event Monitor | Unity Profiler |
|---|---|---|
| Focus | Event system only | Entire engine |
| Granularity | Per-event metrics | Per-method calls |
| Listener Tracking | โ Built-in | โ Manual |
| Frequency Analysis | โ Built-in | โ ๏ธ Indirect |
| Flow Visualization | โ Automation tab | โ N/A |
| Warnings | โ Automatic | โ Manual analysis |
| Learning Curve | Easy | Steep |
| Best For | Event debugging | Overall performance |
Recommended Workflow:
- Monitor: Identify problematic events
- Unity Profiler: Deep-dive into listener methods
- Monitor: Verify fixes reduced execution time
Related Documentationโ
- Runtime Monitor Tool - Complete Monitor documentation
- Best Practices - Performance optimization patterns
- Programmatic Flow - Building graphs in code
- API Reference - Complete method signatures