# `PhoenixGenApi.Diagnostics`
[🔗](https://github.com/ohhi-vn/phoenix_gen_api/blob/main/lib/phoenix_gen_api/diagnostics.ex#L1)

Runtime diagnostics, monitoring, and debugging utilities for PhoenixGenApi.

These helpers are intended for sysadmins and developers who need a safe
runtime snapshot from IEx, remote shells, or custom admin tooling. They return
structured maps rather than printing directly, so callers can expose them in
dashboards or logs.

## Health checks

    PhoenixGenApi.Diagnostics.health_check()
    #=> %{status: :ok | :degraded | :error, checks: %{...}}

## Statistics

    PhoenixGenApi.Diagnostics.statistics()
    #=> %{vm: %{...}, phoenix_gen_api: %{...}}

## Debug reports

    PhoenixGenApi.Diagnostics.debug_report(process_limit: 10)

## Call flow inspection

Trace how a request flows from the gateway to target nodes:

    PhoenixGenApi.Diagnostics.call_flow("user_service", "get_user")
    #=> %{config: %FunConfig{}, local?: true, nodes: [...], steps: [...]}

View the full cluster topology as seen by this node:

    PhoenixGenApi.Diagnostics.cluster_view()
    #=> %{self: :node@host, connected: [...], registered: [...]}

Inspect a specific request's execution path:

    PhoenixGenApi.Diagnostics.inspect_request(%Request{...})

## Tracing

Tracing is gated behind admin actions because it can add overhead and expose
runtime internals. Configure the actions before using it:

    config :phoenix_gen_api, :admin_actions, [
      :enable_tracing,
      :disable_tracing
    ]

    PhoenixGenApi.Diagnostics.trace_processes(:all,
      flags: [:call, :return_to, :procs],
      tracer: self()
    )

    PhoenixGenApi.Diagnostics.trace_functions({MyApp.Api, :get_user, 1},
      tracer: self()
    )

    PhoenixGenApi.Diagnostics.stop_trace(:all)

# `health_report`

```elixir
@type health_report() :: %{
  status: health_status(),
  node: node(),
  checked_at_ms: integer(),
  checks: map()
}
```

# `health_status`

```elixir
@type health_status() :: :ok | :degraded | :error
```

# `call_flow`

```elixir
@spec call_flow(String.t() | atom(), String.t(), String.t() | nil) :: map()
```

Traces the call flow for a given service/request_type from the gateway node
to its target node(s).

Returns a map describing every step a request goes through:

  * `:config` — the resolved `%FunConfig{}` (or `nil` if not found)
  * `:local?` — whether execution is local (`:local`) or remote
  * `:nodes` — the list of target nodes after node selection
  * `:steps` — an ordered list of execution phases with descriptions
  * `:rate_limit` — which rate limiter scopes apply
  * `:permission` — the permission check strategy
  * `:hooks` — before/after hook configurations
  * `:retry` — retry configuration (if any)
  * `:cluster` — which of the target nodes are currently reachable

## Examples

    iex> PhoenixGenApi.Diagnostics.call_flow("user_service", "get_user")
    %{
      config: %FunConfig{request_type: "get_user", ...},
      local?: false,
      nodes: [:"service@host"],
      steps: [
        %{phase: :channel, desc: "WebSocket handle_in receives payload"},
        %{phase: :decode, desc: "Payload decoded into %Request{}"},
        %{phase: :config_lookup, desc: "ConfigDb.get(service, type, version)"},
        %{phase: :hooks_before, desc: "before_execute hooks (none configured)"},
        %{phase: :permission, desc: "Permission.check_permission!/2"},
        %{phase: :rate_limit, desc: "RateLimiter.check_rate_limit/1"},
        %{phase: :argument_validation, desc: "ArgumentHandler.convert_args!/2"},
        %{phase: :node_selection, desc: "NodeSelector picks :random from [node@host]"},
        %{phase: :execution, desc: "RPC to service@host"},
        %{phase: :hooks_after, desc: "after_execute hooks (none configured)"},
        %{phase: :response, desc: "Result pushed back to client via WebSocket"}
      ],
      ...
    }

# `cluster_view`

```elixir
@spec cluster_view() :: map()
```

Returns a cluster topology view from the perspective of this node.

Shows connected nodes, registered processes, and which PhoenixGenApi
services are reachable.

# `debug_report`

```elixir
@spec debug_report(keyword()) :: map()
```

Returns a debug-oriented snapshot for local runtime inspection.

Options:

  * `:process_limit` — Maximum number of processes to include, sorted by
    memory usage. Defaults to `20`.
  * `:include_current_stacktrace` — Includes each process stacktrace when
    `true`. Defaults to `false`.

The returned process summaries intentionally avoid full message queues and
dictionaries by default.

# `health_check`

```elixir
@spec health_check(keyword()) :: health_report()
```

Returns a runtime health report for the VM, Erlang distribution, and
PhoenixGenApi processes.

Options:

  * `:max_memory_bytes` — if set and total memory exceeds it, the vm check
    is marked `:degraded`.

The report is structured and non-destructive. It does not mutate the system.

# `inspect_request`

```elixir
@spec inspect_request(map() | PhoenixGenApi.Structs.Request.t()) :: map()
```

Inspects a `%Request{}` struct and returns a detailed execution plan
showing exactly what will happen when the request is executed.

This is useful for debugging why a request succeeds, fails, or routes
to a particular node.

# `list_call_flows`

```elixir
@spec list_call_flows(keyword()) :: [map()]
```

Returns a summary of all registered call flows across all services.

Each entry shows the service, request_type, version, target nodes,
and execution mode (local vs remote).

# `statistics`

```elixir
@spec statistics(keyword()) :: map()
```

Returns VM and PhoenixGenApi runtime statistics.

The VM section contains process, memory, scheduler, reductions, runtime, and
garbage collection counters. The PhoenixGenApi section contains status for the
config cache, puller, receiver, rate limiter, worker pools, relay server, and
telemetry event coverage.

# `stop_trace`

```elixir
@spec stop_trace(
  term(),
  keyword()
) :: {:ok, map()} | {:error, term()}
```

Disables legacy Erlang tracing for processes or ports.

This operation requires the `:disable_tracing` admin action.

# `stop_trace_functions`

```elixir
@spec stop_trace_functions(term()) :: {:ok, map()} | {:error, term()}
```

Disables call tracing for specific MFAs.

Passing `:all` disables all call trace patterns.

# `trace_functions`

```elixir
@spec trace_functions(
  term(),
  keyword()
) :: {:ok, map()} | {:error, term()}
```

Enables call tracing for specific MFAs.

This operation requires the `:enable_tracing` admin action.

MFAs can be `{Module, Function}`, `{Module, Function, Arity}`, or `:all`.
Arity may be a non-negative integer or `:_` for all arities.

Options:

  * `:flags` — Process trace flags. Defaults to `[:call, :return_to, :procs]`.
  * `:match_spec` — Match specification passed to `:erlang.trace_pattern/3`.
    Defaults to `true`.
  * `:tracer` — PID that receives trace messages. Defaults to `self()`.

# `trace_processes`

```elixir
@spec trace_processes(
  term(),
  keyword()
) :: {:ok, map()} | {:error, term()}
```

Enables legacy Erlang tracing for processes or ports.

This operation requires the `:enable_tracing` admin action.

Supported targets:

  * `:all`
  * `:processes`
  * `:ports`
  * `:existing`
  * `:existing_processes`
  * `:existing_ports`
  * `:new`
  * `:new_processes`
  * `:new_ports`
  * a PID or port
  * a list of the above

Options:

  * `:flags` — Trace flags. Defaults to `[:call, :return_to, :procs]`.
  * `:tracer` — PID that receives trace messages. Defaults to `self()`.

# `trace_status`

```elixir
@spec trace_status() :: map()
```

Returns a small trace status snapshot.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
