def setup_middleware(self): self.validate_config() self.metric_publisher = yield self.worker.start_publisher( MetricPublisher) # We don't use a VumiApi here because we don't have a Riak config for # it. self.redis = yield TxRedisManager.from_config( self.config['redis_manager']) self.metric_manager = MetricManager(self.manager_name + '.', publisher=self.metric_publisher) self.metric_manager.start_polling()
def setup_middleware(self): self.validate_config() self.metric_publisher = yield self.worker.start_publisher(MetricPublisher) # We don't use a VumiApi here because we don't have a Riak config for # it. self.redis = yield TxRedisManager.from_config(self.config["redis_manager"]) self.metric_manager = MetricManager(self.manager_name + ".", publisher=self.metric_publisher) self.metric_manager.start_polling()
def get_metric_manager(self, prefix): if self.metric_publisher is None: raise VumiError("No metric publisher available.") return MetricManager(prefix, publisher=self.metric_publisher)
class MetricsMiddleware(BaseMiddleware): """ Middleware that publishes metrics on messages flowing through. It tracks the number of messages sent & received on the various transports and the average response times for messages received. :param str manager_name: The name of the metrics publisher, this is used for the MetricManager publisher and all metric names will be prefixed with it. :param str count_suffix: Defaults to 'count'. This is the suffix appended to all `transport_name` based counters. If a message is received on endpoint 'foo', counters are published on '<manager_name>.foo.inbound.<count_suffix>' :param str response_time_suffix: Defaults to 'response_time'. This is the suffix appended to all `transport_name` based average response time metrics. If a message is received its `message_id` is stored and when a reply for the given `message_id` is sent out, the timestamps are compared and a averaged metric is published. :param int max_lifetime: How long to keep a timestamp for. Anything older than this is trashed. Defaults to 60 seconds. :param dict redis_manager: Connection configuration details for Redis. :param str op_mode: What mode to operate in, options are `passive` or `active`. Defaults to passive. *passive*: assumes the middleware endpoints are to be used as the names for metrics publishing. *active*: assumes that the individual messages are to be inspected for their `transport_name` values. NOTE: This does not apply for events or failures, the endpoints are always used for those since those message types are not guaranteed to have a `transport_name` value. """ KNOWN_MODES = frozenset(["active", "passive"]) def validate_config(self): self.manager_name = self.config["manager_name"] self.count_suffix = self.config.get("count_suffix", "count") self.response_time_suffix = self.config.get("response_time_suffix", "response_time") self.max_lifetime = int(self.config.get("max_lifetime", 60)) self.op_mode = self.config.get("op_mode", "passive") if self.op_mode not in self.KNOWN_MODES: raise ConfigError("Unknown op_mode: %s" % (self.op_mode,)) @inlineCallbacks def setup_middleware(self): self.validate_config() self.metric_publisher = yield self.worker.start_publisher(MetricPublisher) # We don't use a VumiApi here because we don't have a Riak config for # it. self.redis = yield TxRedisManager.from_config(self.config["redis_manager"]) self.metric_manager = MetricManager(self.manager_name + ".", publisher=self.metric_publisher) self.metric_manager.start_polling() def teardown_middleware(self): self.metric_manager.stop_polling() return self.redis.close_manager() def get_or_create_metric(self, name, metric_class, *args, **kwargs): """ Get the metric for `name`, create it with `metric_class(*args, **kwargs)` if it doesn't exist yet. """ if name not in self.metric_manager: self.metric_manager.register(metric_class(name, *args, **kwargs)) return self.metric_manager[name] def get_counter_metric(self, name): metric_name = "%s.%s" % (name, self.count_suffix) return self.get_or_create_metric(metric_name, Count) def increment_counter(self, transport_name, message_type): metric = self.get_counter_metric("%s.%s" % (transport_name, message_type)) metric.inc() def get_response_time_metric(self, name): metric_name = "%s.%s" % (name, self.response_time_suffix) return self.get_or_create_metric(metric_name, Metric) def set_response_time(self, transport_name, time): metric = self.get_response_time_metric(transport_name) metric.set(time) def key(self, transport_name, message_id): return "%s:%s" % (transport_name, message_id) def set_inbound_timestamp(self, transport_name, message): key = self.key(transport_name, message["message_id"]) return self.redis.setex(key, self.max_lifetime, repr(time.time())) @inlineCallbacks def get_outbound_timestamp(self, transport_name, message): key = self.key(transport_name, message["in_reply_to"]) timestamp = yield self.redis.get(key) if timestamp: returnValue(float(timestamp)) @inlineCallbacks def compare_timestamps(self, transport_name, message): timestamp = yield self.get_outbound_timestamp(transport_name, message) if timestamp: self.set_response_time(transport_name, time.time() - timestamp) def get_name(self, message, endpoint): if self.op_mode == "active": return message["transport_name"] return endpoint @inlineCallbacks def handle_inbound(self, message, endpoint): name = self.get_name(message, endpoint) self.increment_counter(name, "inbound") yield self.set_inbound_timestamp(name, message) returnValue(message) @inlineCallbacks def handle_outbound(self, message, endpoint): name = self.get_name(message, endpoint) self.increment_counter(name, "outbound") yield self.compare_timestamps(name, message) returnValue(message) def handle_event(self, event, endpoint): self.increment_counter(endpoint, "event.%s" % (event["event_type"])) if event["event_type"] == "delivery_report": self.increment_counter(endpoint, "event.%s.%s" % (event["event_type"], event["delivery_status"])) return event def handle_failure(self, failure, endpoint): self.increment_counter(endpoint, "failure.%s" % (failure["failure_code"] or "unspecified",)) return failure
class MetricsMiddleware(BaseMiddleware): """ Middleware that publishes metrics on messages flowing through. It tracks the number of messages sent & received on the various transports and the average response times for messages received. :param str manager_name: The name of the metrics publisher, this is used for the MetricManager publisher and all metric names will be prefixed with it. :param str count_suffix: Defaults to 'count'. This is the suffix appended to all `transport_name` based counters. If a message is received on endpoint 'foo', counters are published on '<manager_name>.foo.inbound.<count_suffix>' :param str response_time_suffix: Defaults to 'response_time'. This is the suffix appended to all `transport_name` based average response time metrics. If a message is received its `message_id` is stored and when a reply for the given `message_id` is sent out, the timestamps are compared and a averaged metric is published. :param int max_lifetime: How long to keep a timestamp for. Anything older than this is trashed. Defaults to 60 seconds. :param dict redis_manager: Connection configuration details for Redis. :param str op_mode: What mode to operate in, options are `passive` or `active`. Defaults to passive. *passive*: assumes the middleware endpoints are to be used as the names for metrics publishing. *active*: assumes that the individual messages are to be inspected for their `transport_name` values. NOTE: This does not apply for events or failures, the endpoints are always used for those since those message types are not guaranteed to have a `transport_name` value. """ KNOWN_MODES = frozenset(['active', 'passive']) def validate_config(self): self.manager_name = self.config['manager_name'] self.count_suffix = self.config.get('count_suffix', 'count') self.response_time_suffix = self.config.get('response_time_suffix', 'response_time') self.max_lifetime = int(self.config.get('max_lifetime', 60)) self.op_mode = self.config.get('op_mode', 'passive') if self.op_mode not in self.KNOWN_MODES: raise ConfigError('Unknown op_mode: %s' % (self.op_mode, )) @inlineCallbacks def setup_middleware(self): self.validate_config() self.metric_publisher = yield self.worker.start_publisher( MetricPublisher) # We don't use a VumiApi here because we don't have a Riak config for # it. self.redis = yield TxRedisManager.from_config( self.config['redis_manager']) self.metric_manager = MetricManager(self.manager_name + '.', publisher=self.metric_publisher) self.metric_manager.start_polling() def teardown_middleware(self): self.metric_manager.stop_polling() return self.redis.close_manager() def get_or_create_metric(self, name, metric_class, *args, **kwargs): """ Get the metric for `name`, create it with `metric_class(*args, **kwargs)` if it doesn't exist yet. """ if name not in self.metric_manager: self.metric_manager.register(metric_class(name, *args, **kwargs)) return self.metric_manager[name] def get_counter_metric(self, name): metric_name = '%s.%s' % (name, self.count_suffix) return self.get_or_create_metric(metric_name, Count) def increment_counter(self, transport_name, message_type): metric = self.get_counter_metric('%s.%s' % (transport_name, message_type)) metric.inc() def get_response_time_metric(self, name): metric_name = '%s.%s' % (name, self.response_time_suffix) return self.get_or_create_metric(metric_name, Metric) def set_response_time(self, transport_name, time): metric = self.get_response_time_metric(transport_name) metric.set(time) def key(self, transport_name, message_id): return '%s:%s' % (transport_name, message_id) def set_inbound_timestamp(self, transport_name, message): key = self.key(transport_name, message['message_id']) return self.redis.setex(key, self.max_lifetime, repr(time.time())) @inlineCallbacks def get_outbound_timestamp(self, transport_name, message): key = self.key(transport_name, message['in_reply_to']) timestamp = yield self.redis.get(key) if timestamp: returnValue(float(timestamp)) @inlineCallbacks def compare_timestamps(self, transport_name, message): timestamp = yield self.get_outbound_timestamp(transport_name, message) if timestamp: self.set_response_time(transport_name, time.time() - timestamp) def get_name(self, message, endpoint): if self.op_mode == 'active': return message['transport_name'] return endpoint @inlineCallbacks def handle_inbound(self, message, endpoint): name = self.get_name(message, endpoint) self.increment_counter(name, 'inbound') yield self.set_inbound_timestamp(name, message) returnValue(message) @inlineCallbacks def handle_outbound(self, message, endpoint): name = self.get_name(message, endpoint) self.increment_counter(name, 'outbound') yield self.compare_timestamps(name, message) returnValue(message) def handle_event(self, event, endpoint): self.increment_counter(endpoint, 'event.%s' % (event['event_type'])) if event['event_type'] == 'delivery_report': self.increment_counter( endpoint, 'event.%s.%s' % (event['event_type'], event['delivery_status'])) return event def handle_failure(self, failure, endpoint): self.increment_counter( endpoint, 'failure.%s' % (failure['failure_code'] or 'unspecified', )) return failure