Skip to content

Commit

Permalink
Add close method to MetricReader (#5109)
Browse files Browse the repository at this point in the history
  • Loading branch information
jack-berg authored Jan 11, 2023
1 parent b300e72 commit 1915f1f
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 35 deletions.
57 changes: 29 additions & 28 deletions buildSrc/src/main/kotlin/otel.japicmp-conventions.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import japicmp.model.JApiCompatibility
import japicmp.model.JApiCompatibilityChange
import japicmp.model.JApiMethod
import me.champeau.gradle.japicmp.JapicmpTask
import me.champeau.gradle.japicmp.report.Severity
import me.champeau.gradle.japicmp.report.Violation
import me.champeau.gradle.japicmp.report.stdrules.AbstractRecordingSeenMembers
import me.champeau.gradle.japicmp.report.stdrules.BinaryIncompatibleRule
import me.champeau.gradle.japicmp.report.stdrules.RecordSeenMembersSetup
import me.champeau.gradle.japicmp.report.stdrules.SourceCompatibleRule
import me.champeau.gradle.japicmp.report.stdrules.UnchangedMemberRule
Expand All @@ -32,32 +32,24 @@ val latestReleasedVersion: String by lazy {
moduleVersion
}

class AllowDefaultMethodRule : AbstractRecordingSeenMembers() {
class AllowNewAbstractMethodOnAutovalueClasses : AbstractRecordingSeenMembers() {
override fun maybeAddViolation(member: JApiCompatibility): Violation? {
for (change in member.compatibilityChanges) {
if (isAbstractMethodOnAutoValue(member, change)) {
continue
}
if (!change.isSourceCompatible) {
return Violation.error(member, "Not source compatible")
}
if (!change.isBinaryCompatible) {
return Violation.notBinaryCompatible(member, Severity.error)
}
if (member.compatibilityChanges == listOf(JApiCompatibilityChange.METHOD_ABSTRACT_ADDED_TO_CLASS) &&
member is JApiMethod &&
member.getjApiClass().newClass.get().getAnnotation(AutoValue::class.java) != null
) {
return Violation.accept(member, "Autovalue will automatically add implementation")
}
return null
}
}

/**
* Checks if the change is an abstract method on a class annotated with AutoValue.
* AutoValues need to override default interface methods and declare them abstract again.
* It causes METHOD_ABSTRACT_ADDED_TO_CLASS - source-incompatible change. It's
* false-positive since AutoValue will generate implementation anyway.
*/
fun isAbstractMethodOnAutoValue(member: JApiCompatibility, change: JApiCompatibilityChange): Boolean {
return change == JApiCompatibilityChange.METHOD_ABSTRACT_ADDED_TO_CLASS &&
member is JApiMethod &&
member.getjApiClass().newClass.get().getAnnotation(AutoValue::class.java) != null
class SourceIncompatibleRule : AbstractRecordingSeenMembers() {
override fun maybeAddViolation(member: JApiCompatibility): Violation? {
if (!member.isSourceCompatible()) {
return Violation.error(member, "Not source compatible")
}
return null
}
}

Expand Down Expand Up @@ -114,17 +106,26 @@ if (!project.hasProperty("otel.release") && !project.name.startsWith("bom")) {
)

// Reproduce defaults from https://github.com/melix/japicmp-gradle-plugin/blob/09f52739ef1fccda6b4310cf3f4b19dc97377024/src/main/java/me/champeau/gradle/japicmp/report/ViolationsGenerator.java#L130
// but allow new default methods on interfaces, adding default implementations to
// interface methods previously abstract, and select additional customizations defined in
// AllowDefaultMethodRule.
compatibilityChangeExcludes.set(listOf("METHOD_NEW_DEFAULT", "METHOD_ABSTRACT_NOW_DEFAULT"))
// with some changes.
val exclusions = mutableListOf<String>()
// Allow new default methods on interfaces
exclusions.add("METHOD_NEW_DEFAULT")
// Allow adding default implementations for default methods
exclusions.add("METHOD_ABSTRACT_NOW_DEFAULT")
// Bug prevents recognizing default methods of superinterface.
// Fixed in https://github.com/siom79/japicmp/pull/343 but not yet available in me.champeau.gradle.japicmp
exclusions.add("METHOD_ABSTRACT_ADDED_IN_IMPLEMENTED_INTERFACE")
compatibilityChangeExcludes.set(exclusions)
richReport {
addSetupRule(RecordSeenMembersSetup::class.java)
addRule(JApiChangeStatus.NEW, SourceCompatibleRule::class.java)
addRule(JApiChangeStatus.MODIFIED, SourceCompatibleRule::class.java)
addRule(JApiChangeStatus.UNCHANGED, UnchangedMemberRule::class.java)
addRule(AllowDefaultMethodRule::class.java)
addRule(SourceCompatibleRule::class.java)
// Allow new abstract methods on autovalue
addRule(AllowNewAbstractMethodOnAutovalueClasses::class.java)
addRule(BinaryIncompatibleRule::class.java)
// Disallow source incompatible changes, which are allowed by default for some reason
addRule(SourceIncompatibleRule::class.java)
}

// this is needed so that we only consider the current artifact, and not dependencies
Expand Down
11 changes: 10 additions & 1 deletion docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
Comparing source compatibility of against
No changes.
*** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.sdk.metrics.export.MetricReader (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW INTERFACE: java.io.Closeable
+++ NEW INTERFACE: java.lang.AutoCloseable
+++ NEW METHOD: PUBLIC(+) void close()
+++ NEW EXCEPTION: java.io.IOException
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.metrics.export.PeriodicMetricReader (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW INTERFACE: java.io.Closeable
+++ NEW INTERFACE: java.lang.AutoCloseable
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import io.opentelemetry.sdk.metrics.export.CollectionRegistration;
import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.opentelemetry.sdk.metrics.internal.export.MetricProducer;
import java.io.Closeable;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UncheckedIOException;
Expand Down Expand Up @@ -53,7 +52,7 @@
*/
// Very similar to
// https://github.com/prometheus/client_java/blob/master/simpleclient_httpserver/src/main/java/io/prometheus/client/exporter/HTTPServer.java
public final class PrometheusHttpServer implements Closeable, MetricReader {
public final class PrometheusHttpServer implements MetricReader {

private static final DaemonThreadFactory THREAD_FACTORY =
new DaemonThreadFactory("prometheus-http");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import io.opentelemetry.sdk.metrics.Aggregation;
import io.opentelemetry.sdk.metrics.InstrumentType;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
* A metric reader reads metrics from an {@link SdkMeterProvider}.
Expand All @@ -18,7 +21,8 @@
*
* @since 1.14.0
*/
public interface MetricReader extends AggregationTemporalitySelector, DefaultAggregationSelector {
public interface MetricReader
extends AggregationTemporalitySelector, DefaultAggregationSelector, Closeable {

/**
* Called by {@link SdkMeterProvider} and supplies the {@link MetricReader} with a handle to
Expand Down Expand Up @@ -63,4 +67,10 @@ default Aggregation getDefaultAggregation(InstrumentType instrumentType) {
* @return the result of the shutdown.
*/
CompletableResultCode shutdown();

/** Close this {@link MetricReader}, releasing any resources. */
@Override
default void close() throws IOException {
shutdown().join(10, TimeUnit.SECONDS);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
Expand All @@ -27,6 +28,7 @@
import io.opentelemetry.sdk.metrics.internal.data.ImmutableSumData;
import io.opentelemetry.sdk.metrics.internal.export.MetricProducer;
import io.opentelemetry.sdk.resources.Resource;
import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -172,14 +174,13 @@ public void intervalExport_exporterThrowsException() throws Exception {
}

@Test
void oneLastExportAfterShutdown() throws Exception {
void shutdown_ExportsOneLastTime() throws Exception {
WaitingMetricExporter waitingMetricExporter = new WaitingMetricExporter();
PeriodicMetricReader reader =
PeriodicMetricReader.builder(waitingMetricExporter)
.setInterval(Duration.ofSeconds(100))
.setInterval(Duration.ofSeconds(Integer.MAX_VALUE))
.build();
reader.register(metricProducer);
// Assume that this will be called in less than 100 seconds.
reader.shutdown();

// This export was called during shutdown.
Expand All @@ -189,6 +190,19 @@ void oneLastExportAfterShutdown() throws Exception {
assertThat(waitingMetricExporter.hasShutdown.get()).isTrue();
}

@Test
void close_CallsShutdown() throws IOException {
PeriodicMetricReader reader =
spy(
PeriodicMetricReader.builder(new WaitingMetricExporter())
.setInterval(Duration.ofSeconds(Integer.MAX_VALUE))
.build());
reader.register(metricProducer);
reader.close();

verify(reader, times(1)).shutdown();
}

@Test
@SuppressWarnings("PreferJavaTimeOverload") // Testing the overload
void invalidConfig() {
Expand Down

0 comments on commit 1915f1f

Please sign in to comment.