Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add close method to MetricReader #5109

Merged
merged 1 commit into from
Jan 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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