예제 #1
0
    def test_add_notification_channels(
        self,
        client,
        monitored_entity,
        created_entities,
    ):
        alerts = monitored_entity.alerts
        name = _utils.generate_default_name()
        alerter = FixedAlerter(comparison.GreaterThan(0.7))
        sample_query = SummarySampleQuery()

        channel1 = client.operations.notification_channels.create(
            _utils.generate_default_name(),
            SlackNotificationChannel(_utils.generate_default_name()),
        )
        created_entities.append(channel1)
        channel2 = client.operations.notification_channels.create(
            _utils.generate_default_name(),
            SlackNotificationChannel(_utils.generate_default_name()),
        )
        created_entities.append(channel2)

        alert = alerts.create(
            name,
            alerter,
            sample_query,
            notification_channels=[channel1],
        )
        retrieved_channel_ids = alert._msg.notification_channels.keys()
        assert set(retrieved_channel_ids) == {channel1.id}

        alert.add_notification_channels([channel2])
        alert._refresh_cache()
        retrieved_channel_ids = alert._msg.notification_channels.keys()
        assert set(retrieved_channel_ids) == {channel1.id, channel2.id}
예제 #2
0
    def test_crud(self, client, monitored_entity, summary_sample):
        alerts = monitored_entity.alerts
        name = _utils.generate_default_name()
        alerter = ReferenceAlerter(comparison.GreaterThan(0.7), summary_sample)
        sample_query = SummarySampleQuery()

        created_alert = alerts.create(name, alerter, sample_query)
        assert isinstance(created_alert, _entities.Alert)
        assert created_alert._msg.alerter_type == alerter._TYPE
        assert created_alert.monitored_entity_id == monitored_entity.id

        retrieved_alert = alerts.get(id=created_alert.id)
        client_retrieved_alert = client.operations.alerts.get(
            id=created_alert.id)
        assert retrieved_alert.id == client_retrieved_alert.id
        assert isinstance(retrieved_alert, _entities.Alert)
        assert retrieved_alert._msg.alerter_type == alerter._TYPE
        assert retrieved_alert.alerter._as_proto() == alerter._as_proto()
        assert retrieved_alert.alerter._reference_sample_id == summary_sample.id

        listed_alerts = alerts.list()
        assert created_alert.id in map(lambda a: a.id, listed_alerts)
        client_listed_alerts = client.operations.alerts.list()
        assert created_alert.id in map(lambda a: a.id, client_listed_alerts)

        assert alerts.delete([created_alert])
예제 #3
0
    def test_summary_sample_query(self, monitored_entity):
        alerts = monitored_entity.alerts
        name = _utils.generate_default_name()
        alerter = FixedAlerter(comparison.GreaterThan(0.7))
        sample_query = SummarySampleQuery()

        alert = alerts.create(name, alerter, sample_query)
        created_query_proto = alerts._combine_query_with_default_summary(
            sample_query)._to_proto_request()
        retrieved_query_proto = alert.summary_sample_query._to_proto_request()
        assert created_query_proto == retrieved_query_proto
예제 #4
0
    def test_repr(self, monitored_entity, created_entities, summary_sample):
        """__repr__() does not raise exceptions"""
        alerts = monitored_entity.alerts
        name = _utils.generate_default_name()
        alerter = ReferenceAlerter(comparison.GreaterThan(0.7), summary_sample)
        sample_query = SummarySampleQuery()

        created_alert = alerts.create(name, alerter, sample_query)
        assert repr(created_alert)

        retrieved_alert = alerts.get(id=created_alert.id)
        assert repr(retrieved_alert)
예제 #5
0
    def test_creation_datetime(self):
        time_window_start = time_utils.now() - datetime.timedelta(weeks=1)
        time_window_end = time_utils.now() - datetime.timedelta(days=1)
        created_after = time_utils.now() - datetime.timedelta(hours=1)
        time_window_start_millis = time_utils.epoch_millis(time_window_start)
        time_window_end_millis = time_utils.epoch_millis(time_window_end)
        created_after_millis = time_utils.epoch_millis(created_after)

        # as datetime
        sample_query = SummarySampleQuery(
            time_window_start=time_window_start,
            time_window_end=time_window_end,
            created_after=created_after,
        )
        proto_request = sample_query._to_proto_request()
        assert (proto_request.filter.time_window_start_at_millis ==
                time_window_start_millis)
        assert proto_request.filter.time_window_end_at_millis == time_window_end_millis
        assert proto_request.filter.created_at_after_millis == created_after_millis

        # as millis
        sample_query = SummarySampleQuery(
            time_window_start=time_window_start_millis,
            time_window_end=time_window_end_millis,
            created_after=created_after_millis,
        )
        proto_request = sample_query._to_proto_request()
        assert (proto_request.filter.time_window_start_at_millis ==
                time_window_start_millis)
        assert proto_request.filter.time_window_end_at_millis == time_window_end_millis
        assert proto_request.filter.created_at_after_millis == created_after_millis
예제 #6
0
    def test_set_status(self, monitored_entity, summary_sample):
        alerts = monitored_entity.alerts
        name = _utils.generate_default_name()
        alerter = FixedAlerter(comparison.GreaterThan(0.7))
        sample_query = SummarySampleQuery()

        alert = alerts.create(name, alerter, sample_query)
        assert alert.status == Ok()
        assert alert._last_evaluated_or_created_millis == alert._msg.created_at_millis

        alert.set_status(Alerting([summary_sample]))
        assert alert.status == Alerting([summary_sample])
        assert (alert._last_evaluated_or_created_millis ==
                alert._msg.last_evaluated_at_millis)

        alert.set_status(Ok())
        assert alert.status == Ok()
예제 #7
0
    def test_update_last_evaluated_at(self, monitored_entity,
                                      created_entities):
        alerts = monitored_entity.alerts
        name = _utils.generate_default_name()
        alerter = FixedAlerter(comparison.GreaterThan(0.7))
        sample_query = SummarySampleQuery()

        alert = alerts.create(name, alerter, sample_query)
        alert._fetch_with_no_cache()
        initial = alert._msg.last_evaluated_at_millis

        alert._update_last_evaluated_at()
        alert._fetch_with_no_cache()
        assert alert._msg.last_evaluated_at_millis > initial

        yesterday = time_utils.now() - datetime.timedelta(days=1)
        yesterday_millis = time_utils.epoch_millis(yesterday)
        # TODO: remove following line when backend stops round to nearest sec
        yesterday_millis = round(yesterday_millis, -3)
        alert._update_last_evaluated_at(yesterday)
        alert._fetch_with_no_cache()
        assert alert._msg.last_evaluated_at_millis == yesterday_millis
예제 #8
0
    def test_creation_datetime(self, monitored_entity, strs, created_entities):
        strs = iter(strs)
        alerts = monitored_entity.alerts
        alerter = FixedAlerter(comparison.GreaterThan(0.7))
        sample_query = SummarySampleQuery()

        created_at = time_utils.now() - datetime.timedelta(weeks=1)
        updated_at = time_utils.now() - datetime.timedelta(days=1)
        last_evaluated_at = time_utils.now() - datetime.timedelta(hours=1)
        created_at_millis = time_utils.epoch_millis(created_at)
        updated_at_millis = time_utils.epoch_millis(updated_at)
        last_evaluated_at_millis = time_utils.epoch_millis(last_evaluated_at)

        # as datetime
        alert = alerts.create(
            next(strs),
            alerter,
            sample_query,
            created_at=created_at,
            updated_at=updated_at,
            last_evaluated_at=last_evaluated_at,
        )
        assert alert._msg.created_at_millis == created_at_millis
        assert alert._msg.updated_at_millis == updated_at_millis
        assert alert._msg.last_evaluated_at_millis == last_evaluated_at_millis

        # as millis
        alert = alerts.create(
            next(strs),
            alerter,
            sample_query,
            created_at=created_at_millis,
            updated_at=updated_at_millis,
            last_evaluated_at=last_evaluated_at_millis,
        )
        assert alert._msg.created_at_millis == created_at_millis
        assert alert._msg.updated_at_millis == updated_at_millis
        assert alert._msg.last_evaluated_at_millis == last_evaluated_at_millis
예제 #9
0
    def test_creation_query_params(self, summary):
        """`labels` and `starting_from`"""
        name = _utils.generate_default_name()
        alerter = FixedAlerter(comparison.GreaterThan(0.7))
        labels = {"datasource": ["census2010", "census2020"]}
        starting_from = datetime.datetime(year=2021,
                                          month=5,
                                          day=10,
                                          tzinfo=time_utils.utc)

        alert = summary.alerts.create(
            name,
            alerter,
            labels=labels,
            starting_from=starting_from,
        )
        expected_sample_query = SummarySampleQuery(
            summary_query=summary.alerts._build_summary_query(),
            labels=labels,
            time_window_end=starting_from,
        )

        assert alert.summary_sample_query == expected_sample_query
예제 #10
0
파일: alert.py 프로젝트: jchristov/modeldb
    def create(
        self,
        name,
        alerter,
        summary_sample_query=None,
        notification_channels=None,
        created_at=None,
        updated_at=None,
        last_evaluated_at=None,
    ):
        """
        Create a new alert.

        Parameters
        ----------
        name : str
            A unique name for this alert.
        alerter : :class:`~verta.operations.monitoring.alert._Alerter`
            The configuration for this alert.
        summary_sample_query : :class:`~verta.operations.monitoring.summaries.SummarySampleQuery`, optional
            Summary samples for this alert to monitor for threshold violations.
        notification_channels : list of :class:`~verta.operations.monitoring.notification_channel._entities.NotificationChannel`, optional
            Channels for this alert to propagate notifications to.
        created_at : datetime.datetime or int, optional
            An override creation time to assign to this alert. Either a
            timezone aware datetime object or unix epoch milliseconds.
        updated_at : datetime.datetime or int, optional
            An override update time to assign to this alert. Either a
            timezone aware datetime object or unix epoch milliseconds.
        last_evaluated_at : datetime.datetime or int, optional
            An override evaluation time to assign to this alert. Either a
            timezone aware datetime object or unix epoch milliseconds.

        Returns
        -------
        :class:`Alert`
            Alert.

        Examples
        --------
        .. code-block:: python

            alert = monitored_entity.alerts.create(
                name="MSE",
                alerter=alerter,
                summary_sample_query=sample_query,
                notification_channels=[channel],
            )

        """
        if self._monitored_entity_id is None:
            raise RuntimeError(
                "this Alert cannot be used to create because it was not"
                " obtained via monitored_entity.alerts")

        summary_sample_query = (copy.copy(summary_sample_query) if
                                summary_sample_query else SummarySampleQuery())
        summary_query = self._build_summary_query()
        if summary_query:
            summary_sample_query.summary_query = summary_query

        if notification_channels is None:
            notification_channels = []
        for channel in notification_channels:
            Alert._validate_notification_channel(channel)

        ctx = _Context(self._conn, self._conf)
        return Alert._create(
            self._conn,
            self._conf,
            ctx,
            name=name,
            monitored_entity_id=self._monitored_entity_id,
            alerter=alerter,
            summary_sample_query=summary_sample_query,
            notification_channels=notification_channels,
            created_at_millis=time_utils.epoch_millis(created_at),
            updated_at_millis=time_utils.epoch_millis(updated_at),
            last_evaluated_at_millis=time_utils.epoch_millis(
                last_evaluated_at),
        )
예제 #11
0
파일: alert.py 프로젝트: jchristov/modeldb
    def summary_sample_query(self):
        self._refresh_cache()

        return SummarySampleQuery._from_proto_request(
            self._msg.sample_find_base, )
예제 #12
0
    def test_summary_labels(self, client):
        pytest.importorskip("scipy")

        summaries = client.operations.summaries

        monitored_entity = client.operations.get_or_create_monitored_entity()
        summary_name = "summary_v2_{}".format(generate_default_name())
        summary = summaries.create(summary_name, data_types.DiscreteHistogram,
                                   monitored_entity)

        assert isinstance(summary, Summary)

        summaries_for_monitored_entity = SummaryQuery(
            monitored_entities=[monitored_entity])
        retrieved_summaries = summaries.find(summaries_for_monitored_entity)
        assert len(retrieved_summaries) > 0
        for s in retrieved_summaries:
            assert isinstance(s, Summary)

        now = time_utils.now()
        yesterday = now - timedelta(days=1)

        discrete_histogram = data_types.DiscreteHistogram(
            buckets=["hotdog", "not hotdog"], data=[100, 20])
        labels = {"env": "test", "color": "blue"}
        summary_sample = summary.log_sample(
            discrete_histogram,
            labels=labels,
            time_window_start=yesterday,
            time_window_end=now,
        )
        assert isinstance(summary_sample, SummarySample)

        float_histogram = data_types.FloatHistogram(
            bucket_limits=[1, 13, 25, 37, 49, 61],
            data=[15, 53, 91, 34, 7],
        )
        labels2 = {"env": "test", "color": "red"}
        with pytest.raises(TypeError):
            summary_sample_2 = summary.log_sample(
                float_histogram,
                labels=labels2,
                time_window_start=yesterday,
                time_window_end=now,
            )

        labels = client.operations.labels

        retrieved_label_keys = labels.find_keys(
            summary_query=summaries_for_monitored_entity)
        assert len(retrieved_label_keys) > 0

        if retrieved_label_keys:
            retrieved_labels = labels.find_values(
                summary_query=summaries_for_monitored_entity,
                keys=retrieved_label_keys)
            for key in retrieved_label_keys:
                assert key in retrieved_labels

        all_samples_for_summary = summary.find_samples()
        assert len(all_samples_for_summary) == 1

        blue_samples = summary.find_samples(
            SummarySampleQuery(labels={"color": ["blue"]}), )
        assert len(blue_samples) == 1
예제 #13
0
    def create(
        self,
        name,
        alerter,
        notification_channels=None,
        labels=None,
        starting_from=None,
        _created_at=None,
        _updated_at=None,
        _last_evaluated_at=None,
    ):
        """
        Create a new alert.

        Parameters
        ----------
        name : str
            A unique name for this alert.
        alerter : :class:`~verta.operations.monitoring.alert._Alerter`
            The configuration for this alert.
        notification_channels : list of :class:`~verta.operations.monitoring.notification_channel._entities.NotificationChannel`, optional
            Channels for this alert to propagate notifications to.
        labels : dict of str to list of str, optional
            Alert on samples that have at least one of these labels. A mapping
            between label keys and lists of corresponding label values.
        starting_from : datetime.datetime or int, optional
            Alert on samples associated with periods after this time; useful
            for monitoring samples representing past data. Either a timezone
            aware datetime object or unix epoch milliseconds.

        Returns
        -------
        :class:`Alert`
            Alert.

        Examples
        --------
        .. code-block:: python

            alert = summary.alerts.create(
                name="MSE",
                alerter=alerter,
                notification_channels=[channel],
            )

        """
        if self._summary is None:
            raise RuntimeError(
                "this Alert cannot be used to create because it was not"
                " obtained via summary.alerts")

        summary_sample_query = SummarySampleQuery(
            summary_query=self._build_summary_query(),
            labels=labels,
            time_window_end=time_utils.epoch_millis(starting_from),
        )

        if notification_channels is None:
            notification_channels = []
        for channel in notification_channels:
            Alert._validate_notification_channel(channel)

        ctx = _Context(self._conn, self._conf)
        return Alert._create(
            self._conn,
            self._conf,
            ctx,
            name=name,
            monitored_entity_id=(self._monitored_entity_id
                                 or self._summary.monitored_entity_id),
            alerter=alerter,
            summary_sample_query=summary_sample_query,
            notification_channels=notification_channels,
            created_at_millis=time_utils.epoch_millis(_created_at),
            updated_at_millis=time_utils.epoch_millis(_updated_at),
            last_evaluated_at_millis=time_utils.epoch_millis(
                _last_evaluated_at),
        )