io.opentelemetry.sdk.internal.ComponentRegistry Maven / Gradle / Ivy
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.internal;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.internal.GuardedBy;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import javax.annotation.Nullable;
/**
* Component (tracer, meter, etc) registry class for all the provider classes (TracerProvider,
* MeterProvider, etc.).
*
* Components are identified by name, version, and schema. Name is required, but version and
* schema are optional. Therefore, we have 4 possible scenarios for component keys:
*
*
* - Only name is provided, represented by {@link #componentByName}
*
- Name and version are provided, represented by {@link #componentByNameAndVersion}
*
- Name and schema are provided, represented by {@link #componentByNameAndSchema}
*
- Name, version and schema are provided, represented by {@link
* #componentByNameVersionAndSchema}
*
*
* This class is internal and is hence not for public use. Its APIs are unstable and can change
* at any time.
*
* @param the type of the registered value.
*/
public final class ComponentRegistry {
private final Map componentByName = new ConcurrentHashMap<>();
private final Map> componentByNameAndVersion = new ConcurrentHashMap<>();
private final Map> componentByNameAndSchema = new ConcurrentHashMap<>();
private final Map>> componentByNameVersionAndSchema =
new ConcurrentHashMap<>();
private final Object lock = new Object();
@GuardedBy("lock")
private final Set allComponents = Collections.newSetFromMap(new IdentityHashMap<>());
private final Function factory;
public ComponentRegistry(Function factory) {
this.factory = factory;
}
/**
* Returns the component associated with the {@code name}, {@code version}, and {@code schemaUrl}.
* {@link Attributes} are not part of component identity. Behavior is undefined when different
* {@link Attributes} are provided where {@code name}, {@code version}, and {@code schemaUrl} are
* identical.
*/
public V get(
String name, @Nullable String version, @Nullable String schemaUrl, Attributes attributes) {
if (version != null && schemaUrl != null) {
Map> componentByVersionAndSchema =
componentByNameVersionAndSchema.computeIfAbsent(
name, unused -> new ConcurrentHashMap<>());
Map componentBySchema =
componentByVersionAndSchema.computeIfAbsent(version, unused -> new ConcurrentHashMap<>());
return componentBySchema.computeIfAbsent(
schemaUrl,
schemaUrl1 ->
buildComponent(
InstrumentationScopeInfo.builder(name)
.setVersion(version)
.setSchemaUrl(schemaUrl1)
.setAttributes(attributes)
.build()));
} else if (version != null) { // schemaUrl == null
Map componentByVersion =
componentByNameAndVersion.computeIfAbsent(name, unused -> new ConcurrentHashMap<>());
return componentByVersion.computeIfAbsent(
version,
version1 ->
buildComponent(
InstrumentationScopeInfo.builder(name)
.setVersion(version1)
.setAttributes(attributes)
.build()));
}
if (schemaUrl != null) { // version == null
Map componentBySchema =
componentByNameAndSchema.computeIfAbsent(name, unused -> new ConcurrentHashMap<>());
return componentBySchema.computeIfAbsent(
schemaUrl,
schemaUrl1 ->
buildComponent(
InstrumentationScopeInfo.builder(name)
.setSchemaUrl(schemaUrl1)
.setAttributes(attributes)
.build()));
} else { // schemaUrl == null && version == null
return componentByName.computeIfAbsent(
name,
name1 ->
buildComponent(
InstrumentationScopeInfo.builder(name1).setAttributes(attributes).build()));
}
}
private V buildComponent(InstrumentationScopeInfo instrumentationScopeInfo) {
V component = factory.apply(instrumentationScopeInfo);
synchronized (lock) {
allComponents.add(component);
}
return component;
}
/**
* Returns a {@code Collection} view of the registered components.
*
* @return a {@code Collection} view of the registered components.
*/
public Collection getComponents() {
synchronized (lock) {
return Collections.unmodifiableCollection(new ArrayList<>(allComponents));
}
}
}