Observability

Tracking And Debugging

Annotate buses, handlers, publishers, and states so the editor tracking window can show live EDA relationships.

  • Tracking window
  • Authored attributes
  • Runtime registration
  • Troubleshooting

Tracking is editor observability for Azkar EDA. It helps you see authored buses, events, states, handlers, publishers, runtime registrations, live connections, recent activity, and supported value samples.

Deep references:

Open The Tracking Window

Open the tracking window from:

Window/Azkar EDA/Tracking

The window includes modes for Dashboard, Graph, Explorer, and State. Use them together:

  • Dashboard: start here for counts, recent activity, and broad health.
  • Graph: inspect live relationships between publishers, events, handlers, and states.
  • Explorer: browse tracked endpoints and metadata.
  • State: inspect state-oriented endpoints and supported value samples.

Authored Tracking With Attributes

Use [AzEdaTrack] to describe buses, events, states, publishers, and handlers.

using Azkar.Eda;

[AzEdaTrack(
    "Combat Bus",
    Role = AzEdaTrackRole.Bus,
    Group = "Combat",
    Description = "Central combat events and state.")]
public static class CombatBus
{
    [AzEdaTrack(
        "Damage Applied",
        Role = AzEdaTrackRole.Event,
        Tag = "combat",
        CaptureValues = true)]
    public static readonly AzEvent<int> DamageApplied = new();

    [AzEdaTrack(
        "Current Player Health",
        Role = AzEdaTrackRole.State,
        Tag = "player",
        CaptureValues = true)]
    public static readonly AzState<int> PlayerHealth = new(100);
}

Useful attribute fields:

DisplayName

Human-readable name in the window.

Group

Organize related endpoints.

Description

Explain intent to future readers.

Tag

Filter related endpoints across groups.

Role

Mark a bus, event, state, handler, or publisher.

CaptureValues

Request capture of supported payload or state value samples.

Use [AzEdaStruct] to give struct payloads a friendly schema name.

using Azkar.Eda;

[AzEdaStruct("Damage Report")]
public readonly struct DamageReport
{
    public readonly int TargetId;
    public readonly int Amount;

    public DamageReport(int targetId, int amount)
    {
        TargetId = targetId;
        Amount = amount;
    }
}

Annotating Handlers And Publishers

Tracking is most useful when it shows both sides of a connection.

using UnityEngine;
using Azkar.Eda;

public sealed class DamageHud : MonoBehaviour
{
    private readonly AzEventTokenBag _tokens = new();

    private void OnEnable()
    {
        CombatBus.DamageApplied.Subscribe(OnDamageApplied).AddTo(_tokens);
    }

    private void OnDisable()
    {
        _tokens.DisposeAll();
    }

    [AzEdaTrack(
        "Damage HUD Handler",
        Role = AzEdaTrackRole.Handler,
        Group = "Combat UI")]
    private void OnDamageApplied(int amount)
    {
        Debug.Log($"Damage: {amount}");
    }
}
using UnityEngine;
using Azkar.Eda;

public sealed class DamageDealer : MonoBehaviour
{
    [AzEdaTrack(
        "Damage Publisher",
        Role = AzEdaTrackRole.Publisher,
        Group = "Combat")]
    public void ApplyDamage(int amount)
    {
        CombatBus.DamageApplied.Invoke(amount);
    }
}

Manual Runtime Registration

Attributes are best for authored static systems. Runtime registration is useful for dynamically created objects, instance-owned buses, or debugging temporary systems.

using UnityEngine;
using Azkar.Eda;

public sealed class InstanceOwnedBus : MonoBehaviour
{
    private readonly AzEvent<int> _ammoChanged = new();
    private AzEdaTrackingRegistration _tracking;

    private void OnEnable()
    {
        _tracking = AzEdaTracking.Register(
            this,
            _ammoChanged,
            "Ammo Changed",
            captureValues: true,
            context: this);
    }

    private void OnDisable()
    {
        _tracking.Dispose();
    }

    public void PublishAmmo(int ammo)
    {
        _ammoChanged.Invoke(ammo);
    }
}

For multiple manual registrations, use a tracking token bag.

using UnityEngine;
using Azkar.Eda;

public sealed class RuntimeTrackingGroup : MonoBehaviour
{
    private readonly AzEvent<int> _scoreChanged = new();
    private readonly AzState<int> _score = new(0);
    private readonly AzEdaTrackingTokenBag _tracking = new();

    private void OnEnable()
    {
        AzEdaTracking.Register(this, _scoreChanged, "Score Changed", true, this).AddTo(_tracking);
        AzEdaTracking.Register(this, _score, "Score State", true, this).AddTo(_tracking);
    }

    private void OnDisable()
    {
        _tracking.DisposeAll();
    }
}

Generated descriptors exist in the repository, but new-user documentation should focus on authored attributes and explicit runtime registration. Those are the workflows you control directly in gameplay code.

Tracking Window Workflow

  1. Add [AzEdaTrack] to your bus, event, state, handler, or publisher.
  2. Open Window/Azkar EDA/Tracking.
  3. Enter Play Mode.
  4. Trigger the event or state change.
  5. Use Dashboard to confirm activity exists.
  6. Use Graph to confirm the publisher, endpoint, and handler are connected.
  7. Use Explorer filters to narrow by role, group, tag, or name.
  8. Use State mode when debugging AzState<T> values and changes.
  9. Select an endpoint to inspect details, activity, and supported value samples.

Troubleshooting

Endpoint is missing

Likely cause

No attribute, no manual registration, or code was not loaded

Fix

Add [AzEdaTrack], register at runtime, and refresh tracking.

Handler is missing

Likely cause

Subscription never ran or token was disposed

Fix

Check OnEnable, OnDisable, and token bag ownership.

No live connection

Likely cause

Publisher or subscriber is not active in Play Mode

Fix

Trigger the publishing path and confirm the subscriber object is enabled.

Connection appears stale

Likely cause

Object disabled without expected lifecycle, or tracking has not refreshed

Fix

Dispose tokens from the owner lifecycle and refresh the window.

Captured value is missing

Likely cause

CaptureValues is false, the endpoint has no payload or state sample, the value type is not captured, or no value has been produced in the current tracking session

Fix

Enable CaptureValues where supported, then trigger a new event or state change during a live tracking session.

State value does not change immediately

Likely cause

State write may be scheduled or coalesced

Fix

Check SourceSet usage and the frame in which notification is expected.

Duplicate callbacks appear

Likely cause

Same object subscribed more than once

Fix

Subscribe once per lifecycle and dispose the bag before resubscribing.