7 from collectors.mon import Mon
8 from collectors.rgw import RGW
9 from collectors.osd import OSDs
10 from collectors.iscsi import ISCSIGateway
11 from collectors.common import flatten_dict, get_hostname
14 PLUGIN_NAME = 'cephmetrics'
23 "iscsi": "ISCSIGateway"
27 self.cluster_name = None
29 self.host_name = get_hostname()
38 set up which collector(s) to use
42 self.mon = Mon(self, self.cluster_name)
45 self.rgw = RGW(self, self.cluster_name)
48 self.osd = OSDs(self, self.cluster_name)
50 if ISCSIGateway.probe():
51 self.iscsi = ISCSIGateway(self, self.cluster_name)
58 stats['mon'] = self.mon.get_stats()
61 stats['rgw'] = self.rgw.get_stats()
64 stats['osd'] = self.osd.get_stats()
67 stats['iscsi'] = self.iscsi.get_stats()
72 def write_stats(role_metrics, stats):
74 flat_stats = flatten_dict(stats, '.')
76 for key_name in flat_stats:
77 attr_name = key_name.split('.')[-1]
79 # TODO: this needs some more think time, since the key from the name
80 # is not the key of the all_metrics dict
81 if attr_name in role_metrics:
82 attr_type = role_metrics[attr_name][1] # gauge / derive etc
87 attr_value = flat_stats[key_name]
89 val = collectd.Values(plugin=PLUGIN_NAME, type=attr_type)
90 instance_name = "{}.{}".format(CEPH.cluster_name,
92 val.type_instance = instance_name
93 val.values = [attr_value]
97 def configure_callback(conf):
99 valid_log_levels = ['debug', 'info']
102 module_parms = {node.key: node.values[0] for node in conf.children}
104 log_level = module_parms.get('LogLevel', 'debug')
105 if log_level not in valid_log_levels:
106 collectd.error("cephmetrics: LogLevel specified is invalid - must"
107 " be :{}".format(' or '.join(valid_log_levels)))
109 if 'EventURL' in module_parms:
110 CEPH.event_url = module_parms['EventURL']
111 collectd.info("cephmetrics: Event messages enabled for target "
112 "{}".format(CEPH.event_url))
114 collectd.warning("cephmetrics: EventURL missing - health events "
115 "will not be reported")
117 if 'ClusterName' in module_parms:
118 cluster_name = module_parms['ClusterName']
119 # cluster name is all we need to get started
120 if not os.path.exists('/etc/ceph/{}.conf'.format(cluster_name)):
121 collectd.error("Clustername given ('{}') not found in "
122 "/etc/ceph".format(module_parms['ClusterName']))
124 # let's assume the conf file is OK to use
125 CEPH.cluster_name = cluster_name
127 setup_module_logging(log_level)
131 collectd.info("{}: Roles detected - "
132 "mon:{} osd:{} rgw:{} "
133 "iscsi:{}".format(__name__,
134 isinstance(CEPH.mon, Mon),
135 isinstance(CEPH.osd, OSDs),
136 isinstance(CEPH.rgw, RGW),
137 isinstance(CEPH.iscsi, ISCSIGateway)))
139 collectd.error("cephmetrics: ClusterName is required")
142 def setup_module_logging(log_level):
144 level = {"debug": logging.DEBUG,
145 "info": logging.INFO}
147 logging.getLogger('cephmetrics')
148 logging.basicConfig(filename='/var/log/collectd-cephmetrics.log',
149 format='%(asctime)s - %(levelname)-7s - '
150 '[%(filename)s:%(lineno)s:%(funcName)s() - '
153 level=level.get(log_level))
158 stats = CEPH.get_stats()
160 for role in Ceph.roles:
162 collector = getattr(CEPH, role)
164 write_stats(collector.all_metrics, stats[role])
166 error_handler(collector)
169 def error_handler(collector):
170 if not collector.error:
173 # detected an error, let's flag it to the collectd log
174 msg_text = ",".join(collector.error_msgs)
176 collectd.error("cephmetrics error: {} - {}".format(collector._name,
179 # reset the collector instance's error tracking
180 collector.error = False
181 del collector.error_msgs[:]
184 if __name__ == '__main__':
186 # run interactively or maybe test the code
194 collectd.register_config(configure_callback)
195 collectd.register_read(read_callback)