Jido.Telemetry.Formatter (Jido v2.3.1)

Copy Markdown View Source

Structured log formatting utilities for the Jido telemetry system.

Provides functions to format durations, metadata, directives, and other telemetry data into human-readable, scannable log output.

Examples

iex> Jido.Telemetry.Formatter.format_duration(1_500_000)
"1.5ms"

iex> Jido.Telemetry.Formatter.format_metadata(%{agent_id: "abc123", trace_id: "xyz"})
"agent_id=abc123 trace_id=xyz"

Summary

Functions

Extract just the keys from a map for safe logging.

Summarize action for logging without exposing full data.

Format directive summary map for logging.

Convert native time to human-readable format.

Format a complete log line with standard telemetry fields.

Format metadata map into a scannable key=value string for logs.

Format signal type for logging.

Inspect a term with a length limit.

Returns a map of directive_type => count from a list of directives.

Convert native time to milliseconds.

Functions

extract_keys(map)

@spec extract_keys(map() | nil) :: [atom() | String.t()]

Extract just the keys from a map for safe logging.

Useful when you want to log what fields are present without exposing values.

Examples

iex> Formatter.extract_keys(%{user_id: 123, secret: "password", data: %{}})
[:data, :secret, :user_id]

iex> Formatter.extract_keys(nil)
[]

iex> Formatter.extract_keys("not a map")
[]

format_action(module)

@spec format_action(term()) :: String.t()

Summarize action for logging without exposing full data.

Shows the action/module name and parameter keys but not values.

Examples

iex> Formatter.format_action({:analyze, %{query: "secret", context: %{}}})
"{:analyze, keys: [:context, :query]}"

iex> Formatter.format_action(MyApp.Actions.ProcessData)
"MyApp.Actions.ProcessData"

iex> Formatter.format_action(%{action: :run, params: %{x: 1}})
"{:run, keys: [:x]}"

format_directive_types(summary)

@spec format_directive_types(map()) :: String.t()

Format directive summary map for logging.

Examples

iex> Formatter.format_directive_types(%{emit: 2, tool: 1, await: 1})
"Await=1 Emit=2 Tool=1"

iex> Formatter.format_directive_types(%{})
""

format_duration(native_time)

@spec format_duration(integer() | nil) :: String.t()

Convert native time to human-readable format.

Returns a string like "1.2ms", "342μs", or "2.1s" depending on the magnitude.

Examples

iex> Formatter.format_duration(1_000)
"1μs"

iex> Formatter.format_duration(1_500_000)
"1.5ms"

iex> Formatter.format_duration(2_500_000_000)
"2.5s"

format_log_line(fields)

@spec format_log_line(map()) :: String.t()

Format a complete log line with standard telemetry fields.

Combines multiple formatting functions into a single log-ready string.

Examples

iex> Formatter.format_log_line(%{
...>   agent_id: "agent-1",
...>   trace_id: "trace-abc",
...>   signal_type: :user_request,
...>   duration: 1_500_000
...> })
"agent_id=agent-1 duration=1.5ms signal_type=user_request trace_id=trace-abc"

format_metadata(metadata, opts \\ [])

@spec format_metadata(
  map() | nil,
  keyword()
) :: String.t()

Format metadata map into a scannable key=value string for logs.

Handles nil values gracefully and truncates long values.

Options

  • :max_value_length - Maximum length for individual values (default: 50)

Examples

iex> Formatter.format_metadata(%{agent_id: "abc123", trace_id: "xyz"})
"agent_id=abc123 trace_id=xyz"

iex> Formatter.format_metadata(%{key: nil, other: "value"})
"other=value"

iex> Formatter.format_metadata(nil)
""

format_signal_type(type)

@spec format_signal_type(atom() | String.t() | nil) :: String.t()

Format signal type for logging.

Handles atoms and strings, converting to a readable format.

Examples

iex> Formatter.format_signal_type(:user_request)
"user_request"

iex> Formatter.format_signal_type("api_call")
"api_call"

iex> Formatter.format_signal_type(nil)
"unknown"

safe_inspect(term, max_length \\ 100)

@spec safe_inspect(term(), pos_integer()) :: String.t()

Inspect a term with a length limit.

Safely inspects any term and truncates if necessary.

Examples

iex> Formatter.safe_inspect(%{a: 1, b: 2})
"%{a: 1, b: 2}"

iex> Formatter.safe_inspect(String.duplicate("x", 200), 50)
"\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx..."

summarize_directives(directives)

@spec summarize_directives(list()) :: map()

Returns a map of directive_type => count from a list of directives.

Examples

iex> directives = [%{type: :emit}, %{type: :emit}, %{type: :tool}]
iex> Formatter.summarize_directives(directives)
%{emit: 2, tool: 1}

iex> Formatter.summarize_directives([])
%{}

to_ms(native_time)

@spec to_ms(integer() | nil) :: number()

Convert native time to milliseconds.

Returns an integer for times >= 1ms, otherwise a float with precision.

Examples

iex> Formatter.to_ms(1_500_000)
1.5

iex> Formatter.to_ms(5_000_000)
5