1010-include_lib (" kernel/include/logger.hrl" ).
1111-include_lib (" rabbit_common/include/rabbit.hrl" ).
1212-include_lib (" amqp10_common/include/amqp10_types.hrl" ).
13+ -include (" rabbit_amqp_reader.hrl" ).
1314-include (" rabbit_amqp.hrl" ).
1415
1516-export ([init /1 ,
7980 pending_recv :: boolean (),
8081 buf :: list (),
8182 buf_len :: non_neg_integer (),
82- tracked_channels :: #{channel_number () => Session :: pid ()}
83+ tracked_channels :: #{channel_number () => Session :: pid ()},
84+ stats_timer :: rabbit_event :state ()
8385 }).
8486
8587-type state () :: # v1 {}.
9092
9193unpack_from_0_9_1 (
9294 {Sock , PendingRecv , SupPid , Buf , BufLen , ProxySocket ,
93- ConnectionName , Host , PeerHost , Port , PeerPort , ConnectedAt },
95+ ConnectionName , Host , PeerHost , Port , PeerPort , ConnectedAt , StatsTimer },
9496 Parent ) ->
9597 logger :update_process_metadata (#{connection => ConnectionName }),
9698 # v1 {parent = Parent ,
@@ -106,6 +108,7 @@ unpack_from_0_9_1(
106108 tracked_channels = maps :new (),
107109 writer = none ,
108110 connection_state = received_amqp3100 ,
111+ stats_timer = StatsTimer ,
109112 connection = # v1_connection {
110113 name = ConnectionName ,
111114 container_id = none ,
@@ -201,6 +204,10 @@ mainloop(Deb, State = #v1{sock = Sock, buf = Buf, buf_len = BufLen}) ->
201204 end
202205 end .
203206
207+ handle_other (emit_stats , State ) ->
208+ emit_stats (State );
209+ handle_other (ensure_stats_timer , State ) ->
210+ ensure_stats_timer (State );
204211handle_other ({'EXIT' , Parent , Reason }, State = # v1 {parent = Parent }) ->
205212 ReasonString = rabbit_misc :format (" broker forced connection closure with reason '~w '" ,
206213 [Reason ]),
@@ -247,8 +254,16 @@ handle_other({'$gen_call', From, {info, Items}}, State) ->
247254 end ,
248255 gen_server :reply (From , Reply ),
249256 State ;
250- handle_other ({'$gen_cast' , {force_event_refresh , _Ref }}, State ) ->
251- State ;
257+ handle_other ({'$gen_cast' , {force_event_refresh , Ref }}, State ) ->
258+ case ? IS_RUNNING (State ) of
259+ true ->
260+ Infos = infos (? CONNECTION_EVENT_KEYS , State ),
261+ rabbit_event :notify (connection_created , Infos , Ref ),
262+ rabbit_event :init_stats_timer (State , # v1 .stats_timer );
263+ false ->
264+ % % Ignore, we will emit a connection_created event once we start running.
265+ State
266+ end ;
252267handle_other (terminate_connection , _State ) ->
253268 stop ;
254269handle_other ({set_credential , Cred }, State ) ->
@@ -527,6 +542,7 @@ handle_connection_frame(
527542 proplists :get_value (pid , Infos ),
528543 Infos ),
529544 ok = rabbit_event :notify (connection_created , Infos ),
545+ ok = maybe_emit_stats (State ),
530546 ok = rabbit_amqp1_0 :register_connection (self ()),
531547 Caps = [% % https://docs.oasis-open.org/amqp/linkpair/v1.0/cs01/linkpair-v1.0-cs01.html#_Toc51331306
532548 <<" LINK_PAIR_V1_0" >>,
@@ -629,25 +645,26 @@ handle_input(handshake,
629645 switch_callback (State , {frame_header , amqp }, 8 );
630646handle_input ({frame_header , Mode },
631647 Header = <<Size :32 , DOff :8 , Type :8 , Channel :16 >>,
632- State ) when DOff >= 2 ->
648+ State0 ) when DOff >= 2 ->
633649 case {Mode , Type } of
634650 {amqp , 0 } -> ok ;
635651 {sasl , 1 } -> ok ;
636- _ -> throw ({bad_1_0_header_type , Header , Mode })
652+ _ -> throw ({bad_1_0_header_type , Header , Mode })
637653 end ,
638- MaxFrameSize = State # v1 .connection # v1_connection .incoming_max_frame_size ,
639- if Size =:= 8 ->
640- % % heartbeat
641- State ;
642- Size > MaxFrameSize ->
643- handle_exception (
644- State , Channel , error_frame (
645- ? V_1_0_CONNECTION_ERROR_FRAMING_ERROR ,
646- " frame size (~b bytes) > maximum frame size (~b bytes)" ,
647- [Size , MaxFrameSize ]));
648- true ->
649- switch_callback (State , {frame_body , Mode , DOff , Channel }, Size - 8 )
650- end ;
654+ MaxFrameSize = State0 # v1 .connection # v1_connection .incoming_max_frame_size ,
655+ State = if Size =:= 8 ->
656+ % % heartbeat
657+ State0 ;
658+ Size > MaxFrameSize ->
659+ Err = error_frame (
660+ ? V_1_0_CONNECTION_ERROR_FRAMING_ERROR ,
661+ " frame size (~b bytes) > maximum frame size (~b bytes)" ,
662+ [Size , MaxFrameSize ]),
663+ handle_exception (State0 , Channel , Err );
664+ true ->
665+ switch_callback (State0 , {frame_body , Mode , DOff , Channel }, Size - 8 )
666+ end ,
667+ ensure_stats_timer (State );
651668handle_input ({frame_header , _Mode }, Malformed , _State ) ->
652669 throw ({bad_1_0_header , Malformed });
653670handle_input ({frame_body , Mode , DOff , Channel },
@@ -1013,13 +1030,18 @@ i(peer_host, #v1{connection = #v1_connection{peer_host = Val}}) ->
10131030 Val ;
10141031i (peer_port , # v1 {connection = # v1_connection {peer_port = Val }}) ->
10151032 Val ;
1016- i (SockStat , S ) when SockStat =:= recv_oct ;
1017- SockStat =:= recv_cnt ;
1018- SockStat =:= send_oct ;
1019- SockStat =:= send_cnt ;
1020- SockStat =:= send_pend ->
1021- socket_info (fun (Sock ) -> rabbit_net :getstat (Sock , [SockStat ]) end ,
1022- fun ([{_ , I }]) -> I end , S );
1033+ i (SockStat , # v1 {sock = Sock })
1034+ when SockStat =:= recv_oct ;
1035+ SockStat =:= recv_cnt ;
1036+ SockStat =:= send_oct ;
1037+ SockStat =:= send_cnt ;
1038+ SockStat =:= send_pend ->
1039+ case rabbit_net :getstat (Sock , [SockStat ]) of
1040+ {ok , [{SockStat , Val }]} ->
1041+ Val ;
1042+ {error , _ } ->
1043+ ''
1044+ end ;
10231045i (ssl , # v1 {sock = Sock }) -> rabbit_net :is_ssl (Sock );
10241046i (SSL , # v1 {sock = Sock , proxy_socket = ProxySock })
10251047 when SSL =:= ssl_protocol ;
@@ -1045,15 +1067,37 @@ i(channels, #v1{tracked_channels = Channels}) ->
10451067 maps :size (Channels );
10461068i (channel_max , # v1 {connection = # v1_connection {channel_max = Max }}) ->
10471069 Max ;
1070+ i (reductions = Item , _State ) ->
1071+ {Item , Reductions } = erlang :process_info (self (), Item ),
1072+ Reductions ;
1073+ i (garbage_collection , _State ) ->
1074+ rabbit_misc :get_gc_info (self ());
10481075i (Item , # v1 {}) ->
10491076 throw ({bad_argument , Item }).
10501077
1051- % % From rabbit_reader
1052- socket_info (Get , Select , # v1 {sock = Sock }) ->
1053- case Get (Sock ) of
1054- {ok , T } -> Select (T );
1055- {error , _ } -> ''
1056- end .
1078+ maybe_emit_stats (State ) ->
1079+ ok = rabbit_event :if_enabled (
1080+ State ,
1081+ # v1 .stats_timer ,
1082+ fun () -> emit_stats (State ) end ).
1083+
1084+ emit_stats (State ) ->
1085+ [{_ , Pid },
1086+ {_ , RecvOct },
1087+ {_ , SendOct },
1088+ {_ , Reductions }] = infos (? SIMPLE_METRICS , State ),
1089+ Infos = infos (? OTHER_METRICS , State ),
1090+ rabbit_core_metrics :connection_stats (Pid , Infos ),
1091+ rabbit_core_metrics :connection_stats (Pid , RecvOct , SendOct , Reductions ),
1092+ % % NB: Don't call ensure_stats_timer because it becomes expensive
1093+ % % if all idle non-hibernating connections emit stats.
1094+ rabbit_event :reset_stats_timer (State , # v1 .stats_timer ).
1095+
1096+ ensure_stats_timer (State )
1097+ when ? IS_RUNNING (State ) ->
1098+ rabbit_event :ensure_stats_timer (State , # v1 .stats_timer , emit_stats );
1099+ ensure_stats_timer (State ) ->
1100+ State .
10571101
10581102ignore_maintenance ({map , Properties }) ->
10591103 lists :member (
0 commit comments