Skip to content

Commit

Permalink
feat: add logging bucket destination for log sinks (#226)
Browse files Browse the repository at this point in the history
  • Loading branch information
chingor13 committed Sep 1, 2020
1 parent d431ea4 commit ef97aae
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 1 deletion.
Expand Up @@ -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. */
Expand Down Expand Up @@ -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 {

Expand Down Expand Up @@ -344,6 +447,8 @@ static <T extends Destination> 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");
}
Expand Down
Expand Up @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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"));
Expand All @@ -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();
Expand All @@ -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
Expand Down Expand Up @@ -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());
Expand Down

0 comments on commit ef97aae

Please sign in to comment.