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

io.opentelemetry.sdk.metrics.SdkMeterProvider Maven / Gradle / Ivy

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

package io.opentelemetry.sdk.metrics;

import static java.util.stream.Collectors.toList;

import io.opentelemetry.api.metrics.MeterBuilder;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.sdk.common.Clock;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.internal.ComponentRegistry;
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.export.CollectionRegistration;
import io.opentelemetry.sdk.metrics.export.MetricProducer;
import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil;
import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter;
import io.opentelemetry.sdk.metrics.internal.export.CardinalityLimitSelector;
import io.opentelemetry.sdk.metrics.internal.export.RegisteredReader;
import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState;
import io.opentelemetry.sdk.metrics.internal.view.RegisteredView;
import io.opentelemetry.sdk.metrics.internal.view.ViewRegistry;
import io.opentelemetry.sdk.resources.Resource;
import java.io.Closeable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;

/**
 * SDK implementation for {@link MeterProvider}.
 *
 * @since 1.14.0
 */
public final class SdkMeterProvider implements MeterProvider, Closeable {

  private static final Logger LOGGER = Logger.getLogger(SdkMeterProvider.class.getName());
  static final String DEFAULT_METER_NAME = "unknown";

  private final List registeredViews;
  private final List registeredReaders;
  private final List metricProducers;
  private final MeterProviderSharedState sharedState;
  private final ComponentRegistry registry;
  private final AtomicBoolean isClosed = new AtomicBoolean(false);

  /** Returns a new {@link SdkMeterProviderBuilder} for {@link SdkMeterProvider}. */
  public static SdkMeterProviderBuilder builder() {
    return new SdkMeterProviderBuilder();
  }

  SdkMeterProvider(
      List registeredViews,
      IdentityHashMap metricReaders,
      List metricProducers,
      Clock clock,
      Resource resource,
      ExemplarFilter exemplarFilter) {
    long startEpochNanos = clock.now();
    this.registeredViews = registeredViews;
    this.registeredReaders =
        metricReaders.entrySet().stream()
            .map(
                entry ->
                    RegisteredReader.create(
                        entry.getKey(),
                        ViewRegistry.create(entry.getKey(), entry.getValue(), registeredViews)))
            .collect(toList());
    this.metricProducers = metricProducers;
    this.sharedState =
        MeterProviderSharedState.create(clock, resource, exemplarFilter, startEpochNanos);
    this.registry =
        new ComponentRegistry<>(
            instrumentationLibraryInfo ->
                new SdkMeter(sharedState, instrumentationLibraryInfo, registeredReaders));
    for (RegisteredReader registeredReader : registeredReaders) {
      List readerMetricProducers = new ArrayList<>(metricProducers);
      readerMetricProducers.add(new LeasedMetricProducer(registry, sharedState, registeredReader));
      registeredReader
          .getReader()
          .register(new SdkCollectionRegistration(readerMetricProducers, sharedState));
      registeredReader.setLastCollectEpochNanos(startEpochNanos);
    }
  }

  @Override
  public MeterBuilder meterBuilder(String instrumentationScopeName) {
    if (registeredReaders.isEmpty()) {
      return MeterProvider.noop().meterBuilder(instrumentationScopeName);
    }
    if (instrumentationScopeName == null || instrumentationScopeName.isEmpty()) {
      LOGGER.fine("Meter requested without instrumentation scope name.");
      instrumentationScopeName = DEFAULT_METER_NAME;
    }
    return new SdkMeterBuilder(registry, instrumentationScopeName);
  }

  /**
   * Reset the provider, clearing all registered instruments.
   *
   * 

Note: not currently stable but available for experimental use via {@link * SdkMeterProviderUtil#resetForTest(SdkMeterProvider)}. */ void resetForTest() { registry.getComponents().forEach(SdkMeter::resetForTest); } /** * Call {@link MetricReader#forceFlush()} on all metric readers associated with this provider. The * resulting {@link CompletableResultCode} completes when all complete. */ public CompletableResultCode forceFlush() { if (registeredReaders.isEmpty()) { return CompletableResultCode.ofSuccess(); } List results = new ArrayList<>(); for (RegisteredReader registeredReader : registeredReaders) { results.add(registeredReader.getReader().forceFlush()); } return CompletableResultCode.ofAll(results); } /** * Shutdown the provider. Calls {@link MetricReader#shutdown()} on all metric readers associated * with this provider. The resulting {@link CompletableResultCode} completes when all complete. */ public CompletableResultCode shutdown() { if (!isClosed.compareAndSet(false, true)) { LOGGER.info("Multiple close calls"); return CompletableResultCode.ofSuccess(); } if (registeredReaders.isEmpty()) { return CompletableResultCode.ofSuccess(); } List results = new ArrayList<>(); for (RegisteredReader info : registeredReaders) { results.add(info.getReader().shutdown()); } return CompletableResultCode.ofAll(results); } /** Close the meter provider. Calls {@link #shutdown()} and blocks waiting for it to complete. */ @Override public void close() { shutdown().join(10, TimeUnit.SECONDS); } @Override public String toString() { return "SdkMeterProvider{" + "clock=" + sharedState.getClock() + ", resource=" + sharedState.getResource() + ", metricReaders=" + registeredReaders.stream().map(RegisteredReader::getReader).collect(toList()) + ", metricProducers=" + metricProducers + ", views=" + registeredViews + "}"; } /** Helper class to expose registered metric exports. */ private static class LeasedMetricProducer implements MetricProducer { private final ComponentRegistry registry; private final MeterProviderSharedState sharedState; private final RegisteredReader registeredReader; LeasedMetricProducer( ComponentRegistry registry, MeterProviderSharedState sharedState, RegisteredReader registeredReader) { this.registry = registry; this.sharedState = sharedState; this.registeredReader = registeredReader; } @Override public Collection produce(Resource unused) { Collection meters = registry.getComponents(); List result = new ArrayList<>(); long collectTime = sharedState.getClock().now(); for (SdkMeter meter : meters) { result.addAll(meter.collectAll(registeredReader, collectTime)); } registeredReader.setLastCollectEpochNanos(collectTime); return Collections.unmodifiableCollection(result); } } private static class SdkCollectionRegistration implements CollectionRegistration { private final List metricProducers; private final MeterProviderSharedState sharedState; private SdkCollectionRegistration( List metricProducers, MeterProviderSharedState sharedState) { this.metricProducers = metricProducers; this.sharedState = sharedState; } @Override public Collection collectAllMetrics() { if (metricProducers.isEmpty()) { return Collections.emptyList(); } Resource resource = sharedState.getResource(); if (metricProducers.size() == 1) { return metricProducers.get(0).produce(resource); } List metricData = new ArrayList<>(); for (MetricProducer metricProducer : metricProducers) { metricData.addAll(metricProducer.produce(resource)); } return Collections.unmodifiableList(metricData); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy