forked from open-telemetry/opentelemetry-java
-
Notifications
You must be signed in to change notification settings - Fork 1
/
ComponentRegistry.java
133 lines (122 loc) · 5.06 KB
/
ComponentRegistry.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
* 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.).
*
* <p>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:
*
* <ol>
* <li>Only name is provided, represented by {@link #componentByName}
* <li>Name and version are provided, represented by {@link #componentByNameAndVersion}
* <li>Name and schema are provided, represented by {@link #componentByNameAndSchema}
* <li>Name, version and schema are provided, represented by {@link
* #componentByNameVersionAndSchema}
* </ol>
*
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
* at any time.
*
* @param <V> the type of the registered value.
*/
public final class ComponentRegistry<V> {
private final Map<String, V> componentByName = new ConcurrentHashMap<>();
private final Map<String, Map<String, V>> componentByNameAndVersion = new ConcurrentHashMap<>();
private final Map<String, Map<String, V>> componentByNameAndSchema = new ConcurrentHashMap<>();
private final Map<String, Map<String, Map<String, V>>> componentByNameVersionAndSchema =
new ConcurrentHashMap<>();
private final Object lock = new Object();
@GuardedBy("lock")
private final Set<V> allComponents = Collections.newSetFromMap(new IdentityHashMap<>());
private final Function<InstrumentationScopeInfo, V> factory;
public ComponentRegistry(Function<InstrumentationScopeInfo, V> 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<String, Map<String, V>> componentByVersionAndSchema =
componentByNameVersionAndSchema.computeIfAbsent(
name, unused -> new ConcurrentHashMap<>());
Map<String, V> 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<String, V> 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<String, V> 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<V> getComponents() {
synchronized (lock) {
return Collections.unmodifiableCollection(new ArrayList<>(allComponents));
}
}
}