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