zuora_observability 0.1.0.pre.c → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/README.md +7 -15
 - data/config/initializers/loggers.rb +4 -6
 - data/lib/zuora_observability/configuration.rb +8 -1
 - data/lib/zuora_observability/engine.rb +21 -71
 - data/lib/zuora_observability/env.rb +23 -2
 - data/lib/zuora_observability/logger.rb +54 -34
 - data/lib/zuora_observability/logging/custom_options.rb +76 -0
 - data/lib/zuora_observability/logging/formatter.rb +159 -33
 - data/lib/zuora_observability/version.rb +1 -1
 - metadata +15 -14
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 9b737913bb82aaa9107e1b6e143c488f40e284f392b50db8c7ebe295c29182d3
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: a69de61e998011b53a88c9a1c1b1b742336b9f47c85b67bea3b60e05ef278e25
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: dcd410016cab08896b3c687e52f7d2e7f9e987c9eaa402ffac539c1c3c6cdd61df13b7a7b758c55d165b4502d894adf43f3087d88999868a3a13c70ec51e5a0d
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: b326d582ea811996cebb8a35430146141f8992fbeb83675bfda5067a4b08cb59714938d6fd0c98fa7f1ea1d8a0e63fbcb843e64c1dcf2da7d8ace5bdda2350b4
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -2,22 +2,10 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            A ruby gem to enable observability into rails applications
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
            ##  
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
            ### Configuration
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
            Observability can be configured through an initializer as shown below.
         
     | 
| 
      
 5 
     | 
    
         
            +
            ## Prerequisites
         
     | 
| 
       10 
6 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
            ZuoraObservability.configure do |config|
         
     | 
| 
       14 
     | 
    
         
            -
              config.enable_metrics = true
         
     | 
| 
       15 
     | 
    
         
            -
            end
         
     | 
| 
       16 
     | 
    
         
            -
            ```
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
            | Configuration Field | Default Value                                                    | Description                          |
         
     | 
| 
       19 
     | 
    
         
            -
            | ------------------- | ---------------------------------------------------------------- | ------------------------------------ |
         
     | 
| 
       20 
     | 
    
         
            -
            | `json_logging`      | `false` in development/test, `true` otherwise                    | Use structured JSON logging for ZuoraObservability::Logger. **This configuration option cannot be changed in an initializer, but can be set to `true` with the presence of `ZUORA_JSON_LOGGING` environment variable** |
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Ruby 2.5+
         
     | 
| 
      
 8 
     | 
    
         
            +
            - Rails 5.0+
         
     | 
| 
       21 
9 
     | 
    
         | 
| 
       22 
10 
     | 
    
         
             
            ## Installation
         
     | 
| 
       23 
11 
     | 
    
         | 
| 
         @@ -39,6 +27,10 @@ Or install it yourself as: 
     | 
|
| 
       39 
27 
     | 
    
         
             
            $ gem install zuora_observability
         
     | 
| 
       40 
28 
     | 
    
         
             
            ```
         
     | 
| 
       41 
29 
     | 
    
         | 
| 
      
 30 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            - [Logging](doc/logging.md)
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
       42 
34 
     | 
    
         
             
            ## License
         
     | 
| 
       43 
35 
     | 
    
         | 
| 
       44 
36 
     | 
    
         
             
            The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
         
     | 
| 
         @@ -1,16 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            if defined?(Resque.logger)
         
     | 
| 
       4 
     | 
    
         
            -
              Resque.logger = ZuoraObservability::Logger.custom_logger(name: 'Resque' 
     | 
| 
      
 4 
     | 
    
         
            +
              Resque.logger = ZuoraObservability::Logger.custom_logger(name: 'Resque')
         
     | 
| 
       5 
5 
     | 
    
         
             
              if defined?(Resque::Scheduler)
         
     | 
| 
       6 
6 
     | 
    
         
             
                Resque::Scheduler.logger = ZuoraObservability::Logger.custom_logger(name: 'ResqueScheduler')
         
     | 
| 
       7 
7 
     | 
    
         
             
              end
         
     | 
| 
       8 
8 
     | 
    
         
             
            end
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
            if defined?(Delayed::Worker.logger)
         
     | 
| 
       11 
     | 
    
         
            -
              Delayed::Worker.logger = ZuoraObservability::Logger.custom_logger(
         
     | 
| 
       12 
     | 
    
         
            -
                name: 'DelayedJob', type: 'Monologger', level: MonoLogger::INFO
         
     | 
| 
       13 
     | 
    
         
            -
              )
         
     | 
| 
      
 11 
     | 
    
         
            +
              Delayed::Worker.logger = ZuoraObservability::Logger.custom_logger(name: 'DelayedJob', level: Logger::INFO)
         
     | 
| 
       14 
12 
     | 
    
         
             
            end
         
     | 
| 
       15 
13 
     | 
    
         | 
| 
       16 
14 
     | 
    
         
             
            if defined?(Makara)
         
     | 
| 
         @@ -18,9 +16,9 @@ if defined?(Makara) 
     | 
|
| 
       18 
16 
     | 
    
         
             
            end
         
     | 
| 
       19 
17 
     | 
    
         | 
| 
       20 
18 
     | 
    
         
             
            if defined?(ElasticAPM) && ElasticAPM.running?
         
     | 
| 
       21 
     | 
    
         
            -
              ElasticAPM.agent.config.logger = ZuoraObservability::Logger.custom_logger(name: 'ElasticAPM', level:  
     | 
| 
      
 19 
     | 
    
         
            +
              ElasticAPM.agent.config.logger = ZuoraObservability::Logger.custom_logger(name: 'ElasticAPM', level: Logger::WARN)
         
     | 
| 
       22 
20 
     | 
    
         
             
            end
         
     | 
| 
       23 
21 
     | 
    
         | 
| 
       24 
22 
     | 
    
         
             
            if defined?(ActionMailer)
         
     | 
| 
       25 
     | 
    
         
            -
              ActionMailer::Base.logger = ZuoraObservability::Logger.custom_logger(name: 'ActionMailer' 
     | 
| 
      
 23 
     | 
    
         
            +
              ActionMailer::Base.logger = ZuoraObservability::Logger.custom_logger(name: 'ActionMailer')
         
     | 
| 
       26 
24 
     | 
    
         
             
            end
         
     | 
| 
         @@ -3,12 +3,19 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            module ZuoraObservability
         
     | 
| 
       4 
4 
     | 
    
         
             
              # Global configuration that can be set in a Rails initializer
         
     | 
| 
       5 
5 
     | 
    
         
             
              class Configuration
         
     | 
| 
       6 
     | 
    
         
            -
                 
     | 
| 
      
 6 
     | 
    
         
            +
                attr_reader :custom_payload_hooks
         
     | 
| 
      
 7 
     | 
    
         
            +
                attr_accessor :zecs_service_hook, :json_logging
         
     | 
| 
       7 
8 
     | 
    
         | 
| 
       8 
9 
     | 
    
         
             
                def initialize
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @custom_payload_hooks = []
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @zecs_service_hook = nil
         
     | 
| 
       9 
12 
     | 
    
         
             
                  # NOTE(hartley): this checks the var for presence rather than value to
         
     | 
| 
       10 
13 
     | 
    
         
             
                  # align with how Rails does RAILS_LOG_TO_STDOUT
         
     | 
| 
       11 
14 
     | 
    
         
             
                  @json_logging = ENV['ZUORA_JSON_LOGGING'].present? ? true : !(Rails.env.development? || Rails.env.test?)
         
     | 
| 
       12 
15 
     | 
    
         
             
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def add_custom_payload_hook(&block)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  custom_payload_hooks << block
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
       13 
20 
     | 
    
         
             
              end
         
     | 
| 
       14 
21 
     | 
    
         
             
            end
         
     | 
| 
         @@ -5,88 +5,38 @@ module ZuoraObservability 
     | 
|
| 
       5 
5 
     | 
    
         
             
              class Engine < ::Rails::Engine
         
     | 
| 
       6 
6 
     | 
    
         
             
                isolate_namespace ZuoraObservability
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
                REQUEST_HEADERS_TO_IGNORE = %w[
         
     | 
| 
       9 
     | 
    
         
            -
                  RAW_POST_DATA
         
     | 
| 
       10 
     | 
    
         
            -
                  REQUEST_METHOD
         
     | 
| 
       11 
     | 
    
         
            -
                  REQUEST_URI
         
     | 
| 
       12 
     | 
    
         
            -
                  REQUEST_PATH
         
     | 
| 
       13 
     | 
    
         
            -
                  PATH_INFO
         
     | 
| 
       14 
     | 
    
         
            -
                  CONTENT_TYPE
         
     | 
| 
       15 
     | 
    
         
            -
                  ORIGINAL_FULLPATH
         
     | 
| 
       16 
     | 
    
         
            -
                  QUERY_STRING
         
     | 
| 
       17 
     | 
    
         
            -
                ].freeze
         
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
8 
     | 
    
         
             
                config.generators do |g|
         
     | 
| 
       20 
9 
     | 
    
         
             
                  g.test_framework :rspec
         
     | 
| 
       21 
10 
     | 
    
         
             
                end
         
     | 
| 
       22 
11 
     | 
    
         | 
| 
       23 
12 
     | 
    
         
             
                initializer(:rails_stdout_logging, before: :initialize_logger) do
         
     | 
| 
       24 
     | 
    
         
            -
                   
     | 
| 
      
 13 
     | 
    
         
            +
                  Rails.application.configure do
         
     | 
| 
      
 14 
     | 
    
         
            +
                    config.logger = ZuoraObservability::Logger.custom_logger(name: 'Rails')
         
     | 
| 
       25 
15 
     | 
    
         | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
      
 16 
     | 
    
         
            +
                    next unless ZuoraObservability.configuration.json_logging
         
     | 
| 
       27 
17 
     | 
    
         | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
                     
     | 
| 
       30 
     | 
    
         
            -
                    Rails.configuration.colorize_logging = false
         
     | 
| 
       31 
     | 
    
         
            -
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
                    require 'lograge'
         
     | 
| 
      
 19 
     | 
    
         
            +
                    require 'zuora_observability/logging/custom_options'
         
     | 
| 
       32 
20 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
                     
     | 
| 
       35 
     | 
    
         
            -
                      Rails.configuration.lograge.formatter = Class.new do |fmt|
         
     | 
| 
       36 
     | 
    
         
            -
                        def fmt.call(data)
         
     | 
| 
       37 
     | 
    
         
            -
                          {
         
     | 
| 
       38 
     | 
    
         
            -
                            msg: 'Rails Request',
         
     | 
| 
       39 
     | 
    
         
            -
                            trace_id: data.delete(:trace_id),
         
     | 
| 
       40 
     | 
    
         
            -
                            zuora_trace_id: data.delete(:zuora_trace_id),
         
     | 
| 
       41 
     | 
    
         
            -
                            request: data
         
     | 
| 
       42 
     | 
    
         
            -
                          }.compact
         
     | 
| 
       43 
     | 
    
         
            -
                        end
         
     | 
| 
       44 
     | 
    
         
            -
                      end
         
     | 
| 
       45 
     | 
    
         
            -
                    end
         
     | 
| 
       46 
     | 
    
         
            -
                    #Rails.configuration.lograge.formatter = Lograge::Formatters::Json.new
         
     | 
| 
       47 
     | 
    
         
            -
                    Rails.configuration.lograge.custom_options = lambda do |event|
         
     | 
| 
       48 
     | 
    
         
            -
                      exceptions = %w(controller action format)
         
     | 
| 
       49 
     | 
    
         
            -
                      items = {
         
     | 
| 
       50 
     | 
    
         
            -
                        #time: event.time.strftime('%FT%T.%6N'),
         
     | 
| 
       51 
     | 
    
         
            -
                        params: event.payload[:params].as_json(except: exceptions).to_json.to_s,
         
     | 
| 
       52 
     | 
    
         
            -
                        trace_id: event.payload[:headers]['action_dispatch.request_id'],
         
     | 
| 
       53 
     | 
    
         
            -
                        zuora_trace_id: event.payload[:headers]['HTTP_ZUORA_REQUEST_ID']
         
     | 
| 
       54 
     | 
    
         
            -
                      }
         
     | 
| 
       55 
     | 
    
         
            -
                      items.merge!({exception_object: event.payload[:exception_object]}) if event.payload[:exception_object].present?
         
     | 
| 
       56 
     | 
    
         
            -
                      items.merge!({exception: event.payload[:exception]}) if event.payload[:exception].present?
         
     | 
| 
      
 21 
     | 
    
         
            +
                    config.lograge.enabled = true
         
     | 
| 
      
 22 
     | 
    
         
            +
                    config.colorize_logging = false
         
     | 
| 
       57 
23 
     | 
    
         | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
                        # By convertion, headers usually do not have dots. Nginx even rejects headers with dots
         
     | 
| 
       60 
     | 
    
         
            -
                        # All Rails headers are namespaced, like 'rack.input'.
         
     | 
| 
       61 
     | 
    
         
            -
                        # Thus, we can obtain the client headers by rejecting dots
         
     | 
| 
       62 
     | 
    
         
            -
                        request_headers =
         
     | 
| 
       63 
     | 
    
         
            -
                          event.payload[:headers].env.
         
     | 
| 
       64 
     | 
    
         
            -
                            reject { |key| key.to_s.include?('.') || REQUEST_HEADERS_TO_IGNORE.include?(key.to_s) }
         
     | 
| 
       65 
     | 
    
         
            -
                        begin
         
     | 
| 
       66 
     | 
    
         
            -
                          if request_headers["HTTP_AUTHORIZATION"].present?
         
     | 
| 
       67 
     | 
    
         
            -
                            if request_headers["HTTP_AUTHORIZATION"].include?("Basic")
         
     | 
| 
       68 
     | 
    
         
            -
                              user_password = request_headers["HTTP_AUTHORIZATION"].split("Basic").last.strip
         
     | 
| 
       69 
     | 
    
         
            -
                              user, password = Base64.decode64(user_password).split(":")
         
     | 
| 
       70 
     | 
    
         
            -
                              request_headers["HTTP_AUTHORIZATION"] = "Basic #{user}:ValueFiltered"
         
     | 
| 
       71 
     | 
    
         
            -
                            elsif
         
     | 
| 
       72 
     | 
    
         
            -
                              request_headers["HTTP_AUTHORIZATION"] = "ValueFiltered"
         
     | 
| 
       73 
     | 
    
         
            -
                            end
         
     | 
| 
       74 
     | 
    
         
            -
                          end
         
     | 
| 
       75 
     | 
    
         
            -
                          request_headers["HTTP_API_TOKEN"] = "ValueFiltered" if request_headers["HTTP_API_TOKEN"].present?
         
     | 
| 
       76 
     | 
    
         
            -
                        rescue
         
     | 
| 
       77 
     | 
    
         
            -
                          request_headers.delete("HTTP_API_TOKEN")
         
     | 
| 
       78 
     | 
    
         
            -
                          request_headers.delete("HTTP_AUTHORIZATION")
         
     | 
| 
       79 
     | 
    
         
            -
                        end
         
     | 
| 
       80 
     | 
    
         
            -
                        items.merge!({ headers: request_headers.to_s })
         
     | 
| 
       81 
     | 
    
         
            -
                      end
         
     | 
| 
      
 24 
     | 
    
         
            +
                    config.lograge.formatter = Lograge::Formatters::Raw.new
         
     | 
| 
       82 
25 
     | 
    
         | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
     | 
    
         
            -
             
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
      
 26 
     | 
    
         
            +
                    config.lograge.custom_options = Logging::CustomOptions
         
     | 
| 
      
 27 
     | 
    
         
            +
                    config.lograge.custom_payload do |controller|
         
     | 
| 
      
 28 
     | 
    
         
            +
                      payload = {}
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                      ZuoraObservability.configuration.custom_payload_hooks.each do |hook|
         
     | 
| 
      
 31 
     | 
    
         
            +
                        payload.merge!(hook.call(controller))
         
     | 
| 
       88 
32 
     | 
    
         
             
                      end
         
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                      next payload unless ZuoraObservability.configuration.zecs_service_hook
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                      payload[:zecs_service] =
         
     | 
| 
      
 37 
     | 
    
         
            +
                        ZuoraObservability.configuration.zecs_service_hook.call(controller)
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                      payload
         
     | 
| 
       90 
40 
     | 
    
         
             
                    end
         
     | 
| 
       91 
41 
     | 
    
         
             
                  end
         
     | 
| 
       92 
42 
     | 
    
         
             
                end
         
     | 
| 
         @@ -4,9 +4,20 @@ module ZuoraObservability 
     | 
|
| 
       4 
4 
     | 
    
         
             
              # Methods to get information about the application environment
         
     | 
| 
       5 
5 
     | 
    
         
             
              class Env
         
     | 
| 
       6 
6 
     | 
    
         
             
                class << self
         
     | 
| 
      
 7 
     | 
    
         
            +
                  def name
         
     | 
| 
      
 8 
     | 
    
         
            +
                    ENV['Z_APPLICATION_NAME']
         
     | 
| 
      
 9 
     | 
    
         
            +
                  end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  def version
         
     | 
| 
      
 12 
     | 
    
         
            +
                    ENV['Z_APPLICATION_VERSION']
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def environment
         
     | 
| 
      
 16 
     | 
    
         
            +
                    ENV['Z_APPLICATION_ENVIRONMENT']
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
       7 
19 
     | 
    
         
             
                  def app_name
         
     | 
| 
       8 
     | 
    
         
            -
                     
     | 
| 
       9 
     | 
    
         
            -
                    ENV['DEIS_APP'].presence || Rails.application.class.parent_name
         
     | 
| 
      
 20 
     | 
    
         
            +
                    ENV['DEIS_APP'].presence || app_parent_name
         
     | 
| 
       10 
21 
     | 
    
         
             
                  end
         
     | 
| 
       11 
22 
     | 
    
         | 
| 
       12 
23 
     | 
    
         
             
                  def pod_name
         
     | 
| 
         @@ -28,6 +39,16 @@ module ZuoraObservability 
     | 
|
| 
       28 
39 
     | 
    
         
             
                    end
         
     | 
| 
       29 
40 
     | 
    
         
             
                    return p_type
         
     | 
| 
       30 
41 
     | 
    
         
             
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  private
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  def app_parent_name
         
     | 
| 
      
 46 
     | 
    
         
            +
                    if Rails::VERSION::MAJOR >= 6 && Rails::VERSION::MINOR >= 1
         
     | 
| 
      
 47 
     | 
    
         
            +
                      Rails.application.class.module_parent_name
         
     | 
| 
      
 48 
     | 
    
         
            +
                    else
         
     | 
| 
      
 49 
     | 
    
         
            +
                      Rails.application.class.parent_name
         
     | 
| 
      
 50 
     | 
    
         
            +
                    end
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
       31 
52 
     | 
    
         
             
                end
         
     | 
| 
       32 
53 
     | 
    
         
             
              end
         
     | 
| 
       33 
54 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,44 +1,63 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            require 'ougai'
         
     | 
| 
       3 
4 
     | 
    
         
             
            require 'mono_logger'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'zuora_observability/logging/formatter'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'ougai/formatters/customizable'
         
     | 
| 
       4 
7 
     | 
    
         | 
| 
       5 
8 
     | 
    
         
             
            module ZuoraObservability
         
     | 
| 
       6 
9 
     | 
    
         
             
              # A configurable logger that can be used for Rails and additional libraries
         
     | 
| 
       7 
     | 
    
         
            -
               
     | 
| 
       8 
     | 
    
         
            -
                #  
     | 
| 
       9 
     | 
    
         
            -
                # - enable silence method for Rails 5.2 asset requests
         
     | 
| 
      
 10 
     | 
    
         
            +
              class Logger < Ougai::Logger
         
     | 
| 
      
 11 
     | 
    
         
            +
                # TODO(hartley): enable silence method for Rails 5.2 asset requests
         
     | 
| 
       10 
12 
     | 
    
         
             
                # https://github.com/tilfin/ougai/wiki/Use-as-Rails-logger
         
     | 
| 
       11 
     | 
    
         
            -
                 
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
                  # 
     | 
| 
      
 13 
     | 
    
         
            +
                def initialize(logdev, **)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  super
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  # NOTE(hartley): the purpose for the original split between Ougai and
         
     | 
| 
      
 17 
     | 
    
         
            +
                  # MonoLogger was that MonoLogger enables logging in a trap context
         
     | 
| 
      
 18 
     | 
    
         
            +
                  # https://github.com/tilfin/ougai/issues/74
         
     | 
| 
      
 19 
     | 
    
         
            +
                  # By using our own Logger class, we can override the LogDevice created
         
     | 
| 
      
 20 
     | 
    
         
            +
                  # by ruby with MonoLogger's, enabling logging in a trap context
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @logdev = MonoLogger::LocklessLogDevice.new(logdev)
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                def create_formatter
         
     | 
| 
      
 25 
     | 
    
         
            +
                  return ZuoraObservability::Logging::Formatter.new if ZuoraObservability.configuration.json_logging
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  formatter = Ougai::Formatters::Customizable.new(
         
     | 
| 
      
 28 
     | 
    
         
            +
                    format_err: method(:custom_error_formatter),
         
     | 
| 
      
 29 
     | 
    
         
            +
                    format_data: method(:custom_data_formatter),
         
     | 
| 
      
 30 
     | 
    
         
            +
                    format_msg: method(:custom_message_formatter)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  )
         
     | 
| 
      
 32 
     | 
    
         
            +
                  formatter.datetime_format = '%FT%T.%3NZ'
         
     | 
| 
      
 33 
     | 
    
         
            +
                  formatter
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                def custom_message_formatter(severity, datetime, _progname, data)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  msg = data.delete(:msg)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  "#{severity.ljust(6)} #{datetime}: #{msg}"
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                def custom_data_formatter(data)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  data.delete_if do |k|
         
     | 
| 
      
 43 
     | 
    
         
            +
                    %i[app_instance_id tenant_ids organization environment].include? k
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  return nil if data.blank?
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  "#{'DATA'.ljust(6)} #{Time.current.strftime('%FT%T.%3NZ')}: #{data.to_json}"
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                def custom_error_formatter(data)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  return nil unless data.key?(:err)
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  err = data.delete(:err)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  "  #{err[:name]} (#{err[:message]})\n #{err[:stack]}"
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                def self.custom_logger(name: '', level: Rails.logger.present? ? Rails.logger.level : MonoLogger::INFO, type: :ougai)
         
     | 
| 
       15 
59 
     | 
    
         
             
                  if type == :ougai
         
     | 
| 
       16 
     | 
    
         
            -
                     
     | 
| 
       17 
     | 
    
         
            -
                    require "ougai/formatters/customizable"
         
     | 
| 
       18 
     | 
    
         
            -
                    #logger = Ougai::Logger.new(MonoLogger.new(STDOUT))
         
     | 
| 
       19 
     | 
    
         
            -
                    logger = Ougai::Logger.new(STDOUT)
         
     | 
| 
       20 
     | 
    
         
            -
                    logger.level = level
         
     | 
| 
       21 
     | 
    
         
            -
                    if ZuoraObservability.configuration.json_logging
         
     | 
| 
       22 
     | 
    
         
            -
                      require 'zuora_observability/logging/formatter'
         
     | 
| 
       23 
     | 
    
         
            -
                      logger.formatter = ZuoraObservability::Logging::Formatter.new(name)
         
     | 
| 
       24 
     | 
    
         
            -
                    else
         
     | 
| 
       25 
     | 
    
         
            -
                      logger.formatter = Ougai::Formatters::Customizable.new(
         
     | 
| 
       26 
     | 
    
         
            -
                        format_err: proc do |data|
         
     | 
| 
       27 
     | 
    
         
            -
                          next nil unless data.key?(:err)
         
     | 
| 
       28 
     | 
    
         
            -
                          err = data.delete(:err)
         
     | 
| 
       29 
     | 
    
         
            -
                          "  #{err[:name]} (#{err[:message]})\n #{err[:stack]}"
         
     | 
| 
       30 
     | 
    
         
            -
                        end,
         
     | 
| 
       31 
     | 
    
         
            -
                        format_data: proc do |data|
         
     | 
| 
       32 
     | 
    
         
            -
                          data.delete(:app_instance_id); data.delete(:tenant_ids); data.delete(:organization); data.delete(:environment)
         
     | 
| 
       33 
     | 
    
         
            -
                          format('%s %s: %s', 'DATA'.ljust(6), Time.now.strftime('%FT%T.%6NZ'), "#{data.to_json}") if data.present?
         
     | 
| 
       34 
     | 
    
         
            -
                        end,
         
     | 
| 
       35 
     | 
    
         
            -
                        format_msg: proc do |severity, datetime, _progname, data|
         
     | 
| 
       36 
     | 
    
         
            -
                          msg = data.delete(:msg)
         
     | 
| 
       37 
     | 
    
         
            -
                          format('%s %s: %s', severity.ljust(6), datetime, msg)
         
     | 
| 
       38 
     | 
    
         
            -
                        end
         
     | 
| 
       39 
     | 
    
         
            -
                      )
         
     | 
| 
       40 
     | 
    
         
            -
                      logger.formatter.datetime_format = '%FT%T.%6NZ'
         
     | 
| 
       41 
     | 
    
         
            -
                    end
         
     | 
| 
      
 60 
     | 
    
         
            +
                    logger = new($stdout, level: level, progname: name)
         
     | 
| 
       42 
61 
     | 
    
         
             
                  else
         
     | 
| 
       43 
62 
     | 
    
         
             
                    require 'mono_logger'
         
     | 
| 
       44 
63 
     | 
    
         
             
                    logger = MonoLogger.new(STDOUT)
         
     | 
| 
         @@ -63,7 +82,8 @@ module ZuoraObservability 
     | 
|
| 
       63 
82 
     | 
    
         
             
                      end
         
     | 
| 
       64 
83 
     | 
    
         
             
                    end
         
     | 
| 
       65 
84 
     | 
    
         
             
                  end
         
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                  logger
         
     | 
| 
       67 
87 
     | 
    
         
             
                end
         
     | 
| 
       68 
88 
     | 
    
         
             
              end
         
     | 
| 
       69 
89 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,76 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module ZuoraObservability
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Logging
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Custom Options for lograge to add additional fields to logged data
         
     | 
| 
      
 6 
     | 
    
         
            +
                module CustomOptions
         
     | 
| 
      
 7 
     | 
    
         
            +
                  IGNORE_HEADERS = %w[
         
     | 
| 
      
 8 
     | 
    
         
            +
                    RAW_POST_DATA
         
     | 
| 
      
 9 
     | 
    
         
            +
                    REQUEST_METHOD
         
     | 
| 
      
 10 
     | 
    
         
            +
                    REQUEST_URI
         
     | 
| 
      
 11 
     | 
    
         
            +
                    REQUEST_PATH
         
     | 
| 
      
 12 
     | 
    
         
            +
                    PATH_INFO
         
     | 
| 
      
 13 
     | 
    
         
            +
                    CONTENT_TYPE
         
     | 
| 
      
 14 
     | 
    
         
            +
                    ORIGINAL_FULLPATH
         
     | 
| 
      
 15 
     | 
    
         
            +
                    QUERY_STRING
         
     | 
| 
      
 16 
     | 
    
         
            +
                    HTTP_COOKIE
         
     | 
| 
      
 17 
     | 
    
         
            +
                  ].freeze
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  IGNORE_PARAMS = %w[controller action format].freeze
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  FILTERED = '[FILTERED]'
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  class << self
         
     | 
| 
      
 24 
     | 
    
         
            +
                    def call(event)
         
     | 
| 
      
 25 
     | 
    
         
            +
                      items = {
         
     | 
| 
      
 26 
     | 
    
         
            +
                        msg: 'Rails Request',
         
     | 
| 
      
 27 
     | 
    
         
            +
                        params: event.payload[:params].as_json(except: IGNORE_PARAMS).to_s,
         
     | 
| 
      
 28 
     | 
    
         
            +
                        trace_id: event.payload[:headers]['action_dispatch.request_id'],
         
     | 
| 
      
 29 
     | 
    
         
            +
                        zuora_trace_id: event.payload[:headers]['HTTP_ZUORA_REQUEST_ID'],
         
     | 
| 
      
 30 
     | 
    
         
            +
                        error: event.payload[:exception_object]
         
     | 
| 
      
 31 
     | 
    
         
            +
                      }
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                      if event.payload[:headers].present?
         
     | 
| 
      
 34 
     | 
    
         
            +
                        request_headers = filter_request_headers(event.payload[:headers])
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                        filtered_headers = filter_sensitive_headers(request_headers)
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                        items.merge!({ headers: filtered_headers })
         
     | 
| 
      
 39 
     | 
    
         
            +
                      end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                      items
         
     | 
| 
      
 42 
     | 
    
         
            +
                    end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                    private
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    def filter_request_headers(action_dispatch_headers)
         
     | 
| 
      
 47 
     | 
    
         
            +
                      action_dispatch_headers.env.select do |header|
         
     | 
| 
      
 48 
     | 
    
         
            +
                        next false if IGNORE_HEADERS.include? header
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                        header =~ /^HTTP_/ || ActionDispatch::Http::Headers::CGI_VARIABLES.include?(header)
         
     | 
| 
      
 51 
     | 
    
         
            +
                      end
         
     | 
| 
      
 52 
     | 
    
         
            +
                    end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                    def filter_sensitive_headers(headers)
         
     | 
| 
      
 55 
     | 
    
         
            +
                      filtered = {}
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                      auth = headers['HTTP_AUTHORIZATION']
         
     | 
| 
      
 58 
     | 
    
         
            +
                      filtered['HTTP_AUTHORIZATION'] = filter_auth_header(auth) if auth
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                      filtered['HTTP_API_TOKEN'] = FILTERED if headers['HTTP_API_TOKEN']
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                      headers.merge(filtered)
         
     | 
| 
      
 63 
     | 
    
         
            +
                    end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                    def filter_auth_header(authorization)
         
     | 
| 
      
 66 
     | 
    
         
            +
                      return FILTERED unless authorization.include? 'Basic'
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                      encoded = authorization.split(' ', 2).second
         
     | 
| 
      
 69 
     | 
    
         
            +
                      user, _password = Base64.decode64(encoded).split(':')
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                      "Basic #{user}:#{FILTERED}"
         
     | 
| 
      
 72 
     | 
    
         
            +
                    end
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,45 +1,171 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            require 'ougai/formatters/base'
         
     | 
| 
       4 
     | 
    
         
            -
            require 'ougai/formatters/for_json'
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
3 
     | 
    
         
             
            module ZuoraObservability
         
     | 
| 
       7 
4 
     | 
    
         
             
              module Logging
         
     | 
| 
       8 
     | 
    
         
            -
                #  
     | 
| 
       9 
     | 
    
         
            -
                 
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
                   
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
                   
     | 
| 
       16 
     | 
    
         
            -
                   
     | 
| 
       17 
     | 
    
         
            -
                  # @option opts [String] :trace_max_lines (100) the value of trace_max_lines attribute
         
     | 
| 
       18 
     | 
    
         
            -
                  # @option opts [String] :serialize_backtrace (true) the value of serialize_backtrace attribute
         
     | 
| 
       19 
     | 
    
         
            -
                  # @option opts [String] :jsonize (true) the value of jsonize attribute
         
     | 
| 
       20 
     | 
    
         
            -
                  # @option opts [String] :with_newline (true) the value of with_newline attribute
         
     | 
| 
       21 
     | 
    
         
            -
                  def initialize(app_name = nil, hostname = nil, opts = {})
         
     | 
| 
       22 
     | 
    
         
            -
                    aname, hname, opts = Ougai::Formatters::Base.parse_new_params([app_name, hostname, opts])
         
     | 
| 
       23 
     | 
    
         
            -
                    super(aname, hname, opts)
         
     | 
| 
       24 
     | 
    
         
            -
                    init_opts_for_json(opts)
         
     | 
| 
       25 
     | 
    
         
            -
                  end
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Formats data into ZECS Logging Standard and dumps as JSON
         
     | 
| 
      
 6 
     | 
    
         
            +
                # https://tag.pages.gitlab.zeta.tools/standards/logging
         
     | 
| 
      
 7 
     | 
    
         
            +
                class Formatter < Ougai::Formatters::Bunyan
         
     | 
| 
      
 8 
     | 
    
         
            +
                  ECS_VERSION = '1.5.0'
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  ZECS_TOP_LEVEL_FIELDS = %i[
         
     | 
| 
      
 11 
     | 
    
         
            +
                    error event http organization process url user
         
     | 
| 
      
 12 
     | 
    
         
            +
                  ].freeze
         
     | 
| 
      
 13 
     | 
    
         
            +
                  ECS_HTTP_FIELDS = %i[request response].freeze
         
     | 
| 
       26 
14 
     | 
    
         | 
| 
       27 
15 
     | 
    
         
             
                  def _call(severity, time, progname, data)
         
     | 
| 
       28 
     | 
    
         
            -
                     
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
                     
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
                      timestamp: time.utc.strftime('%FT%T.%6NZ'),
         
     | 
| 
       38 
     | 
    
         
            -
                    }.merge(data))
         
     | 
| 
      
 16 
     | 
    
         
            +
                    output = base_fields(severity, time, progname, data)
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    other_fields = get_fields_for(ZECS_TOP_LEVEL_FIELDS, data)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    output.merge!(other_fields)
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                    zuora_fields = ZuoraFields.call(data)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    output[:zuora] = zuora_fields unless zuora_fields.empty?
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                    dump(output)
         
     | 
| 
       39 
25 
     | 
    
         
             
                  end
         
     | 
| 
       40 
26 
     | 
    
         | 
| 
      
 27 
     | 
    
         
            +
                  # Note(hartley): Ougai::Formatters::ForJson requires this be present
         
     | 
| 
       41 
28 
     | 
    
         
             
                  def convert_time(data)
         
     | 
| 
       42 
     | 
    
         
            -
                     
     | 
| 
      
 29 
     | 
    
         
            +
                    data[:@timestamp] = data[:@timestamp].utc.iso8601(3)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  private
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  def get_fields_for(list, data)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    final_hash = {}
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    list.each do |field|
         
     | 
| 
      
 38 
     | 
    
         
            +
                      field_output = send("#{field}_fields", data)
         
     | 
| 
      
 39 
     | 
    
         
            +
                      final_hash[field] = field_output unless field_output.empty?
         
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                    final_hash
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  # Fields required by ECS
         
     | 
| 
      
 46 
     | 
    
         
            +
                  def base_fields(severity, time, progname, data)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    {
         
     | 
| 
      
 48 
     | 
    
         
            +
                      :@timestamp => time,
         
     | 
| 
      
 49 
     | 
    
         
            +
                      message: data[:msg],
         
     | 
| 
      
 50 
     | 
    
         
            +
                      ecs: { version: ECS_VERSION },
         
     | 
| 
      
 51 
     | 
    
         
            +
                      log: { level: severity, logger: progname || @app_name },
         
     | 
| 
      
 52 
     | 
    
         
            +
                      service: { name: Env.name, version: Env.version },
         
     | 
| 
      
 53 
     | 
    
         
            +
                      trace: { id: data[:trace_id] }
         
     | 
| 
      
 54 
     | 
    
         
            +
                    }
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  # error
         
     | 
| 
      
 58 
     | 
    
         
            +
                  def error_fields(data)
         
     | 
| 
      
 59 
     | 
    
         
            +
                    return {} unless data[:error]
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                    {
         
     | 
| 
      
 62 
     | 
    
         
            +
                      message: data[:error].message,
         
     | 
| 
      
 63 
     | 
    
         
            +
                      stack_trace: data[:error].backtrace.join("\n"),
         
     | 
| 
      
 64 
     | 
    
         
            +
                      type: data[:error].class
         
     | 
| 
      
 65 
     | 
    
         
            +
                    }.compact
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                  # http
         
     | 
| 
      
 69 
     | 
    
         
            +
                  def http_fields(data)
         
     | 
| 
      
 70 
     | 
    
         
            +
                    get_fields_for(ECS_HTTP_FIELDS, data)
         
     | 
| 
      
 71 
     | 
    
         
            +
                  end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  # http.request
         
     | 
| 
      
 74 
     | 
    
         
            +
                  def request_fields(data)
         
     | 
| 
      
 75 
     | 
    
         
            +
                    {
         
     | 
| 
      
 76 
     | 
    
         
            +
                      method: data[:method],
         
     | 
| 
      
 77 
     | 
    
         
            +
                      body: ({ content: data[:params] } if data.key? :params)
         
     | 
| 
      
 78 
     | 
    
         
            +
                    }.compact
         
     | 
| 
      
 79 
     | 
    
         
            +
                  end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                  # http.response
         
     | 
| 
      
 82 
     | 
    
         
            +
                  def response_fields(data)
         
     | 
| 
      
 83 
     | 
    
         
            +
                    {
         
     | 
| 
      
 84 
     | 
    
         
            +
                      status_code: data[:status]
         
     | 
| 
      
 85 
     | 
    
         
            +
                    }.compact
         
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                  # organization
         
     | 
| 
      
 89 
     | 
    
         
            +
                  def organization_fields(data)
         
     | 
| 
      
 90 
     | 
    
         
            +
                    {
         
     | 
| 
      
 91 
     | 
    
         
            +
                      name: data[:organization]
         
     | 
| 
      
 92 
     | 
    
         
            +
                    }.compact
         
     | 
| 
      
 93 
     | 
    
         
            +
                  end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                  # process
         
     | 
| 
      
 96 
     | 
    
         
            +
                  def process_fields(_data)
         
     | 
| 
      
 97 
     | 
    
         
            +
                    { id: Process.pid }
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  # url
         
     | 
| 
      
 101 
     | 
    
         
            +
                  def url_fields(data)
         
     | 
| 
      
 102 
     | 
    
         
            +
                    {
         
     | 
| 
      
 103 
     | 
    
         
            +
                      path: data[:path]
         
     | 
| 
      
 104 
     | 
    
         
            +
                    }.compact
         
     | 
| 
      
 105 
     | 
    
         
            +
                  end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                  # user
         
     | 
| 
      
 108 
     | 
    
         
            +
                  def user_fields(data)
         
     | 
| 
      
 109 
     | 
    
         
            +
                    {
         
     | 
| 
      
 110 
     | 
    
         
            +
                      id: data[:user_id],
         
     | 
| 
      
 111 
     | 
    
         
            +
                      email: data[:email]
         
     | 
| 
      
 112 
     | 
    
         
            +
                    }.compact
         
     | 
| 
      
 113 
     | 
    
         
            +
                  end
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                  # event
         
     | 
| 
      
 116 
     | 
    
         
            +
                  def event_fields(data)
         
     | 
| 
      
 117 
     | 
    
         
            +
                    full_action = "#{data[:controller]}##{data[:action]}"
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                    {
         
     | 
| 
      
 120 
     | 
    
         
            +
                      action: (full_action unless full_action == '#'),
         
     | 
| 
      
 121 
     | 
    
         
            +
                      duration: data[:duration]
         
     | 
| 
      
 122 
     | 
    
         
            +
                    }.compact
         
     | 
| 
      
 123 
     | 
    
         
            +
                  end
         
     | 
| 
      
 124 
     | 
    
         
            +
                end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                # The Zuora Extension to ECS defined by ZECS
         
     | 
| 
      
 127 
     | 
    
         
            +
                module ZuoraFields
         
     | 
| 
      
 128 
     | 
    
         
            +
                  ZECS_VERSION = '1.1'
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                  class << self
         
     | 
| 
      
 131 
     | 
    
         
            +
                    # zuora top level field
         
     | 
| 
      
 132 
     | 
    
         
            +
                    def call(data)
         
     | 
| 
      
 133 
     | 
    
         
            +
                      hash = base_fields(data)
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
                      z_http = http_fields(data)
         
     | 
| 
      
 136 
     | 
    
         
            +
                      hash[:http] = z_http unless z_http.empty?
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                      z_service = service_fields(data)
         
     | 
| 
      
 139 
     | 
    
         
            +
                      hash[Env.name.to_sym] = z_service unless z_service.empty?
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                      return {} if hash.empty?
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                      hash.merge({ ecs: { version: ZECS_VERSION } })
         
     | 
| 
      
 144 
     | 
    
         
            +
                    end
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
                    def base_fields(data)
         
     | 
| 
      
 147 
     | 
    
         
            +
                      {
         
     | 
| 
      
 148 
     | 
    
         
            +
                        apartment_id: data[:app_instance_id],
         
     | 
| 
      
 149 
     | 
    
         
            +
                        cp_id: data[:zuora_track_id],
         
     | 
| 
      
 150 
     | 
    
         
            +
                        environment: data[:environment],
         
     | 
| 
      
 151 
     | 
    
         
            +
                        tenant_id: data[:tenant_ids],
         
     | 
| 
      
 152 
     | 
    
         
            +
                        trace_id: data[:zuora_trace_id]
         
     | 
| 
      
 153 
     | 
    
         
            +
                      }.compact
         
     | 
| 
      
 154 
     | 
    
         
            +
                    end
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
                    # zuora.http
         
     | 
| 
      
 157 
     | 
    
         
            +
                    def http_fields(data)
         
     | 
| 
      
 158 
     | 
    
         
            +
                      z_http_request = { headers: data[:headers] }.compact
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
                      {
         
     | 
| 
      
 161 
     | 
    
         
            +
                        request: (z_http_request unless z_http_request.empty?)
         
     | 
| 
      
 162 
     | 
    
         
            +
                      }.compact
         
     | 
| 
      
 163 
     | 
    
         
            +
                    end
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
                    # Service's Custom Fields
         
     | 
| 
      
 166 
     | 
    
         
            +
                    def service_fields(data)
         
     | 
| 
      
 167 
     | 
    
         
            +
                      data[:zecs_service].presence || {}
         
     | 
| 
      
 168 
     | 
    
         
            +
                    end
         
     | 
| 
       43 
169 
     | 
    
         
             
                  end
         
     | 
| 
       44 
170 
     | 
    
         
             
                end
         
     | 
| 
       45 
171 
     | 
    
         
             
              end
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: zuora_observability
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0.1. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.1.1
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Hartley McGuire
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2021- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2021-02-17 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: lograge
         
     | 
| 
         @@ -140,16 +140,16 @@ dependencies: 
     | 
|
| 
       140 
140 
     | 
    
         
             
              name: rubocop
         
     | 
| 
       141 
141 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       142 
142 
     | 
    
         
             
                requirements:
         
     | 
| 
       143 
     | 
    
         
            -
                - - " 
     | 
| 
      
 143 
     | 
    
         
            +
                - - ">="
         
     | 
| 
       144 
144 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       145 
     | 
    
         
            -
                    version: ' 
     | 
| 
      
 145 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
       146 
146 
     | 
    
         
             
              type: :development
         
     | 
| 
       147 
147 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       148 
148 
     | 
    
         
             
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       149 
149 
     | 
    
         
             
                requirements:
         
     | 
| 
       150 
     | 
    
         
            -
                - - " 
     | 
| 
      
 150 
     | 
    
         
            +
                - - ">="
         
     | 
| 
       151 
151 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       152 
     | 
    
         
            -
                    version: ' 
     | 
| 
      
 152 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
       153 
153 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       154 
154 
     | 
    
         
             
              name: rubocop-rails
         
     | 
| 
       155 
155 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
         @@ -168,16 +168,16 @@ dependencies: 
     | 
|
| 
       168 
168 
     | 
    
         
             
              name: rubocop-rspec
         
     | 
| 
       169 
169 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       170 
170 
     | 
    
         
             
                requirements:
         
     | 
| 
       171 
     | 
    
         
            -
                - - " 
     | 
| 
      
 171 
     | 
    
         
            +
                - - ">="
         
     | 
| 
       172 
172 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       173 
     | 
    
         
            -
                    version:  
     | 
| 
      
 173 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
       174 
174 
     | 
    
         
             
              type: :development
         
     | 
| 
       175 
175 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       176 
176 
     | 
    
         
             
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       177 
177 
     | 
    
         
             
                requirements:
         
     | 
| 
       178 
     | 
    
         
            -
                - - " 
     | 
| 
      
 178 
     | 
    
         
            +
                - - ">="
         
     | 
| 
       179 
179 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       180 
     | 
    
         
            -
                    version:  
     | 
| 
      
 180 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
       181 
181 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       182 
182 
     | 
    
         
             
              name: simplecov
         
     | 
| 
       183 
183 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
         @@ -261,6 +261,7 @@ files: 
     | 
|
| 
       261 
261 
     | 
    
         
             
            - lib/zuora_observability/engine.rb
         
     | 
| 
       262 
262 
     | 
    
         
             
            - lib/zuora_observability/env.rb
         
     | 
| 
       263 
263 
     | 
    
         
             
            - lib/zuora_observability/logger.rb
         
     | 
| 
      
 264 
     | 
    
         
            +
            - lib/zuora_observability/logging/custom_options.rb
         
     | 
| 
       264 
265 
     | 
    
         
             
            - lib/zuora_observability/logging/formatter.rb
         
     | 
| 
       265 
266 
     | 
    
         
             
            - lib/zuora_observability/metrics.rb
         
     | 
| 
       266 
267 
     | 
    
         
             
            - lib/zuora_observability/version.rb
         
     | 
| 
         @@ -276,14 +277,14 @@ required_ruby_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       276 
277 
     | 
    
         
             
              requirements:
         
     | 
| 
       277 
278 
     | 
    
         
             
              - - ">="
         
     | 
| 
       278 
279 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       279 
     | 
    
         
            -
                  version: '2. 
     | 
| 
      
 280 
     | 
    
         
            +
                  version: '2.5'
         
     | 
| 
       280 
281 
     | 
    
         
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
       281 
282 
     | 
    
         
             
              requirements:
         
     | 
| 
       282 
     | 
    
         
            -
              - - " 
     | 
| 
      
 283 
     | 
    
         
            +
              - - ">="
         
     | 
| 
       283 
284 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       284 
     | 
    
         
            -
                  version:  
     | 
| 
      
 285 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
       285 
286 
     | 
    
         
             
            requirements: []
         
     | 
| 
       286 
     | 
    
         
            -
            rubygems_version: 3. 
     | 
| 
      
 287 
     | 
    
         
            +
            rubygems_version: 3.2.3
         
     | 
| 
       287 
288 
     | 
    
         
             
            signing_key: 
         
     | 
| 
       288 
289 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       289 
290 
     | 
    
         
             
            summary: Summary of ZuoraObservability.
         
     |