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

org.apache.rocketmq.shaded.io.opentelemetry.sdk.metrics.internal.state.TemporalMetricStorage Maven / Gradle / Ivy

There is a newer version: 5.0.7
Show newest version
/*
 * Copyright The OpenTelemetry Authors
 * SPDX-License-Identifier: Apache-2.0
 */

package org.apache.rocketmq.shaded.io.opentelemetry.sdk.metrics.internal.state;

import org.apache.rocketmq.shaded.io.opentelemetry.api.common.Attributes;
import org.apache.rocketmq.shaded.io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import org.apache.rocketmq.shaded.io.opentelemetry.sdk.metrics.data.AggregationTemporality;
import org.apache.rocketmq.shaded.io.opentelemetry.sdk.metrics.data.ExemplarData;
import org.apache.rocketmq.shaded.io.opentelemetry.sdk.metrics.data.MetricData;
import org.apache.rocketmq.shaded.io.opentelemetry.sdk.metrics.internal.aggregator.Aggregator;
import org.apache.rocketmq.shaded.io.opentelemetry.sdk.metrics.internal.aggregator.EmptyMetricData;
import org.apache.rocketmq.shaded.io.opentelemetry.sdk.metrics.internal.descriptor.MetricDescriptor;
import org.apache.rocketmq.shaded.io.opentelemetry.sdk.metrics.internal.export.CollectionHandle;
import org.apache.rocketmq.shaded.io.opentelemetry.sdk.resources.Resource;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.concurrent.ThreadSafe;

/** Stores last reported time and (optional) accumulation for metrics. */
@ThreadSafe
class TemporalMetricStorage {
  private final Aggregator aggregator;
  private final boolean isSynchronous;
  private final Map> reportHistory = new HashMap<>();

  TemporalMetricStorage(Aggregator aggregator, boolean isSynchronous) {
    this.aggregator = aggregator;
    this.isSynchronous = isSynchronous;
  }

  /**
   * Builds the {@link MetricData} streams to report against a specific metric reader.
   *
   * @param collector The handle of the metric reader.
   * @param resource The resource to attach these metrics against.
   * @param instrumentationScopeInfo The instrumentation scope that generated these metrics.
   * @param temporality The aggregation temporality requested by the reader.
   * @param currentAccumulation THe current accumulation of metric data from instruments. This might
   *     be delta (for synchronous) or cumulative (for asynchronous).
   * @param startEpochNanos The timestamp when the metrics SDK started.
   * @param epochNanos The current collection timestamp.
   * @return The {@link MetricData} points.
   */
  synchronized MetricData buildMetricFor(
      CollectionHandle collector,
      Resource resource,
      InstrumentationScopeInfo instrumentationScopeInfo,
      MetricDescriptor descriptor,
      // Temporality is requested by the collector.
      AggregationTemporality temporality,
      Map currentAccumulation,
      long startEpochNanos,
      long epochNanos) {
    // In case it's our first collection, default to start timestamp.
    long lastCollectionEpoch = startEpochNanos;
    Map result = currentAccumulation;
    // Check our last report time.
    if (reportHistory.containsKey(collector)) {
      LastReportedAccumulation last = reportHistory.get(collector);
      lastCollectionEpoch = last.getEpochNanos();
      // Use aggregation temporality + instrument to determine if we do a merge or a diff of
      // previous.  We have the following four scenarios:
      // 1. Delta Aggregation (temporality) + Cumulative recording (async instrument).
      //    Here we diff with last cumulative to get a delta.
      // 2. Cumulative Aggregation + Delta recording (sync instrument).
      //    Here we merge with our last record to get a cumulative aggregation.
      // 3. Cumulative Aggregation + Cumulative recording - do nothing
      // 4. Delta Aggregation + Delta recording - do nothing.
      if (temporality == AggregationTemporality.DELTA && !isSynchronous) {
        MetricStorageUtils.diffInPlace(last.getAccumulation(), currentAccumulation, aggregator);
        result = last.getAccumulation();
      } else if (temporality == AggregationTemporality.CUMULATIVE && isSynchronous) {
        // We need to make sure the current delta recording gets merged into the previous cumulative
        // for the next cumulative measurement.
        MetricStorageUtils.mergeAndPreserveInPlace(
            last.getAccumulation(), currentAccumulation, aggregator);
        // Note: We allow going over our hard limit on attribute streams when first merging, but
        // preserve after this point.
        if (last.getAccumulation().size() > MetricStorageUtils.MAX_ACCUMULATIONS) {
          MetricStorageUtils.removeUnseen(last.getAccumulation(), currentAccumulation);
        }
        result = last.getAccumulation();
      }
    }
    // Update last reported (cumulative) accumulation.
    // For synchronous instruments, we need the merge result.
    // For asynchronous instruments, we need the recorded value.
    // This assumes aggregation remains consistent for the lifetime of a collector, and
    // could be optimised to not record results for cases 3+4 listed above.
    if (isSynchronous) {
      // Sync instruments remember the full recording.
      reportHistory.put(collector, new LastReportedAccumulation<>(result, epochNanos));
    } else {
      // Async instruments record the raw measurement.
      reportHistory.put(collector, new LastReportedAccumulation<>(currentAccumulation, epochNanos));
    }
    if (result.isEmpty()) {
      return EmptyMetricData.getInstance();
    }
    return aggregator.toMetricData(
        resource,
        instrumentationScopeInfo,
        descriptor,
        result,
        temporality,
        startEpochNanos,
        lastCollectionEpoch,
        epochNanos);
  }

  /** Remembers what was presented to a specific exporter. */
  private static class LastReportedAccumulation {
    private final Map accumulation;
    private final long epochNanos;

    /**
     * Constructs a new reporting record.
     *
     * @param accumulation The last accumulation of metric data.
     * @param epochNanos The timestamp the data was reported.
     */
    LastReportedAccumulation(Map accumulation, long epochNanos) {
      this.accumulation = accumulation;
      this.epochNanos = epochNanos;
    }

    long getEpochNanos() {
      return epochNanos;
    }

    Map getAccumulation() {
      return accumulation;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy