JustBash.Telemetry (JustBash v0.4.0)
View SourceTelemetry instrumentation for the JustBash interpreter.
This module emits telemetry events for script execution, allowing you to monitor performance, track usage, and integrate with observability tools.
All events use :telemetry.span/3, which automatically includes a
telemetry_span_context in metadata for distributed tracing correlation.
Available Events
All events follow the span pattern with :start, :stop, and :exception suffixes.
Session Execution
[:just_bash, :session, :run, :start]- Emitted whenJustBash.exec/2begins execution- Measurement:
%{system_time: integer, monotonic_time: integer} - Metadata:
%{session: pid(), telemetry_span_context: reference()}
- Measurement:
[:just_bash, :session, :run, :stop]- Emitted whenJustBash.exec/2completes- Measurement:
%{duration: native_time, monotonic_time: integer} Metadata:
%{session: pid(), status: :ok | :error, exit_code: integer, bytes_in: integer, bytes_out: integer, telemetry_span_context: reference()}
- Measurement:
[:just_bash, :session, :run, :exception]- Emitted whenJustBash.exec/2raises- Measurement:
%{duration: native_time, monotonic_time: integer} Metadata:
%{session: pid(), kind: :error | :exit | :throw, reason: term, stacktrace: list, telemetry_span_context: reference()}- Rare by design: the interpreter contains a crashed command and a raise
from the statement loop, so those produce a
:stopwith a non-zeroexit_code— plus a[:just_bash, :command, :exception]when a command was the cause — rather than an exception here.
- Measurement:
Command Execution
[:just_bash, :command, :start]- Emitted before a command executes- Measurement:
%{system_time: integer, monotonic_time: integer} - Metadata:
%{command: String.t(), args: list(String.t()), telemetry_span_context: reference()}
- Measurement:
[:just_bash, :command, :stop]- Emitted after a command completes- Measurement:
%{duration: native_time, monotonic_time: integer} - Metadata:
%{command: String.t(), args: list(String.t()), exit_code: integer, bytes_in: integer, bytes_out: integer, telemetry_span_context: reference()} - When the command is a
JustBash.CLItool, metadata also includessubcommand: list(String.t())— the resolved subcommand path (e.g.["pr", "review"]) — so observability doesn't collapse an entire CLI into a singlecommandbucket.
- Measurement:
[:just_bash, :command, :exception]- Emitted when a command raises- Measurement:
%{duration: native_time, monotonic_time: integer} - Metadata:
%{command: String.t(), args: list(String.t()), kind: atom, reason: term, stacktrace: list, telemetry_span_context: reference()} - A command that raises is contained —
JustBash.exec/2still returns a shell result — but the containment sits outside this span deliberately, so a crash stays distinguishable from a script that legitimately fails. The:stopevent does not fire for the same command.
- Measurement:
For Loop Execution
[:just_bash, :for_loop, :start]- Emitted before a for loop begins- Measurement:
%{system_time: integer, monotonic_time: integer} - Metadata:
%{variable: String.t(), item_count: integer, telemetry_span_context: reference()}
- Measurement:
[:just_bash, :for_loop, :stop]- Emitted after a for loop completes- Measurement:
%{duration: native_time, monotonic_time: integer} - Metadata:
%{variable: String.t(), item_count: integer, iteration_count: integer, exit_code: integer | nil, telemetry_span_context: reference()}
- Measurement:
[:just_bash, :for_loop, :exception]- Emitted when a for loop raises- Measurement:
%{duration: native_time, monotonic_time: integer} - Metadata:
%{variable: String.t(), item_count: integer, kind: atom, reason: term, stacktrace: list, telemetry_span_context: reference()}
- Measurement:
While/Until Loop Execution
[:just_bash, :while_loop, :start]- Emitted before a while/until loop begins- Measurement:
%{system_time: integer, monotonic_time: integer} - Metadata:
%{until: boolean, telemetry_span_context: reference()}
- Measurement:
[:just_bash, :while_loop, :stop]- Emitted after a while/until loop completes- Measurement:
%{duration: native_time, monotonic_time: integer} - Metadata:
%{until: boolean, iteration_count: integer, exit_code: integer | nil, telemetry_span_context: reference()}
- Measurement:
[:just_bash, :while_loop, :exception]- Emitted when a while/until loop raises- Measurement:
%{duration: native_time, monotonic_time: integer} - Metadata:
%{until: boolean, kind: atom, reason: term, stacktrace: list, telemetry_span_context: reference()}
- Measurement:
Usage Example
Attach handlers to receive telemetry events:
:telemetry.attach_many(
"just-bash-handler",
[
[:just_bash, :session, :run, :start],
[:just_bash, :session, :run, :stop],
[:just_bash, :session, :run, :exception],
[:just_bash, :command, :start],
[:just_bash, :command, :stop],
[:just_bash, :command, :exception],
[:just_bash, :for_loop, :start],
[:just_bash, :for_loop, :stop],
[:just_bash, :for_loop, :exception],
[:just_bash, :while_loop, :start],
[:just_bash, :while_loop, :stop],
[:just_bash, :while_loop, :exception]
],
&MyApp.TelemetryHandler.handle_event/4,
nil
)Note on Output
Output (stdout/stderr) is intentionally NOT included in telemetry metadata
to avoid memory issues with large outputs. Byte counts (bytes_in, bytes_out)
are provided instead. Use output collectors or sinks if you need to capture
command output.