Esempio n. 1
0
def as_metric_with_inferred_type(value):
    # type: (Any) -> Optional[MetricDefinition]
    if is_counter(value):
        return {'type': 'rate', 'value': int(value)}

    if is_gauge(value):
        return {'type': 'gauge', 'value': int(value)}

    if is_opaque(value):
        # Arbitrary ASN.1 syntax encoded as an octet string. Let's try to decode it as a float.
        # See: http://snmplabs.com/pysnmp/docs/api-reference.html#opaque-type
        try:
            decoded, _ = pyasn1_decode(bytes(value))
            value = float(decoded)
        except Exception:
            pass
        else:
            return {'type': 'gauge', 'value': value}

    # Fallback for unknown SNMP types.
    try:
        number = float(value)
    except ValueError:
        return None
    else:
        return {'type': 'gauge', 'value': number}
Esempio n. 2
0
def as_metric_with_inferred_type(value):
    # type: (Any) -> Optional[MetricDefinition]

    # Ugly hack but couldn't find a cleaner way. Proper way would be to use the ASN.1
    # method `.isSameTypeWith()`, or at least `isinstance()`.
    # But these wrongfully return `True` in some cases, eg:
    # ```python
    # >>> from pysnmp.proto.rfc1902 import Counter64
    # >>> from datadog_checks.snmp.pysnmp_types import CounterBasedGauge64
    # >>> issubclass(CounterBasedGauge64, Counter64)
    # True  # <-- WRONG! (CounterBasedGauge64 values are gauges, not counters.)
    # ````

    pysnmp_class_name = value.__class__.__name__

    if pysnmp_class_name in SNMP_COUNTER_CLASSES:
        return {'type': 'rate', 'value': int(value)}

    if pysnmp_class_name in SNMP_GAUGE_CLASSES:
        return {'type': 'gauge', 'value': int(value)}

    if pysnmp_class_name == 'Opaque':
        # Arbitrary ASN.1 syntax encoded as an octet string. Let's try to decode it as a float.
        # See: http://snmplabs.com/pysnmp/docs/api-reference.html#opaque-type
        try:
            decoded, _ = pyasn1_decode(bytes(value))
            value = float(decoded)
        except Exception:
            pass
        else:
            return {'type': 'gauge', 'value': value}

    # Fallback for unknown SNMP types.
    try:
        number = float(value)
    except ValueError:
        return None
    else:
        return {'type': 'gauge', 'value': number}
Esempio n. 3
0
    def submit_metric(self, name, snmp_value, forced_type, tags):
        # type: (str, Any, Optional[str], List[str]) -> None
        """
        Convert the values reported as pysnmp-Managed Objects to values and
        report them to the aggregator.
        """
        if reply_invalid(snmp_value):
            # Metrics not present in the queried object
            self.log.warning('No such Mib available: %s', name)
            return

        metric_name = self.normalize(name, prefix='snmp')

        value = 0.0  # type: float

        if forced_type:
            forced_type = forced_type.lower()
            if forced_type == 'gauge':
                value = int(snmp_value)
                self.gauge(metric_name, value, tags)
            elif forced_type == 'percent':
                value = total_time_to_temporal_percent(int(snmp_value),
                                                       scale=1)
                self.rate(metric_name, value, tags)
            elif forced_type == 'counter':
                value = int(snmp_value)
                self.rate(metric_name, value, tags)
            elif forced_type == 'monotonic_count':
                value = int(snmp_value)
                self.monotonic_count(metric_name, value, tags)
            else:
                self.warning('Invalid forced-type specified: %s in %s',
                             forced_type, name)
                raise ConfigurationError(
                    'Invalid forced-type in config file: {}'.format(name))
            return

        # Ugly hack but couldn't find a cleaner way
        # Proper way would be to use the ASN1 method isSameTypeWith but it
        # wrongfully returns True in the case of CounterBasedGauge64
        # and Counter64 for example
        snmp_class = snmp_value.__class__.__name__
        if snmp_class in SNMP_COUNTERS:
            value = int(snmp_value)
            self.rate(metric_name, value, tags)
            return
        if snmp_class in SNMP_GAUGES:
            value = int(snmp_value)
            self.gauge(metric_name, value, tags)
            return

        if snmp_class == 'Opaque':
            # Try support for floats
            try:
                value = float(pyasn1_decode(bytes(snmp_value))[0])
            except Exception:
                pass
            else:
                self.gauge(metric_name, value, tags)
                return

        # Falls back to try to cast the value.
        try:
            value = float(snmp_value)
        except ValueError:
            pass
        else:
            self.gauge(metric_name, value, tags)
            return

        self.log.warning('Unsupported metric type %s for %s', snmp_class,
                         metric_name)