@@ -318,6 +318,7 @@ start_connection(Parent, HelperSups, RanchRef, Deb, Sock) ->
318318 {PeerHost , PeerPort , Host , Port } =
319319 socket_op (Sock , fun (S ) -> rabbit_net :socket_ends (S , inbound ) end ),
320320 ? store_proc_name (Name ),
321+ ConnectedAt = os :system_time (milli_seconds ),
321322 State = # v1 {parent = Parent ,
322323 ranch_ref = RanchRef ,
323324 sock = RealSocket ,
@@ -337,8 +338,7 @@ start_connection(Parent, HelperSups, RanchRef, Deb, Sock) ->
337338 capabilities = [],
338339 auth_mechanism = none ,
339340 auth_state = none ,
340- connected_at = os :system_time (
341- milli_seconds )},
341+ connected_at = ConnectedAt },
342342 callback = uninitialized_callback ,
343343 recv_len = 0 ,
344344 pending_recv = false ,
@@ -362,17 +362,23 @@ start_connection(Parent, HelperSups, RanchRef, Deb, Sock) ->
362362 handshake , 8 )]}) of
363363 % % connection was closed cleanly by the client
364364 # v1 {connection = # connection {user = # user {username = Username },
365- vhost = VHost }} ->
366- rabbit_log_connection :info (" closing AMQP connection (~ts , vhost: '~ts ', user: '~ts ')" ,
367- [dynamic_connection_name (Name ), VHost , Username ]);
365+ vhost = VHost ,
366+ connected_at = ConnectedAt0 }} ->
367+ ConnName = dynamic_connection_name (Name ),
368+ ConnDuration = connection_duration (ConnectedAt0 ),
369+ rabbit_log_connection :info (" closing AMQP connection (~ts , vhost: '~ts ', user: '~ts ', duration: '~ts ')" ,
370+ [ConnName , VHost , Username , ConnDuration ]);
368371 % % just to be more defensive
369372 _ ->
370- rabbit_log_connection :info (" closing AMQP connection (~ts )" ,
371- [dynamic_connection_name (Name )])
372- end
373+ ConnName = dynamic_connection_name (Name ),
374+ ConnDuration = connection_duration (ConnectedAt ),
375+ rabbit_log_connection :info (" closing AMQP connection (~ts , duration: '~ts ')" ,
376+ [ConnName , ConnDuration ])
377+ end
373378 catch
374379 Ex ->
375- log_connection_exception (dynamic_connection_name (Name ), Ex )
380+ ConnNameEx = dynamic_connection_name (Name ),
381+ log_connection_exception (ConnNameEx , ConnectedAt , Ex )
376382 after
377383 % % We don't call gen_tcp:close/1 here since it waits for
378384 % % pending output to be sent, which results in unnecessary
@@ -400,56 +406,67 @@ start_connection(Parent, HelperSups, RanchRef, Deb, Sock) ->
400406 end ,
401407 done .
402408
403- log_connection_exception (Name , Ex ) ->
409+ log_connection_exception (Name , ConnectedAt , Ex ) ->
404410 Severity = case Ex of
405411 connection_closed_with_no_data_received -> debug ;
406412 {connection_closed_abruptly , _ } -> warning ;
407413 connection_closed_abruptly -> warning ;
408414 _ -> error
409415 end ,
410- log_connection_exception (Severity , Name , Ex ).
416+ log_connection_exception (Severity , Name , ConnectedAt , Ex ).
411417
412- log_connection_exception (Severity , Name , {heartbeat_timeout , TimeoutSec }) ->
418+ log_connection_exception (Severity , Name , ConnectedAt , {heartbeat_timeout , TimeoutSec }) ->
419+ ConnDuration = connection_duration (ConnectedAt ),
420+ Fmt = " closing AMQP connection ~tp (~ts , duration: '~ts '):~n "
421+ " missed heartbeats from client, timeout: ~p s" ,
413422 % % Long line to avoid extra spaces and line breaks in log
414- log_connection_exception_with_severity (Severity ,
415- " closing AMQP connection ~tp (~ts ):~n "
416- " missed heartbeats from client, timeout: ~p s" ,
417- [self (), Name , TimeoutSec ]);
418- log_connection_exception (Severity , Name , {connection_closed_abruptly ,
419- # v1 {connection = # connection {user = # user {username = Username },
420- vhost = VHost }}}) ->
421- log_connection_exception_with_severity (Severity ,
422- " closing AMQP connection ~tp (~ts , vhost: '~ts ', user: '~ts '):~n client unexpectedly closed TCP connection" ,
423- [self (), Name , VHost , Username ]);
423+ log_connection_exception_with_severity (Severity , Fmt ,
424+ [self (), Name , ConnDuration , TimeoutSec ]);
425+ log_connection_exception (Severity , Name , _ConnectedAt ,
426+ {connection_closed_abruptly ,
427+ # v1 {connection = # connection {user = # user {username = Username },
428+ vhost = VHost ,
429+ connected_at = ConnectedAt }}}) ->
430+ ConnDuration = connection_duration (ConnectedAt ),
431+ Fmt = " closing AMQP connection ~tp (~ts , vhost: '~ts ', user: '~ts ', duration: '~ts '):~n "
432+ " client unexpectedly closed TCP connection" ,
433+ log_connection_exception_with_severity (Severity , Fmt ,
434+ [self (), Name , VHost , Username , ConnDuration ]);
424435% % when client abruptly closes connection before connection.open/authentication/authorization
425436% % succeeded, don't log username and vhost as 'none'
426- log_connection_exception (Severity , Name , {connection_closed_abruptly , _ }) ->
427- log_connection_exception_with_severity (Severity ,
428- " closing AMQP connection ~tp (~ts ):~n client unexpectedly closed TCP connection" ,
429- [self (), Name ]);
437+ log_connection_exception (Severity , Name , ConnectedAt , {connection_closed_abruptly , _ }) ->
438+ ConnDuration = connection_duration (ConnectedAt ),
439+ Fmt = " closing AMQP connection ~tp (~ts , duration: '~ts '):~n "
440+ " client unexpectedly closed TCP connection" ,
441+ log_connection_exception_with_severity (Severity , Fmt ,
442+ [self (), Name , ConnDuration ]);
430443% % failed connection.tune negotiations
431- log_connection_exception (Severity , Name , {handshake_error , tuning , _Channel ,
432- {exit , # amqp_error {explanation = Explanation },
433- _Method , _Stacktrace }}) ->
434- log_connection_exception_with_severity (Severity ,
435- " closing AMQP connection ~tp (~ts ):~n failed to negotiate connection parameters: ~ts " ,
436- [self (), Name , Explanation ]);
437- log_connection_exception (Severity , Name , {sasl_required , ProtocolId }) ->
438- log_connection_exception_with_severity (
439- Severity ,
440- " closing AMQP 1.0 connection (~ts ): RabbitMQ requires SASL "
441- " security layer (expected protocol ID 3, but client sent protocol ID ~b )" ,
442- [Name , ProtocolId ]);
444+ log_connection_exception (Severity , Name , ConnectedAt , {handshake_error , tuning , _Channel ,
445+ {exit , # amqp_error {explanation = Explanation },
446+ _Method , _Stacktrace }}) ->
447+ ConnDuration = connection_duration (ConnectedAt ),
448+ Fmt = " closing AMQP connection ~tp (~ts ):~n "
449+ " failed to negotiate connection parameters: ~ts " ,
450+ log_connection_exception_with_severity (Severity , Fmt , [self (), Name , ConnDuration , Explanation ]);
451+ log_connection_exception (Severity , Name , ConnectedAt , {sasl_required , ProtocolId }) ->
452+ ConnDuration = connection_duration (ConnectedAt ),
453+ Fmt = " closing AMQP 1.0 connection (~ts , duration: '~ts '): RabbitMQ requires SASL "
454+ " security layer (expected protocol ID 3, but client sent protocol ID ~b )" ,
455+ log_connection_exception_with_severity (Severity , Fmt ,
456+ [Name , ConnDuration , ProtocolId ]);
443457% % old exception structure
444- log_connection_exception (Severity , Name , connection_closed_abruptly ) ->
445- log_connection_exception_with_severity (Severity ,
446- " closing AMQP connection ~tp (~ts ):~n "
447- " client unexpectedly closed TCP connection" ,
448- [self (), Name ]);
449- log_connection_exception (Severity , Name , Ex ) ->
450- log_connection_exception_with_severity (Severity ,
451- " closing AMQP connection ~tp (~ts ):~n~tp " ,
452- [self (), Name , Ex ]).
458+ log_connection_exception (Severity , Name , ConnectedAt , connection_closed_abruptly ) ->
459+ ConnDuration = connection_duration (ConnectedAt ),
460+ Fmt = " closing AMQP connection ~tp (~ts , duration: '~ts '):~n "
461+ " client unexpectedly closed TCP connection" ,
462+ log_connection_exception_with_severity (Severity , Fmt ,
463+ [self (), Name , ConnDuration ]);
464+ log_connection_exception (Severity , Name , ConnectedAt , Ex ) ->
465+ ConnDuration = connection_duration (ConnectedAt ),
466+ Fmt = " closing AMQP connection ~tp (~ts , duration: '~ts '):~n "
467+ " ~tp " ,
468+ log_connection_exception_with_severity (Severity , Fmt ,
469+ [self (), Name , ConnDuration , Ex ]).
453470
454471log_connection_exception_with_severity (Severity , Fmt , Args ) ->
455472 case Severity of
@@ -1828,3 +1845,23 @@ get_client_value_detail(channel_max, 0) ->
18281845 " (no limit)" ;
18291846get_client_value_detail (_Field , _ClientValue ) ->
18301847 " " .
1848+
1849+ connection_duration (ConnectedAt ) ->
1850+ Now = os :system_time (milli_seconds ),
1851+ DurationMillis = Now - ConnectedAt ,
1852+ if
1853+ DurationMillis >= 1000 ->
1854+ DurationSecs = DurationMillis div 1000 ,
1855+ case calendar :seconds_to_daystime (DurationSecs ) of
1856+ {0 , {0 , 0 , Seconds }} ->
1857+ io_lib :format (" ~B s" , [Seconds ]);
1858+ {0 , {0 , Minutes , Seconds }} ->
1859+ io_lib :format (" ~B M, ~B s" , [Minutes , Seconds ]);
1860+ {0 , {Hours , Minutes , Seconds }} ->
1861+ io_lib :format (" ~B H, ~B M, ~B s" , [Hours , Minutes , Seconds ]);
1862+ {Days , {Hours , Minutes , Seconds }} ->
1863+ io_lib :format (" ~B D, ~B H, ~B M, ~B s" , [Days , Hours , Minutes , Seconds ])
1864+ end ;
1865+ true ->
1866+ io_lib :format (" ~B ms" , [DurationMillis ])
1867+ end .
0 commit comments