-
Notifications
You must be signed in to change notification settings - Fork 866
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature: EmfMetricLoggingPublisher (#5792)
* EmfMetricPublisher class added (#5752) * EmfMetricPublisher class with basic unit test added * Edge cases handled * javadoc for class added * Java doc for methods added * minor unit test changes * Change from using jacksonCore directly to using jsonWriter * EmfMetricConfiguration class added * MetricEmfConverter class added * new module checklist done * checkStyle fixed * minor build problem fixed * internal package added * fixed the issue passing raw objects * added java clock to unit test * added unit test for publish method * minor changes * config class to builder pattern * config class to builder pattern * minor change * End to end test passed * added valid case in WARN_LOG allowlist * unit tests adjusted * Change logGroupName to required field * move MetricValueNormalizer class to utils package * converter implementation changed * schemaConformTest added * SchemaConformTest adjusted * minor change * emf metric publisher performance test (#5775) * Benchmark test for emfMetricPublisher added * input name changed * add emfBenchmarkTest to BenchmarkRunner * enabled METRIC_BENCHMARKS * checkStyle fixed * Changed the classname to EmfMetricLoggingPublisher (#5783) * change class name and artifactId * test-coverage pom changed * javadoc fixed * Cloudwatch and Logging benchmark test added / Changed logGroupName config (#5790) * more benchmark test added/changed logGroupName config * teardown method overrided * logGroupName access method changed * Snapshot version changed * LogGroupName in lambda unit test added * suppression added for system * changelog added * changeLog modified * minor fix * snapshot version fixed * Snapshot version changed
- Loading branch information
Showing
28 changed files
with
1,542 additions
and
14 deletions.
There are no files selected for viewing
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
6 changes: 6 additions & 0 deletions
6
.changes/next-release/feature-EmfMetricLoggingPublisher-d96a2fb.json
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,6 @@ | ||
{ | ||
"type": "feature", | ||
"category": "Emf Metric Logging Publisher", | ||
"contributor": "", | ||
"description": "Added a new EmfMetricLoggingPublisher class that transforms SdkMetricCollection to emf format string and logs it, which will be automatically collected by cloudwatch." | ||
} |
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
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
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
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
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,78 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!-- | ||
~ Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
~ | ||
~ Licensed under the Apache License, Version 2.0 (the "License"). | ||
~ You may not use this file except in compliance with the License. | ||
~ A copy of the License is located at | ||
~ | ||
~ http://aws.amazon.com/apache2.0 | ||
~ | ||
~ or in the "license" file accompanying this file. This file 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. | ||
--> | ||
|
||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<parent> | ||
<groupId>software.amazon.awssdk</groupId> | ||
<artifactId>metric-publishers</artifactId> | ||
<version>2.30.3-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>emf-metric-logging-publisher</artifactId> | ||
<name>AWS Java SDK :: Metric Publishers :: Emf</name> | ||
<packaging>jar</packaging> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-jar-plugin</artifactId> | ||
<configuration> | ||
<archive> | ||
<manifestEntries> | ||
<Automatic-Module-Name>software.amazon.awssdk.metrics.publishers.emf</Automatic-Module-Name> | ||
</manifestEntries> | ||
</archive> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>software.amazon.awssdk</groupId> | ||
<artifactId>annotations</artifactId> | ||
<version>${awsjavasdk.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>software.amazon.awssdk</groupId> | ||
<artifactId>http-client-spi</artifactId> | ||
<version>${awsjavasdk.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>software.amazon.awssdk</groupId> | ||
<artifactId>json-utils</artifactId> | ||
<version>${awsjavasdk.version}</version> | ||
<scope>compile</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>software.amazon.awssdk</groupId> | ||
<artifactId>sdk-core</artifactId> | ||
<version>${awsjavasdk.version}</version> | ||
<scope>compile</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.networknt</groupId> | ||
<artifactId>json-schema-validator</artifactId> | ||
<version>${json-schema-validator.version}</version> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
</project> |
228 changes: 228 additions & 0 deletions
228
...rc/main/java/software/amazon/awssdk/metrics/publishers/emf/EmfMetricLoggingPublisher.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,228 @@ | ||
/* | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"). | ||
* You may not use this file except in compliance with the License. | ||
* A copy of the License is located at | ||
* | ||
* http://aws.amazon.com/apache2.0 | ||
* | ||
* or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.metrics.publishers.emf; | ||
|
||
|
||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.Collection; | ||
import java.util.List; | ||
import software.amazon.awssdk.annotations.Immutable; | ||
import software.amazon.awssdk.annotations.SdkPublicApi; | ||
import software.amazon.awssdk.annotations.ThreadSafe; | ||
import software.amazon.awssdk.core.metrics.CoreMetric; | ||
import software.amazon.awssdk.metrics.MetricCategory; | ||
import software.amazon.awssdk.metrics.MetricCollection; | ||
import software.amazon.awssdk.metrics.MetricLevel; | ||
import software.amazon.awssdk.metrics.MetricPublisher; | ||
import software.amazon.awssdk.metrics.SdkMetric; | ||
import software.amazon.awssdk.metrics.publishers.emf.internal.EmfMetricConfiguration; | ||
import software.amazon.awssdk.metrics.publishers.emf.internal.MetricEmfConverter; | ||
import software.amazon.awssdk.utils.Logger; | ||
|
||
/** | ||
* A metric publisher implementation that converts metrics into CloudWatch Embedded Metric Format (EMF). | ||
* EMF allows metrics to be published through CloudWatch Logs using a structured JSON format, which | ||
* CloudWatch automatically extracts and processes into metrics. | ||
* | ||
* <p> | ||
* This publisher is particularly well-suited for serverless environments like AWS Lambda and container | ||
* environments like Amazon ECS that have built-in integration with CloudWatch Logs. Using EMF eliminates | ||
* the need for separate metric publishing infrastructure as metrics are automatically extracted from | ||
* log entries. | ||
* </p> | ||
* | ||
* <p> | ||
* The EMF publisher converts metric collections into JSON-formatted log entries that conform to the | ||
* CloudWatch EMF specification. The logGroupName field is required for EMF to work. | ||
* CloudWatch automatically processes these logs to generate corresponding metrics that can be used for | ||
* monitoring and alerting. | ||
* </p> | ||
* | ||
* @snippet | ||
* // Create a EmfMetricLoggingPublisher using a custom namespace. | ||
* MetricPublisher emfMetricLoggingPublisher = EmfMetricLoggingPublisher.builder() | ||
* .logGroupName("myLogGroupName") | ||
* .namespace("myApplication") | ||
* .build(); | ||
* | ||
* @see MetricPublisher The base interface for metric publishers | ||
* @see MetricCollection For the collection of metrics to be published | ||
* @see EmfMetricConfiguration For configuration options | ||
* @see MetricEmfConverter For the conversion logic | ||
* | ||
*/ | ||
|
||
@ThreadSafe | ||
@Immutable | ||
@SdkPublicApi | ||
public final class EmfMetricLoggingPublisher implements MetricPublisher { | ||
|
||
private static final Logger logger = Logger.loggerFor(EmfMetricLoggingPublisher.class); | ||
private final MetricEmfConverter metricConverter; | ||
|
||
|
||
private EmfMetricLoggingPublisher(Builder builder) { | ||
EmfMetricConfiguration config = new EmfMetricConfiguration.Builder() | ||
.namespace(builder.namespace) | ||
.logGroupName(builder.logGroupName) | ||
.dimensions(builder.dimensions) | ||
.metricLevel(builder.metricLevel) | ||
.metricCategories(builder.metricCategories) | ||
.build(); | ||
|
||
this.metricConverter = new MetricEmfConverter(config); | ||
} | ||
|
||
|
||
public static Builder builder() { | ||
return new Builder(); | ||
} | ||
|
||
|
||
@Override | ||
public void publish(MetricCollection metricCollection) { | ||
if (metricCollection == null) { | ||
logger.warn(() -> "Null metric collection passed to the publisher"); | ||
return; | ||
} | ||
try { | ||
List<String> emfStrings = metricConverter.convertMetricCollectionToEmf(metricCollection); | ||
for (String emfString : emfStrings) { | ||
logger.info(() -> emfString); | ||
} | ||
} catch (Exception e) { | ||
logger.error(() -> "Failed to log metrics in EMF format", e); | ||
} | ||
} | ||
|
||
/** | ||
* Closes this metric publisher. This implementation is empty as the EMF metric logging publisher | ||
* does not maintain any resources that require explicit cleanup. | ||
*/ | ||
@Override | ||
public void close() { | ||
} | ||
|
||
public static final class Builder { | ||
private String namespace; | ||
private String logGroupName; | ||
private Collection<SdkMetric<String>> dimensions; | ||
private Collection<MetricCategory> metricCategories; | ||
private MetricLevel metricLevel; | ||
|
||
private Builder() { | ||
} | ||
|
||
/** | ||
* Configure the namespace that will be put into the emf log to this publisher. | ||
* | ||
* <p>If this is not specified, {@code AwsSdk/JavaSdk2} will be used. | ||
*/ | ||
public Builder namespace(String namespace) { | ||
this.namespace = namespace; | ||
return this; | ||
} | ||
|
||
/** | ||
* Configure the {@link SdkMetric} that are used to define the Dimension Set Array that will be put into the emf log to | ||
* this | ||
* publisher. | ||
* | ||
* <p>If this is not specified, {@link CoreMetric#SERVICE_ID} and {@link CoreMetric#OPERATION_NAME} will be used. | ||
*/ | ||
public Builder dimensions(Collection<SdkMetric<String>> dimensions) { | ||
this.dimensions = new ArrayList<>(dimensions); | ||
return this; | ||
} | ||
|
||
/** | ||
* @see #dimensions(SdkMetric[]) | ||
*/ | ||
@SafeVarargs | ||
public final Builder dimensions(SdkMetric<String>... dimensions) { | ||
return dimensions(Arrays.asList(dimensions)); | ||
} | ||
|
||
|
||
/** | ||
* Configure the {@link MetricCategory}s that should be uploaded to CloudWatch. | ||
* | ||
* <p>If this is not specified, {@link MetricCategory#ALL} is used. | ||
* | ||
* <p>All {@link SdkMetric}s are associated with at least one {@code MetricCategory}. This setting determines which | ||
* category of metrics uploaded to CloudWatch. Any metrics {@link #publish(MetricCollection)}ed that do not fall under | ||
* these configured categories are ignored. | ||
* | ||
* <p>Note: If there are {@link #dimensions(Collection)} configured that do not fall under these {@code MetricCategory} | ||
* values, the dimensions will NOT be ignored. In other words, the metric category configuration only affects which | ||
* metrics are uploaded to CloudWatch, not which values can be used for {@code dimensions}. | ||
*/ | ||
public Builder metricCategories(Collection<MetricCategory> metricCategories) { | ||
this.metricCategories = new ArrayList<>(metricCategories); | ||
return this; | ||
} | ||
|
||
/** | ||
* @see #metricCategories(Collection) | ||
*/ | ||
public Builder metricCategories(MetricCategory... metricCategories) { | ||
return metricCategories(Arrays.asList(metricCategories)); | ||
} | ||
|
||
/** | ||
* Configure the LogGroupName key that will be put into the emf log to this publisher. This is required when using | ||
* the CloudWatch agent to send embedded metric format logs that tells the agent which log | ||
* group to use. | ||
* | ||
* <p> If this is not specified, for AWS lambda environments, {@code AWS_LAMBDA_LOG_GROUP_NAME} | ||
* is used. | ||
* This field is required and must not be null or empty for non-lambda environments. | ||
* @throws NullPointerException if non-lambda environment and logGroupName is null | ||
*/ | ||
public Builder logGroupName(String logGroupName) { | ||
this.logGroupName = logGroupName; | ||
return this; | ||
} | ||
|
||
/** | ||
* Configure the {@link MetricLevel} that should be uploaded to CloudWatch. | ||
* | ||
* <p>If this is not specified, {@link MetricLevel#INFO} is used. | ||
* | ||
* <p>All {@link SdkMetric}s are associated with one {@code MetricLevel}. This setting determines which level of metrics | ||
* uploaded to CloudWatch. Any metrics {@link #publish(MetricCollection)}ed that do not fall under these configured | ||
* categories are ignored. | ||
* | ||
* <p>Note: If there are {@link #dimensions(Collection)} configured that do not fall under this {@code MetricLevel} | ||
* values, the dimensions will NOT be ignored. In other words, the metric category configuration only affects which | ||
* metrics are uploaded to CloudWatch, not which values can be used for {@code dimensions}. | ||
*/ | ||
public Builder metricLevel(MetricLevel metricLevel) { | ||
this.metricLevel = metricLevel; | ||
return this; | ||
} | ||
|
||
|
||
/** | ||
* Build a {@link EmfMetricLoggingPublisher} using the configuration currently configured on this publisher. | ||
*/ | ||
public EmfMetricLoggingPublisher build() { | ||
return new EmfMetricLoggingPublisher(this); | ||
} | ||
|
||
} | ||
} |
Oops, something went wrong.