-
Notifications
You must be signed in to change notification settings - Fork 851
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Bogdan Cristian Drutu <[email protected]>
- Loading branch information
1 parent
84f4443
commit 33e845d
Showing
11 changed files
with
549 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
sdk/src/main/java/io/opentelemetry/sdk/metrics/AbstractInstrumentWithBinding.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/* | ||
* Copyright 2020, OpenTelemetry Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package io.opentelemetry.sdk.metrics; | ||
|
||
import io.opentelemetry.metrics.LabelSet; | ||
import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; | ||
import io.opentelemetry.sdk.metrics.common.InstrumentType; | ||
import io.opentelemetry.sdk.metrics.common.InstrumentValueType; | ||
import io.opentelemetry.sdk.metrics.data.MetricData; | ||
import java.util.Collection; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
import java.util.concurrent.locks.ReentrantLock; | ||
|
||
abstract class AbstractInstrumentWithBinding<B extends AbstractBoundInstrument> | ||
extends AbstractInstrument { | ||
private final ConcurrentHashMap<LabelSet, B> boundLabels; | ||
private final ReentrantLock collectLock; | ||
private long collectionStartTime; | ||
|
||
AbstractInstrumentWithBinding( | ||
String name, | ||
String description, | ||
String unit, | ||
Map<String, String> constantLabels, | ||
List<String> labelKeys, | ||
InstrumentType instrumentType, | ||
InstrumentValueType instrumentValueType, | ||
MeterSharedState meterSharedState, | ||
InstrumentationLibraryInfo instrumentationLibraryInfo) { | ||
super( | ||
name, | ||
description, | ||
unit, | ||
constantLabels, | ||
labelKeys, | ||
instrumentType, | ||
instrumentValueType, | ||
meterSharedState, | ||
instrumentationLibraryInfo); | ||
boundLabels = new ConcurrentHashMap<>(); | ||
collectLock = new ReentrantLock(); | ||
collectionStartTime = getMeterSharedState().getClock().now(); | ||
} | ||
|
||
// Cannot make this "bind" because of a Java problem if we make this class also implement the | ||
// InstrumentWithBinding then the subclass will fail to compile because of different "bind" | ||
// signature. This is a good trade-off. | ||
final B bindInternal(LabelSet labelSet) { | ||
B binding = boundLabels.get(labelSet); | ||
if (binding != null && binding.bind()) { | ||
// At this moment it is guaranteed that the Bound is in the map and will not be removed. | ||
return binding; | ||
} | ||
|
||
// Missing entry or no longer mapped, try to add a new entry. | ||
binding = newBinding(); | ||
while (true) { | ||
B oldBound = boundLabels.putIfAbsent(labelSet, binding); | ||
if (oldBound != null) { | ||
if (oldBound.bind()) { | ||
// At this moment it is guaranteed that the Bound is in the map and will not be removed. | ||
return oldBound; | ||
} | ||
// Try to remove the oldBound. This will race with the collect method, but only one will | ||
// succeed. | ||
boundLabels.remove(labelSet, oldBound); | ||
continue; | ||
} | ||
return binding; | ||
} | ||
} | ||
|
||
/** | ||
* Collects records from all the entries (labelSet, Bound) that changed since the last collect() | ||
* call. | ||
*/ | ||
final Collection<MetricData> collect() { | ||
getActiveViewAggregator().startCollection(); | ||
long previousCollectionStartTime = collectionStartTime; | ||
collectionStartTime = getMeterSharedState().getClock().now(); | ||
collectLock.lock(); | ||
try { | ||
for (Map.Entry<LabelSet, B> entry : boundLabels.entrySet()) { | ||
if (entry.getValue().tryUnmap()) { | ||
// If able to unmap then remove the record from the current Map. This can race with the | ||
// acquire but because we requested a specific value only one will succeed. | ||
boundLabels.remove(entry.getKey(), entry.getValue()); | ||
} | ||
|
||
entry.getValue().collect(entry.getKey()); | ||
} | ||
} finally { | ||
collectLock.unlock(); | ||
} | ||
return getActiveViewAggregator() | ||
.stopCollection(previousCollectionStartTime, collectionStartTime); | ||
} | ||
|
||
abstract B newBinding(); | ||
} |
120 changes: 120 additions & 0 deletions
120
sdk/src/main/java/io/opentelemetry/sdk/metrics/ActiveViewAggregator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
/* | ||
* Copyright 2020, OpenTelemetry Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package io.opentelemetry.sdk.metrics; | ||
|
||
import io.opentelemetry.metrics.LabelSet; | ||
import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; | ||
import io.opentelemetry.sdk.metrics.aggregator.Aggregator; | ||
import io.opentelemetry.sdk.metrics.common.InstrumentType; | ||
import io.opentelemetry.sdk.metrics.common.InstrumentValueType; | ||
import io.opentelemetry.sdk.metrics.data.MetricData; | ||
import io.opentelemetry.sdk.metrics.data.MetricData.Descriptor; | ||
import io.opentelemetry.sdk.metrics.view.Aggregation; | ||
import io.opentelemetry.sdk.resources.Resource; | ||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.Map; | ||
import javax.annotation.Nullable; | ||
|
||
// The current implementation allows to change the active ViewAggregator only before any record | ||
// or binding happens. This is good for the moment to support default aggregation for all the | ||
// instruments but needs to support adding/removing views at any moment, as well as support for | ||
// multiple views in the same time. | ||
final class ActiveViewAggregator { | ||
private final InstrumentType instrumentType; | ||
private final InstrumentValueType instrumentValueType; | ||
private final Resource resource; | ||
private final InstrumentationLibraryInfo instrumentationLibraryInfo; | ||
private AggregatorMap aggregatorMap; | ||
private volatile AggregatorView currentAggregatorView; | ||
|
||
ActiveViewAggregator( | ||
InstrumentType instrumentType, | ||
InstrumentValueType instrumentValueType, | ||
Resource resource, | ||
InstrumentationLibraryInfo instrumentationLibraryInfo) { | ||
this.instrumentType = instrumentType; | ||
this.instrumentValueType = instrumentValueType; | ||
this.resource = resource; | ||
this.instrumentationLibraryInfo = instrumentationLibraryInfo; | ||
currentAggregatorView = AggregatorView.getNoop(); | ||
} | ||
|
||
// TODO: Change this to: void addViewAggregator(View view); | ||
void addView( | ||
String name, | ||
String description, | ||
String unit, | ||
Map<String, String> constantLabels, | ||
Aggregation aggregation) { | ||
// TODO: Add support to reduce labels. | ||
this.currentAggregatorView = | ||
AggregatorView.getAllLabels( | ||
toDescriptor( | ||
name, | ||
description, | ||
unit, | ||
constantLabels, | ||
aggregation, | ||
instrumentType, | ||
instrumentValueType), | ||
resource, | ||
instrumentationLibraryInfo, | ||
aggregation.getAggregatorFactory(instrumentValueType)); | ||
} | ||
|
||
// Caller needs to call these methods in the following order (while holding a lock): | ||
// * startCollection(); | ||
// * collect(); // May be called multiple times. | ||
// * startCollection() | ||
void startCollection() { | ||
aggregatorMap = currentAggregatorView.newAggregatorMap(); | ||
} | ||
|
||
void collect(LabelSet labelSet, Aggregator aggregator) { | ||
aggregatorMap.collect(labelSet, aggregator); | ||
} | ||
|
||
Collection<MetricData> stopCollection(long startEpochNanos, long epochNanos) { | ||
@Nullable MetricData metricData = aggregatorMap.toMetricData(startEpochNanos, epochNanos); | ||
return metricData == null | ||
? Collections.<MetricData>emptyList() | ||
: Collections.singletonList(metricData); | ||
} | ||
|
||
Aggregator newAggregator() { | ||
return currentAggregatorView.getAggregator(); | ||
} | ||
|
||
// This should change the signature when we add View to be: | ||
// static Descriptor toDescriptor(View, InstrumentType, InstrumentValueType); | ||
private static Descriptor toDescriptor( | ||
String name, | ||
String description, | ||
String unit, | ||
Map<String, String> constantLabels, | ||
Aggregation aggregation, | ||
InstrumentType instrumentType, | ||
InstrumentValueType instrumentValueType) { | ||
return Descriptor.create( | ||
name, | ||
description, | ||
unit, | ||
aggregation.getDescriptorType(instrumentType, instrumentValueType), | ||
constantLabels); | ||
} | ||
} |
Oops, something went wrong.