lib/statsd.rb in dogstatsd-ruby-1.4.1 vs lib/statsd.rb in dogstatsd-ruby-1.5.0
- old
+ new
@@ -30,10 +30,22 @@
['priority', 'p'],
['source_type_name', 's'],
['alert_type', 't']
]
+ # Service check options
+ SC_OPT_KEYS = [
+ ['timestamp', 'd:'],
+ ['hostname', 'h:'],
+ ['tags', '#'],
+ ['message', 'm:']
+ ]
+ OK = 0
+ WARNING = 1
+ CRITICAL = 2
+ UNKNOWN = 3
+
# A namespace to prepend to all statsd calls. Defaults to no namespace.
attr_reader :namespace
# StatsD host. Defaults to 127.0.0.1.
attr_reader :host
@@ -55,11 +67,11 @@
attr_accessor :logger
end
# Return the current version of the library.
def self.VERSION
- "1.4.1"
+ "1.5.0"
end
# @param [String] host your statsd host
# @param [Integer] port your statsd port
# @option opts [String] :namespace set a namespace to be prepended to every metric name
@@ -70,11 +82,11 @@
@socket = UDPSocket.new
self.namespace = opts[:namespace]
self.tags = opts[:tags]
@buffer = Array.new
self.max_buffer_size = max_buffer_size
- alias :send :send_to_socket
+ alias :send_stat :send_to_socket
end
def namespace=(namespace) #:nodoc:
@namespace = namespace
@prefix = namespace.nil? ? nil : "#{namespace}."
@@ -169,10 +181,13 @@
send_stats stat, ms, :ms, opts
end
# Reports execution time of the provided block using {#timing}.
#
+ # If the block fails, the stat is still reported, then the error
+ # is reraised
+ #
# @param [String] stat stat name
# @param [Hash] opts the options to create the metric with
# @option opts [Numeric] :sample_rate sample rate, 1 for always
# @option opts [Array<String>] :tags An array of tags
# @yield The operation to be timed
@@ -180,12 +195,15 @@
# @example Report the time (in ms) taken to activate an account
# $statsd.time('account.activate') { @account.activate! }
def time(stat, opts={})
start = Time.now
result = yield
- timing(stat, ((Time.now - start) * 1000).round, opts)
+ time_since(stat, start, opts)
result
+ rescue
+ time_since(stat, start, opts)
+ raise
end
# Sends a value to be tracked as a set to the statsd server.
#
# @param [String] stat stat name.
# @param [Numeric] value set value.
@@ -196,26 +214,69 @@
# $statsd.set('visitors.uniques', User.id)
def set(stat, value, opts={})
send_stats stat, value, :s, opts
end
+
+ # This method allows you to send custom service check statuses.
+ #
+ # @param [String] name Service check name
+ # @param [String] status Service check status.
+ # @param [Hash] opts the additional data about the service check
+ # @option opts [Integer, nil] :timestamp (nil) Assign a timestamp to the event. Default is now when none
+ # @option opts [String, nil] :hostname (nil) Assign a hostname to the event.
+ # @option opts [Array<String>, nil] :tags (nil) An array of tags
+ # @option opts [String, nil] :message (nil) A message to associate with this service check status
+ # @example Report a critical service check status
+ # $statsd.service_check('my.service.check', Statsd::CRITICAL, :tags=>['urgent'])
+ def service_check(name, status, opts={})
+ service_check_string = format_service_check(name, status, opts)
+ send_to_socket service_check_string
+ end
+ def format_service_check(name, status, opts={})
+ sc_string = "_sc|#{name}|#{status}"
+
+ SC_OPT_KEYS.each do |name_key|
+ if opts[name_key[0].to_sym]
+ if name_key[0] == 'tags'
+ tags = opts[:tags]
+ tags.each do |tag|
+ rm_pipes tag
+ end
+ tags = "#{tags.join(",")}" unless tags.empty?
+ sc_string << "|##{tags}"
+ elsif name_key[0] == 'message'
+ message = opts[:message]
+ rm_pipes message
+ escape_service_check_message message
+ sc_string << "|m:#{message}"
+ else
+ value = opts[name_key[0].to_sym]
+ rm_pipes value
+ sc_string << "|#{name_key[1]}#{value}"
+ end
+ end
+ end
+ return sc_string
+ end
+
# This end point allows you to post events to the stream. You can tag them, set priority and even aggregate them with other events.
#
# Aggregation in the stream is made on hostname/event_type/source_type/aggregation_key.
# If there's no event type, for example, then that won't matter;
# it will be grouped with other events that don't have an event type.
#
# @param [String] title Event title
# @param [String] text Event text. Supports \n
# @param [Hash] opts the additional data about the event
- # @option opts [Time, nil] :date_happened (nil) Assign a timestamp to the event. Default is now when none
+ # @option opts [Integer, nil] :date_happened (nil) Assign a timestamp to the event. Default is now when none
# @option opts [String, nil] :hostname (nil) Assign a hostname to the event.
# @option opts [String, nil] :aggregation_key (nil) Assign an aggregation key to the event, to group it with some others
# @option opts [String, nil] :priority ('normal') Can be "normal" or "low"
# @option opts [String, nil] :source_type_name (nil) Assign a source type to the event
# @option opts [String, nil] :alert_type ('info') Can be "error", "warning", "info" or "success".
- # @option opts [Array<String>, nil] :source_type_name (nil) An array of tags
+ # @option opts [Array<String>] :tags tags to be added to every metric
# @example Report an awful event:
# $statsd.event('Something terrible happened', 'The end is near if we do nothing', :alert_type=>'warning', :tags=>['end_of_times','urgent'])
def event(title, text, opts={})
event_string = format_event(title, text, opts)
raise "Event #{title} payload is too big (more that 8KB), event discarded" if event_string.length > 8 * 1024
@@ -230,59 +291,70 @@
# $statsd.batch do |s|
# s.gauge('users.online',156)
# s.increment('page.views')
# end
def batch()
- alias :send :send_to_buffer
+ alias :send_stat :send_to_buffer
yield self
flush_buffer
- alias :send :send_to_socket
+ alias :send_stat :send_to_socket
end
def format_event(title, text, opts={})
escape_event_content title
escape_event_content text
event_string_data = "_e{#{title.length},#{text.length}}:#{title}|#{text}"
# We construct the string to be sent by adding '|key:value' parts to it when needed
- # All pipes ('|') in the metada are removed. Title and Text can keep theirs
+ # All pipes ('|') in the metadata are removed. Title and Text can keep theirs
OPTS_KEYS.each do |name_key|
if name_key[0] != 'tags' && opts[name_key[0].to_sym]
value = opts[name_key[0].to_sym]
rm_pipes value
event_string_data << "|#{name_key[1]}:#{value}"
end
end
- tags = opts[:tags] || nil
+ full_tags = tags + (opts[:tags] || [])
# Tags are joined and added as last part to the string to be sent
- if tags
- tags.each do |tag|
+ unless full_tags.empty?
+ full_tags.each do |tag|
rm_pipes tag
end
- tags = "#{tags.join(",")}" unless tags.empty?
- event_string_data << "|##{tags}"
+ event_string_data << "|##{full_tags.join(',')}"
end
raise "Event #{title} payload is too big (more that 8KB), event discarded" if event_string_data.length > 8 * 1024
return event_string_data
end
+
private
+
def escape_event_content(msg)
- msg = msg.sub! "\n", "\\n"
+ msg.gsub! "\n", "\\n"
end
+
def rm_pipes(msg)
- msg = msg.sub! "|", ""
+ msg.gsub! "|", ""
end
+ def escape_service_check_message(msg)
+ msg.gsub! 'm:', 'm\:'
+ msg.gsub! "\n", "\\n"
+ end
+
+ def time_since(stat, start, opts)
+ timing(stat, ((Time.now - start) * 1000).round, opts)
+ end
+
def send_stats(stat, delta, type, opts={})
sample_rate = opts[:sample_rate] || 1
if sample_rate == 1 or rand < sample_rate
# Replace Ruby module scoping with '.' and reserved chars (: | @) with underscores.
stat = stat.to_s.gsub('::', '.').tr(':|@', '_')
rate = "|@#{sample_rate}" unless sample_rate == 1
ts = (tags || []) + (opts[:tags] || [])
tags = "|##{ts.join(",")}" unless ts.empty?
- send "#{@prefix}#{stat}:#{delta}|#{type}#{rate}#{tags}"
+ send_stat "#{@prefix}#{stat}:#{delta}|#{type}#{rate}#{tags}"
end
end
def send_to_buffer(message)
@buffer << message