diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/SinkInfo.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/SinkInfo.java index 4b7d8695c..c265d4873 100644 --- a/google-cloud-logging/src/main/java/com/google/cloud/logging/SinkInfo.java +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/SinkInfo.java @@ -62,7 +62,10 @@ public enum Type { DATASET, /** Specifies a Google Cloud Pub/Sub topic as destination for the sink. */ - TOPIC; + TOPIC, + + /** Specifies a Logging bucket as destination for the sink. */ + LOGGING_BUCKET; } /** Class for specifying a Google Cloud Storage bucket as destination for the sink. */ @@ -225,6 +228,106 @@ static DatasetDestination fromPb(String destinationPb) { } } + public static final class LoggingBucketDestination extends Destination { + + private static final long serialVersionUID = 4894431968778789038L; + private static final String BASE_NAME = "logging.googleapis.com/"; + private static final String REGEX = + BASE_NAME + "projects/([^/]+)/locations/([^/]+)/buckets/([^/]+)"; + private static final Pattern PATTERN = Pattern.compile(REGEX); + + private final String project; + private final String location; + private final String bucket; + + LoggingBucketDestination(String project, String location, String bucket) { + super(Type.LOGGING_BUCKET); + this.project = project; + this.location = checkNotNull(location); + this.bucket = checkNotNull(bucket); + } + + /** + * Returns the name of the project where the Google Cloud BigQuery dataset resides. If {@code + * null}, the default project is used. + */ + public String getProject() { + return project; + } + + /** Returns the name of the bucket location this destination represents. */ + public String getLocation() { + return location; + } + + /** Returns the name of the logging bucket this destination represents. */ + public String getBucket() { + return bucket; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj == null || !(obj instanceof LoggingBucketDestination)) { + return false; + } + LoggingBucketDestination other = (LoggingBucketDestination) obj; + return baseEquals(other) + && Objects.equals(project, other.project) + && Objects.equals(location, other.location); + } + + @Override + public int hashCode() { + return Objects.hash(baseHashCode(), project, location, bucket); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("project", project) + .add("location", location) + .add("bucket", bucket) + .toString(); + } + + @Override + String toPb(String projectId) { + String project = this.project == null ? projectId : this.project; + return BASE_NAME + "projects/" + project + "/locations/" + location + "/buckets/" + bucket; + } + + /** + * Creates a {@code DatasetDestination} object given the name of the project and dataset to be + * used as sink destination. + */ + public static LoggingBucketDestination of(String project, String location, String bucket) { + return new LoggingBucketDestination(project, location, bucket); + } + + /** + * Creates a {@code DatasetDestination} object given the name of the dataset to be used as + * sink destination. Dataset is assumed to reside in the default project. + */ + public static LoggingBucketDestination of(String location, String bucket) { + return new LoggingBucketDestination(null, location, bucket); + } + + static boolean matchesDestination(String destinationPb) { + return PATTERN.matcher(destinationPb).matches(); + } + + static LoggingBucketDestination fromPb(String destinationPb) { + Matcher matcher = PATTERN.matcher(destinationPb); + if (!matcher.matches()) { + throw new IllegalArgumentException(destinationPb + " is not a valid sink destination"); + } + return new LoggingBucketDestination(matcher.group(1), matcher.group(2), matcher.group(3)); + } + } + /** Class for specifying a Google Cloud BigQuery dataset as destination for the sink. */ public static final class TopicDestination extends Destination { @@ -344,6 +447,8 @@ static T fromPb(String destinationPb) { return (T) DatasetDestination.fromPb(destinationPb); } else if (TopicDestination.matchesDestination(destinationPb)) { return (T) TopicDestination.fromPb(destinationPb); + } else if (LoggingBucketDestination.matchesDestination(destinationPb)) { + return (T) LoggingBucketDestination.fromPb(destinationPb); } throw new IllegalArgumentException(destinationPb + " is not a valid sink destination"); } diff --git a/google-cloud-logging/src/test/java/com/google/cloud/logging/SinkInfoTest.java b/google-cloud-logging/src/test/java/com/google/cloud/logging/SinkInfoTest.java index f0121ad67..1578e262b 100644 --- a/google-cloud-logging/src/test/java/com/google/cloud/logging/SinkInfoTest.java +++ b/google-cloud-logging/src/test/java/com/google/cloud/logging/SinkInfoTest.java @@ -23,6 +23,7 @@ import com.google.cloud.logging.SinkInfo.Destination; import com.google.cloud.logging.SinkInfo.Destination.BucketDestination; import com.google.cloud.logging.SinkInfo.Destination.DatasetDestination; +import com.google.cloud.logging.SinkInfo.Destination.LoggingBucketDestination; import com.google.cloud.logging.SinkInfo.Destination.TopicDestination; import com.google.cloud.logging.SinkInfo.VersionFormat; import org.junit.Test; @@ -37,6 +38,8 @@ public class SinkInfoTest { private static final DatasetDestination DATASET_DESTINATION = DatasetDestination.of("project", "dataset"); private static final TopicDestination TOPIC_DESTINATION = TopicDestination.of("project", "topic"); + private static final LoggingBucketDestination LOGGING_BUCKET_DESTINATION = + LoggingBucketDestination.of("project", "location", "bucket"); private static final SinkInfo BUCKET_SINK_INFO = SinkInfo.newBuilder(NAME, BUCKET_DESTINATION) .setFilter(FILTER) @@ -79,6 +82,19 @@ public void testOfTopicDestination() { assertEquals("topic", topicDestination.getTopic()); } + @Test + public void testOfLoggingBucketDestination() { + assertEquals(Destination.Type.LOGGING_BUCKET, LOGGING_BUCKET_DESTINATION.getType()); + assertEquals("project", LOGGING_BUCKET_DESTINATION.getProject()); + assertEquals("location", LOGGING_BUCKET_DESTINATION.getLocation()); + assertEquals("bucket", LOGGING_BUCKET_DESTINATION.getBucket()); + LoggingBucketDestination loggingBucketDestination = + LoggingBucketDestination.of("location", "bucket"); + assertNull(loggingBucketDestination.getProject()); + assertEquals("location", loggingBucketDestination.getLocation()); + assertEquals("bucket", loggingBucketDestination.getBucket()); + } + @Test public void testToAndFromPbDestination() { BucketDestination bucketDestination = Destination.fromPb(BUCKET_DESTINATION.toPb("other")); @@ -95,6 +111,13 @@ public void testToAndFromPbDestination() { assertEquals("project", topicDestination.getProject()); assertEquals("topic", topicDestination.getTopic()); compareTopicDestination(TOPIC_DESTINATION, topicDestination); + LoggingBucketDestination loggingBucketDestination = + Destination.fromPb(LOGGING_BUCKET_DESTINATION.toPb("other")); + assertEquals(Destination.Type.LOGGING_BUCKET, loggingBucketDestination.getType()); + assertEquals("project", loggingBucketDestination.getProject()); + assertEquals("location", loggingBucketDestination.getLocation()); + assertEquals("bucket", loggingBucketDestination.getBucket()); + compareLoggingBucketDestination(LOGGING_BUCKET_DESTINATION, loggingBucketDestination); try { Destination.fromPb("wrongDestination"); fail(); @@ -113,6 +136,11 @@ public void testToAndFromPbDestination_NoProjectId() { TopicDestination.fromPb(TopicDestination.of("topic").toPb("project")); assertEquals("project", topicDestination.getProject()); compareTopicDestination(TOPIC_DESTINATION, topicDestination); + LoggingBucketDestination loggingBucketDestination = + LoggingBucketDestination.fromPb( + LoggingBucketDestination.of("location", "bucket").toPb("project")); + assertEquals("project", loggingBucketDestination.getProject()); + compareLoggingBucketDestination(LOGGING_BUCKET_DESTINATION, loggingBucketDestination); } @Test @@ -209,6 +237,16 @@ private void compareTopicDestination(TopicDestination expected, TopicDestination assertEquals(expected.toString(), value.toString()); } + private void compareLoggingBucketDestination( + LoggingBucketDestination expected, LoggingBucketDestination value) { + assertEquals(expected, value); + assertEquals(expected.getProject(), value.getProject()); + assertEquals(expected.getLocation(), value.getLocation()); + assertEquals(expected.getBucket(), value.getBucket()); + assertEquals(expected.hashCode(), value.hashCode()); + assertEquals(expected.toString(), value.toString()); + } + private void compareSinkInfo(SinkInfo expected, SinkInfo value) { assertEquals(expected, value); assertEquals(expected.getName(), value.getName());