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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: be19d78e7a52c884e0bd5cc705a3725ea9616cd96491116d6ac047abbe8018b3
4
- data.tar.gz: 446dc9c840d1d00cf66c0316d2fca0b38718d2b4ac32bcda718069515283c3f9
3
+ metadata.gz: 9b737913bb82aaa9107e1b6e143c488f40e284f392b50db8c7ebe295c29182d3
4
+ data.tar.gz: a69de61e998011b53a88c9a1c1b1b742336b9f47c85b67bea3b60e05ef278e25
5
5
  SHA512:
6
- metadata.gz: a70635409b8672344d7efd3c4025507ca0f450fc64aa78d5d81de9558926d1e5a59716832e7408a83abf24ed6492e4470a80fbb8bf1f84ad6391d1e188eaf94f
7
- data.tar.gz: 7718bfc8650dc24092149163861a6f55ae7164cecda3f91534ee98c92645462195b9be625d0f212df974d2b87d4cc767ef9721d6f45581d47dfa0c878a53fccb
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
- ## Usage
6
-
7
- ### Configuration
8
-
9
- Observability can be configured through an initializer as shown below.
5
+ ## Prerequisites
10
6
 
11
- ```ruby
12
- # config/initializers/zuora_observability.rb
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', type: 'Monologger', level: MonoLogger::INFO)
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: MonoLogger::WARN)
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', type: 'Monologger')
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
- attr_accessor :json_logging
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
- require 'lograge'
13
+ Rails.application.configure do
14
+ config.logger = ZuoraObservability::Logger.custom_logger(name: 'Rails')
25
15
 
26
- Rails.configuration.logger = ZuoraObservability::Logger.custom_logger(name: "Rails")
16
+ next unless ZuoraObservability.configuration.json_logging
27
17
 
28
- if ZuoraObservability.configuration.json_logging
29
- Rails.configuration.lograge.enabled = true
30
- Rails.configuration.colorize_logging = false
31
- end
18
+ require 'lograge'
19
+ require 'zuora_observability/logging/custom_options'
32
20
 
33
- if Rails.configuration.lograge.enabled
34
- if Rails.configuration.logger.class.to_s == 'Ougai::Logger'
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
- if event.payload[:headers].present?
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
- if Thread.current[:appinstance].present?
84
- items.merge!({connect_user: Thread.current[:appinstance].connect_user, new_session: Thread.current[:appinstance].new_session_message})
85
- if Thread.current[:appinstance].logitems.present? && Thread.current[:appinstance].logitems.class == Hash
86
- items.merge!(Thread.current[:appinstance].logitems)
87
- end
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
- return items
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
- # parent_name is deprecated in Rails 6.0, removed in 6.1
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
- module Logger
8
- # NOTE(hartley): replace this with a subclass of Ougai Logger
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
- # - potentially integrate with MonoLogger so no conditional is needed
12
- # https://github.com/tilfin/ougai/issues/74
13
- def self.custom_logger(name: "", level: Rails.logger.present? ? Rails.logger.level : MonoLogger::INFO, type: :ougai)
14
- #puts name + ' - ' + {Logger::WARN => 'Logger::WARN', Logger::ERROR => 'Logger::ERROR', Logger::DEBUG => 'Logger::DEBUG', Logger::INFO => 'Logger::INFO' }[level] + ' - '
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
- require 'ougai'
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
- return logger
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
- # A JSON formatter compatible with node-bunyan
9
- class Formatter < Ougai::Formatters::Base
10
- include Ougai::Formatters::ForJson
11
-
12
- # Intialize a formatter
13
- # @param [String] app_name application name (execution program name if nil)
14
- # @param [String] hostname hostname (hostname if nil)
15
- # @param [Hash] opts the initial values of attributes
16
- # @option opts [String] :trace_indent (2) the value of trace_indent attribute
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
- data.merge!({ message: data.delete(:msg) })
29
- if data[:timestamp].present?
30
- time = data[:timestamp]
31
- data.delete(:timestamp)
32
- end
33
- dump({
34
- name: progname || @app_name,
35
- pid: $$,
36
- level: severity,
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
- # data[:timestamp] = format_datetime(data[:time])
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ZuoraObservability
4
- VERSION = '0.1.0-c'
4
+ VERSION = '0.1.1'
5
5
  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.0.pre.c
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-01-05 00:00:00.000000000 Z
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: '1.2'
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: '1.2'
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: 2.0.0.pre
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: 2.0.0.pre
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.4'
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: 1.3.1
285
+ version: '0'
285
286
  requirements: []
286
- rubygems_version: 3.1.4
287
+ rubygems_version: 3.2.3
287
288
  signing_key:
288
289
  specification_version: 4
289
290
  summary: Summary of ZuoraObservability.