def test_flush_many(self): interface.state.global_monitor = mock.create_autospec(monitors.Monitor) interface.state.target = mock.create_autospec(targets.Target) interface.state.target.__hash__.return_value = 42 # pylint: disable=unused-argument def populate_data_set(pb): pb.metric_name = 'foo' # We can't use the mock's call_args_list here because the same object is # reused as the argument to both calls and cleared inbetween. data_lengths = [] def send(proto): data_lengths.append( len(proto.metrics_collection[0].metrics_data_set[0].data)) interface.state.global_monitor.send.side_effect = send fake_metric = mock.create_autospec(metrics.Metric, spec_set=True) fake_metric.name = 'fake' fake_metric.populate_data_set.side_effect = populate_data_set interface.register(fake_metric) for i in range(501): interface.state.store.set('fake', ('field', i), None, 123) interface.flush() self.assertEquals(2, interface.state.global_monitor.send.call_count) self.assertListEqual([500, 1], data_lengths)
def test_send_modifies_metric_values(self): interface.state.global_monitor = stubs.MockMonitor() interface.state.target = stubs.MockTarget() # pylint: disable=unused-argument def serialize_to(pb, start_time, fields, value, target): pb.data.add().name = 'foo' fake_metric = mock.create_autospec(metrics.Metric, spec_set=True) fake_metric.name = 'fake' fake_metric.serialize_to.side_effect = serialize_to interface.register(fake_metric) # Setting this will modify store._values in the middle of iteration. delayed_metric = metrics.CounterMetric('foo') def send(proto): delayed_metric.increment_by(1) interface.state.global_monitor.send.side_effect = send for i in xrange(1001): interface.state.store.set('fake', ('field', i), None, 123) # Shouldn't raise an exception. interface.flush()
def test_flush_many_new(self): interface.state.global_monitor = mock.create_autospec(monitors.Monitor) interface.state.target = targets.TaskTarget('a', 'b', 'c', 'd', 1) # We can't use the mock's call_args_list here because the same object is # reused as the argument to both calls and cleared inbetween. data_lengths = [] def send(proto): count = 0 for coll in proto.metrics_collection: for data_set in coll.metrics_data_set: for _ in data_set.data: count += 1 data_lengths.append(count) interface.state.global_monitor.send.side_effect = send counter = metrics.CounterMetric('counter', 'desc', [metrics.IntegerField('field')]) interface.register(counter) for i in range(interface.METRICS_DATA_LENGTH_LIMIT + 1): counter.increment_by(i, {'field': i}) interface.flush() self.assertEquals(2, interface.state.global_monitor.send.call_count) self.assertListEqual([500, 1], data_lengths)
def test_flush(self): interface.state.global_monitor = mock.create_autospec(monitors.Monitor) interface.state.target = mock.create_autospec(targets.Target) interface.state.global_monitor.send.return_value = None interface.state.global_monitor.failed.return_value = False # pylint: disable=unused-argument def populate_data_set(pb): pb.metric_name = 'foo' fake_metric = mock.create_autospec(metrics.Metric, spec_set=True) fake_metric.name = 'fake' fake_metric.populate_data_set.side_effect = populate_data_set interface.register(fake_metric) interface.state.store.set('fake', (), None, 123) interface.flush() self.assertEqual(1, interface.state.global_monitor.send.call_count) self.assertEqual(1, interface.state.global_monitor.failed.call_count) proto = interface.state.global_monitor.send.call_args[0][0] self.assertEqual(1, len(proto.metrics_collection[0].metrics_data_set[0].data)) self.assertEqual('foo', proto.metrics_collection[0].metrics_data_set[0].metric_name) self.assertFalse(interface.state.global_monitor.wait.called)
def test_register_unregister(self): fake_metric = mock.create_autospec(metrics.Metric, spec_set=True) self.assertEqual(0, len(interface.state.metrics)) interface.register(fake_metric) self.assertEqual(1, len(interface.state.metrics)) interface.unregister(fake_metric) self.assertEqual(0, len(interface.state.metrics))
def test_send_modifies_metric_values(self): interface.state.global_monitor = mock.create_autospec(monitors.Monitor) interface.state.target = mock.create_autospec(targets.Target) interface.state.target.__hash__.return_value = 42 # pylint: disable=unused-argument def populate_data_set(pb): pb.metric_name = 'foo' fake_metric = mock.create_autospec(metrics.Metric, spec_set=True) fake_metric.name = 'fake' fake_metric.populate_data_set.side_effect = populate_data_set interface.register(fake_metric) # Setting this will modify store._values in the middle of iteration. delayed_metric = metrics.CounterMetric('foo', 'desc', None) def send(proto): delayed_metric.increment_by(1) interface.state.global_monitor.send.side_effect = send for i in range(1001): interface.state.store.set('fake', (i, ), None, 123) # Shouldn't raise an exception. interface.flush()
def test_flush_many(self): interface.state.global_monitor = stubs.MockMonitor() interface.state.target = stubs.MockTarget() # pylint: disable=unused-argument def serialize_to(pb, start_time, fields, value, target): pb.data.add().name = 'foo' # We can't use the mock's call_args_list here because the same object is # reused as the argument to both calls and cleared inbetween. data_lengths = [] def send(proto): data_lengths.append(len(proto.data)) interface.state.global_monitor.send.side_effect = send fake_metric = mock.create_autospec(metrics.Metric, spec_set=True) fake_metric.name = 'fake' fake_metric.serialize_to.side_effect = serialize_to interface.register(fake_metric) for i in xrange(1001): interface.state.store.set('fake', ('field', i), 123) interface.flush() self.assertEquals(2, interface.state.global_monitor.send.call_count) self.assertEqual(1000, data_lengths[0]) self.assertEqual(1, data_lengths[1])
def test_generate_every_type_of_field(self): counter = metrics.CounterMetric('counter', 'desc', [ metrics.IntegerField('a'), metrics.BooleanField('b'), metrics.StringField('c'), ]) interface.register(counter) counter.increment({'a': 1, 'b': True, 'c': 'test'}) proto = list(interface._generate_proto())[0] data_set = proto.metrics_collection[0].metrics_data_set[0] field_type = metrics_pb2.MetricsDataSet.MetricFieldDescriptor self.assertEqual('a', data_set.field_descriptor[0].name) self.assertEqual(field_type.INT64, data_set.field_descriptor[0].field_type) self.assertEqual('b', data_set.field_descriptor[1].name) self.assertEqual(field_type.BOOL, data_set.field_descriptor[1].field_type) self.assertEqual('c', data_set.field_descriptor[2].name) self.assertEqual(field_type.STRING, data_set.field_descriptor[2].field_type) self.assertEqual(1, data_set.data[0].int64_value) self.assertEqual('a', data_set.data[0].field[0].name) self.assertEqual(1, data_set.data[0].field[0].int64_value) self.assertEqual('b', data_set.data[0].field[1].name) self.assertTrue(data_set.data[0].field[1].bool_value) self.assertEqual('c', data_set.data[0].field[2].name) self.assertEqual('test', data_set.data[0].field[2].string_value)
def test_flush_many(self): interface.state.global_monitor = stubs.MockMonitor() interface.state.target = stubs.MockTarget() # pylint: disable=unused-argument def serialize_to(pb, start_time, fields, value, target): pb.data.add().name = 'foo' # We can't use the mock's call_args_list here because the same object is # reused as the argument to both calls and cleared inbetween. data_lengths = [] def send(proto): data_lengths.append(len(proto.data)) interface.state.global_monitor.send.side_effect = send fake_metric = mock.create_autospec(metrics.Metric, spec_set=True) fake_metric.name = 'fake' fake_metric.serialize_to.side_effect = serialize_to interface.register(fake_metric) for i in xrange(1001): interface.state.store.set('fake', ('field', i), None, 123) interface.flush() self.assertEquals(2, interface.state.global_monitor.send.call_count) self.assertEqual(1000, data_lengths[0]) self.assertEqual(1, data_lengths[1])
def __init__(self, name, description, field_spec, units=None, target_type=None): """Create an instance of a Metric. Args: name (str): the file-like name of this metric description (string): help string for the metric. Should be enough to know what the metric is about. field_spec (list): a list of Field subclasses to define the fields that are allowed on this metric. Pass a list of either StringField, IntegerField or BooleanField here. units (string): the unit used to measure data for given metric. Some common units are pre-defined in the MetricsDataUnits class. target_type (type): the subclass of google.protobuf.message.Message that represents the target type. """ field_spec = field_spec or [] self._name = name.lstrip('/') if not isinstance(description, basestring): raise errors.MetricDefinitionError( 'Metric description must be a string') if not description: raise errors.MetricDefinitionError( 'Metric must have a description') if (not isinstance(field_spec, (list, tuple)) or any(not isinstance(x, Field) for x in field_spec)): raise errors.MetricDefinitionError( 'Metric constructor takes a list of Fields, or None') if len(field_spec) > 12: # Monarch imposes a limit of a cardinality of 5000 for a single metric # (see http://shortn/_WBupjZf2of). # If a user set 12 fields, and each of those is just a boolean field # with two possible values, the _lower limit_ on the cardinality of # that metric is 2^12, or 4096. # Note that since a combination of 5 built-in fields is fixed, we do # not need to count them. raise errors.MonitoringTooManyFieldsError(self._name, field_spec) if target_type and not (inspect.isclass(target_type) and issubclass(target_type, message.Message)): raise errors.MetricDefinitionError( 'Metric target type must be a class (not an instance of a class) ' 'and that must be a subclass of google.protobuf.message.Message.' ) self._start_time = None self._field_spec = field_spec self._sorted_field_names = sorted(x.name for x in field_spec) self._description = description self._units = units self._target_type = target_type self._enable_cumulative_set = False interface.register(self)
def test_duplicate_register_raises(self): fake_metric = mock.Mock() fake_metric.name = 'foo' phake_metric = mock.Mock() phake_metric.name = 'foo' interface.register(fake_metric) with self.assertRaises(errors.MonitoringDuplicateRegistrationError): interface.register(phake_metric) self.assertEqual(1, len(interface.state.metrics))
def _test_proto(self, metric, set_fn, value_type, stream_kind): self.time_fn.return_value = 100.3 interface.register(metric) set_fn(metric) self.time_fn.return_value = 1000.6 proto = list(interface._generate_proto())[0] data_set = proto.metrics_collection[0].metrics_data_set[0] data = data_set.data[0] self.assertEqual(stream_kind, data_set.stream_kind) self.assertEqual(value_type, data_set.value_type) self.assertEqual(100, data.start_timestamp.seconds) self.assertEqual(1000, data.end_timestamp.seconds) self.assertFalse(data_set.annotations.HasField('unit')) return data
def test_flush_new(self): interface.state.metric_name_prefix = '/infra/test/' interface.state.global_monitor = mock.create_autospec(monitors.Monitor) interface.state.target = targets.TaskTarget('a', 'b', 'c', 'd', 1) counter = metrics.CounterMetric('counter', 'desc', None) interface.register(counter) counter.increment_by(3) interface.flush() self.assertEqual(1, interface.state.global_monitor.send.call_count) proto = interface.state.global_monitor.send.call_args[0][0] self.assertEqual(1, len(proto.metrics_collection)) self.assertEqual(1, len(proto.metrics_collection[0].metrics_data_set)) data_set = proto.metrics_collection[0].metrics_data_set[0] self.assertEqual('/infra/test/counter', data_set.metric_name)
def test_generate_proto_with_dangerously_set_start_time(self): counter0 = metrics.CounterMetric('counter0', 'desc0', [metrics.IntegerField('test')]) interface.register(counter0) counter0.increment_by(3, {'test': 123}) counter0.increment_by(3, {'test': 456}) counter0.dangerously_set_start_time(1000) proto = list(interface._generate_proto())[0] data_set = proto.metrics_collection[0].metrics_data_set[0] for d in data_set.data: self.assertEqual(1000, d.start_timestamp.seconds) counter0.dangerously_set_start_time(2000) proto = list(interface._generate_proto())[0] data_set = proto.metrics_collection[0].metrics_data_set[0] for d in data_set.data: self.assertEqual(2000, d.start_timestamp.seconds)
def test_flush(self): interface.state.global_monitor = stubs.MockMonitor() interface.state.target = stubs.MockTarget() # pylint: disable=unused-argument def serialize_to(pb, start_time, fields, value, target): pb.data.add().name = 'foo' fake_metric = mock.create_autospec(metrics.Metric, spec_set=True) fake_metric.name = 'fake' fake_metric.serialize_to.side_effect = serialize_to interface.register(fake_metric) interface.state.store.set('fake', (), 123) interface.flush() interface.state.global_monitor.send.assert_called_once() proto = interface.state.global_monitor.send.call_args[0][0] self.assertEqual(1, len(proto.data)) self.assertEqual('foo', proto.data[0].name)
def __init__(self, name, fields=None, description=None): """Create an instance of a Metric. Args: name (str): the file-like name of this metric fields (dict): a set of key-value pairs to be set as default metric fields description (string): help string for the metric. Should be enough to know what the metric is about. """ self._name = name.lstrip('/') self._start_time = None fields = fields or {} if len(fields) > 7: raise errors.MonitoringTooManyFieldsError(self._name, fields) self._fields = fields self._normalized_fields = self._normalize_fields(self._fields) self._description = description interface.register(self)
def test_flush(self): interface.state.global_monitor = stubs.MockMonitor() interface.state.target = stubs.MockTarget() # pylint: disable=unused-argument def serialize_to(pb, start_time, fields, value, target): pb.data.add().name = 'foo' fake_metric = mock.create_autospec(metrics.Metric, spec_set=True) fake_metric.name = 'fake' fake_metric.serialize_to.side_effect = serialize_to interface.register(fake_metric) interface.state.store.set('fake', (), None, 123) interface.flush() interface.state.global_monitor.send.assert_called_once() proto = interface.state.global_monitor.send.call_args[0][0] self.assertEqual(1, len(proto.data)) self.assertEqual('foo', proto.data[0].name)
def _test_distribution_proto(self, dist): interface.register(dist) self.time_fn.return_value = 100.3 for num in [0, 1, 5, 5.5, 9, 10, 10000]: dist.add(num) self.time_fn.return_value = 1000.6 proto = list(interface._generate_proto())[0] data_set = proto.metrics_collection[0].metrics_data_set[0] data = data_set.data[0] self.assertAlmostEqual(1432.928571428, data.distribution_value.mean) self.assertEqual(metrics_pb2.DISTRIBUTION, data_set.value_type) self.assertEqual(100, data.start_timestamp.seconds) self.assertEqual(1000, data.end_timestamp.seconds) self.assertFalse(data_set.annotations.HasField('unit')) return data_set, data
def __init__(self, name, description, field_spec, units=None): """Create an instance of a Metric. Args: name (str): the file-like name of this metric description (string): help string for the metric. Should be enough to know what the metric is about. field_spec (list): a list of Field subclasses to define the fields that are allowed on this metric. Pass a list of either StringField, IntegerField or BooleanField here. units (string): the unit used to measure data for given metric. Some common units are pre-defined in the MetricsDataUnits class. """ field_spec = field_spec or [] self._name = name.lstrip('/') if not isinstance(description, basestring): raise errors.MetricDefinitionError( 'Metric description must be a string') if not description: raise errors.MetricDefinitionError( 'Metric must have a description') if (not isinstance(field_spec, (list, tuple)) or any(not isinstance(x, Field) for x in field_spec)): raise errors.MetricDefinitionError( 'Metric constructor takes a list of Fields, or None') if len(field_spec) > 7: raise errors.MonitoringTooManyFieldsError(self._name, field_spec) self._start_time = None self._field_spec = field_spec self._sorted_field_names = sorted(x.name for x in field_spec) self._description = description self._units = units interface.register(self)
def __init__(self, name, fields=None, description=None, units=None): """Create an instance of a Metric. Args: name (str): the file-like name of this metric fields (dict): a set of key-value pairs to be set as default metric fields description (string): help string for the metric. Should be enough to know what the metric is about. units (int): the unit used to measure data for given metric. Please use the attributes of MetricDataUnit to find valid integer values for this argument. """ self._name = name.lstrip('/') self._start_time = None fields = fields or {} if len(fields) > 7: raise errors.MonitoringTooManyFieldsError(self._name, fields) self._fields = fields self._normalized_fields = self._normalize_fields(self._fields) self._description = description self._units = units interface.register(self)
def test_grouping(self): counter0 = metrics.CounterMetric('counter0', 'desc0', [metrics.IntegerField('test')]) counter1 = metrics.CounterMetric('counter1', 'desc1', None) counter2 = metrics.CounterMetric('counter2', 'desc2', None) interface.register(counter0) interface.register(counter1) interface.register(counter2) counter0.increment_by(3, {'test': 123}) counter0.increment_by(5, {'test': 999}) counter1.increment() counter2.increment_by(4, target_fields={'task_num': 1}) protos = list(interface._generate_proto()) self.assertEqual(1, len(protos)) proto = protos[0] self.assertEqual(2, len(proto.metrics_collection)) for coll in proto.metrics_collection: self.assertEqual('service', coll.task.service_name) self.assertEqual('job', coll.task.job_name) self.assertEqual('region', coll.task.data_center) self.assertEqual('hostname', coll.task.host_name) first_coll = proto.metrics_collection[0] second_coll = proto.metrics_collection[1] self.assertEqual(0, first_coll.task.task_num) self.assertEqual(1, second_coll.task.task_num) self.assertEqual(2, len(first_coll.metrics_data_set)) self.assertEqual(1, len(second_coll.metrics_data_set)) data_sets = [ first_coll.metrics_data_set[0], first_coll.metrics_data_set[1], second_coll.metrics_data_set[0] ] for i, data_set in enumerate(data_sets): self.assertEqual('/infra/test/counter%d' % i, data_set.metric_name)
def test_identical_register(self): fake_metric = mock.Mock(_name='foo') interface.register(fake_metric) interface.register(fake_metric) self.assertEqual(1, len(interface.state.metrics))