zuora_observability 0.1.0.pre.b → 0.1.0.pre.c
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 +0 -3
- data/lib/zuora_observability.rb +0 -2
- data/lib/zuora_observability/configuration.rb +1 -5
- data/lib/zuora_observability/engine.rb +9 -10
- data/lib/zuora_observability/logger.rb +0 -5
- data/lib/zuora_observability/metrics.rb +0 -11
- data/lib/zuora_observability/version.rb +1 -1
- metadata +2 -5
- data/lib/zuora_observability/metrics/page_request.rb +0 -35
- data/lib/zuora_observability/metrics/point_value.rb +0 -84
- data/lib/zuora_observability/metrics/telegraf.rb +0 -98
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: be19d78e7a52c884e0bd5cc705a3725ea9616cd96491116d6ac047abbe8018b3
|
4
|
+
data.tar.gz: 446dc9c840d1d00cf66c0316d2fca0b38718d2b4ac32bcda718069515283c3f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a70635409b8672344d7efd3c4025507ca0f450fc64aa78d5d81de9558926d1e5a59716832e7408a83abf24ed6492e4470a80fbb8bf1f84ad6391d1e188eaf94f
|
7
|
+
data.tar.gz: 7718bfc8650dc24092149163861a6f55ae7164cecda3f91534ee98c92645462195b9be625d0f212df974d2b87d4cc767ef9721d6f45581d47dfa0c878a53fccb
|
data/README.md
CHANGED
@@ -17,9 +17,6 @@ end
|
|
17
17
|
|
18
18
|
| Configuration Field | Default Value | Description |
|
19
19
|
| ------------------- | ---------------------------------------------------------------- | ------------------------------------ |
|
20
|
-
| `enable_metrics` | `false` | Enables writing metrics to telegraf |
|
21
|
-
| `telegraf_endpoint` | `'udp://telegraf-app-metrics.monitoring.svc.cluster.local:8094'` | The URL to send telegraf metrics to |
|
22
|
-
| `telegraf_debug` | `false` | Log info about data sent to telegraf |
|
23
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** |
|
24
21
|
|
25
22
|
## Installation
|
data/lib/zuora_observability.rb
CHANGED
@@ -7,8 +7,6 @@ require 'zuora_observability/metrics'
|
|
7
7
|
require 'zuora_observability/logger'
|
8
8
|
|
9
9
|
require 'zuora_observability/logging/formatter'
|
10
|
-
require 'zuora_observability/metrics/telegraf'
|
11
|
-
require 'zuora_observability/metrics/point_value'
|
12
10
|
|
13
11
|
# Provides Rails application with tools for observabilty
|
14
12
|
module ZuoraObservability
|
@@ -3,13 +3,9 @@
|
|
3
3
|
module ZuoraObservability
|
4
4
|
# Global configuration that can be set in a Rails initializer
|
5
5
|
class Configuration
|
6
|
-
attr_accessor :
|
7
|
-
:json_logging
|
6
|
+
attr_accessor :json_logging
|
8
7
|
|
9
8
|
def initialize
|
10
|
-
@enable_metrics = false
|
11
|
-
@telegraf_endpoint = 'udp://telegraf-app-metrics.monitoring.svc.cluster.local:8094'
|
12
|
-
@telegraf_debug = false
|
13
9
|
# NOTE(hartley): this checks the var for presence rather than value to
|
14
10
|
# align with how Rails does RAILS_LOG_TO_STDOUT
|
15
11
|
@json_logging = ENV['ZUORA_JSON_LOGGING'].present? ? true : !(Rails.env.development? || Rails.env.test?)
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'zuora_observability/metrics/page_request'
|
4
|
-
|
5
3
|
module ZuoraObservability
|
6
4
|
# The ZuoraObservability Engine is mounted to hook into Rails
|
7
5
|
class Engine < ::Rails::Engine
|
@@ -22,12 +20,6 @@ module ZuoraObservability
|
|
22
20
|
g.test_framework :rspec
|
23
21
|
end
|
24
22
|
|
25
|
-
# hook to process_action
|
26
|
-
ActiveSupport::Notifications.subscribe(
|
27
|
-
'process_action.action_controller',
|
28
|
-
ZuoraObservability::Metrics::PageRequest.new
|
29
|
-
)
|
30
|
-
|
31
23
|
initializer(:rails_stdout_logging, before: :initialize_logger) do
|
32
24
|
require 'lograge'
|
33
25
|
|
@@ -42,7 +34,12 @@ module ZuoraObservability
|
|
42
34
|
if Rails.configuration.logger.class.to_s == 'Ougai::Logger'
|
43
35
|
Rails.configuration.lograge.formatter = Class.new do |fmt|
|
44
36
|
def fmt.call(data)
|
45
|
-
{
|
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
|
46
43
|
end
|
47
44
|
end
|
48
45
|
end
|
@@ -51,7 +48,9 @@ module ZuoraObservability
|
|
51
48
|
exceptions = %w(controller action format)
|
52
49
|
items = {
|
53
50
|
#time: event.time.strftime('%FT%T.%6N'),
|
54
|
-
params: event.payload[:params].as_json(except: exceptions).to_json.to_s
|
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']
|
55
54
|
}
|
56
55
|
items.merge!({exception_object: event.payload[:exception_object]}) if event.payload[:exception_object].present?
|
57
56
|
items.merge!({exception: event.payload[:exception]}) if event.payload[:exception].present?
|
@@ -21,11 +21,6 @@ module ZuoraObservability
|
|
21
21
|
if ZuoraObservability.configuration.json_logging
|
22
22
|
require 'zuora_observability/logging/formatter'
|
23
23
|
logger.formatter = ZuoraObservability::Logging::Formatter.new(name)
|
24
|
-
logger.before_log = lambda do |data|
|
25
|
-
data[:trace_id] = ZuoraConnect::RequestIdMiddleware.request_id if ZuoraConnect::RequestIdMiddleware.request_id.present?
|
26
|
-
data[:zuora_trace_id] = ZuoraConnect::RequestIdMiddleware.zuora_request_id if ZuoraConnect::RequestIdMiddleware.zuora_request_id.present?
|
27
|
-
#data[:traces] = {amazon_id: data[:trace_id], zuora_id: data[:zuora_trace_id]}
|
28
|
-
end
|
29
24
|
else
|
30
25
|
logger.formatter = Ougai::Formatters::Customizable.new(
|
31
26
|
format_err: proc do |data|
|
@@ -3,18 +3,7 @@
|
|
3
3
|
module ZuoraObservability
|
4
4
|
# Methods to gather and format metrics
|
5
5
|
module Metrics
|
6
|
-
@@telegraf_host = nil
|
7
|
-
|
8
6
|
class << self
|
9
|
-
def write_to_telegraf(*args)
|
10
|
-
if ZuoraObservability.configuration.enable_metrics && !defined?(Prometheus)
|
11
|
-
@@telegraf_host = Metrics::Telegraf.new() if @@telegraf_host == nil
|
12
|
-
unicorn_stats = Metrics.unicorn_listener if defined?(Unicorn) && Unicorn.respond_to?(:listener_names)
|
13
|
-
@@telegraf_host.write(direction: 'Raindrops', tags: {}, values: unicorn_stats) unless unicorn_stats.blank?
|
14
|
-
return @@telegraf_host.write(*args)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
7
|
def resque
|
19
8
|
Resque.redis.ping
|
20
9
|
|
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.
|
4
|
+
version: 0.1.0.pre.c
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hartley McGuire
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: lograge
|
@@ -263,9 +263,6 @@ files:
|
|
263
263
|
- lib/zuora_observability/logger.rb
|
264
264
|
- lib/zuora_observability/logging/formatter.rb
|
265
265
|
- lib/zuora_observability/metrics.rb
|
266
|
-
- lib/zuora_observability/metrics/page_request.rb
|
267
|
-
- lib/zuora_observability/metrics/point_value.rb
|
268
|
-
- lib/zuora_observability/metrics/telegraf.rb
|
269
266
|
- lib/zuora_observability/version.rb
|
270
267
|
homepage:
|
271
268
|
licenses:
|
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ZuoraObservability
|
4
|
-
module Metrics
|
5
|
-
# Object of this class is passed to the ActiveSupport::Notification hook
|
6
|
-
class PageRequest
|
7
|
-
# This method is triggered when a non error page is loaded (not 404)
|
8
|
-
def call(_name, started, finished, unique_id, payload)
|
9
|
-
# If the url contains any css or JavaScript files then do not collect metrics for them
|
10
|
-
return nil if %w[css assets jpg png jpeg ico].any? { |word| payload[:path].include?(word) }
|
11
|
-
|
12
|
-
# Getting the endpoint and the content_type
|
13
|
-
content_hash = { :html => 'text/html', :js => 'application/javascript', :json => 'application/json', :csv => 'text/csv' }
|
14
|
-
content_type = content_hash.key?(payload[:format]) ? content_hash[payload[:format]] : payload[:format]
|
15
|
-
content_type = content_type.to_s.gsub('text/javascript', 'application/javascript')
|
16
|
-
|
17
|
-
# payloads with 500 requests do not have status as it is not set by the controller
|
18
|
-
# https://github.com/rails/rails/issues/33335
|
19
|
-
# status_code = payload[:status] ? payload[:status] : payload[:exception_object].present? ? 500 : ""
|
20
|
-
if payload[:exception].present?
|
21
|
-
status_code, exception = [500, payload[:exception].first]
|
22
|
-
else
|
23
|
-
status_code, exception = [payload[:status], nil]
|
24
|
-
end
|
25
|
-
|
26
|
-
tags = { method: payload[:method], status: status_code, error_type: exception, content_type: content_type, controller: payload[:controller], action: payload[:action] }.compact
|
27
|
-
|
28
|
-
values = { view_time: payload[:view_runtime], db_time: payload[:db_runtime], response_time: ((finished - started) * 1000) }.compact
|
29
|
-
values = values.map { |k, v| [k, v.round(2)] }.to_h
|
30
|
-
|
31
|
-
ZuoraObservability::Metrics.write_to_telegraf(direction: :inbound, tags: tags, values: values)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,84 +0,0 @@
|
|
1
|
-
# this looks copied from https://github.com/influxdata/influxdb-ruby, it may be
|
2
|
-
# worth just using the gem instead of vendoring the file
|
3
|
-
# module InfluxDB
|
4
|
-
module ZuoraObservability
|
5
|
-
module Metrics
|
6
|
-
# Convert data point to string using Line protocol
|
7
|
-
class PointValue
|
8
|
-
attr_reader :series, :values, :tags, :timestamp
|
9
|
-
|
10
|
-
def initialize(data)
|
11
|
-
@series = escape data[:series], :measurement
|
12
|
-
@values = escape_values data[:values]
|
13
|
-
@tags = escape_tags data[:tags]
|
14
|
-
@timestamp = data[:timestamp]
|
15
|
-
end
|
16
|
-
|
17
|
-
def dump
|
18
|
-
dump = @series.dup
|
19
|
-
dump << ",#{@tags}" if @tags
|
20
|
-
dump << " #{@values}"
|
21
|
-
dump << " #{@timestamp}" if @timestamp
|
22
|
-
dump
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
ESCAPES = {
|
28
|
-
measurement: [' '.freeze, ','.freeze],
|
29
|
-
tag_key: ['='.freeze, ' '.freeze, ','.freeze],
|
30
|
-
tag_value: ['='.freeze, ' '.freeze, ','.freeze],
|
31
|
-
field_key: ['='.freeze, ' '.freeze, ','.freeze, '"'.freeze],
|
32
|
-
field_value: ["\\".freeze, '"'.freeze],
|
33
|
-
}.freeze
|
34
|
-
|
35
|
-
private_constant :ESCAPES
|
36
|
-
|
37
|
-
def escape(str, type)
|
38
|
-
# rubocop:disable Layout/AlignParameters
|
39
|
-
str = str.encode "UTF-8".freeze, "UTF-8".freeze,
|
40
|
-
invalid: :replace,
|
41
|
-
undef: :replace,
|
42
|
-
replace: "".freeze
|
43
|
-
# rubocop:enable Layout/AlignParameters
|
44
|
-
|
45
|
-
ESCAPES[type].each do |ch|
|
46
|
-
str = str.gsub(ch) { "\\#{ch}" }
|
47
|
-
end
|
48
|
-
str
|
49
|
-
end
|
50
|
-
|
51
|
-
def escape_values(values)
|
52
|
-
return if values.nil?
|
53
|
-
values.map do |k, v|
|
54
|
-
key = escape(k.to_s, :field_key)
|
55
|
-
val = escape_value(v)
|
56
|
-
"#{key}=#{val}"
|
57
|
-
end.join(",".freeze)
|
58
|
-
end
|
59
|
-
|
60
|
-
def escape_value(value)
|
61
|
-
if value.is_a?(String)
|
62
|
-
'"'.freeze + escape(value, :field_value) + '"'.freeze
|
63
|
-
elsif value.is_a?(Integer)
|
64
|
-
"#{value}i"
|
65
|
-
else
|
66
|
-
value.to_s
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def escape_tags(tags)
|
71
|
-
return if tags.nil?
|
72
|
-
|
73
|
-
tags = tags.map do |k, v|
|
74
|
-
key = escape(k.to_s, :tag_key)
|
75
|
-
val = escape(v.to_s, :tag_value)
|
76
|
-
|
77
|
-
"#{key}=#{val}" unless key == "".freeze || val == "".freeze
|
78
|
-
end.compact
|
79
|
-
|
80
|
-
tags.join(",") unless tags.empty?
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
@@ -1,98 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ZuoraObservability
|
4
|
-
module Metrics
|
5
|
-
# Functionality for sending metrics to a Telegraf endpoint
|
6
|
-
#
|
7
|
-
# it looks like https://github.com/influxdata/influxdb-ruby may provide some
|
8
|
-
# more high level abstractions instead of using a UDPSocket directly
|
9
|
-
class Telegraf
|
10
|
-
attr_accessor :host
|
11
|
-
|
12
|
-
OUTBOUND_METRICS = true
|
13
|
-
OUTBOUND_METRICS_NAME = 'request-outbound'
|
14
|
-
INBOUND_METRICS = true
|
15
|
-
INBOUND_METRICS_NAME = 'request-inbound'
|
16
|
-
|
17
|
-
def initialize
|
18
|
-
connect
|
19
|
-
end
|
20
|
-
|
21
|
-
def connect
|
22
|
-
# TODO(hartley): this Rails logger was originally ZuoraConnect.logger
|
23
|
-
Rails.logger.debug(format_metric_log('Telegraf', 'Need new connection')) if ZuoraObservability.configuration.telegraf_debug
|
24
|
-
uri = URI.parse(ZuoraObservability.configuration.telegraf_endpoint)
|
25
|
-
self.host = UDPSocket.new.tap do |socket|
|
26
|
-
socket.connect uri.host, uri.port
|
27
|
-
end
|
28
|
-
rescue => ex
|
29
|
-
self.host = nil
|
30
|
-
# TODO(hartley): this Rails logger was originally ZuoraConnect.logger
|
31
|
-
Rails.logger.warn(self.format_metric_log('Telegraf', "Failed to connect: #{ex.class}")) if Rails.env.to_s != 'production'
|
32
|
-
end
|
33
|
-
|
34
|
-
def write(direction: 'Unknown', tags: {}, values: {})
|
35
|
-
time = Benchmark.measure do
|
36
|
-
# To avoid writing metrics from rspec tests
|
37
|
-
if Rails.env.to_sym != :test
|
38
|
-
app_instance = Thread.current[:appinstance].present? ? Thread.current[:appinstance].id : 0
|
39
|
-
tags = {
|
40
|
-
app_name: Env.app_name, process_type: Env.process_type,
|
41
|
-
app_instance: app_instance, pod_name: Env.pod_name
|
42
|
-
}.merge(tags)
|
43
|
-
|
44
|
-
if direction == :inbound
|
45
|
-
# This condition relies on a monkey patch in the connect gem that
|
46
|
-
# adds a to_bool method for Nil, True, and False that are not
|
47
|
-
# present by default
|
48
|
-
if INBOUND_METRICS && !Thread.current[:inbound_metric].to_bool
|
49
|
-
self.write_udp(series: INBOUND_METRICS_NAME, tags: tags, values: values)
|
50
|
-
Thread.current[:inbound_metric] = true
|
51
|
-
else
|
52
|
-
return
|
53
|
-
end
|
54
|
-
elsif direction == :outbound
|
55
|
-
write_udp(series: OUTBOUND_METRICS_NAME, tags: tags, values: values) if OUTBOUND_METRICS
|
56
|
-
else
|
57
|
-
write_udp(series: direction, tags: tags, values: values)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
return unless ZuoraObservability.configuration.telegraf_debug
|
63
|
-
|
64
|
-
# TODO(hartley): these Rails loggers were originally ZuoraConnect.logger
|
65
|
-
Rails.logger.debug(format_metric_log('Telegraf', tags.to_s))
|
66
|
-
Rails.logger.debug(format_metric_log('Telegraf', values.to_s))
|
67
|
-
Rails.logger.debug(
|
68
|
-
format_metric_log(
|
69
|
-
'Telegraf',
|
70
|
-
"Writing '#{direction.capitalize}': #{time.real.round(5)} ms"
|
71
|
-
)
|
72
|
-
)
|
73
|
-
end
|
74
|
-
|
75
|
-
def write_udp(series: '', tags: {}, values: {})
|
76
|
-
return if values.blank?
|
77
|
-
|
78
|
-
host.write PointValue.new({ series: series, tags: tags, values: values }).dump
|
79
|
-
rescue => ex
|
80
|
-
self.connect
|
81
|
-
ZuoraConnect.logger.warn(self.format_metric_log('Telegraf', "Failed to write udp: #{ex.class}")) if Rails.env.to_s != 'production'
|
82
|
-
end
|
83
|
-
|
84
|
-
def format_metric_log(message, dump = nil)
|
85
|
-
message_color = '1;91'
|
86
|
-
dump_color = '0;1'
|
87
|
-
log_entry = " \e[#{message_color}m#{message}\e[0m #{
|
88
|
-
"\e[#{dump_color}m#{dump}\e[0m" if dump
|
89
|
-
}"
|
90
|
-
if Rails.env.development?
|
91
|
-
log_entry
|
92
|
-
else
|
93
|
-
[message, dump].compact.join(' - ')
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|