inst_statsd 2.2.0 → 3.0.4
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/lib/inst_statsd/block_stat.rb +14 -14
- data/lib/inst_statsd/block_tracking.rb +12 -13
- data/lib/inst_statsd/counter.rb +2 -4
- data/lib/inst_statsd/default_tracking.rb +30 -27
- data/lib/inst_statsd/event.rb +64 -0
- data/lib/inst_statsd/null_logger.rb +3 -4
- data/lib/inst_statsd/request_logger.rb +4 -6
- data/lib/inst_statsd/request_stat.rb +26 -14
- data/lib/inst_statsd/request_tracking.rb +19 -18
- data/lib/inst_statsd/sql_tracker.rb +9 -11
- data/lib/inst_statsd/statsd.rb +63 -52
- data/lib/inst_statsd/version.rb +5 -0
- data/lib/inst_statsd.rb +36 -28
- data/spec/inst_statsd/block_stat_spec.rb +2 -2
- data/spec/inst_statsd/block_tracking_spec.rb +66 -46
- data/spec/inst_statsd/counter_spec.rb +21 -23
- data/spec/inst_statsd/event_spec.rb +160 -0
- data/spec/inst_statsd/inst_statsd_spec.rb +85 -81
- data/spec/inst_statsd/null_logger_spec.rb +11 -13
- data/spec/inst_statsd/request_logger_spec.rb +43 -50
- data/spec/inst_statsd/request_stat_spec.rb +98 -84
- data/spec/inst_statsd/request_tracking_spec.rb +6 -7
- data/spec/inst_statsd/sql_tracker_spec.rb +29 -31
- data/spec/inst_statsd/statsd_spec.rb +126 -87
- data/spec/spec_helper.rb +2 -2
- metadata +67 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a91fe00f6ca513926589fdd5d3cb3f316e26a6fc5bb5b8ceb1a49ba20f42769f
|
4
|
+
data.tar.gz: 82a6dd4759cb55054a20e6c394d19c000b571aabe8df48251f0661fdb86de7ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dbddd5f2e3069681cd2f6e4b2843d4c7ea123cbaee2a3537cd35ef4b6fffe8f2c90b20b4bf30d5e109967151d29926ad993597575ee6042942587ef7ba75fa43
|
7
|
+
data.tar.gz: e5d8af2078d7d320732285b3e071c1c18da70e9aeb0cad060eb589b8b1de592d6093fab0d836c74a9380e10df19e3f46090edb73a14bf1a18e8a2e5d95bf51fa
|
@@ -2,13 +2,9 @@
|
|
2
2
|
|
3
3
|
module InstStatsd
|
4
4
|
class BlockStat
|
5
|
+
attr_accessor :stats, :common_key, :short_stat, :tags
|
5
6
|
|
6
|
-
|
7
|
-
attr_accessor :common_key
|
8
|
-
attr_accessor :short_stat
|
9
|
-
attr_accessor :tags
|
10
|
-
|
11
|
-
def initialize(common_key, statsd=InstStatsd::Statsd, tags: {}, short_stat: nil)
|
7
|
+
def initialize(common_key, statsd = InstStatsd::Statsd, tags: {}, short_stat: nil)
|
12
8
|
self.common_key = common_key
|
13
9
|
@tags = tags
|
14
10
|
@short_stat = short_stat
|
@@ -27,17 +23,21 @@ module InstStatsd
|
|
27
23
|
|
28
24
|
def exclusive_stats
|
29
25
|
return nil unless @exclusives
|
30
|
-
|
26
|
+
|
27
|
+
stats.to_h { |key, value| [key, value - (@exclusives[key] || 0.0)] }
|
31
28
|
end
|
32
29
|
|
33
30
|
def report
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
31
|
+
return unless common_key
|
32
|
+
|
33
|
+
stats.each do |(key, value)|
|
34
|
+
@statsd.timing("#{common_key}.#{key}", value, tags: @tags, short_stat: "#{@short_stat}.#{key}")
|
35
|
+
end
|
36
|
+
exclusive_stats&.each do |(key, value)|
|
37
|
+
@statsd.timing("#{common_key}.exclusive.#{key}",
|
38
|
+
value,
|
39
|
+
tags: @tags,
|
40
|
+
short_stat: "#{@short_stat}.exclusive.#{key}")
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -1,21 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "benchmark"
|
4
4
|
|
5
5
|
module InstStatsd
|
6
6
|
class BlockTracking
|
7
7
|
class << self
|
8
8
|
attr_accessor :logger
|
9
9
|
|
10
|
-
[
|
10
|
+
%i[mask negative_mask].each do |method|
|
11
11
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
12
|
-
def #{method}
|
13
|
-
InstStatsd.settings[:#{method}]
|
14
|
-
end
|
15
|
-
|
16
|
-
def #{method}=(value)
|
17
|
-
InstStatsd.settings[:#{method}] = value
|
18
|
-
end
|
12
|
+
def #{method} # def mask
|
13
|
+
InstStatsd.settings[:#{method}] # InstStatsd.settings[:mask]
|
14
|
+
end # end
|
15
|
+
#
|
16
|
+
def #{method}=(value) # def mask=(value)
|
17
|
+
InstStatsd.settings[:#{method}] = value # InstStatsd.settings[:mask] = value
|
18
|
+
end # end
|
19
19
|
RUBY
|
20
20
|
end
|
21
21
|
|
@@ -38,12 +38,12 @@ module InstStatsd
|
|
38
38
|
# to be consistent with ActionPack, measure in milliseconds
|
39
39
|
elapsed *= 1000
|
40
40
|
|
41
|
-
block_stat.stats = cookies.
|
42
|
-
block_stat.stats[
|
41
|
+
block_stat.stats = cookies.to_h { |(name, cookie)| [name, Counter.counters[name].finalize_count(cookie)] }
|
42
|
+
block_stat.stats["total"] = elapsed
|
43
43
|
# we need to make sure to report exclusive timings, even if nobody called us re-entrantly
|
44
44
|
block_stat.subtract_exclusives({}) if category
|
45
45
|
block_stat.report
|
46
|
-
logger
|
46
|
+
logger&.log(block_stat, "STATSD #{key}")
|
47
47
|
# -1 is ourselves; we want to subtract from the block above us
|
48
48
|
stack(category)[-2].subtract_exclusives(block_stat.stats) if category && stack(category)[-2]
|
49
49
|
|
@@ -59,6 +59,5 @@ module InstStatsd
|
|
59
59
|
Thread.current[:stats_block_stack][category] ||= []
|
60
60
|
end
|
61
61
|
end
|
62
|
-
|
63
62
|
end
|
64
63
|
end
|
data/lib/inst_statsd/counter.rb
CHANGED
@@ -12,10 +12,9 @@ module InstStatsd
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
attr_reader :key
|
16
|
-
attr_reader :blocked_names
|
15
|
+
attr_reader :key, :blocked_names
|
17
16
|
|
18
|
-
def initialize(key, blocked_names=[], tags: {}, short_stat: nil)
|
17
|
+
def initialize(key, blocked_names = [], tags: {}, short_stat: nil)
|
19
18
|
@blocked_names = blocked_names
|
20
19
|
@key = key
|
21
20
|
@tls_key = "statsd.#{key}"
|
@@ -41,6 +40,5 @@ module InstStatsd
|
|
41
40
|
def accepted_name?(name)
|
42
41
|
!blocked_names.include?(name)
|
43
42
|
end
|
44
|
-
|
45
43
|
end
|
46
44
|
end
|
@@ -4,41 +4,44 @@ require "active_support"
|
|
4
4
|
|
5
5
|
module InstStatsd
|
6
6
|
class DefaultTracking
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
ActiveSupport::Notifications.subscribe(/sql\.active_record/) {|*args| update_sql_count(*args)}
|
11
|
-
end
|
7
|
+
class << self
|
8
|
+
def track_sql
|
9
|
+
return if @sql_tracker
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
@sql_tracker = InstStatsd::SqlTracker.new(blocked_names: ["SCHEMA"])
|
12
|
+
ActiveSupport::Notifications.subscribe(/sql\.active_record/) { |*args| update_sql_count(*args) }
|
13
|
+
end
|
16
14
|
|
17
|
-
|
18
|
-
|
19
|
-
ActiveSupport::Notifications.subscribe(/instance\.active_record/) {|*args| update_active_record_count(*args)}
|
20
|
-
end
|
15
|
+
def track_active_record
|
16
|
+
return if @ar_counter
|
21
17
|
|
22
|
-
|
23
|
-
return if @cache_read_counter
|
18
|
+
require "aroi"
|
24
19
|
|
25
|
-
|
26
|
-
|
27
|
-
|
20
|
+
::Aroi::Instrumentation.instrument_creation!
|
21
|
+
@ar_counter = InstStatsd::Counter.new("active_record")
|
22
|
+
ActiveSupport::Notifications.subscribe(/instance\.active_record/) { |*args| update_active_record_count(*args) }
|
23
|
+
end
|
28
24
|
|
29
|
-
|
25
|
+
def track_cache
|
26
|
+
return if @cache_read_counter
|
30
27
|
|
31
|
-
|
32
|
-
|
33
|
-
|
28
|
+
@cache_read_counter = InstStatsd::Counter.new("cache.read")
|
29
|
+
ActiveSupport::Notifications.subscribe(/cache_read\.active_support/) { |*args| update_cache_read_count(*args) }
|
30
|
+
end
|
34
31
|
|
35
|
-
|
36
|
-
@ar_counter.track payload.fetch(:name, '')
|
37
|
-
end
|
32
|
+
private
|
38
33
|
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
def update_sql_count(_name, _start, _finish, _id, payload)
|
35
|
+
@sql_tracker.track payload.fetch(:name), payload.fetch(:sql)
|
36
|
+
end
|
42
37
|
|
38
|
+
def update_active_record_count(_name, _start, _finish, _id, payload)
|
39
|
+
@ar_counter.track payload.fetch(:name, "")
|
40
|
+
end
|
41
|
+
|
42
|
+
def update_cache_read_count(_name, _start, _finish, _id, _payload)
|
43
|
+
@cache_read_counter.track "read"
|
44
|
+
end
|
45
|
+
end
|
43
46
|
end
|
44
47
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module InstStatsd
|
4
|
+
# Mix-in methods for supporting DataDog events
|
5
|
+
# See https://docs.datadoghq.com/service_management/events/
|
6
|
+
module Event
|
7
|
+
SUPPORTED_TYPES = %i[
|
8
|
+
deploy
|
9
|
+
feature_disabled
|
10
|
+
feature_enabled
|
11
|
+
provision
|
12
|
+
refresh
|
13
|
+
].freeze
|
14
|
+
|
15
|
+
def instance; end
|
16
|
+
def data_dog?; end
|
17
|
+
def dog_tags; end
|
18
|
+
|
19
|
+
# This end point allows you to post events to the DatDog event stream.
|
20
|
+
#
|
21
|
+
# @param [String] title Event title
|
22
|
+
# @param [String] text Event text. Supports newlines (+\n+)
|
23
|
+
# @param [String, nil] :type Can be "deploy", "feature_disabled",
|
24
|
+
# "feature_enabled", "provision", or "refresh"
|
25
|
+
# @param [Hash] :tags tags to be added to event. Note that the
|
26
|
+
# environment, service, and other data are automatically
|
27
|
+
# added as tags for you without specifying them here.
|
28
|
+
# @param [Integer, String, nil] :date_happened (nil) Assign a timestamp
|
29
|
+
# to the event. Default is now when none
|
30
|
+
# @param [String, nil] :priority ('normal') Can be "normal" or "low"
|
31
|
+
# @param [String, nil] :alert_type ('info') Can be "error", "warning", "info" or "success".
|
32
|
+
#
|
33
|
+
# @example Report an event:
|
34
|
+
# InstStatsd::Statsd.event(
|
35
|
+
# "Quiz API Deploy",
|
36
|
+
# "<release> was deployed to Quiz API",
|
37
|
+
# tags: {foo: 'bar'},
|
38
|
+
# type: 'deploy',
|
39
|
+
# alert_type: :success
|
40
|
+
# )
|
41
|
+
def event(title, text, type: nil, tags: {}, alert_type: nil, priority: nil, date_happened: nil)
|
42
|
+
return unless instance && data_dog?
|
43
|
+
|
44
|
+
instance.event(
|
45
|
+
title,
|
46
|
+
text,
|
47
|
+
**{
|
48
|
+
alert_type: alert_type,
|
49
|
+
priority: priority,
|
50
|
+
date_happened: date_happened,
|
51
|
+
tags: tags_from_opts(tags, type, dog_tags)
|
52
|
+
}.compact
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def tags_from_opts(tags, type, dd_tags)
|
59
|
+
custom_tags = tags.merge(dd_tags)
|
60
|
+
custom_tags[:type] = type if SUPPORTED_TYPES.include? type
|
61
|
+
custom_tags.compact
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,13 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "logger"
|
4
4
|
|
5
5
|
module InstStatsd
|
6
6
|
class NullLogger < Logger
|
7
|
-
def initialize(*
|
7
|
+
def initialize(*) # rubocop:disable Lint/MissingSuper
|
8
8
|
end
|
9
9
|
|
10
|
-
def add(*
|
11
|
-
end
|
10
|
+
def add(*); end
|
12
11
|
end
|
13
12
|
end
|
@@ -2,26 +2,24 @@
|
|
2
2
|
|
3
3
|
module InstStatsd
|
4
4
|
class RequestLogger
|
5
|
-
|
6
5
|
def initialize(logger)
|
7
6
|
@logger = logger || InstStatsd::NullLogger.new
|
8
7
|
end
|
9
8
|
|
10
|
-
def log(request_stat, header=nil)
|
9
|
+
def log(request_stat, header = nil)
|
11
10
|
@logger.info(build_log_message(request_stat, header))
|
12
11
|
end
|
13
12
|
|
14
|
-
def build_log_message(request_stat, header=nil)
|
13
|
+
def build_log_message(request_stat, header = nil)
|
15
14
|
header ||= "STATSD"
|
16
15
|
message = "[#{header}]"
|
17
16
|
request_stat.stats.each do |(name, value)|
|
18
|
-
message += " (#{name.to_s.
|
17
|
+
message += " (#{name.to_s.tr(".", "_")}: #{format("%.2f", value)})"
|
19
18
|
end
|
20
19
|
request_stat.exclusive_stats&.each do |(name, value)|
|
21
|
-
message += " (exclusive_#{name.to_s.
|
20
|
+
message += " (exclusive_#{name.to_s.tr(".", "_")}: #{format("%.2f", value)})"
|
22
21
|
end
|
23
22
|
message
|
24
23
|
end
|
25
|
-
|
26
24
|
end
|
27
25
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module InstStatsd
|
4
4
|
class RequestStat < BlockStat
|
5
|
-
def initialize(name, start, finish, id, payload, statsd=InstStatsd::Statsd)
|
5
|
+
def initialize(name, start, finish, id, payload, statsd = InstStatsd::Statsd)
|
6
6
|
super(nil, statsd)
|
7
7
|
@name = name
|
8
8
|
@start = start
|
@@ -15,20 +15,22 @@ module InstStatsd
|
|
15
15
|
def common_key
|
16
16
|
common_key = super
|
17
17
|
return common_key if common_key
|
18
|
+
|
18
19
|
if @statsd.data_dog?
|
19
20
|
self.common_key = "request"
|
20
21
|
self.short_stat = "request"
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
tags[:controller] = controller if controller
|
23
|
+
tags[:action] = action if action
|
24
|
+
tags[:status] = status if status
|
25
|
+
elsif controller && action
|
26
|
+
self.common_key = "request.#{controller}.#{action}"
|
25
27
|
end
|
26
28
|
end
|
27
29
|
|
28
30
|
def report
|
29
|
-
stats[
|
30
|
-
stats[
|
31
|
-
stats[
|
31
|
+
stats["total"] = total
|
32
|
+
stats["view"] = view_runtime if view_runtime
|
33
|
+
stats["db"] = db_runtime if db_runtime
|
32
34
|
super
|
33
35
|
end
|
34
36
|
|
@@ -41,19 +43,29 @@ module InstStatsd
|
|
41
43
|
end
|
42
44
|
|
43
45
|
def controller
|
44
|
-
@payload.fetch(:params, {})[
|
46
|
+
@payload.fetch(:params, {})["controller"]
|
45
47
|
end
|
46
48
|
|
47
49
|
def action
|
48
|
-
@payload.fetch(:params, {})[
|
50
|
+
@payload.fetch(:params, {})["action"]
|
51
|
+
end
|
52
|
+
|
53
|
+
def status
|
54
|
+
status = @payload.fetch(:status, 0)
|
55
|
+
# Only return status group to reduce the number of indexed custom metrics (and cost) of datadog
|
56
|
+
return "1XX" if (status >= 100) && (status < 200)
|
57
|
+
return "2XX" if (status >= 200) && (status < 300)
|
58
|
+
return "3XX" if (status >= 300) && (status < 400)
|
59
|
+
return "4XX" if (status >= 400) && (status < 500)
|
60
|
+
return "5XX" if (status >= 500) && (status < 600)
|
61
|
+
|
62
|
+
nil
|
49
63
|
end
|
50
64
|
|
51
65
|
def total
|
52
|
-
if
|
53
|
-
|
54
|
-
end
|
66
|
+
return 0 if !@finish || !@start
|
67
|
+
|
55
68
|
(@finish - @start) * 1000
|
56
69
|
end
|
57
|
-
|
58
70
|
end
|
59
71
|
end
|
@@ -2,28 +2,29 @@
|
|
2
2
|
|
3
3
|
module InstStatsd
|
4
4
|
class RequestTracking
|
5
|
+
class << self
|
6
|
+
def enable(logger: nil)
|
7
|
+
@logger = RequestLogger.new(logger)
|
8
|
+
track_timing
|
9
|
+
end
|
5
10
|
|
6
|
-
|
7
|
-
@logger = RequestLogger.new(logger)
|
8
|
-
track_timing
|
9
|
-
end
|
10
|
-
|
11
|
-
private
|
11
|
+
private
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
def track_timing
|
14
|
+
ActiveSupport::Notifications.subscribe(/start_processing\.action_controller/, &method(:start_processing))
|
15
|
+
ActiveSupport::Notifications.subscribe(/process_action\.action_controller/, &method(:finalize_processing))
|
16
|
+
end
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
def start_processing(*_args)
|
19
|
+
@cookies = Counter.counters.map { |(name, counter)| [name, counter.start] }
|
20
|
+
end
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
22
|
+
def finalize_processing *args
|
23
|
+
request_stat = InstStatsd::RequestStat.new(*args)
|
24
|
+
request_stat.stats = @cookies.to_h { |(name, cookie)| [name, Counter.counters[name].finalize_count(cookie)] }
|
25
|
+
request_stat.report
|
26
|
+
@logger.log(request_stat)
|
27
|
+
end
|
27
28
|
end
|
28
29
|
end
|
29
30
|
end
|
@@ -2,27 +2,26 @@
|
|
2
2
|
|
3
3
|
module InstStatsd
|
4
4
|
class SqlTracker
|
5
|
-
|
6
5
|
attr_reader :blocked_names, :read_counts, :write_counts, :cache_counts
|
7
6
|
|
8
|
-
def initialize(opts=nil)
|
7
|
+
def initialize(opts = nil)
|
9
8
|
opts ||= {}
|
10
9
|
@blocked_names = opts.fetch(:blocked_names, [])
|
11
|
-
@read_counts = opts.fetch(:read_counter, InstStatsd::Counter.new(
|
12
|
-
@write_counts = opts.fetch(:write_counter, InstStatsd::Counter.new(
|
13
|
-
@cache_counts = opts.fetch(:cache_counter, InstStatsd::Counter.new(
|
10
|
+
@read_counts = opts.fetch(:read_counter, InstStatsd::Counter.new("sql.read"))
|
11
|
+
@write_counts = opts.fetch(:write_counter, InstStatsd::Counter.new("sql.write"))
|
12
|
+
@cache_counts = opts.fetch(:cache_counter, InstStatsd::Counter.new("sql.cache"))
|
14
13
|
end
|
15
14
|
|
16
15
|
def start
|
17
16
|
[read_counts, write_counts, cache_counts].map(&:start)
|
18
17
|
end
|
19
18
|
|
20
|
-
def track
|
19
|
+
def track(name, sql)
|
21
20
|
return unless sql && accepted_name?(name)
|
22
21
|
|
23
|
-
if name.
|
22
|
+
if name.include?("CACHE")
|
24
23
|
cache_counts.track name
|
25
|
-
elsif truncate(sql).
|
24
|
+
elsif truncate(sql).include?("SELECT") || name.include?("LOAD")
|
26
25
|
read_counts.track(sql)
|
27
26
|
else
|
28
27
|
write_counts.track(sql)
|
@@ -43,10 +42,9 @@ module InstStatsd
|
|
43
42
|
!!(name && !blocked_names.include?(name))
|
44
43
|
end
|
45
44
|
|
46
|
-
def truncate(sql, length=15)
|
47
|
-
sql ||=
|
45
|
+
def truncate(sql, length = 15)
|
46
|
+
sql ||= ""
|
48
47
|
sql.strip[0..length]
|
49
48
|
end
|
50
|
-
|
51
49
|
end
|
52
50
|
end
|
data/lib/inst_statsd/statsd.rb
CHANGED
@@ -10,27 +10,33 @@
|
|
10
10
|
# InstStatsd::Statsd.timing("my_stat", ms)
|
11
11
|
#
|
12
12
|
# Configured in config/statsd.yml, see config/statsd.yml.example
|
13
|
-
# At least a host needs to be defined for the environment, all other config is
|
13
|
+
# At least a host needs to be defined for the environment, all other config is
|
14
|
+
# optional
|
14
15
|
#
|
15
16
|
# If a namespace is defined in statsd.yml, it'll be prepended to the stat name.
|
16
|
-
# The hostname of the server will be appended to the stat name, unless
|
17
|
-
#
|
18
|
-
#
|
17
|
+
# The hostname of the server will be appended to the stat name, unless
|
18
|
+
# `append_hostname: false` is specified in the config.
|
19
|
+
# So if the namespace is "canvas" and the hostname is "app01", the final stat
|
20
|
+
# name of "my_stat" would be "stats.canvas.my_stat.app01" (assuming the default
|
21
|
+
# statsd/graphite configuration)
|
19
22
|
#
|
20
23
|
# If dog_tags is set in statsd.yml, it'll use the tags param and will use
|
21
24
|
# Data Dog instead of Statsd
|
22
25
|
#
|
23
|
-
# If statsd isn't configured and enabled, then calls to InstStatsd::Statsd.*
|
26
|
+
# If statsd isn't configured and enabled, then calls to InstStatsd::Statsd.*
|
27
|
+
# will do nothing and return nil
|
24
28
|
|
25
29
|
module InstStatsd
|
26
30
|
module Statsd
|
31
|
+
extend InstStatsd::Event
|
32
|
+
|
27
33
|
# replace "." in key names with another character to avoid creating spurious sub-folders in graphite
|
28
|
-
def self.escape(str, replacement =
|
29
|
-
str.respond_to?(:gsub) ? str.gsub(
|
34
|
+
def self.escape(str, replacement = "_")
|
35
|
+
str.respond_to?(:gsub) ? str.gsub(".", replacement) : str
|
30
36
|
end
|
31
37
|
|
32
38
|
def self.hostname
|
33
|
-
@hostname ||= Socket.gethostname.split(
|
39
|
+
@hostname ||= Socket.gethostname.split(".").first
|
34
40
|
end
|
35
41
|
|
36
42
|
def self.dog_tags
|
@@ -39,50 +45,49 @@ module InstStatsd
|
|
39
45
|
|
40
46
|
%w[increment decrement count gauge timing].each do |method|
|
41
47
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
48
|
+
def self.#{method}(stat, *args, tags: {}, short_stat: nil) # def self.increment(stat, *args, tags: {}, short_stat: nil)
|
49
|
+
if self.instance # if self.instance
|
50
|
+
if Array === stat # if Array === stat
|
51
|
+
stat.each do |st| # stat.each do |st|
|
52
|
+
self.#{method}(st, *args, tags: tags, short_stat: nil) # self.increment(st, *args, tags: tags, short_stat: nil)
|
53
|
+
end # end
|
54
|
+
return # return
|
55
|
+
end # end
|
56
|
+
#
|
57
|
+
if self.append_hostname? # if self.append_hostname?
|
58
|
+
stat_name = "\#{stat}.\#{hostname}" # stat_name = "\#{stat}.\#{hostname}"
|
59
|
+
else # else
|
60
|
+
stat_name = stat.to_s # stat_name = stat.to_s
|
61
|
+
end # end
|
62
|
+
#
|
63
|
+
if data_dog? # if data_dog?
|
64
|
+
tags = tags ? tags.dup : {} # tags ||= {}
|
65
|
+
tags.merge!(dog_tags) if tags.is_a? Hash # tags.merge!(dog_tags) if tags.is_a? Hash
|
66
|
+
tags = convert_tags(tags) # tags = convert_tags(tags)
|
67
|
+
tags << 'host:' unless self.append_hostname? # tags << 'host:' unless self.append_hostname?
|
68
|
+
short_stat ||= stat_name # short_stat ||= stat_name
|
69
|
+
opts = { tags: tags } # opts = { tags: tags }
|
70
|
+
opts[:sample_rate] = args.pop if args.length == 2 # opts[:sample_rate] = args.pop if args.length == 2
|
71
|
+
args << opts # args << opts
|
72
|
+
self.instance.#{method}(short_stat, *args) # self.instance.increment(short_stat, *args)
|
73
|
+
else # else
|
74
|
+
self.instance.#{method}(stat_name, *args) # self.instance.increment(stat_name, *args)
|
75
|
+
end # end
|
76
|
+
else # else
|
77
|
+
nil # nil
|
78
|
+
end # end
|
79
|
+
end # end
|
74
80
|
RUBY
|
75
81
|
end
|
76
82
|
|
77
83
|
def self.convert_tags(tags)
|
78
84
|
new_tags = []
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
else
|
84
|
-
return tags
|
85
|
+
return tags unless tags.is_a? Hash
|
86
|
+
|
87
|
+
tags.each do |tag, v|
|
88
|
+
new_tags << "#{tag}:#{v}"
|
85
89
|
end
|
90
|
+
|
86
91
|
new_tags
|
87
92
|
end
|
88
93
|
|
@@ -95,6 +100,7 @@ module InstStatsd
|
|
95
100
|
|
96
101
|
def self.batch
|
97
102
|
return yield unless (old_instance = instance)
|
103
|
+
|
98
104
|
old_instance.batch do |batch|
|
99
105
|
Thread.current[:inst_statsd] = batch
|
100
106
|
yield
|
@@ -111,19 +117,24 @@ module InstStatsd
|
|
111
117
|
statsd_settings = InstStatsd.settings
|
112
118
|
if statsd_settings.key?(:dog_tags)
|
113
119
|
@data_dog = true
|
114
|
-
host = statsd_settings[:host] ||
|
120
|
+
host = statsd_settings[:host] || "localhost"
|
115
121
|
port = statsd_settings[:port] || 8125
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
122
|
+
socket_path = statsd_settings[:socket_path]
|
123
|
+
require "datadog/statsd"
|
124
|
+
@statsd = if socket_path
|
125
|
+
Datadog::Statsd.new(socket_path: socket_path, namespace: statsd_settings[:namespace])
|
126
|
+
else
|
127
|
+
Datadog::Statsd.new(host, port, namespace: statsd_settings[:namespace])
|
128
|
+
end
|
129
|
+
dog_tags.replace(statsd_settings[:dog_tags] || {})
|
130
|
+
@append_hostname = statsd_settings[:append_hostname]
|
120
131
|
elsif statsd_settings && statsd_settings[:host]
|
121
132
|
@statsd = ::Statsd.new(statsd_settings[:host])
|
122
133
|
@statsd.port = statsd_settings[:port] if statsd_settings[:port]
|
123
134
|
@statsd.namespace = statsd_settings[:namespace] if statsd_settings[:namespace]
|
124
135
|
@statsd.batch_size = statsd_settings[:batch_size] if statsd_settings.key?(:batch_size)
|
125
136
|
@statsd.batch_byte_size = statsd_settings[:batch_byte_size] if statsd_settings.key?(:batch_byte_size)
|
126
|
-
@append_hostname =
|
137
|
+
@append_hostname = statsd_settings[:append_hostname]
|
127
138
|
else
|
128
139
|
@statsd = nil
|
129
140
|
end
|