@@ -40,6 +40,7 @@ defmodule IEx.Helpers do
4040 * `pid/3` - creates a PID with the 3 integer arguments passed
4141 * `port/1` - creates a port from a string
4242 * `port/2` - creates a port with the 2 non-negative integers passed
43+ * `process_info/1` - returns information about the given process
4344 * `pwd/0` - prints the current working directory
4445 * `r/1` - recompiles the given module's source file
4546 * `recompile/0` - recompiles the current project
@@ -817,6 +818,168 @@ defmodule IEx.Helpers do
817818
818819 defp pad_key ( key ) , do: String . pad_trailing ( key , 21 , " " )
819820
821+ @ process_info_keys_and_labels [
822+ { :initial_call , "Initial call" } ,
823+ { :dictionary , "Dictionary" } ,
824+ { :registered_name , "Registered name" } ,
825+ { :current_function , "Current function" } ,
826+ { :status , "Status" } ,
827+ { :message_queue_len , "Message queue length" } ,
828+ { :trap_exit , "Trap exit" } ,
829+ { :priority , "Priority" } ,
830+ { :group_leader , "Group leader" } ,
831+ { :reductions , "Reductions" } ,
832+ { :links , "Links" } ,
833+ { :monitors , "Monitors" } ,
834+ { :memory , "Memory" } ,
835+ { :total_heap_size , "Total heap size" } ,
836+ { :heap_size , "Heap size" } ,
837+ { :stack_size , "Stack size" } ,
838+ { :current_stacktrace , "Current stacktrace" }
839+ ]
840+ @ process_info_keys Enum . map ( @ process_info_keys_and_labels , fn { key , _ } -> key end )
841+ @ process_info_label_mapping Map . new ( @ process_info_keys_and_labels )
842+
843+ @ doc """
844+ Prints information about the given process.
845+
846+ Includes a generic overview and details such as the linked and monitored processes,
847+ the memory usage and the current stacktrace.
848+
849+ ## Examples
850+
851+ iex> process_info(self())
852+ ...
853+ iex> process_info({:via, Registry, {MyApp.Registry, :name}})
854+ ...
855+
856+ """
857+ @ doc since: "1.19.0"
858+ def process_info ( pid ) do
859+ with pid when is_pid ( pid ) <- GenServer . whereis ( pid ) ,
860+ info when is_list ( info ) <-
861+ :erpc . call ( node ( pid ) , :erlang , :process_info , [ pid , @ process_info_keys ] ) do
862+ info = Map . new ( info )
863+
864+ IO . puts ( IEx . color ( :eval_result , [ "\n # Process " , inspect ( pid ) ] ) )
865+
866+ print_process_overview ( info )
867+ print_process_links ( info [ :links ] )
868+ print_process_monitors ( info [ :monitors ] )
869+ print_process_memory ( info )
870+ print_process_stacktrace ( info [ :current_stacktrace ] )
871+ else
872+ _ ->
873+ IO . puts (
874+ IEx . color (
875+ :eval_error ,
876+ "Failed to get process info. Either the process was not found or is not alive."
877+ )
878+ )
879+ end
880+
881+ dont_display_result ( )
882+ end
883+
884+ defp print_process_overview ( info ) do
885+ print_pane ( "Overview" )
886+
887+ for key <- [
888+ :initial_call ,
889+ :current_function ,
890+ :registered_name ,
891+ :status ,
892+ :message_queue_len ,
893+ :group_leader ,
894+ :priority ,
895+ :trap_exit ,
896+ :reductions
897+ ] do
898+ print_entry (
899+ @ process_info_label_mapping [ key ] ,
900+ inspect ( info [ key ] , printable_limit: 256 , limit: 5 )
901+ )
902+ end
903+ end
904+
905+ defp print_process_links ( [ ] ) , do: :ok
906+
907+ defp print_process_links ( ports_and_pids ) do
908+ print_pane ( "Links" )
909+
910+ for link <- ports_and_pids do
911+ print_entry ( inspect ( link ) , pid_or_port_details ( link ) )
912+ end
913+ end
914+
915+ defp print_process_monitors ( [ ] ) , do: :ok
916+
917+ defp print_process_monitors ( monitors ) do
918+ print_pane ( "Monitors" )
919+
920+ for { _ , pid_or_port } <- monitors do
921+ print_entry ( inspect ( pid_or_port ) , pid_or_port_details ( pid_or_port ) )
922+ end
923+ end
924+
925+ defp print_process_memory ( info ) do
926+ print_pane ( "Memory" )
927+
928+ for key <- [ :memory , :total_heap_size , :heap_size , :stack_size ] do
929+ print_entry ( @ process_info_label_mapping [ key ] , format_bytes ( info [ key ] ) )
930+ end
931+ end
932+
933+ defp print_process_stacktrace ( [ ] ) , do: :ok
934+
935+ defp print_process_stacktrace ( stacktrace ) do
936+ print_pane ( "Current stacktrace" )
937+
938+ IO . puts ( IEx . color ( :eval_info , Exception . format_stacktrace ( stacktrace ) ) )
939+ end
940+
941+ defp pid_or_port_details ( pid ) when is_pid ( pid ) , do: to_process_details ( pid )
942+ defp pid_or_port_details ( name ) when is_atom ( name ) , do: to_process_details ( name )
943+ defp pid_or_port_details ( port ) when is_port ( port ) , do: to_port_details ( port )
944+ defp pid_or_port_details ( reference ) when is_reference ( reference ) , do: reference
945+
946+ defp to_process_details ( pid ) when is_pid ( pid ) do
947+ case Process . info ( pid , [ :initial_call , :dictionary , :registered_name ] ) do
948+ [ { :initial_call , initial_call } , { :dictionary , dictionary } , { :registered_name , name } ] ->
949+ initial_call = Keyword . get ( dictionary , :"$initial_call" , initial_call )
950+
951+ format_registered_name ( name ) ||
952+ format_process_label ( Keyword . get ( dictionary , :"$process_label" ) ) ||
953+ format_initial_call ( initial_call )
954+
955+ _ ->
956+ "-"
957+ end
958+ end
959+
960+ defp to_process_details ( name ) when is_atom ( name ) do
961+ Process . whereis ( name )
962+ |> to_process_details ( )
963+ end
964+
965+ defp format_process_label ( nil ) , do: nil
966+ defp format_process_label ( label ) when is_binary ( label ) , do: label
967+ defp format_process_label ( label ) , do: inspect ( label )
968+
969+ defp format_registered_name ( [ ] ) , do: nil
970+ defp format_registered_name ( name ) , do: inspect ( name )
971+
972+ defp format_initial_call ( { :supervisor , mod , arity } ) , do: Exception . format_mfa ( mod , :init , arity )
973+ defp format_initial_call ( { m , f , a } ) , do: Exception . format_mfa ( m , f , a )
974+ defp format_initial_call ( nil ) , do: nil
975+
976+ defp to_port_details ( port ) when is_port ( port ) do
977+ case Port . info ( port , :name ) do
978+ { :name , name } -> name
979+ _ -> "-"
980+ end
981+ end
982+
820983 @ doc """
821984 Clears out all messages sent to the shell's inbox and prints them out.
822985 """
0 commit comments