This repository has been archived by the owner on Dec 19, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding CloudWatchEmbeddedMetricsReporter
- Loading branch information
Showing
15 changed files
with
898 additions
and
12 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
20 changes: 20 additions & 0 deletions
20
reporters/src/main/java/com/nextdoor/bender/monitoring/ReporterUtils.java
This file contains 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,20 @@ | ||
package com.nextdoor.bender.monitoring; | ||
|
||
import com.amazonaws.services.cloudwatch.model.Dimension; | ||
|
||
import java.util.*; | ||
import java.util.stream.Collectors; | ||
|
||
/** | ||
* Utils class to capture static methods used across multiple reporters | ||
*/ | ||
public class ReporterUtils { | ||
|
||
public static List<Dimension> tagsToDimensions(final Set<Tag> tags) { | ||
return tags.stream().map(e -> tagToDim(e.getKey(), e.getValue())).collect(Collectors.toList()); | ||
} | ||
|
||
private static Dimension tagToDim(String name, String value) { | ||
return new Dimension().withName(name).withValue(value != null ? value : "None"); | ||
} | ||
} |
This file contains 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
35 changes: 35 additions & 0 deletions
35
reporters/src/main/java/com/nextdoor/bender/monitoring/embedded/metrics/AWSMetricObject.java
This file contains 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,35 @@ | ||
package com.nextdoor.bender.monitoring.embedded.metrics; | ||
|
||
import com.google.gson.annotations.SerializedName; | ||
|
||
import java.util.List; | ||
|
||
public class AWSMetricObject { | ||
@SerializedName(value = "Timestamp") | ||
private long timestamp; | ||
|
||
@SerializedName(value = "CloudWatchMetrics") | ||
private List<CloudWatchMetricObject> cloudWatchMetricObjects; | ||
|
||
public AWSMetricObject(long timestamp, | ||
List<CloudWatchMetricObject> cloudWatchMetricObjects) { | ||
this.timestamp = timestamp; | ||
this.cloudWatchMetricObjects = cloudWatchMetricObjects; | ||
} | ||
|
||
public long getTimestamp() { | ||
return timestamp; | ||
} | ||
|
||
public void setTimestamp(int timestamp) { | ||
this.timestamp = timestamp; | ||
} | ||
|
||
public List<CloudWatchMetricObject> getCloudWatchMetricObjects() { | ||
return cloudWatchMetricObjects; | ||
} | ||
|
||
public void setCloudWatchMetricObjects(List<CloudWatchMetricObject> cloudWatchMetricObjects) { | ||
this.cloudWatchMetricObjects = cloudWatchMetricObjects; | ||
} | ||
} |
132 changes: 132 additions & 0 deletions
132
...va/com/nextdoor/bender/monitoring/embedded/metrics/CloudWatchEmbeddedMetricsReporter.java
This file contains 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,132 @@ | ||
/* | ||
* 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. | ||
* | ||
* Copyright 2017 Nextdoor.com, Inc | ||
* | ||
*/ | ||
|
||
package com.nextdoor.bender.monitoring.embedded.metrics; | ||
|
||
import com.amazonaws.services.cloudwatch.model.Dimension; | ||
import com.amazonaws.services.cloudwatch.model.StandardUnit; | ||
import com.google.gson.Gson; | ||
import com.nextdoor.bender.monitoring.Reporter; | ||
import com.nextdoor.bender.monitoring.Stat; | ||
import com.nextdoor.bender.monitoring.StatFilter; | ||
import com.nextdoor.bender.monitoring.Tag; | ||
|
||
import java.util.*; | ||
import java.util.stream.Collectors; | ||
|
||
import static com.nextdoor.bender.monitoring.ReporterUtils.tagsToDimensions; | ||
|
||
/** | ||
* This reporter writes metrics by outputting to the Lambda stdout in the CW embedded metrics format | ||
* Doc link: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format_Generation.html | ||
*/ | ||
public class CloudWatchEmbeddedMetricsReporter implements Reporter { | ||
private final String namespace; | ||
private final List<StatFilter> statFilters; | ||
private final Gson gson; | ||
|
||
public CloudWatchEmbeddedMetricsReporter(final String namespace, | ||
final List<StatFilter> statFilters) { | ||
this.namespace = namespace; | ||
this.statFilters = statFilters; | ||
this.gson = new Gson(); | ||
} | ||
|
||
@Override | ||
public void write(ArrayList<Stat> stats, long invokeTimeMs, Set<Tag> tags) { | ||
Map<String, String> dimensions = tagsToDimensions(tags).stream() | ||
.collect(Collectors.toMap(Dimension::getName, Dimension::getValue)); | ||
String metricsJson = getCloudWatchEmbeddedMetricsJson(namespace, invokeTimeMs, dimensions, stats, gson); | ||
System.out.println(metricsJson); | ||
} | ||
|
||
|
||
@Override | ||
public List<StatFilter> getStatFilters() { | ||
return this.statFilters; | ||
} | ||
|
||
/** | ||
* Example of accepted format: | ||
* { | ||
* "_aws": { | ||
* "Timestamp": 1574109732004, | ||
* "CloudWatchMetrics": [ | ||
* { | ||
* "Namespace": "lambda-function-metrics", | ||
* "Dimensions": [["functionVersion"]], | ||
* "Metrics": [ | ||
* { | ||
* "Name": "time", | ||
* "Unit": "Milliseconds" | ||
* } | ||
* ] | ||
* } | ||
* ] | ||
* }, | ||
* "functionVersion": "$LATEST", | ||
* "time": 100, | ||
* "requestId": "989ffbf8-9ace-4817-a57c-e4dd734019ee" | ||
* } | ||
* | ||
* Java code example: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format_Generation_PutLogEvents.html | ||
*/ | ||
public static String getCloudWatchEmbeddedMetricsJson(String namespace, | ||
long timestamp, | ||
Map<String, String> dimensions, | ||
List<Stat> stats, | ||
Gson gson) { | ||
Map<String, Object> embeddedMetricsObject = new HashMap<>(); | ||
|
||
/* first add nodes for each dimension in the embedded object since it'll be shared by all stats/metrics */ | ||
dimensions.forEach(embeddedMetricsObject::put); | ||
|
||
/* Each stat is essentially a metric so iterate through each stat (metric). | ||
We can be confident there are now duplicate stats since handler guarantees that | ||
*/ | ||
List<CloudWatchMetricObject> cwMetricObjects = new ArrayList<>(); | ||
stats.forEach(s -> { | ||
/* each CloudWatchMetric object will have the overall dimensions at the operation level */ | ||
List<String> allDimensions = new ArrayList<>(dimensions.keySet()); | ||
List<Dimension> statDimensions = tagsToDimensions(s.getTags()); | ||
allDimensions.addAll(statDimensions.stream() | ||
.map(Dimension::getName) | ||
.collect(Collectors.toList())); | ||
|
||
allDimensions = allDimensions.stream() | ||
.distinct() | ||
.collect(Collectors.toList()); | ||
|
||
/* add dimension name/value to main embedded metrics object */ | ||
statDimensions.forEach(d -> embeddedMetricsObject.put(d.getName(), d.getValue())); | ||
|
||
/* add stat metric info as overall field */ | ||
embeddedMetricsObject.put(s.getName(), s.getValue()); | ||
|
||
/* each stat will have a unique CloudWatchMetric object */ | ||
cwMetricObjects.add(new CloudWatchMetricObject(namespace, | ||
Collections.singletonList(allDimensions), | ||
Collections.singletonList(new MetricPOJO(s.getName(), StandardUnit.None.toString()))) | ||
); | ||
|
||
}); | ||
|
||
/* finally add overall node with list of CWMetric objects */ | ||
embeddedMetricsObject.put("_aws", new AWSMetricObject(timestamp, cwMetricObjects)); | ||
|
||
return gson.toJson(embeddedMetricsObject); | ||
} | ||
|
||
} |
43 changes: 43 additions & 0 deletions
43
.../nextdoor/bender/monitoring/embedded/metrics/CloudWatchEmbeddedMetricsReporterConfig.java
This file contains 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,43 @@ | ||
/* | ||
* 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. | ||
* | ||
* Copyright 2017 Nextdoor.com, Inc | ||
* | ||
*/ | ||
|
||
package com.nextdoor.bender.monitoring.embedded.metrics; | ||
|
||
import com.fasterxml.jackson.annotation.JsonTypeName; | ||
import com.kjetland.jackson.jsonSchema.annotations.JsonSchemaDefault; | ||
import com.kjetland.jackson.jsonSchema.annotations.JsonSchemaDescription; | ||
import com.nextdoor.bender.monitoring.RegionalReporterConfig; | ||
|
||
@JsonTypeName("CloudWatchEmbeddedMetrics") | ||
@JsonSchemaDescription("Writes metrics to Cloudwatch by printing to stdout. It is important to consider costs when " | ||
+ "using this reporter see https://aws.amazon.com/cloudwatch/pricing/.") | ||
public class CloudWatchEmbeddedMetricsReporterConfig extends RegionalReporterConfig { | ||
@JsonSchemaDefault("Nextdoor/bender") | ||
@JsonSchemaDescription("Cloudwatch namespace to write metrics under.") | ||
private String namespace = "Nextdoor/bender"; | ||
|
||
@Override | ||
public Class<CloudWatchEmbeddedMetricsReporterFactory> getFactoryClass() { | ||
return CloudWatchEmbeddedMetricsReporterFactory.class; | ||
} | ||
|
||
public String getNamespace() { | ||
return namespace; | ||
} | ||
|
||
public void setNamespace(String namespace) { | ||
this.namespace = namespace; | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
...nextdoor/bender/monitoring/embedded/metrics/CloudWatchEmbeddedMetricsReporterFactory.java
This file contains 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,42 @@ | ||
/* | ||
* 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. | ||
* | ||
* Copyright 2017 Nextdoor.com, Inc | ||
* | ||
*/ | ||
|
||
package com.nextdoor.bender.monitoring.embedded.metrics; | ||
|
||
import com.nextdoor.bender.config.AbstractConfig; | ||
import com.nextdoor.bender.monitoring.ReporterFactory; | ||
|
||
/** | ||
* Crate a {@link CloudWatchEmbeddedMetricsReporter}. | ||
*/ | ||
public class CloudWatchEmbeddedMetricsReporterFactory implements ReporterFactory { | ||
private CloudWatchEmbeddedMetricsReporterConfig config; | ||
|
||
@Override | ||
public void setConf(AbstractConfig config) { | ||
this.config = (CloudWatchEmbeddedMetricsReporterConfig) config; | ||
} | ||
|
||
@Override | ||
public CloudWatchEmbeddedMetricsReporter newInstance() { | ||
return new CloudWatchEmbeddedMetricsReporter(this.config.getNamespace(), | ||
this.config.getStatFilters()); | ||
} | ||
|
||
@Override | ||
public Class<CloudWatchEmbeddedMetricsReporter> getChildClass() { | ||
return CloudWatchEmbeddedMetricsReporter.class; | ||
} | ||
} |
49 changes: 49 additions & 0 deletions
49
...src/main/java/com/nextdoor/bender/monitoring/embedded/metrics/CloudWatchMetricObject.java
This file contains 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,49 @@ | ||
package com.nextdoor.bender.monitoring.embedded.metrics; | ||
|
||
import com.google.gson.annotations.SerializedName; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class CloudWatchMetricObject { | ||
@SerializedName(value = "Namespace") | ||
private String namespace; | ||
|
||
@SerializedName(value = "Dimensions") | ||
private List<List<String>> dimensions = new ArrayList<>(); | ||
|
||
@SerializedName(value = "Metrics") | ||
private List<MetricPOJO> metrics = new ArrayList<>(); | ||
|
||
public CloudWatchMetricObject(String namespace, | ||
List<List<String>> dimensions, | ||
List<MetricPOJO> metrics) { | ||
this.namespace = namespace; | ||
this.dimensions = dimensions; | ||
this.metrics = metrics; | ||
} | ||
|
||
public void setNamespace(String namespace) { | ||
this.namespace = namespace; | ||
} | ||
|
||
public String getNamespace() { | ||
return namespace; | ||
} | ||
|
||
public void setDimensions(List<List<String>> dimensions) { | ||
this.dimensions = dimensions; | ||
} | ||
|
||
public List<List<String>> getDimensions() { | ||
return dimensions; | ||
} | ||
|
||
public void setMetrics(List<MetricPOJO> metrics) { | ||
this.metrics = metrics; | ||
} | ||
|
||
public List<MetricPOJO> getMetrics() { | ||
return metrics; | ||
} | ||
} |
Oops, something went wrong.