def evaluate_rule(rule, alerts):
    """
    Evaluates the current status of a single rule and posts events if
    necessary.
    """
    _logger.debug("evaluating rule %r", rule)

    evaluator = rule.get_evaluator()
    try:
        if not evaluator.get_values():
            _logger.warning(
                "did not find any matching values for rule %r %s",
                rule.target, rule.alert
            )
    except Exception:
        _logger.exception(
            "Unhandled exception while getting values for rule: %r", rule
        )
        return

    # post new exceed events
    try:
        exceeded = evaluator.evaluate(rule.alert)
    except Exception:
        _logger.exception("Unhandled exception while evaluating rule alert: %r",
                          rule)
        return

    for metric, value in exceeded:
        alert = alerts.get(rule.id, {}).get(metric, None)
        _logger.info("%s: %s %s (=%s)",
                     "old" if alert else "new", metric, rule.alert, value)
        if not alert:
            start_event(rule, metric, value)

    # try to clear any existing threshold alerts
    if rule.id in alerts:
        clearable = alerts[rule.id]
        try:
            if rule.clear:
                cleared = evaluator.evaluate(rule.clear)
            else:
                cleared = evaluator.evaluate(rule.alert, invert=True)
        except Exception:
            _logger.exception(
                "Unhandled exception while evaluating rule clear: %r", rule)
            return

        for metric, value in cleared:
            if metric in clearable:
                _logger.info("cleared: %s %s (=%s)",
                             metric, rule.clear, value)
                end_event(rule, metric, value)