# frozen_string_literal: truerequire"active_support/core_ext/module/delegation"require"securerandom"moduleActiveSupportmoduleNotifications# Instrumenters are stored in a thread local.classInstrumenterattr_reader:iddefinitialize(notifier)unlessnotifier.respond_to?(:build_handle)notifier=LegacyHandle::Wrapper.new(notifier)end@id=unique_id@notifier=notifierendclassLegacyHandle# :nodoc:classWrapper# :nodoc:definitialize(notifier)@notifier=notifierenddefbuild_handle(name,id,payload)LegacyHandle.new(@notifier,name,id,payload)enddelegate:start,:finish,to: :@notifierenddefinitialize(notifier,name,id,payload)@notifier=notifier@name=name@id=id@payload=payloadenddefstart@listener_state=@notifier.start@name,@id,@payloadenddeffinish@notifier.finish(@name,@id,@payload,@listener_state)endend# Given a block, instrument it by measuring the time taken to execute# and publish it. Without a block, simply send a message via the# notifier. Notice that events get sent even if an error occurs in the# passed-in block.definstrument(name,payload={})handle=build_handle(name,payload)handle.startbeginyieldpayloadifblock_given?rescueException=>epayload[:exception]=[e.class.name,e.message]payload[:exception_object]=eraiseeensurehandle.finishendend# Returns a "handle" for an event with the given +name+ and +payload+.## #start and #finish must each be called exactly once on the returned object.## Where possible, it's best to use #instrument, which will record the# start and finish of the event and correctly handle any exceptions.# +build_handle+ is a low-level API intended for cases where using# +instrument+ isn't possible.## See ActiveSupport::Notifications::Fanout::Handle.defbuild_handle(name,payload)@notifier.build_handle(name,@id,payload)enddefnew_event(name,payload={})# :nodoc:Event.new(name,nil,nil,@id,payload)end# Send a start notification with +name+ and +payload+.defstart(name,payload)@notifier.startname,@id,payloadend# Send a finish notification with +name+ and +payload+.deffinish(name,payload)@notifier.finishname,@id,payloadenddeffinish_with_state(listeners_state,name,payload)@notifier.finishname,@id,payload,listeners_stateendprivatedefunique_idSecureRandom.hex(10)endendclassEventattr_reader:name,:time,:end,:transaction_idattr_accessor:payloaddefinitialize(name,start,ending,transaction_id,payload)@name=name@payload=payload.dup@time=start?start.to_f*1_000.0:start@transaction_id=transaction_id@end=ending?ending.to_f*1_000.0:ending@cpu_time_start=0.0@cpu_time_finish=0.0@allocation_count_start=0@allocation_count_finish=0enddefrecordstart!beginyieldpayloadifblock_given?rescueException=>epayload[:exception]=[e.class.name,e.message]payload[:exception_object]=eraiseeensurefinish!endend# Record information at the time this event startsdefstart!@time=now@cpu_time_start=now_cpu@allocation_count_start=now_allocationsend# Record information at the time this event finishesdeffinish!@cpu_time_finish=now_cpu@end=now@allocation_count_finish=now_allocationsend# Returns the CPU time (in milliseconds) passed between the call to# #start! and the call to #finish!.defcpu_time@cpu_time_finish-@cpu_time_startend# Returns the idle time time (in milliseconds) passed between the call to# #start! and the call to #finish!.defidle_timediff=duration-cpu_timediff>0.0?diff:0.0end# Returns the number of allocations made between the call to #start! and# the call to #finish!.defallocations@allocation_count_finish-@allocation_count_startenddefchildren# :nodoc:ActiveSupport.deprecator.warn<<~EOM
ActiveSupport::Notifications::Event#children is deprecated and will
be removed in Rails 7.2.
EOM[]enddefparent_of?(event)# :nodoc:ActiveSupport.deprecator.warn<<~EOM
ActiveSupport::Notifications::Event#parent_of? is deprecated and will
be removed in Rails 7.2.
EOMstart=(time-event.time)*1000start<=0&&(start+duration>=event.duration)end# Returns the difference in milliseconds between when the execution of the# event started and when it ended.## ActiveSupport::Notifications.subscribe('wait') do |*args|# @event = ActiveSupport::Notifications::Event.new(*args)# end## ActiveSupport::Notifications.instrument('wait') do# sleep 1# end## @event.duration # => 1000.138defdurationself.end-timeendprivatedefnowProcess.clock_gettime(Process::CLOCK_MONOTONIC,:float_millisecond)endbeginProcess.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID,:float_millisecond)defnow_cpuProcess.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID,:float_millisecond)endrescuedefnow_cpu# rubocop:disable Lint/DuplicateMethods0.0endendifGC.stat.key?(:total_allocated_objects)defnow_allocationsGC.stat(:total_allocated_objects)endelse# Likely on JRuby, TruffleRubydefnow_allocations0endendendendend