diff --git a/api/src/main/java/org/apache/iceberg/metrics/LoggingMetricsReporter.java b/api/src/main/java/org/apache/iceberg/metrics/LoggingMetricsReporter.java
index 26e9a0b527f1..8d41f10e74fb 100644
--- a/api/src/main/java/org/apache/iceberg/metrics/LoggingMetricsReporter.java
+++ b/api/src/main/java/org/apache/iceberg/metrics/LoggingMetricsReporter.java
@@ -28,6 +28,11 @@
*/
public class LoggingMetricsReporter implements MetricsReporter {
private static final Logger LOG = LoggerFactory.getLogger(LoggingMetricsReporter.class);
+ private static final LoggingMetricsReporter INSTANCE = new LoggingMetricsReporter();
+
+ public static LoggingMetricsReporter instance() {
+ return INSTANCE;
+ }
@Override
public void report(MetricsReport report) {
diff --git a/core/src/main/java/org/apache/iceberg/CatalogProperties.java b/core/src/main/java/org/apache/iceberg/CatalogProperties.java
index 95fe6a074c0a..c2490ee3ea83 100644
--- a/core/src/main/java/org/apache/iceberg/CatalogProperties.java
+++ b/core/src/main/java/org/apache/iceberg/CatalogProperties.java
@@ -29,6 +29,7 @@ private CatalogProperties() {}
public static final String WAREHOUSE_LOCATION = "warehouse";
public static final String TABLE_DEFAULT_PREFIX = "table-default.";
public static final String TABLE_OVERRIDE_PREFIX = "table-override.";
+ public static final String METRICS_REPORTER_IMPL = "metrics-reporter-impl";
/**
* Controls whether the catalog will cache table entries upon load.
diff --git a/core/src/main/java/org/apache/iceberg/CatalogUtil.java b/core/src/main/java/org/apache/iceberg/CatalogUtil.java
index c0c5078a3f34..ef4d17c24997 100644
--- a/core/src/main/java/org/apache/iceberg/CatalogUtil.java
+++ b/core/src/main/java/org/apache/iceberg/CatalogUtil.java
@@ -35,6 +35,7 @@
import org.apache.iceberg.hadoop.Configurable;
import org.apache.iceberg.io.FileIO;
import org.apache.iceberg.io.SupportsBulkOperations;
+import org.apache.iceberg.metrics.MetricsReporter;
import org.apache.iceberg.relocated.com.google.common.base.Joiner;
import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
import org.apache.iceberg.relocated.com.google.common.collect.Iterables;
@@ -400,4 +401,42 @@ public static void configureHadoopConf(Object maybeConfigurable, Object conf) {
setConf.invoke(conf);
}
+
+ /**
+ * Load a custom {@link MetricsReporter} implementation.
+ *
+ *
The implementation must have a no-arg constructor.
+ *
+ * @param impl full class name of a custom {@link MetricsReporter} implementation
+ * @return An initialized {@link MetricsReporter}.
+ * @throws IllegalArgumentException if class path not found or right constructor not found or the
+ * loaded class cannot be cast to the given interface type
+ */
+ public static MetricsReporter loadMetricsReporter(String impl) {
+ LOG.info("Loading custom MetricsReporter implementation: {}", impl);
+ DynConstructors.Ctor ctor;
+ try {
+ ctor =
+ DynConstructors.builder(MetricsReporter.class)
+ .loader(CatalogUtil.class.getClassLoader())
+ .impl(impl)
+ .buildChecked();
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException(
+ String.format("Cannot initialize MetricsReporter, missing no-arg constructor: %s", impl),
+ e);
+ }
+
+ MetricsReporter reporter;
+ try {
+ reporter = ctor.newInstance();
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException(
+ String.format(
+ "Cannot initialize MetricsReporter, %s does not implement MetricsReporter.", impl),
+ e);
+ }
+
+ return reporter;
+ }
}
diff --git a/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java b/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java
index 0b4edc9a84f0..d4757c4ed529 100644
--- a/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java
+++ b/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java
@@ -177,7 +177,11 @@ public void initialize(String name, Map unresolved) {
this.io =
CatalogUtil.loadFileIO(
ioImpl != null ? ioImpl : ResolvingFileIO.class.getName(), mergedProps, conf);
- this.reporter = new LoggingMetricsReporter();
+ String metricsReporterImpl = mergedProps.get(CatalogProperties.METRICS_REPORTER_IMPL);
+ this.reporter =
+ null != metricsReporterImpl
+ ? CatalogUtil.loadMetricsReporter(metricsReporterImpl)
+ : LoggingMetricsReporter.instance();
super.initialize(name, mergedProps);
}
@@ -316,8 +320,8 @@ private void reportMetrics(
TableIdentifier tableIdentifier,
MetricsReport report,
Supplier