Skip to content

Commit

Permalink
Use Tags.empty() as no-op argument. Reject multiple calls to withLogL…
Browse files Browse the repository at this point in the history
…evelMap.

Accepting no-op arguments allows ScopedLoggingContext to conditionally add values. A complete no-op, however, allows for syntactic misuse of the builder, calling the same method multiple times as long as all but the last provide null values.

LogLevelMap requires special care, as once a LogLevelMap is set (even if logically empty), every single log statement needs to evaluate the map.

RELNOTES=Enforce calling ScopedLoggingContext.Builder methods at most once, even with no-op params.
PiperOrigin-RevId: 559193241
  • Loading branch information
java-team-github-bot authored and Flogger Team committed Aug 23, 2023
1 parent 5aa0649 commit 50b7f60
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -137,25 +137,25 @@ public abstract static class Builder {
private Tags tags = null;
private ContextMetadata.Builder metadata = null;
private LogLevelMap logLevelMap = null;
private boolean hasLogLevelMap = false;

protected Builder() {}

/**
* Sets the tags to be used with the context. This method can be called at most once per
* builder. Calling with a null value does nothing.
* builder.
*/
@CanIgnoreReturnValue
public final Builder withTags(@NullableDecl Tags tags) {
public final Builder withTags(Tags tags) {
checkState(this.tags == null, "tags already set");
if (tags != null) {
this.tags = tags;
}
checkNotNull(tags, "tags");
this.tags = tags;
return this;
}

/**
* Adds a single metadata key/value pair to the context. This method can be called multiple
* times on a builder. Calling with a null value does nothing.
* times on a builder. Calling with a null value does not add metadata.
*/
@CanIgnoreReturnValue
public final <T> Builder withMetadata(MetadataKey<T> key, @NullableDecl T value) {
Expand All @@ -171,14 +171,13 @@ public final <T> Builder withMetadata(MetadataKey<T> key, @NullableDecl T value)

/**
* Sets the log level map to be used with the context being built. This method can be called at
* most once per builder. Calling with a null value does nothing.
* most once per builder. Calling with a null value does not set a log level map.
*/
@CanIgnoreReturnValue
public final Builder withLogLevelMap(@NullableDecl LogLevelMap logLevelMap) {
checkState(this.logLevelMap == null, "log level map already set");
if (logLevelMap != null) {
this.logLevelMap = logLevelMap;
}
checkState(!hasLogLevelMap, "log level map already set");
hasLogLevelMap = true;
this.logLevelMap = logLevelMap;
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static com.google.common.flogger.testing.MetadataSubject.assertThat;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.fail;

import com.google.common.collect.ImmutableMap;
import com.google.common.flogger.LoggingScope;
Expand Down Expand Up @@ -129,11 +130,11 @@ public void testLoggedTags_areMerged() {
}

@Test
public void testNewContext_withNullTags_ignored() {
public void testNewContext_withNoOpTags_ignored() {
assertThat(getTagMap()).isEmpty();
context
.newContext()
.withTags(null)
.withTags(Tags.empty())
.run(
() -> {
assertThat(getTagMap()).isEmpty();
Expand All @@ -143,6 +144,17 @@ public void testNewContext_withNullTags_ignored() {
checkDone();
}

@Test
public void testNewContext_withTagsTwice_rejected() {
try {
context.newContext().withTags(Tags.empty()).withTags(Tags.of("foo", "bar")).run(() -> {});
fail("Expected IllegalStateException");
} catch (IllegalStateException e) {
markTestAsDone();
}
checkDone();
}

@Test
public void testNewContext_withMetadata() {
assertThat(getMetadata()).hasSize(0);
Expand Down Expand Up @@ -205,6 +217,17 @@ public void testNewContext_withNullLogLevelMap_ignored() {
checkDone();
}

@Test
public void testNewContext_withLogLevelMapTwice_rejected() {
try {
context.newContext().withLogLevelMap(null).withLogLevelMap(null).run(() -> {});
fail("Expected IllegalStateException");
} catch (IllegalStateException e) {
markTestAsDone();
}
checkDone();
}

@Test
public void testNewContext_withMergedTags() {
assertThat(getTagMap()).isEmpty();
Expand Down

0 comments on commit 50b7f60

Please sign in to comment.