diff --git a/README.md b/README.md
index 2e249d9b..c2db7ba2 100644
--- a/README.md
+++ b/README.md
@@ -275,6 +275,9 @@ Out of the box output writers:
* `retentionPolicy`: retention policy to use - optional
* `connectTimeoutMillis`: connect timeout for the HTTP connection to influx - optional, defaults to 3000
* `readTimeoutMillis`: read timeout for the HTTP connection to influx - optional, defaults to 5000
+* [CloudWatchOutputWriter](https://github.com/jmxtrans/jmxtrans-agent/blob/master/src/main/java/org/jmxtrans/agent/CloudWatchOutputWriter.java): Output to AWS CloudWatch Metrics. Credentials and region are loaded using the default region and credential providers (https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudwatch/CloudWatchClient.html#create--). Configuration parameters:
+ * `namespace`: Cloudwatch namespace. Default is "JMX". e.g. `JMX/Production`. - optional
+ * `dimensions`: additional dimensions to use for all metrics. Use `n1:v1,n2:v2` format, e.g. `host:#hostname#` - optional
Output writers configuration support an [expression language](https://github.com/jmxtrans/jmxtrans-agent/wiki/Expression-Language) based on property placeholders with the `{prop-name[:default-value]}` syntax (e.g. "`${graphite.port:2003}`").
@@ -365,6 +368,13 @@ tomcat.bytesReceived 0
application.activeSessions 0
```
+# Building
+
+```
+mvn compile
+mvn package
+```
+
# Release Notes
diff --git a/pom.xml b/pom.xml
index dd44d194..4874b8be 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,6 +40,17 @@
https://github.com/jmxtrans/jmxtrans-agent
HEAD
+
+
+
+ software.amazon.awssdk
+ bom
+ 2.13.0
+ pom
+ import
+
+
+
com.sun
@@ -90,14 +101,16 @@
2.5.1
test
-
+
+ software.amazon.awssdk
+ cloudwatch
+
org.apache.maven.plugins
- maven-jar-plugin
- 3.0.2
+ maven-assembly-plugin
@@ -111,14 +124,28 @@
+
+
+ create-my-bundle
+ package
+
+ single
+
+
+
+ jar-with-dependencies
+
+
+
+
org.apache.maven.plugins
maven-compiler-plugin
3.6.1
-
- 1.7
+
+ 1.8
diff --git a/src/main/java/org/jmxtrans/agent/CloudWatchOutputWriter.java b/src/main/java/org/jmxtrans/agent/CloudWatchOutputWriter.java
new file mode 100644
index 00000000..1651cbfa
--- /dev/null
+++ b/src/main/java/org/jmxtrans/agent/CloudWatchOutputWriter.java
@@ -0,0 +1,81 @@
+package org.jmxtrans.agent;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import org.jmxtrans.agent.util.ConfigurationUtils;
+import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient;
+import software.amazon.awssdk.services.cloudwatch.model.CloudWatchException;
+import software.amazon.awssdk.services.cloudwatch.model.Dimension;
+import software.amazon.awssdk.services.cloudwatch.model.MetricDatum;
+import software.amazon.awssdk.services.cloudwatch.model.PutMetricDataRequest;
+
+public class CloudWatchOutputWriter extends AbstractOutputWriter {
+
+ private CloudWatchAsyncClient client;
+ private String configNamespace;
+ private String configDimensions;
+ private List listOfDimensions;
+ private Collection dimensions;
+
+ @Override
+ public void postConstruct(Map settings) {
+
+ client = CloudWatchAsyncClient.create();
+ configNamespace = ConfigurationUtils.getString(settings, "namespace", "JMX");
+ configDimensions = ConfigurationUtils.getString(settings, "dimensions", "");
+ listOfDimensions = Tag.tagsFromCommaSeparatedString(configDimensions);
+
+ dimensions = new ArrayList();
+
+ for (Tag thisDimension : listOfDimensions) {
+ dimensions.add(
+ Dimension.builder()
+ .name(thisDimension.getName())
+ .value(thisDimension.getValue())
+ .build());
+ }
+ }
+
+ @Override
+ public void writeQueryResult(String name, String type, Object value) {
+
+ Double doubleValue;
+
+ if (value instanceof Number) {
+ Number numberValue = (Number) value;
+ doubleValue = numberValue.doubleValue();
+ } else {
+ logger.log(Level.WARNING, "Cannot write result " + name + ". " + value + " is not a Number.");
+ return;
+ }
+
+ try {
+
+ MetricDatum datum =
+ MetricDatum.builder().metricName(name).value(doubleValue).dimensions(dimensions).build();
+
+ PutMetricDataRequest request =
+ PutMetricDataRequest.builder().namespace(configNamespace).metricData(datum).build();
+
+ client.putMetricData(request);
+
+ } catch (CloudWatchException e) {
+ logger.log(Level.SEVERE, e.awsErrorDetails().errorMessage());
+ }
+ }
+
+ @Override
+ public void writeInvocationResult(String invocationName, Object value) throws IOException {
+ writeQueryResult(invocationName, null, value);
+ }
+
+ @Override
+ public void preDestroy() {
+ super.preDestroy();
+ client.close();
+ }
+}