@@ -40,6 +40,7 @@ defmodule IEx.Helpers do
40
40
* `pid/3` - creates a PID with the 3 integer arguments passed
41
41
* `port/1` - creates a port from a string
42
42
* `port/2` - creates a port with the 2 non-negative integers passed
43
+ * `process_info/1` - returns information about the given process
43
44
* `pwd/0` - prints the current working directory
44
45
* `r/1` - recompiles the given module's source file
45
46
* `recompile/0` - recompiles the current project
@@ -817,6 +818,168 @@ defmodule IEx.Helpers do
817
818
818
819
defp pad_key ( key ) , do: String . pad_trailing ( key , 21 , " " )
819
820
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
+
820
983
@ doc """
821
984
Clears out all messages sent to the shell's inbox and prints them out.
822
985
"""
0 commit comments