This repository was archived by the owner on Apr 21, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
First draft of FFWD java client Metric with distribution support #10
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,15 @@ | |
| <description>FastForward client for Java.</description> | ||
|
|
||
| <dependencies> | ||
| <dependency> | ||
| <groupId>com.google.auto.value</groupId> | ||
| <artifactId>auto-value</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>javax.annotation</groupId> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need this one?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, library for annotation, it adds annotation to generated code. |
||
| <artifactId>javax.annotation-api</artifactId> | ||
| <version>1.3.2</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>com.google.protobuf</groupId> | ||
| <artifactId>protobuf-java</artifactId> | ||
|
|
||
286 changes: 286 additions & 0 deletions
286
ffwd-client/src/main/java/com/spotify/ffwd/v1/Metric.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,286 @@ | ||
| /*- | ||
| * -\-\- | ||
| * FastForward Java Client | ||
| * -- | ||
| * Copyright (C) 2016 - 2020 Spotify AB | ||
| * -- | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| * -/-/- | ||
| */ | ||
|
|
||
| /* | ||
| * FastForward Client | ||
| * -- | ||
| * Copyright (C) 2016 - 2019 Spotify AB | ||
| * -- | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package com.spotify.ffwd.v1; | ||
|
|
||
| import com.google.protobuf.ByteString; | ||
| import com.spotify.ffwd.protocol1.Protocol1; | ||
| import java.util.ArrayList; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
|
|
||
| public class Metric { | ||
|
|
||
| private static final long TIME = 1 << 1; | ||
| private static final long KEY = 1 << 2; | ||
| private static final long VALUE = 1 << 3; | ||
| private static final long HOST = 1 << 4; | ||
| private static final long TAGS = 1 << 5; | ||
| private static final long ATTRIBUTES = 1 << 6; | ||
|
|
||
| private final long has; | ||
| private final long time; | ||
| private final String key; | ||
| private final Value value; | ||
| private final String host; | ||
| private final List<String> tags; | ||
| private final Map<String, String> attributes; | ||
|
|
||
| public Metric() { | ||
| this.has = 0; | ||
| this.time = 0; | ||
| this.key = null; | ||
| this.value = null; | ||
| this.host = null; | ||
| this.tags = new ArrayList<>(); | ||
| this.attributes = new HashMap<>(); | ||
| } | ||
|
|
||
| public Metric( | ||
| long has, long time, String key, Value value, String host, | ||
| List<String> tags, Map<String, String> attributes | ||
| ) { | ||
| this.has = has; | ||
| this.time = time; | ||
| this.key = key; | ||
| this.value = value; | ||
| this.host = host; | ||
| this.tags = tags; | ||
| this.attributes = attributes; | ||
| } | ||
|
|
||
| private boolean test(long n) { | ||
| return (has & n) != 0; | ||
| } | ||
|
|
||
| private long set(long n) { | ||
| return has | n; | ||
| } | ||
|
|
||
| public Metric time(long time) { | ||
| return new Metric(set(TIME), time, key, value, host, tags, attributes); | ||
| } | ||
|
|
||
| public Metric key(String key) { | ||
| return new Metric(set(KEY), time, key, value, host, tags, attributes); | ||
| } | ||
|
|
||
| public Metric value(Value value) { | ||
| return new Metric(set(VALUE), time, key, value, host, tags, attributes); | ||
| } | ||
|
|
||
| public Metric host(String host) { | ||
| return new Metric(set(HOST), time, key, value, host, tags, attributes); | ||
| } | ||
|
|
||
| public Metric tag(String tag) { | ||
| final List<String> tags = new ArrayList<>(this.tags); | ||
| tags.add(tag); | ||
| return new Metric(set(TAGS), time, key, value, host, tags, attributes); | ||
| } | ||
|
|
||
| public Metric tags(List<String> tags) { | ||
| return new Metric(set(TAGS), time, key, value, host, | ||
| new ArrayList<>(tags), attributes); | ||
| } | ||
|
|
||
| public Metric attribute(String k, String v) { | ||
| final Map<String, String> attributes = new HashMap<>(this.attributes); | ||
| attributes.put(k, v); | ||
| return new Metric(set(ATTRIBUTES), time, key, value, host, tags, attributes); | ||
| } | ||
|
|
||
| public Metric attributes(Map<String, String> attributes) { | ||
| return new Metric(set(ATTRIBUTES), time, key, value, host, tags, | ||
| new HashMap<>(attributes)); | ||
| } | ||
|
|
||
| public byte[] serialize() { | ||
| final Protocol1.Metric.Builder builder = Protocol1.Metric.newBuilder(); | ||
|
|
||
| if (test(TIME)) { | ||
| builder.setTime(time); | ||
| } | ||
|
|
||
| if (test(KEY)) { | ||
| builder.setKey(key); | ||
| } | ||
|
|
||
| if (test(VALUE)) { | ||
| if (value instanceof Value.DoubleValue) { | ||
| Value.DoubleValue doubleValue = (Value.DoubleValue) value; | ||
| builder.setValue(Protocol1.Value.newBuilder().setDoubleValue(doubleValue.getValue())); | ||
| } else if (value instanceof Value.DistributionValue) { | ||
| Value.DistributionValue distributionValue = (Value.DistributionValue) value; | ||
| ByteString byteString = ByteString.copyFrom(distributionValue.getValue()); | ||
| builder.setValue(Protocol1.Value.newBuilder().setDistributionValue(byteString)); | ||
| } | ||
|
|
||
| } | ||
|
|
||
| if (test(HOST)) { | ||
| builder.setHost(host); | ||
| } | ||
|
|
||
| if (test(TAGS)) { | ||
| for (final String tag : tags) { | ||
| builder.addTags(tag); | ||
| } | ||
| } | ||
|
|
||
| if (test(ATTRIBUTES)) { | ||
| for (final Map.Entry<String, String> entry : attributes.entrySet()) { | ||
| if (entry.getKey() == null) { | ||
| continue; | ||
| } | ||
|
|
||
| final Protocol1.Attribute.Builder attributeBuilder = | ||
| Protocol1.Attribute.newBuilder().setKey(entry.getKey()); | ||
|
|
||
| if (entry.getValue() != null) { | ||
| attributeBuilder.setValue(entry.getValue()); | ||
| } | ||
|
|
||
| builder.addAttributes(attributeBuilder.build()); | ||
| } | ||
| } | ||
|
|
||
| final Protocol1.Metric m = builder.build(); | ||
| return Protocol1.Message.newBuilder().setMetric(m).build() | ||
| .toByteArray(); | ||
| } | ||
|
|
||
| public boolean equals(final Object o) { | ||
| if (o == this) { | ||
| return true; | ||
| } | ||
| if (!(o instanceof Metric)) { | ||
| return false; | ||
| } | ||
| final Metric other = (Metric) o; | ||
| if (!other.canEqual((Object) this)) { | ||
| return false; | ||
| } | ||
| if (this.has != other.has) { | ||
| return false; | ||
| } | ||
|
|
||
| if (this.time != other.time) { | ||
| return false; | ||
| } | ||
| final Object this$key = this.key; | ||
| final Object other$key = other.key; | ||
| if (this$key == null ? other$key != null : !this$key.equals(other$key)) { | ||
| return false; | ||
| } | ||
| final Object this$value = this.value; | ||
| final Object other$value = other.value; | ||
| if (this$value == null ? other$value != null : !this$value.equals(other$value)) { | ||
| return false; | ||
| } | ||
| final Object this$host = this.host; | ||
| final Object other$host = other.host; | ||
| if (this$host == null ? other$host != null : !this$host.equals(other$host)) { | ||
| return false; | ||
| } | ||
| final Object this$tags = this.tags; | ||
| final Object other$tags = other.tags; | ||
| if (this$tags == null ? other$tags != null : !this$tags.equals(other$tags)) { | ||
| return false; | ||
| } | ||
| final Object this$attributes = this.attributes; | ||
| final Object other$attributes = other.attributes; | ||
| if (this$attributes == null ? other$attributes != null | ||
| : !this$attributes.equals(other$attributes)) { | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| private boolean canEqual(final Object other) { | ||
| return other instanceof com.spotify.ffwd.Metric; | ||
| } | ||
|
|
||
| @SuppressWarnings({ "AbbreviationAsWordInName" }) | ||
| public int hashCode() { | ||
| final int PRIME = 59; | ||
| int result = 1; | ||
| final long $has = this.has; | ||
| result = result * PRIME + (int) ($has >>> 32 ^ $has); | ||
| final long $time = this.time; | ||
| result = result * PRIME + (int) ($time >>> 32 ^ $time); | ||
| final Object $key = this.key; | ||
| result = result * PRIME + ($key == null ? 43 : $key.hashCode()); | ||
| final Object $value = this.value; | ||
| result = result * PRIME + ($value == null ? 43 : $value.hashCode()); | ||
| final Object $host = this.host; | ||
| result = result * PRIME + ($host == null ? 43 : $host.hashCode()); | ||
| final Object $tags = this.tags; | ||
| result = result * PRIME + ($tags == null ? 43 : $tags.hashCode()); | ||
| final Object $attributes = this.attributes; | ||
| result = result * PRIME + ($attributes == null ? 43 : $attributes.hashCode()); | ||
| return result; | ||
| } | ||
|
|
||
|
|
||
| public long getTime() { | ||
| return this.time; | ||
| } | ||
|
|
||
| public String getKey() { | ||
| return this.key; | ||
| } | ||
|
|
||
| public Value getValue() { | ||
| return this.value; | ||
| } | ||
|
|
||
| public String getHost() { | ||
| return this.host; | ||
| } | ||
|
|
||
| public List<String> getTags() { | ||
| return this.tags; | ||
| } | ||
|
|
||
| public Map<String, String> getAttributes() { | ||
| return this.attributes; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| /*- | ||
| * -\-\- | ||
| * FastForward Java Client | ||
| * -- | ||
| * Copyright (C) 2016 - 2020 Spotify AB | ||
| * -- | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| * -/-/- | ||
| */ | ||
|
|
||
| package com.spotify.ffwd.v1; | ||
|
|
||
| import com.google.auto.value.AutoValue; | ||
|
|
||
| import java.nio.ByteBuffer; | ||
| import java.util.function.Function; | ||
|
|
||
|
|
||
|
|
||
| public abstract class Value { | ||
|
|
||
| Value() {} | ||
|
|
||
|
|
||
| public static Value doubleValue(double value) { | ||
| return DoubleValue.create(value); | ||
| } | ||
|
|
||
| public static Value distributionValue(ByteBuffer byteBuffer) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should take ByteString as input instead of ByteBuffer since ByteBuffer is not immutable |
||
| return DistributionValue.create(byteBuffer); | ||
| } | ||
|
|
||
|
|
||
| public abstract <T> T match( | ||
| Function<? super Double, T> doubleFunction, | ||
| Function<? super ByteBuffer, T> distributionFunction, | ||
| Function<? super Value, T> defaultFunction); | ||
|
|
||
|
|
||
| @AutoValue | ||
| abstract static class DoubleValue extends Value { | ||
|
|
||
| DoubleValue() {} | ||
|
|
||
| @Override | ||
| public final <T> T match( | ||
| Function<? super Double, T> doubleFunction, | ||
| Function<? super ByteBuffer, T> distributionFunction, | ||
| Function<? super Value, T> defaultFunction) { | ||
| return doubleFunction.apply(getValue()); | ||
| } | ||
|
|
||
|
|
||
| static DoubleValue create(double value) { | ||
| return new AutoValue_Value_DoubleValue(value); | ||
| } | ||
|
|
||
|
|
||
| abstract double getValue(); | ||
| } | ||
|
|
||
| @AutoValue | ||
| abstract static class DistributionValue extends Value { | ||
|
|
||
| DistributionValue() {} | ||
|
|
||
| @Override | ||
| public final <T> T match( | ||
| Function<? super Double, T> doubleFunction, | ||
| Function<? super ByteBuffer, T> distributionFunction, | ||
| Function<? super Value, T> defaultFunction) { | ||
| return distributionFunction.apply(getValue()); | ||
| } | ||
|
|
||
|
|
||
| static DistributionValue create(ByteBuffer value) { | ||
| return new AutoValue_Value_DistributionValue(value); | ||
| } | ||
|
|
||
|
|
||
| abstract ByteBuffer getValue(); | ||
| } | ||
|
|
||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we avoid using auto value and try keep this client lean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above