io.opentelemetry.sdk.metrics.internal.view.ViewRegistry Maven / Gradle / Ivy
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.metrics.internal.view;
import static io.opentelemetry.sdk.metrics.internal.view.NoopAttributesProcessor.NOOP;
import static java.util.Objects.requireNonNull;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import io.opentelemetry.sdk.internal.GlobUtil;
import io.opentelemetry.sdk.metrics.Aggregation;
import io.opentelemetry.sdk.metrics.InstrumentSelector;
import io.opentelemetry.sdk.metrics.InstrumentType;
import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder;
import io.opentelemetry.sdk.metrics.View;
import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector;
import io.opentelemetry.sdk.metrics.internal.aggregator.AggregationUtil;
import io.opentelemetry.sdk.metrics.internal.aggregator.AggregatorFactory;
import io.opentelemetry.sdk.metrics.internal.debug.SourceInfo;
import io.opentelemetry.sdk.metrics.internal.descriptor.Advice;
import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor;
import io.opentelemetry.sdk.metrics.internal.export.CardinalityLimitSelector;
import io.opentelemetry.sdk.metrics.internal.state.MetricStorage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable;
/**
* Central location for Views to be registered. Registration of a view is done via the {@link
* SdkMeterProviderBuilder}.
*
* This class is internal and is hence not for public use. Its APIs are unstable and can change
* at any time.
*/
@Immutable
public final class ViewRegistry {
static final View DEFAULT_VIEW = View.builder().build();
static final RegisteredView DEFAULT_REGISTERED_VIEW =
RegisteredView.create(
InstrumentSelector.builder().setName("*").build(),
DEFAULT_VIEW,
NOOP,
MetricStorage.DEFAULT_MAX_CARDINALITY,
SourceInfo.noSourceInfo());
private static final Logger logger = Logger.getLogger(ViewRegistry.class.getName());
private final Map instrumentDefaultRegisteredView;
private final List registeredViews;
ViewRegistry(
DefaultAggregationSelector defaultAggregationSelector,
CardinalityLimitSelector cardinalityLimitSelector,
List registeredViews) {
instrumentDefaultRegisteredView = new HashMap<>();
for (InstrumentType instrumentType : InstrumentType.values()) {
instrumentDefaultRegisteredView.put(
instrumentType,
RegisteredView.create(
InstrumentSelector.builder().setName("*").build(),
View.builder()
.setAggregation(defaultAggregationSelector.getDefaultAggregation(instrumentType))
.build(),
AttributesProcessor.noop(),
cardinalityLimitSelector.getCardinalityLimit(instrumentType),
SourceInfo.noSourceInfo()));
}
this.registeredViews = registeredViews;
}
/** Returns a {@link ViewRegistry}. */
public static ViewRegistry create(
DefaultAggregationSelector defaultAggregationSelector,
CardinalityLimitSelector cardinalityLimitSelector,
List registeredViews) {
return new ViewRegistry(
defaultAggregationSelector, cardinalityLimitSelector, new ArrayList<>(registeredViews));
}
/** Return a {@link ViewRegistry} using the default aggregation and no views registered. */
public static ViewRegistry create() {
return create(
unused -> Aggregation.defaultAggregation(),
CardinalityLimitSelector.defaultCardinalityLimitSelector(),
Collections.emptyList());
}
/**
* Returns the metric {@link View} for a given instrument.
*
* @param descriptor description of the instrument.
* @return The list of {@link View}s for this instrument, or a default view.
*/
public List findViews(
InstrumentDescriptor descriptor, InstrumentationScopeInfo meterScope) {
List result = new ArrayList<>();
// Find matching views for the instrument
for (RegisteredView entry : registeredViews) {
if (matchesSelector(entry.getInstrumentSelector(), descriptor, meterScope)) {
AggregatorFactory viewAggregatorFactory =
(AggregatorFactory) entry.getView().getAggregation();
if (viewAggregatorFactory.isCompatibleWithInstrument(descriptor)) {
result.add(entry);
} else {
logger.log(
Level.WARNING,
"View aggregation "
+ AggregationUtil.aggregationName(entry.getView().getAggregation())
+ " is incompatible with instrument "
+ descriptor.getName()
+ " of type "
+ descriptor.getType());
}
}
}
// If a view matched, return it
if (!result.isEmpty()) {
return Collections.unmodifiableList(result);
}
// No views matched, use default view
RegisteredView instrumentDefaultView =
requireNonNull(instrumentDefaultRegisteredView.get(descriptor.getType()));
AggregatorFactory viewAggregatorFactory =
(AggregatorFactory) instrumentDefaultView.getView().getAggregation();
if (!viewAggregatorFactory.isCompatibleWithInstrument(descriptor)) {
// The aggregation from default aggregation selector was incompatible with instrument, use
// default aggregation instead
logger.log(
Level.WARNING,
"Instrument default aggregation "
+ AggregationUtil.aggregationName(instrumentDefaultView.getView().getAggregation())
+ " is incompatible with instrument "
+ descriptor.getName()
+ " of type "
+ descriptor.getType());
instrumentDefaultView = DEFAULT_REGISTERED_VIEW;
}
// if the user defined an attributes advice, use it
if (descriptor.getAdvice().hasAttributes()) {
instrumentDefaultView =
applyAdviceToDefaultView(instrumentDefaultView, descriptor.getAdvice());
}
return Collections.singletonList(instrumentDefaultView);
}
// Matches an instrument selector against an instrument + meter.
private static boolean matchesSelector(
InstrumentSelector selector,
InstrumentDescriptor descriptor,
InstrumentationScopeInfo meterScope) {
if (selector.getInstrumentType() != null
&& selector.getInstrumentType() != descriptor.getType()) {
return false;
}
if (selector.getInstrumentUnit() != null
&& !selector.getInstrumentUnit().equals(descriptor.getUnit())) {
return false;
}
if (selector.getInstrumentName() != null
&& !GlobUtil.toGlobPatternPredicate(selector.getInstrumentName())
.test(descriptor.getName())) {
return false;
}
return matchesMeter(selector, meterScope);
}
// Matches a meter selector against a meter.
private static boolean matchesMeter(
InstrumentSelector selector, InstrumentationScopeInfo meterScope) {
if (selector.getMeterName() != null && !selector.getMeterName().equals(meterScope.getName())) {
return false;
}
if (selector.getMeterVersion() != null
&& !selector.getMeterVersion().equals(meterScope.getVersion())) {
return false;
}
return selector.getMeterSchemaUrl() == null
|| selector.getMeterSchemaUrl().equals(meterScope.getSchemaUrl());
}
private static RegisteredView applyAdviceToDefaultView(
RegisteredView instrumentDefaultView, Advice advice) {
return RegisteredView.create(
instrumentDefaultView.getInstrumentSelector(),
instrumentDefaultView.getView(),
new AdviceAttributesProcessor(requireNonNull(advice.getAttributes())),
instrumentDefaultView.getCardinalityLimit(),
instrumentDefaultView.getViewSourceInfo());
}
}