Module: Librato::Metrics::Taps::JMX

Defined in:
lib/librato/metrics/taps/jmx.rb

Class Method Summary collapse

Class Method Details

.connect!(host = 'localhost', port = 3000, username = nil, password = nil) ⇒ Object



6
7
8
9
10
11
12
13
# File 'lib/librato/metrics/taps/jmx.rb', line 6

def connect!(host = 'localhost', port = 3000, username = nil, password = nil)
  begin
    ::JMX::MBean.establish_connection :host => host, :port => port, :username => username, :password => password
  rescue => err
    return false
  end
  @connected = true
end

.match_beans(beans) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
# File 'lib/librato/metrics/taps/jmx.rb', line 15

def match_beans(beans)
  raise "Not connected" unless @connected || connect!

  begin
    b = ::JMX::MBean.find_all_by_name(beans.to_s)
  rescue => err
    return nil
  end

  b.collect { |bean| bean.object_name.to_s }
end

.metric_name(bean_name, attr_name) ⇒ Object



134
135
136
# File 'lib/librato/metrics/taps/jmx.rb', line 134

def metric_name(bean_name, attr_name)
  "#{bean_name.gsub('=', ':').gsub(/[, ]/, '_').gsub(/[^A-Za-z0-9\.:\-_]/, '_')}::#{attr_name}"
end

.retrieve(bean_names, ignore_missing = false) ⇒ Object

Retrieves a list of JMX attributes converted to gauges and counters.

Argument options:

beans = ['bean1', 'bean2']
  Will retrieve each attribute of each beanname as
  a gauge with a count value of 1.

beans = {'bean1' => ['attr1', 'attr2'], 'bean2' => true}
  Will retrieve only the specified attributes for each
  bean name. To retrieve all attributes, simply set
  to true instead of a list.

beans = {'bean1' => {'attr' => 'gauge',
                     'attr2' => 'counter'}}
  Will retrieve the specified beans and their
  attributes like the example above, but with the
  ability to specify how each attribute is returned. By
  default, all attributes are returned as
  gauges. However, if you set the attribute name to
  'counter', it will return the attribute as a counter.


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/librato/metrics/taps/jmx.rb', line 52

def retrieve(bean_names, ignore_missing = false)
  raise "Not connected" unless @connected || connect!

  gauges = {}
  counters = {}
  (bean_names.keys rescue bean_names).each do |bean|
    begin
      b = ::JMX::MBean.find_by_name(bean.to_s)
    rescue
      if ignore_missing
        next
      else
        raise "No such bean: #{bean}"
      end
    end

    if bean_names.respond_to?(:keys) &&
        ( bean_names[bean].class == Array ||
          bean_names[bean].class == Hash)
      attrs = bean_names[bean]
    else
      attrs = b.attributes.keys
    end

    attrs.each do |attr|
      attrname = attr.first
      begin
        value = b.send(snake_case(attrname.to_s))
      rescue
        if ignore_missing
          value = nil
        else
          raise "Bean #{bean} has no such attribute: #{attrname}"
        end
      end

      # Skip attributes without a value
      next unless value

      # Take a look at the type and only handle types that we know how to handle
      if value.kind_of? Java::JavaxManagementOpenmbean::CompositeDataSupport
        # If this is a composit data type loop through the elements assuming they are numbers
        value.each do |value_subkey, value_subvalue|
          if value_subvalue.kind_of? Numeric
            if attrs.respond_to?(:keys) && "#{attr.last}".downcase == 'counter'
              counters[metric_name(bean, attrname + "." + value_subkey)] = value_subvalue.to_i
            else
              gauges[metric_name(bean, attrname + "." + value_subkey)] = value_subvalue
            end
          else
            raise "The subvalue \"#{value_subkey}\" of value \"#{value}\" in Bean \"#{bean}\" is of type \"#{value_subvalue.class}\" and I only know how to handle numbers.\n"
          end
        end
      elsif value.kind_of? Numeric
        # Skip bogus values
        next if value.to_f.nan? || value.to_f.infinite?

        # If this is a number go ahead and submit it as either a counter or gauge
        # depending on what we set in the attributes
        if attrs.respond_to?(:keys) && "#{attr.last}".downcase == 'counter'
          counters[metric_name(bean, attrname)] = value.to_i
        else
          gauges[metric_name(bean, attrname)] = value
        end
      else
        raise "The value \"#{value}\" of Bean \"#{bean}\" is of type \"#{value.class}\" and I do not know how to handle that type.\n"
      end
    end
  end

  [counters, gauges]
end

.snake_case(camel_cased_word) ⇒ Object

From ActiveSupport



126
127
128
129
130
131
132
# File 'lib/librato/metrics/taps/jmx.rb', line 126

def snake_case(camel_cased_word)
  camel_cased_word.to_s.gsub(/::/, '/').
    gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
    gsub(/([a-z\d])([A-Z])/,'\1_\2').
    tr("-", "_").
    downcase
end