All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.opentelemetry.instrumentation.jmx.engine.MetricRegistrar Maven / Gradle / Ivy

/*
 * Copyright The OpenTelemetry Authors
 * SPDX-License-Identifier: Apache-2.0
 */

package io.opentelemetry.instrumentation.jmx.engine;

import static java.util.logging.Level.INFO;

import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.api.metrics.DoubleGaugeBuilder;
import io.opentelemetry.api.metrics.LongCounterBuilder;
import io.opentelemetry.api.metrics.LongUpDownCounterBuilder;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.ObservableDoubleMeasurement;
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
import java.util.Collection;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.logging.Logger;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;

/** A class responsible for maintaining the set of metrics to collect and report. */
class MetricRegistrar {

  private static final Logger logger = Logger.getLogger(MetricRegistrar.class.getName());

  private final Meter meter;

  MetricRegistrar(OpenTelemetry openTelemetry, String instrumentationScope) {
    meter = openTelemetry.getMeter(instrumentationScope);
  }

  /**
   * Accepts a MetricExtractor for registration and activation.
   *
   * @param connection the {@link MBeanServerConnection} to use to query for metric values
   * @param objectNames the {@link ObjectName} that are known to the server and that know the
   *     attribute that is required to get the metric values
   * @param extractor the {@link MetricExtractor} responsible for getting the metric values
   * @param attributeInfo the {@link AttributeInfo}
   */
  void enrollExtractor(
      MBeanServerConnection connection,
      Collection objectNames,
      MetricExtractor extractor,
      AttributeInfo attributeInfo) {
    // For the first enrollment of the extractor we have to build the corresponding Instrument
    DetectionStatus status = new DetectionStatus(connection, objectNames);
    boolean firstEnrollment;
    synchronized (extractor) {
      firstEnrollment = extractor.getStatus() == null;
      // For successive enrollments, it is sufficient to refresh the status
      extractor.setStatus(status);
    }

    if (!firstEnrollment) {
      return;
    }

    MetricInfo metricInfo = extractor.getInfo();
    String metricName = metricInfo.getMetricName();
    MetricInfo.Type instrumentType = metricInfo.getType();
    String description =
        metricInfo.getDescription() != null
            ? metricInfo.getDescription()
            : attributeInfo.getDescription();
    String unit = metricInfo.getUnit();

    switch (instrumentType) {
        // CHECKSTYLE:OFF
      case COUNTER:
        {
          // CHECKSTYLE:ON
          LongCounterBuilder builder = meter.counterBuilder(metricName);
          Optional.ofNullable(description).ifPresent(builder::setDescription);
          Optional.ofNullable(unit).ifPresent(builder::setUnit);

          if (attributeInfo.usesDoubleValues()) {
            builder.ofDoubles().buildWithCallback(doubleTypeCallback(extractor));
          } else {
            builder.buildWithCallback(longTypeCallback(extractor));
          }
          logger.log(INFO, "Created Counter for {0}", metricName);
        }
        break;

        // CHECKSTYLE:OFF
      case UPDOWNCOUNTER:
        {
          // CHECKSTYLE:ON
          LongUpDownCounterBuilder builder = meter.upDownCounterBuilder(metricName);
          Optional.ofNullable(description).ifPresent(builder::setDescription);
          Optional.ofNullable(unit).ifPresent(builder::setUnit);

          if (attributeInfo.usesDoubleValues()) {
            builder.ofDoubles().buildWithCallback(doubleTypeCallback(extractor));
          } else {
            builder.buildWithCallback(longTypeCallback(extractor));
          }
          logger.log(INFO, "Created UpDownCounter for {0}", metricName);
        }
        break;

        // CHECKSTYLE:OFF
      case GAUGE:
        {
          // CHECKSTYLE:ON
          DoubleGaugeBuilder builder = meter.gaugeBuilder(metricName);
          Optional.ofNullable(description).ifPresent(builder::setDescription);
          Optional.ofNullable(unit).ifPresent(builder::setUnit);

          if (attributeInfo.usesDoubleValues()) {
            builder.buildWithCallback(doubleTypeCallback(extractor));
          } else {
            builder.ofLongs().buildWithCallback(longTypeCallback(extractor));
          }
          logger.log(INFO, "Created Gauge for {0}", metricName);
        }
        break;
        // CHECKSTYLE:OFF
      case STATE:
        {
          // CHECKSTYLE:ON
          throw new IllegalStateException("state metrics should not be registered");
        }
    }
  }

  /*
   * A method generating metric collection callback for asynchronous Measurement
   * of Double type.
   */
  static Consumer doubleTypeCallback(MetricExtractor extractor) {
    return measurement -> {
      DetectionStatus status = extractor.getStatus();
      if (status != null) {
        MBeanServerConnection connection = status.getConnection();
        for (ObjectName objectName : status.getObjectNames()) {
          Number metricValue =
              extractor.getMetricValueExtractor().extractNumericalAttribute(connection, objectName);
          if (metricValue != null) {
            // get the metric attributes
            Attributes attr = createMetricAttributes(connection, objectName, extractor);
            measurement.record(metricValue.doubleValue(), attr);
          }
        }
      }
    };
  }

  /*
   * A method generating metric collection callback for asynchronous Measurement
   * of Long type.
   */
  static Consumer longTypeCallback(MetricExtractor extractor) {
    return measurement -> {
      DetectionStatus status = extractor.getStatus();
      if (status != null) {
        MBeanServerConnection connection = status.getConnection();
        for (ObjectName objectName : status.getObjectNames()) {
          Number metricValue =
              extractor.getMetricValueExtractor().extractNumericalAttribute(connection, objectName);
          if (metricValue != null) {
            // get the metric attributes
            Attributes attr = createMetricAttributes(connection, objectName, extractor);
            measurement.record(metricValue.longValue(), attr);
          }
        }
      }
    };
  }

  /*
   * An auxiliary method for collecting measurement attributes to go along
   * the metric values
   */
  static Attributes createMetricAttributes(
      MBeanServerConnection connection, ObjectName objectName, MetricExtractor extractor) {
    AttributesBuilder attrBuilder = Attributes.builder();
    for (MetricAttribute metricAttribute : extractor.getAttributes()) {
      String attributeValue = metricAttribute.acquireAttributeValue(connection, objectName);
      if (attributeValue != null) {
        attrBuilder = attrBuilder.put(metricAttribute.getAttributeName(), attributeValue);
      }
    }
    return attrBuilder.build();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy