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

feat: add logging bucket destination for log sinks #226

Merged
merged 1 commit into from
Sep 1, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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