class SemanticLogger::Base

def measure_internal(level, index, message, params)

Measure the supplied block and log the message
def measure_internal(level, index, message, params)
  exception = nil
  # Single parameter is a hash
  if params.empty? && message.is_a?(Hash)
    params  = message
    message = nil
  end
  start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  begin
    if block_given?
      if (silence_level = params[:silence])
        # In case someone accidentally sets `silence: true` instead of `silence: :error`
        silence_level = :error if silence_level == true
        silence(silence_level) { yield(params) }
      else
        yield(params)
      end
    end
  rescue Exception => e
    exception = e
  ensure
    # Must use ensure block otherwise a `return` in the yield above will skip the log entry
    log = Log.new(name, level, index)
    exception ||= params[:exception]
    message   = params[:message] if params[:message]
    duration  =
      if block_given?
        1_000.0 * (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start)
      else
        params[:duration] || raise("Mandatory block missing when :duration option is not supplied")
      end
    # Extract options after block completes so that block can modify any of the options
    payload = params[:payload]
    # May return false due to elastic logging
    should_log = log.assign(
      message:            message,
      payload:            payload,
      min_duration:       params[:min_duration] || 0.0,
      exception:          exception,
      metric:             params[:metric],
      metric_amount:      params[:metric_amount],
      duration:           duration,
      log_exception:      params[:log_exception] || :partial,
      on_exception_level: params[:on_exception_level]
    )
    # Log level may change during assign due to :on_exception_level
    self.log(log) if should_log && should_log?(log)
    raise exception if exception
  end
end