logging.rb 3.8 KB
Newer Older
1 2 3 4
require "active_support/core_ext/hash/transform_values"
require "active_support/core_ext/string/filters"
require "active_support/tagged_logging"
require "active_support/logger"
5

C
Cristian Bica 已提交
6
module ActiveJob
M
mo khan 已提交
7
  module Logging #:nodoc:
8
    extend ActiveSupport::Concern
C
Cristian Bica 已提交
9

10
    included do
11 12
      cattr_accessor(:logger) { ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDOUT)) }

13
      around_enqueue do |_, block, _|
C
Cristian Bica 已提交
14 15 16 17 18 19 20
        tag_logger do
          block.call
        end
      end

      around_perform do |job, block, _|
        tag_logger(job.class.name, job.job_id) do
21
          payload = { adapter: job.class.queue_adapter, job: job }
C
Cristian Bica 已提交
22
          ActiveSupport::Notifications.instrument("perform_start.active_job", payload.dup)
23
          ActiveSupport::Notifications.instrument("perform.active_job", payload) do
C
Cristian Bica 已提交
24 25 26 27 28
            block.call
          end
        end
      end

29
      after_enqueue do |job|
C
Cristian Bica 已提交
30
        if job.scheduled_at
C
Cristian Bica 已提交
31
          ActiveSupport::Notifications.instrument "enqueue_at.active_job",
C
Cristian Bica 已提交
32
            adapter: job.class.queue_adapter, job: job
33 34
        else
          ActiveSupport::Notifications.instrument "enqueue.active_job",
C
Cristian Bica 已提交
35
            adapter: job.class.queue_adapter, job: job
36 37 38
        end
      end
    end
C
Cristian Bica 已提交
39 40 41 42 43

    private
      def tag_logger(*tags)
        if logger.respond_to?(:tagged)
          tags.unshift "ActiveJob" unless logger_tagged_by_active_job?
44
          logger.tagged(*tags) { yield }
C
Cristian Bica 已提交
45 46 47 48 49 50 51 52 53
        else
          yield
        end
      end

      def logger_tagged_by_active_job?
        logger.formatter.current_tags.include?("ActiveJob")
      end

54 55 56 57 58 59
      class LogSubscriber < ActiveSupport::LogSubscriber #:nodoc:
        def enqueue(event)
          info do
            job = event.payload[:job]
            "Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)}" + args_info(job)
          end
60
        end
61

62 63 64 65 66
        def enqueue_at(event)
          info do
            job = event.payload[:job]
            "Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)} at #{scheduled_at(event)}" + args_info(job)
          end
67
        end
C
Cristian Bica 已提交
68

69 70 71
        def perform_start(event)
          info do
            job = event.payload[:job]
72
            "Performing #{job.class.name} (Job ID: #{job.job_id}) from #{queue_name(event)}" + args_info(job)
73
          end
74
        end
75

76
        def perform(event)
S
Steven Bull 已提交
77 78 79 80 81 82 83 84 85 86
          job = event.payload[:job]
          ex = event.payload[:exception_object]
          if ex
            error do
              "Error performing #{job.class.name} (Job ID: #{job.job_id}) from #{queue_name(event)} in #{event.duration.round(2)}ms: #{ex.class} (#{ex.message}):\n" + Array(ex.backtrace).join("\n")
            end
          else
            info do
              "Performed #{job.class.name} (Job ID: #{job.job_id}) from #{queue_name(event)} in #{event.duration.round(2)}ms"
            end
87
          end
88
        end
89

90 91 92 93
        private
          def queue_name(event)
            event.payload[:adapter].class.name.demodulize.remove("Adapter") + "(#{event.payload[:job].queue_name})"
          end
94

95 96 97 98 99 100 101
          def args_info(job)
            if job.arguments.any?
              " with arguments: " +
                job.arguments.map { |arg| format(arg).inspect }.join(", ")
            else
              ""
            end
102
          end
C
Cristian Bica 已提交
103

104 105 106 107 108 109 110 111 112 113 114
          def format(arg)
            case arg
            when Hash
              arg.transform_values { |value| format(value) }
            when Array
              arg.map { |value| format(value) }
            when GlobalID::Identification
              arg.to_global_id rescue arg
            else
              arg
            end
115 116
          end

117 118 119
          def scheduled_at(event)
            Time.at(event.payload[:job].scheduled_at).utc
          end
120

121 122 123 124
          def logger
            ActiveJob::Base.logger
          end
      end
C
Cristian Bica 已提交
125 126
  end
end
127 128

ActiveJob::Logging::LogSubscriber.attach_to :active_job