thrift_runtime_events (thrift_runtime v0.7.0)

View Source

The runtime's observability callbacks: one on_event handler per client or server, no dependencies.

The on_event option accepted by thrift_runtime_client, thrift_runtime_reconnecting_client and thrift_runtime_server (it rides the whitelisted connection options down to thrift_runtime_connection) is one of:

  • undefined (the default) — nothing is emitted and the emit sites cost a pattern match;
  • a fun of arity 1 — called with each event;
  • {Module, Function, Args} — Module:Function(Args ++ [Event]), so a handler can carry its own context (a pool id, an ETS table).

Dispatch is synchronous in the emitting process and crash-isolated: a handler exception is discarded, it never reaches the caller, the client or the server. Handlers must still be fast — they run on the call path. Counting here complements, not replaces, logger: the warning logs keep the stack traces and the exceptional traffic.

The event catalogue (one map per event, type first):

  • thrift_runtime_client, one event per caller-facing answer, so counting call_ok / call_error reproduces get_stats/1: #{type => call_ok, function => binary(), duration_us => N, oneway => boolean()} — duration_us covers the queue wait and the wire round-trip, the same span the per-call timeout arms over; #{type => call_error, function => binary(), reason => term(), duration_us => N, oneway => boolean()} — the reason is whatever the caller receives (queue_full, closed, a timeout atom, a protocol error, a declared exception tuple, ...).
  • thrift_runtime_reconnecting_client (the connection axis only; call events come from the wrapped client, which gets the same handler): #{type => connected}, #{type => connect_failed, reason => term(), retry_in_ms => N}, #{type => disconnected, reason => term(), retry_in_ms => N}.
  • thrift_runtime_connection (server side): #{type => connection_open, peer => {inet:ip_address(), inet:port_number()} | undefined}, #{type => connection_closed, reason => term()}, #{type => handler_error, function => binary(), reason => term()} — a handler crash (reason is the handler's exception) or an unsupported handler result (reason is {bad_result, Result}); declared exceptions and protocol errors are answers, not handler errors.

Summary

Functions

Calls the handler with the event; handler exceptions are discarded.

Emits an event of Type unless the handler is undefined — the map is not built on the no-handler path, which is the default one.

Types

event()

-type event() ::
          #{type := call_ok,
            function := binary(),
            duration_us := non_neg_integer(),
            oneway := boolean()} |
          #{type := call_error,
            function := binary(),
            reason := term(),
            duration_us := non_neg_integer(),
            oneway := boolean()} |
          #{type := connected} |
          #{type := connect_failed, reason := term(), retry_in_ms := pos_integer()} |
          #{type := disconnected, reason := term(), retry_in_ms := pos_integer()} |
          #{type := connection_open, peer := term()} |
          #{type := connection_closed, reason := term()} |
          #{type := handler_error, function := binary(), reason := term()}.

handler()

-type handler() :: undefined | fun((event()) -> any()) | {module(), atom(), [term()]}.

Functions

dispatch(Handler, Event)

-spec dispatch(handler(), event()) -> ok.

Calls the handler with the event; handler exceptions are discarded.

emit/3

-spec emit(handler(), atom(), map()) -> ok.

Emits an event of Type unless the handler is undefined — the map is not built on the no-handler path, which is the default one.