zuora_observability 0.1.0.pre.c → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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.