This is an automated email from the ASF dual-hosted git repository.

ritesh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git


The following commit(s) were added to refs/heads/master by this push:
     new daeb18bf53 HDDS-9717. Add P99 quantiles and Min/Max Metrics for S3G 
Performance Metrics (#5627)
daeb18bf53 is described below

commit daeb18bf53c445e79853d7c017c22bc3949a29c9
Author: XiChen <[email protected]>
AuthorDate: Fri Jan 12 05:23:00 2024 +0800

    HDDS-9717. Add P99 quantiles and Min/Max Metrics for S3G Performance 
Metrics (#5627)
---
 .../java/org/apache/hadoop/util/MetricUtil.java    | 36 ++++++++
 .../java/org/apache/hadoop/util/MutableMinMax.java | 93 +++++++++++++++++++++
 .../org/apache/hadoop/util/PerformanceMetrics.java | 97 ++++++++++++++++++++++
 .../hadoop/util/PerformanceMetricsInitializer.java | 83 ++++++++++++++++++
 .../common/src/main/resources/ozone-default.xml    |  8 ++
 .../hadoop/ozone/TestMultipartObjectGet.java       |  2 +
 .../java/org/apache/hadoop/ozone/s3/Gateway.java   |  2 +-
 .../hadoop/ozone/s3/S3GatewayConfigKeys.java       |  3 +
 .../hadoop/ozone/s3/endpoint/EndpointBase.java     |  2 +-
 .../ozone/s3/endpoint/ObjectEndpointStreaming.java | 12 ++-
 .../hadoop/ozone/s3/metrics/S3GatewayMetrics.java  | 96 +++++++++++----------
 .../hadoop/ozone/client/OzoneClientStub.java       |  4 +
 .../ozone/s3/endpoint/TestPermissionCheck.java     |  2 +
 13 files changed, 388 insertions(+), 52 deletions(-)

diff --git 
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/util/MetricUtil.java 
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/util/MetricUtil.java
index 879f8ed0cc..381314e69c 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/util/MetricUtil.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/util/MetricUtil.java
@@ -17,12 +17,18 @@
  */
 package org.apache.hadoop.util;
 
+import org.apache.hadoop.metrics2.lib.MetricsRegistry;
+import org.apache.hadoop.metrics2.lib.MutableQuantiles;
 import org.apache.hadoop.metrics2.lib.MutableRate;
 import org.apache.ratis.util.function.CheckedRunnable;
 import org.apache.ratis.util.function.CheckedSupplier;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
 
 /**
  * Encloses helpers to deal with metrics.
@@ -63,4 +69,34 @@ public final class MetricUtil {
       latencySetter.accept(Time.monotonicNowNanos() - start);
     }
   }
+
+  /**
+   * Creates MutableQuantiles metrics with one or multiple intervals.
+   *
+   * @param registry    The MetricsRegistry to register the new 
MutableQuantiles
+   *                   instances.
+   * @param name        The base name of the metric.
+   * @param description The description of the metric.
+   * @param sampleName of the metric (e.g., "Ops")
+   * @param valueName of the metric (e.g., "Time" or "Latency")
+   * @param intervals   An array of intervals for the quantiles.
+   * @return A list of created MutableQuantiles instances.
+   */
+  public static List<MutableQuantiles> createQuantiles(MetricsRegistry 
registry,
+      String name, String description, String sampleName, String valueName,
+      int... intervals) {
+    if (intervals == null) {
+      throw new IllegalArgumentException(
+          "At least one interval should be provided.");
+    }
+    if (intervals.length == 0) {
+      return new ArrayList<>();
+    }
+
+    return Arrays.stream(intervals).mapToObj(interval -> {
+      String quantileName = name + interval + "s";
+      return registry.newQuantiles(quantileName, description,
+          sampleName, valueName, interval);
+    }).collect(Collectors.toList());
+  }
 }
diff --git 
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/util/MutableMinMax.java 
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/util/MutableMinMax.java
new file mode 100644
index 0000000000..1f056ed742
--- /dev/null
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/util/MutableMinMax.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.util;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.metrics2.MetricsInfo;
+import org.apache.hadoop.metrics2.MetricsRecordBuilder;
+import org.apache.hadoop.metrics2.lib.MetricsRegistry;
+import org.apache.hadoop.metrics2.lib.MutableMetric;
+import org.apache.hadoop.metrics2.util.SampleStat.MinMax;
+import org.apache.commons.lang3.StringUtils;
+
+import static org.apache.hadoop.metrics2.lib.Interns.info;
+
+/**
+ * A mutable metric that tracks the minimum and maximum
+ * values of a dataset over time.
+ */
[email protected]
[email protected]
+public class MutableMinMax extends MutableMetric {
+  private final MinMax intervalMinMax = new MinMax();
+  private final MinMax prevMinMax = new MinMax();
+  private final MetricsInfo iMinInfo;
+  private final MetricsInfo iMaxInfo;
+
+  /**
+   * Construct a minMax metric.
+   * @param registry    MetricsRegistry of the metric
+   * @param name        of the metric
+   * @param description of the metric
+   * @param valueName   of the metric (e.g. "Time", "Latency")
+   */
+  public MutableMinMax(MetricsRegistry registry,
+      String name, String description, String valueName) {
+    String ucName = StringUtils.capitalize(name);
+    String desc = StringUtils.uncapitalize(description);
+    String uvName = StringUtils.capitalize(valueName);
+    String lvName = StringUtils.uncapitalize(valueName);
+    iMinInfo = info(ucName + "IMin" + uvName,
+        "Min " + lvName + " for " + desc + "in the last reporting interval");
+    iMaxInfo = info(ucName + "IMax" + uvName,
+        "Max " + lvName + " for " + desc + "in the last reporting interval");
+    // hadoop.metrics2 only supports standard types of Metrics registered
+    // with annotations, but not custom types of metrics.
+    // Registering here is for compatibility with metric classes
+    // that are only registered with annotations and do not override 
getMetrics.
+    registry.newGauge(iMinInfo, 0);
+    registry.newGauge(iMaxInfo, 0);
+  }
+
+  /**
+   * Add a snapshot to the metric.
+   * @param value of the metric
+   */
+  public synchronized void add(long value) {
+    intervalMinMax.add(value);
+    setChanged();
+  }
+
+  private MinMax lastMinMax() {
+    return changed() ? intervalMinMax : prevMinMax;
+  }
+
+  @Override
+  public synchronized void snapshot(MetricsRecordBuilder builder, boolean all) 
{
+    if (all || this.changed()) {
+      builder.addGauge(iMinInfo, lastMinMax().min());
+      builder.addGauge(iMaxInfo, lastMinMax().max());
+      if (changed()) {
+        prevMinMax.reset(intervalMinMax);
+        intervalMinMax.reset();
+        clearChanged();
+      }
+    }
+  }
+}
diff --git 
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/util/PerformanceMetrics.java
 
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/util/PerformanceMetrics.java
new file mode 100644
index 0000000000..a470ff9657
--- /dev/null
+++ 
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/util/PerformanceMetrics.java
@@ -0,0 +1,97 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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 org.apache.hadoop.util;
+
+import org.apache.hadoop.metrics2.MetricsRecordBuilder;
+import org.apache.hadoop.metrics2.lib.MetricsRegistry;
+import org.apache.hadoop.metrics2.lib.MutableQuantiles;
+import org.apache.hadoop.metrics2.lib.MutableStat;
+
+import java.util.List;
+
+/**
+ * The {@code PerformanceMetrics} class encapsulates a collection of related
+ * metrics including a MutableStat, MutableQuantiles, and a MutableMinMax.
+ * This class provides methods to update these metrics and to
+ * snapshot their values for reporting.
+ */
+public class PerformanceMetrics {
+  private final MutableStat stat;
+  private final List<MutableQuantiles> quantiles;
+  private final MutableMinMax minMax;
+
+  /**
+   * Initializes aggregated metrics for the specified metrics source.
+   *
+   * @param source the metrics source
+   * @param registry the metrics registry
+   * @param intervals the intervals for quantiles computation. Note, each
+   *        interval in 'intervals' increases memory usage, as it corresponds
+   *        to a separate quantile calculator.
+   */
+  public static synchronized <T> void initializeMetrics(T source,
+      MetricsRegistry registry, String sampleName, String valueName,
+      int[] intervals) {
+    try {
+      PerformanceMetricsInitializer.initialize(
+          source, registry, sampleName, valueName, intervals);
+    } catch (IllegalAccessException e) {
+      throw new RuntimeException("Failed to initialize PerformanceMetrics", e);
+    }
+  }
+
+  /**
+   * Construct an instance of PerformanceMetrics with the specified 
MutableStat,
+   * MutableQuantiles, and MutableMinMax.
+   *
+   * @param stat the stat metric
+   * @param quantiles the quantiles metrics
+   * @param minMax the min/max tracker
+   */
+  public PerformanceMetrics(MutableStat stat,
+      List<MutableQuantiles> quantiles, MutableMinMax minMax) {
+    this.stat = stat;
+    this.quantiles = quantiles;
+    this.minMax = minMax;
+  }
+
+  /**
+   * Adds a value to all the aggregated metrics.
+   *
+   * @param value the value to add
+   */
+  public void add(long value) {
+    this.stat.add(value);
+    this.quantiles.forEach(quantile -> quantile.add(value));
+    this.minMax.add(value);
+  }
+
+  /**
+   * Snapshots the values of all the aggregated metrics for reporting.
+   *
+   * @param recordBuilder the metrics record builder
+   * @param all flag to indicate whether to snapshot all metrics or only 
changed
+   */
+  public void snapshot(MetricsRecordBuilder recordBuilder, boolean all) {
+    this.stat.snapshot(recordBuilder, all);
+    this.quantiles.forEach(quantile -> quantile.snapshot(recordBuilder, all));
+    this.minMax.snapshot(recordBuilder, all);
+  }
+
+}
+
diff --git 
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/util/PerformanceMetricsInitializer.java
 
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/util/PerformanceMetricsInitializer.java
new file mode 100644
index 0000000000..83d61cab68
--- /dev/null
+++ 
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/util/PerformanceMetricsInitializer.java
@@ -0,0 +1,83 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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 org.apache.hadoop.util;
+
+import org.apache.hadoop.metrics2.annotation.Metric;
+import org.apache.hadoop.metrics2.lib.MetricsRegistry;
+
+import java.lang.reflect.Field;
+
+/**
+ * Utility class for initializing PerformanceMetrics in a MetricsSource.
+ */
+public final class PerformanceMetricsInitializer {
+  private PerformanceMetricsInitializer() { }
+
+  /**
+   * Initializes aggregated metrics in the given metrics source.
+   *
+   * @param source the metrics source
+   * @param registry the metrics registry
+   * @param sampleName sample name
+   * @param valueName value name
+   * @param intervals intervals for quantiles
+   * @throws IllegalAccessException if unable to access the field
+   */
+  public static <T> void initialize(T source, MetricsRegistry registry,
+      String sampleName, String valueName, int[] intervals)
+      throws IllegalAccessException {
+    Field[] fields = source.getClass().getDeclaredFields();
+
+    for (Field field : fields) {
+      if (field.getType() == PerformanceMetrics.class) {
+        Metric annotation = field.getAnnotation(Metric.class);
+        if (annotation != null) {
+          String description = annotation.about();
+          String name = field.getName();
+          PerformanceMetrics performanceMetrics =
+              getMetrics(registry, name, description,
+                  sampleName, valueName, intervals);
+          field.setAccessible(true);
+          field.set(source, performanceMetrics);
+        }
+      }
+    }
+  }
+
+  /**
+   * Helper method to create PerformanceMetrics.
+   *
+   * @param registry the metrics registry
+   * @param name metric name
+   * @param description metric description
+   * @param sampleName sample name
+   * @param valueName value name
+   * @param intervals intervals for quantiles
+   * @return an instance of PerformanceMetrics
+   */
+  private static PerformanceMetrics getMetrics(
+      MetricsRegistry registry, String name, String description,
+      String sampleName, String valueName, int[] intervals) {
+    return new PerformanceMetrics(
+        registry.newStat(
+            name, description, sampleName, valueName, false),
+        MetricUtil.createQuantiles(
+            registry, name, description, sampleName, valueName, intervals),
+        new MutableMinMax(registry, name, description, valueName));
+  }
+}
diff --git a/hadoop-hdds/common/src/main/resources/ozone-default.xml 
b/hadoop-hdds/common/src/main/resources/ozone-default.xml
index 079362f916..f7a1e7ef66 100644
--- a/hadoop-hdds/common/src/main/resources/ozone-default.xml
+++ b/hadoop-hdds/common/src/main/resources/ozone-default.xml
@@ -1876,6 +1876,14 @@
       will be used for http authentication.
     </description>
   </property>
+  <property>
+    <name>ozone.s3g.metrics.percentiles.intervals.seconds</name>
+    <value>60</value>
+    <tag>S3GATEWAY, PERFORMANCE</tag>
+    <description>Specifies the interval in seconds for the rollover of 
MutableQuantiles metrics.
+      Setting this interval equal to the metrics sampling time ensures more 
detailed metrics.
+    </description>
+  </property>
 
   <property>
     <name>ozone.om.save.metrics.interval</name>
diff --git 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestMultipartObjectGet.java
 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestMultipartObjectGet.java
index c3e6c288d7..cec90067da 100644
--- 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestMultipartObjectGet.java
+++ 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestMultipartObjectGet.java
@@ -27,6 +27,7 @@ import 
org.apache.hadoop.ozone.s3.endpoint.CompleteMultipartUploadResponse;
 import org.apache.hadoop.ozone.s3.endpoint.MultipartUploadInitiateResponse;
 import org.apache.hadoop.ozone.s3.endpoint.ObjectEndpoint;
 import org.apache.hadoop.ozone.s3.exception.OS3Exception;
+import org.apache.hadoop.ozone.s3.metrics.S3GatewayMetrics;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
@@ -101,6 +102,7 @@ public class TestMultipartObjectGet {
     REST.setClient(client);
     REST.setOzoneConfiguration(conf);
     REST.setContext(context);
+    S3GatewayMetrics.create(conf);
   }
 
   private static void startCluster()
diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/Gateway.java 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/Gateway.java
index 6fc55ac012..cfbcb51d26 100644
--- 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/Gateway.java
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/Gateway.java
@@ -79,7 +79,7 @@ public class Gateway extends GenericCli {
     loginS3GUser(ozoneConfiguration);
     setHttpBaseDir(ozoneConfiguration);
     httpServer = new S3GatewayHttpServer(ozoneConfiguration, "s3gateway");
-    metrics = S3GatewayMetrics.create();
+    metrics = S3GatewayMetrics.create(ozoneConfiguration);
     start();
 
     ShutdownHookManager.get().addShutdownHook(() -> {
diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/S3GatewayConfigKeys.java
 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/S3GatewayConfigKeys.java
index 179c5eeee7..a058e413b9 100644
--- 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/S3GatewayConfigKeys.java
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/S3GatewayConfigKeys.java
@@ -81,6 +81,9 @@ public final class S3GatewayConfigKeys {
   public static final boolean OZONE_S3G_LIST_KEYS_SHALLOW_ENABLED_DEFAULT =
       true;
 
+  public static final String 
OZONE_S3G_METRICS_PERCENTILES_INTERVALS_SECONDS_KEY
+      = "ozone.s3g.metrics.percentiles.intervals.seconds";
+
   /**
    * Never constructed.
    */
diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/EndpointBase.java
 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/EndpointBase.java
index 6f0f3c4847..5694d6f9f4 100644
--- 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/EndpointBase.java
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/EndpointBase.java
@@ -387,7 +387,7 @@ public abstract class EndpointBase implements Auditor {
 
   @VisibleForTesting
   public S3GatewayMetrics getMetrics() {
-    return S3GatewayMetrics.create();
+    return S3GatewayMetrics.getMetrics();
   }
 
   protected Map<String, String> getAuditParameters() {
diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpointStreaming.java
 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpointStreaming.java
index dbc7f374a9..e509acb05b 100644
--- 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpointStreaming.java
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpointStreaming.java
@@ -52,6 +52,7 @@ final class ObjectEndpointStreaming {
 
   private static final Logger LOG =
       LoggerFactory.getLogger(ObjectEndpointStreaming.class);
+  private static final S3GatewayMetrics METRICS = 
S3GatewayMetrics.getMetrics();
 
   private ObjectEndpointStreaming() {
   }
@@ -99,13 +100,12 @@ final class ObjectEndpointStreaming {
       Map<String, String> keyMetadata,
       DigestInputStream body, PerformanceStringBuilder perf)
       throws IOException {
-    S3GatewayMetrics metrics = S3GatewayMetrics.create();
     long startNanos = Time.monotonicNowNanos();
     long writeLen;
     String eTag;
     try (OzoneDataStreamOutput streamOutput = bucket.createStreamKey(keyPath,
         length, replicationConfig, keyMetadata)) {
-      long metadataLatencyNs = metrics.updatePutKeyMetadataStats(startNanos);
+      long metadataLatencyNs = METRICS.updatePutKeyMetadataStats(startNanos);
       writeLen = writeToStreamOutput(streamOutput, body, bufferSize, length);
       eTag = DatatypeConverter.printHexBinary(body.getMessageDigest().digest())
           .toLowerCase();
@@ -126,11 +126,10 @@ final class ObjectEndpointStreaming {
       InputStream body, PerformanceStringBuilder perf, long startNanos)
       throws IOException {
     long writeLen = 0;
-    S3GatewayMetrics metrics = S3GatewayMetrics.create();
     try (OzoneDataStreamOutput streamOutput = bucket.createStreamKey(keyPath,
         length, replicationConfig, keyMetadata)) {
       long metadataLatencyNs =
-          metrics.updateCopyKeyMetadataStats(startNanos);
+          METRICS.updateCopyKeyMetadataStats(startNanos);
       perf.appendMetaLatencyNanos(metadataLatencyNs);
       writeLen = writeToStreamOutput(streamOutput, body, bufferSize, length);
     }
@@ -162,7 +161,6 @@ final class ObjectEndpointStreaming {
       throws IOException, OS3Exception {
     long startNanos = Time.monotonicNowNanos();
     String eTag;
-    S3GatewayMetrics metrics = S3GatewayMetrics.create();
     // OmMultipartCommitUploadPartInfo can only be gotten after the
     // OzoneDataStreamOutput is closed, so we need to save the
     // KeyDataStreamOutput in the OzoneDataStreamOutput and use it to get the
@@ -171,13 +169,13 @@ final class ObjectEndpointStreaming {
     try {
       try (OzoneDataStreamOutput streamOutput = ozoneBucket
           .createMultipartStreamKey(key, length, partNumber, uploadID)) {
-        long metadataLatencyNs = metrics.updatePutKeyMetadataStats(startNanos);
+        long metadataLatencyNs = METRICS.updatePutKeyMetadataStats(startNanos);
         long putLength =
             writeToStreamOutput(streamOutput, body, chunkSize, length);
         eTag = DatatypeConverter.printHexBinary(
             body.getMessageDigest().digest()).toLowerCase();
         ((KeyMetadataAware)streamOutput).getMetadata().put("ETag", eTag);
-        metrics.incPutKeySuccessLength(putLength);
+        METRICS.incPutKeySuccessLength(putLength);
         perf.appendMetaLatencyNanos(metadataLatencyNs);
         perf.appendSizeBytes(putLength);
         keyDataStreamOutput = streamOutput.getKeyDataStreamOutput();
diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/metrics/S3GatewayMetrics.java
 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/metrics/S3GatewayMetrics.java
index 10b7b167b9..ef7df24fec 100644
--- 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/metrics/S3GatewayMetrics.java
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/metrics/S3GatewayMetrics.java
@@ -18,6 +18,7 @@
 package org.apache.hadoop.ozone.s3.metrics;
 
 import org.apache.hadoop.hdds.annotation.InterfaceAudience;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
 import org.apache.hadoop.metrics2.MetricsCollector;
 import org.apache.hadoop.metrics2.MetricsRecordBuilder;
 import org.apache.hadoop.metrics2.MetricsSource;
@@ -27,8 +28,9 @@ import org.apache.hadoop.metrics2.annotation.Metrics;
 import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
 import org.apache.hadoop.metrics2.lib.MetricsRegistry;
 import org.apache.hadoop.metrics2.lib.MutableCounterLong;
-import org.apache.hadoop.metrics2.lib.MutableRate;
 import org.apache.hadoop.ozone.OzoneConsts;
+import org.apache.hadoop.ozone.s3.S3GatewayConfigKeys;
+import org.apache.hadoop.util.PerformanceMetrics;
 import org.apache.hadoop.util.Time;
 
 /**
@@ -95,156 +97,160 @@ public final class S3GatewayMetrics implements 
MetricsSource {
 
   @Metric(about = "Latency for successfully retrieving an S3 bucket in " +
       "nanoseconds")
-  private MutableRate getBucketSuccessLatencyNs;
+  private PerformanceMetrics getBucketSuccessLatencyNs;
 
   @Metric(about = "Latency for failing to retrieve an S3 bucket in 
nanoseconds")
-  private MutableRate getBucketFailureLatencyNs;
+  private PerformanceMetrics getBucketFailureLatencyNs;
 
   @Metric(about = "Latency for successfully creating an S3 bucket in " +
       "nanoseconds")
-  private MutableRate createBucketSuccessLatencyNs;
+  private PerformanceMetrics createBucketSuccessLatencyNs;
 
   @Metric(about = "Latency for failing to create an S3 bucket in nanoseconds")
-  private MutableRate createBucketFailureLatencyNs;
+  private PerformanceMetrics createBucketFailureLatencyNs;
 
   @Metric(about = "Latency for successfully checking the existence of an " +
       "S3 bucket in nanoseconds")
-  private MutableRate headBucketSuccessLatencyNs;
+  private PerformanceMetrics headBucketSuccessLatencyNs;
 
   @Metric(about = "Latency for successfully deleting an S3 bucket in " +
       "nanoseconds")
-  private MutableRate deleteBucketSuccessLatencyNs;
+  private PerformanceMetrics deleteBucketSuccessLatencyNs;
 
   @Metric(about = "Latency for failing to delete an S3 bucket in nanoseconds")
-  private MutableRate deleteBucketFailureLatencyNs;
+  private PerformanceMetrics deleteBucketFailureLatencyNs;
 
   @Metric(about = "Latency for successfully retrieving an S3 bucket ACL " +
       "in nanoseconds")
-  private MutableRate getAclSuccessLatencyNs;
+  private PerformanceMetrics getAclSuccessLatencyNs;
 
   @Metric(about = "Latency for failing to retrieve an S3 bucket ACL " +
       "in nanoseconds")
-  private MutableRate getAclFailureLatencyNs;
+  private PerformanceMetrics getAclFailureLatencyNs;
 
   @Metric(about = "Latency for successfully setting an S3 bucket ACL " +
       "in nanoseconds")
-  private MutableRate putAclSuccessLatencyNs;
+  private PerformanceMetrics putAclSuccessLatencyNs;
 
   @Metric(about = "Latency for failing to set an S3 bucket ACL " +
       "in nanoseconds")
-  private MutableRate putAclFailureLatencyNs;
+  private PerformanceMetrics putAclFailureLatencyNs;
 
   @Metric(about = "Latency for successfully listing multipart uploads " +
       "in nanoseconds")
-  private MutableRate listMultipartUploadsSuccessLatencyNs;
+  private PerformanceMetrics listMultipartUploadsSuccessLatencyNs;
 
   @Metric(about = "Latency for failing to list multipart uploads " +
       "in nanoseconds")
-  private MutableRate listMultipartUploadsFailureLatencyNs;
+  private PerformanceMetrics listMultipartUploadsFailureLatencyNs;
 
   // RootEndpoint
 
   @Metric(about = "Latency for successfully listing S3 buckets " +
       "in nanoseconds")
-  private MutableRate listS3BucketsSuccessLatencyNs;
+  private PerformanceMetrics listS3BucketsSuccessLatencyNs;
 
   @Metric(about = "Latency for failing to list S3 buckets " +
       "in nanoseconds")
-  private MutableRate listS3BucketsFailureLatencyNs;
+  private PerformanceMetrics listS3BucketsFailureLatencyNs;
 
   // ObjectEndpoint
 
   @Metric(about = "Latency for successfully creating a multipart object key " +
       "in nanoseconds")
-  private MutableRate createMultipartKeySuccessLatencyNs;
+  private PerformanceMetrics createMultipartKeySuccessLatencyNs;
 
   @Metric(about = "Latency for failing to create a multipart object key in " +
       "nanoseconds")
-  private MutableRate createMultipartKeyFailureLatencyNs;
+  private PerformanceMetrics createMultipartKeyFailureLatencyNs;
 
   @Metric(about = "Latency for successfully copying an S3 object in " +
       "nanoseconds")
-  private MutableRate copyObjectSuccessLatencyNs;
+  private PerformanceMetrics copyObjectSuccessLatencyNs;
 
   @Metric(about = "Latency for failing to copy an S3 object in nanoseconds")
-  private MutableRate copyObjectFailureLatencyNs;
+  private PerformanceMetrics copyObjectFailureLatencyNs;
 
   @Metric(about = "Latency for successfully creating an S3 object key in " +
       "nanoseconds")
-  private MutableRate createKeySuccessLatencyNs;
+  private PerformanceMetrics createKeySuccessLatencyNs;
 
   @Metric(about = "Latency for failing to create an S3 object key in " +
       "nanoseconds")
-  private MutableRate createKeyFailureLatencyNs;
+  private PerformanceMetrics createKeyFailureLatencyNs;
 
   @Metric(about = "Latency for successfully listing parts of a multipart " +
       "upload in nanoseconds")
-  private MutableRate listPartsSuccessLatencyNs;
+  private PerformanceMetrics listPartsSuccessLatencyNs;
 
   @Metric(about = "Latency for failing to list parts of a multipart upload " +
       "in nanoseconds")
-  private MutableRate listPartsFailureLatencyNs;
+  private PerformanceMetrics listPartsFailureLatencyNs;
 
   @Metric(about = "Latency for successfully retrieving an S3 object in " +
       "nanoseconds")
-  private MutableRate getKeySuccessLatencyNs;
+  private PerformanceMetrics getKeySuccessLatencyNs;
 
   @Metric(about = "Latency for failing to retrieve an S3 object in 
nanoseconds")
-  private MutableRate getKeyFailureLatencyNs;
+  private PerformanceMetrics getKeyFailureLatencyNs;
 
   @Metric(about = "Latency for successfully retrieving metadata for an S3 " +
       "object in nanoseconds")
-  private MutableRate headKeySuccessLatencyNs;
+  private PerformanceMetrics headKeySuccessLatencyNs;
 
   @Metric(about = "Latency for failing to retrieve metadata for an S3 object " 
+
       "in nanoseconds")
-  private MutableRate headKeyFailureLatencyNs;
+  private PerformanceMetrics headKeyFailureLatencyNs;
 
   @Metric(about = "Latency for successfully initiating a multipart upload in " 
+
       "nanoseconds")
-  private MutableRate initMultipartUploadSuccessLatencyNs;
+  private PerformanceMetrics initMultipartUploadSuccessLatencyNs;
 
   @Metric(about = "Latency for failing to initiate a multipart upload in " +
       "nanoseconds")
-  private MutableRate initMultipartUploadFailureLatencyNs;
+  private PerformanceMetrics initMultipartUploadFailureLatencyNs;
 
   @Metric(about = "Latency for successfully completing a multipart upload in " 
+
       "nanoseconds")
-  private MutableRate completeMultipartUploadSuccessLatencyNs;
+  private PerformanceMetrics completeMultipartUploadSuccessLatencyNs;
 
   @Metric(about = "Latency for failing to complete a multipart upload in " +
       "nanoseconds")
-  private MutableRate completeMultipartUploadFailureLatencyNs;
+  private PerformanceMetrics completeMultipartUploadFailureLatencyNs;
 
   @Metric(about = "Latency for successfully aborting a multipart upload in " +
       "nanoseconds")
-  private MutableRate abortMultipartUploadSuccessLatencyNs;
+  private PerformanceMetrics abortMultipartUploadSuccessLatencyNs;
 
   @Metric(about = "Latency for failing to abort a multipart upload in " +
       "nanoseconds")
-  private MutableRate abortMultipartUploadFailureLatencyNs;
+  private PerformanceMetrics abortMultipartUploadFailureLatencyNs;
 
   @Metric(about = "Latency for successfully deleting an S3 object in " +
       "nanoseconds")
-  private MutableRate deleteKeySuccessLatencyNs;
+  private PerformanceMetrics deleteKeySuccessLatencyNs;
 
   @Metric(about = "Latency for failing to delete an S3 object in nanoseconds")
-  private MutableRate deleteKeyFailureLatencyNs;
+  private PerformanceMetrics deleteKeyFailureLatencyNs;
 
   @Metric(about = "Latency for put metadata of an key in nanoseconds")
-  private MutableRate putKeyMetadataLatencyNs;
+  private PerformanceMetrics putKeyMetadataLatencyNs;
 
   @Metric(about = "Latency for get metadata of an key in nanoseconds")
-  private MutableRate getKeyMetadataLatencyNs;
+  private PerformanceMetrics getKeyMetadataLatencyNs;
 
   @Metric(about = "Latency for copy metadata of an key in nanoseconds")
-  private MutableRate copyKeyMetadataLatencyNs;
+  private PerformanceMetrics copyKeyMetadataLatencyNs;
 
   /**
    * Private constructor.
    */
-  private S3GatewayMetrics() {
+  private S3GatewayMetrics(OzoneConfiguration conf) {
     this.registry = new MetricsRegistry(SOURCE_NAME);
+    int[] intervals = conf.getInts(S3GatewayConfigKeys
+        .OZONE_S3G_METRICS_PERCENTILES_INTERVALS_SECONDS_KEY);
+    PerformanceMetrics.initializeMetrics(
+        this, registry, "Ops", "Time", intervals);
   }
 
   /**
@@ -252,13 +258,13 @@ public final class S3GatewayMetrics implements 
MetricsSource {
    *
    * @return S3GatewayMetrics
    */
-  public static synchronized S3GatewayMetrics create() {
+  public static synchronized S3GatewayMetrics create(OzoneConfiguration conf) {
     if (instance != null) {
       return instance;
     }
     MetricsSystem ms = DefaultMetricsSystem.instance();
     instance = ms.register(SOURCE_NAME, "S3 Gateway Metrics",
-        new S3GatewayMetrics());
+        new S3GatewayMetrics(conf));
     return instance;
   }
 
@@ -719,9 +725,13 @@ public final class S3GatewayMetrics implements 
MetricsSource {
     return listS3BucketsFailure.value();
   }
 
-  private long updateAndGetStats(MutableRate metric, long startNanos) {
+  private long updateAndGetStats(PerformanceMetrics metric, long startNanos) {
     long value = Time.monotonicNowNanos() - startNanos;
     metric.add(value);
     return value;
   }
+
+  public static synchronized S3GatewayMetrics getMetrics() {
+    return instance;
+  }
 }
diff --git 
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/OzoneClientStub.java
 
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/OzoneClientStub.java
index 64f515060b..2ca712ae94 100644
--- 
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/OzoneClientStub.java
+++ 
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/OzoneClientStub.java
@@ -19,6 +19,9 @@
  */
 package org.apache.hadoop.ozone.client;
 
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.s3.metrics.S3GatewayMetrics;
+
 /**
  * In-memory OzoneClient for testing.
  */
@@ -29,6 +32,7 @@ public class OzoneClientStub extends OzoneClient {
 
   public OzoneClientStub(ObjectStoreStub objectStoreStub) {
     super(objectStoreStub, new ClientProtocolStub(objectStoreStub));
+    S3GatewayMetrics.create(new OzoneConfiguration());
   }
 
   @Override
diff --git 
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestPermissionCheck.java
 
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestPermissionCheck.java
index 2eb572f6b9..92bcec5c6e 100644
--- 
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestPermissionCheck.java
+++ 
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestPermissionCheck.java
@@ -28,6 +28,7 @@ import org.apache.hadoop.ozone.client.OzoneVolume;
 import org.apache.hadoop.ozone.client.protocol.ClientProtocol;
 import org.apache.hadoop.ozone.om.exceptions.OMException;
 import org.apache.hadoop.ozone.s3.exception.OS3Exception;
+import org.apache.hadoop.ozone.s3.metrics.S3GatewayMetrics;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
@@ -84,6 +85,7 @@ public class TestPermissionCheck {
     when(client.getConfiguration()).thenReturn(conf);
     headers = mock(HttpHeaders.class);
     clientProtocol = mock(ClientProtocol.class);
+    S3GatewayMetrics.create(conf);
     when(client.getProxy()).thenReturn(clientProtocol);
   }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to