diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f07b3cb1f61..cdbd7b234bc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -320,11 +320,7 @@ cybozulabs-langdetect = { module = "com.cybozu.labs:langdetect", version.ref = " decompose-decompose = { module = "com.arkivanov.decompose:decompose", version.ref = "decompose" } decompose-extensions-compose = { module = "com.arkivanov.decompose:extensions-compose", version.ref = "decompose" } dropwizard-metrics-core = { module = "io.dropwizard.metrics:metrics-core", version.ref = "dropwizard-metrics" } -dropwizard-metrics-graphite = { module = "io.dropwizard.metrics:metrics-graphite", version.ref = "dropwizard-metrics" } -dropwizard-metrics-jetty12 = { module = "io.dropwizard.metrics:metrics-jetty12", version.ref = "dropwizard-metrics" } dropwizard-metrics-jetty12-ee10 = { module = "io.dropwizard.metrics:metrics-jetty12-ee10", version.ref = "dropwizard-metrics" } -dropwizard-metrics-jmx = { module = "io.dropwizard.metrics:metrics-jmx", version.ref = "dropwizard-metrics" } -dropwizard-metrics-jvm = { module = "io.dropwizard.metrics:metrics-jvm", version.ref = "dropwizard-metrics" } dropwizard-metrics-servlets = { module = "io.dropwizard.metrics:metrics-jakarta-servlets", version.ref = "dropwizard-metrics" } eclipse-jdt-ecj = { module = "org.eclipse.jdt:ecj", version.ref = "eclipse-ecj" } eclipse-jetty-alpnjavaclient = { module = "org.eclipse.jetty:jetty-alpn-java-client", version.ref = "eclipse-jetty" } diff --git a/solr/api/gradle.lockfile b/solr/api/gradle.lockfile index bdefb4ffab8..8730941bd5a 100644 --- a/solr/api/gradle.lockfile +++ b/solr/api/gradle.lockfile @@ -38,12 +38,9 @@ commons-cli:commons-cli:1.10.0=jarValidation,testRuntimeClasspath commons-codec:commons-codec:1.19.0=jarValidation,testRuntimeClasspath commons-io:commons-io:2.17.0=jarValidation,testCompileClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,testRuntimeClasspath io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=jarValidation,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=jarValidation,testRuntimeClasspath io.github.classgraph:classgraph:4.8.165=swaggerBuild io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor diff --git a/solr/benchmark/gradle.lockfile b/solr/benchmark/gradle.lockfile index 11e15e44546..0f20e0f3806 100644 --- a/solr/benchmark/gradle.lockfile +++ b/solr/benchmark/gradle.lockfile @@ -35,11 +35,8 @@ commons-codec:commons-codec:1.19.0=jarValidation,runtimeClasspath,testRuntimeCla commons-io:commons-io:2.17.0=compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,runtimeClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-core:4.2.26=compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=jarValidation,runtimeClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,runtimeClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,runtimeClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=jarValidation,runtimeClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=jarValidation,runtimeClasspath,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath diff --git a/solr/core/build.gradle b/solr/core/build.gradle index 84db3e87650..087af01d6d4 100644 --- a/solr/core/build.gradle +++ b/solr/core/build.gradle @@ -51,12 +51,7 @@ dependencies { api project(':solr:solrj-zookeeper') api project(':solr:solrj-streaming') - api libs.dropwizard.metrics.core - implementation (libs.dropwizard.metrics.graphite, { - exclude group: "com.rabbitmq", module: "amqp-client" - }) - implementation libs.dropwizard.metrics.jmx - implementation libs.dropwizard.metrics.jvm + implementation libs.dropwizard.metrics.core implementation(libs.jersey.containers.jettyhttp, { exclude group: "org.eclipse.jetty", module: "jetty-continuation" @@ -224,4 +219,5 @@ dependencies { testImplementation libs.apache.httpcomponents.httpcore testImplementation libs.opentelemetry.sdktesting + testImplementation libs.dropwizard.metrics.core } diff --git a/solr/core/gradle.lockfile b/solr/core/gradle.lockfile index 780c9cfbd15..72e0c074473 100644 --- a/solr/core/gradle.lockfile +++ b/solr/core/gradle.lockfile @@ -39,12 +39,9 @@ commons-cli:commons-cli:1.10.0=compileClasspath,jarValidation,runtimeClasspath,r commons-codec:commons-codec:1.19.0=apiHelper,compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath commons-io:commons-io:2.17.0=apiHelper,compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=apiHelper,compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.2.6.Final=apiHelper,compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath diff --git a/solr/core/src/java/org/apache/solr/blockcache/Metrics.java b/solr/core/src/java/org/apache/solr/blockcache/Metrics.java index 4de589a1103..ed820fbb500 100644 --- a/solr/core/src/java/org/apache/solr/blockcache/Metrics.java +++ b/solr/core/src/java/org/apache/solr/blockcache/Metrics.java @@ -54,8 +54,7 @@ public class Metrics extends SolrCacheBase implements SolrInfoBean { private AutoCloseable toClose; @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { solrMetricsContext = parentContext.getChildContext(this); var baseAttributes = attributes.toBuilder().put(CATEGORY_ATTR, getCategory().toString()).build(); diff --git a/solr/core/src/java/org/apache/solr/cloud/Overseer.java b/solr/core/src/java/org/apache/solr/cloud/Overseer.java index 6f7cba71767..aabe559662b 100644 --- a/solr/core/src/java/org/apache/solr/cloud/Overseer.java +++ b/solr/core/src/java/org/apache/solr/cloud/Overseer.java @@ -217,13 +217,11 @@ public ClusterStateUpdater( this.compressor = compressor; this.clusterStateUpdaterMetricContext = solrMetricsContext.getChildContext(this); - initializeMetrics( - solrMetricsContext, Attributes.of(CATEGORY_ATTR, getCategory().toString()), ""); + initializeMetrics(solrMetricsContext, Attributes.of(CATEGORY_ATTR, getCategory().toString())); } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { this.toClose = parentContext.observableLongGauge( "solr_overseer_state_update_queue_size", @@ -660,7 +658,6 @@ private LeaderStatus amILeader() { public void close() { this.isClosed = true; IOUtils.closeQuietly(toClose); - clusterStateUpdaterMetricContext.unregister(); } @Override @@ -750,8 +747,7 @@ public Overseer( this.solrMetricsContext = new SolrMetricsContext( zkController.getCoreContainer().getMetricManager(), - SolrInfoBean.Group.overseer.toString(), - metricTag); + SolrInfoBean.Group.overseer.toString()); } public synchronized void start(String id) { diff --git a/solr/core/src/java/org/apache/solr/cloud/OverseerTaskProcessor.java b/solr/core/src/java/org/apache/solr/cloud/OverseerTaskProcessor.java index e29df029de7..150d8e8f0ac 100644 --- a/solr/core/src/java/org/apache/solr/cloud/OverseerTaskProcessor.java +++ b/solr/core/src/java/org/apache/solr/cloud/OverseerTaskProcessor.java @@ -152,8 +152,7 @@ public OverseerTaskProcessor( thisNode = MDCLoggingContext.getNodeName(); this.overseerTaskProcessorMetricsContext = solrMetricsContext.getChildContext(this); - initializeMetrics( - solrMetricsContext, Attributes.of(CATEGORY_ATTR, getCategory().toString()), ""); + initializeMetrics(solrMetricsContext, Attributes.of(CATEGORY_ATTR, getCategory().toString())); } @Override @@ -407,8 +406,7 @@ private void cleanUpRunningTasks() { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { this.toClose = parentContext.observableLongGauge( "solr_overseer_collection_work_queue_size", diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java index b16027f8f4b..476963f940d 100644 --- a/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java +++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java @@ -853,7 +853,10 @@ public static void checkDiskSpace( SolrIndexSplitter.SplitMethod method, SolrCloudManager cloudManager) throws Exception { - + if (true) { + log.warn("checkDiskSpace disabled SOLR-17458"); // nocommit + return; + } // check that enough disk space is available on the parent leader node // otherwise the actual index splitting will always fail diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java index 9c287aca769..c50531d8715 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -26,6 +26,7 @@ import static org.apache.solr.common.params.CommonParams.METRICS_PATH; import static org.apache.solr.common.params.CommonParams.ZK_PATH; import static org.apache.solr.common.params.CommonParams.ZK_STATUS_PATH; +import static org.apache.solr.metrics.SolrMetricManager.NODE_REGISTRY; import static org.apache.solr.metrics.SolrMetricProducer.CATEGORY_ATTR; import static org.apache.solr.metrics.SolrMetricProducer.HANDLER_ATTR; import static org.apache.solr.metrics.SolrMetricProducer.NAME_ATTR; @@ -521,9 +522,7 @@ private void initializeAuditloggerPlugin(Map auditConf) { newAuditloggerPlugin.plugin.init(auditConf); newAuditloggerPlugin.plugin.initializeMetrics( - solrMetricsContext, - Attributes.builder().put(HANDLER_ATTR, "/auditlogging").build(), - "/auditlogging"); + solrMetricsContext, Attributes.builder().put(HANDLER_ATTR, "/auditlogging").build()); } else { log.debug("Security conf doesn't exist. Skipping setup for audit logging module."); } @@ -589,9 +588,7 @@ private synchronized void initializeAuthenticationPlugin( authenticationPlugin.plugin.init(authenticationConfig); setupHttpClientForAuthPlugin(authenticationPlugin.plugin); authenticationPlugin.plugin.initializeMetrics( - solrMetricsContext, - Attributes.builder().put(HANDLER_ATTR, "/authentication").build(), - "/authentication"); + solrMetricsContext, Attributes.builder().put(HANDLER_ATTR, "/authentication").build()); } this.authenticationPlugin = authenticationPlugin; try { @@ -779,21 +776,18 @@ private void loadInternal() { containerPluginsRegistry.registerListener( clusterEventProducerFactory.getPluginRegistryListener()); - solrMetricsContext = - new SolrMetricsContext( - metricManager, SolrMetricManager.getRegistryName(SolrInfoBean.Group.node), metricTag); + solrMetricsContext = new SolrMetricsContext(metricManager, NODE_REGISTRY); shardHandlerFactory = ShardHandlerFactory.newInstance(cfg.getShardHandlerFactoryPluginInfo(), loader); if (shardHandlerFactory instanceof SolrMetricProducer metricProducer) { - metricProducer.initializeMetrics(solrMetricsContext, Attributes.empty(), "httpShardHandler"); + metricProducer.initializeMetrics(solrMetricsContext, Attributes.empty()); } updateShardHandler = new UpdateShardHandler(cfg.getUpdateShardHandlerConfig()); solrClientProvider = new HttpSolrClientProvider(cfg.getUpdateShardHandlerConfig(), solrMetricsContext); - updateShardHandler.initializeMetrics( - solrMetricsContext, Attributes.empty(), "updateShardHandler"); + updateShardHandler.initializeMetrics(solrMetricsContext, Attributes.empty()); solrClientCache = new SolrClientCache(solrClientProvider.getSolrClient()); Map cachesConfig = cfg.getCachesConfig(); @@ -827,8 +821,7 @@ private void loadInternal() { .getZkMetricsProducer() .initializeMetrics( solrMetricsContext, - Attributes.of(CATEGORY_ATTR, SolrInfoBean.Category.CONTAINER.toString()), - "zkClient"); + Attributes.of(CATEGORY_ATTR, SolrInfoBean.Category.CONTAINER.toString())); pkiAuthenticationSecurityBuilder = new PKIAuthenticationPlugin( this, @@ -836,8 +829,7 @@ private void loadInternal() { (PublicKeyHandler) containerHandlers.get(PublicKeyHandler.PATH)); pkiAuthenticationSecurityBuilder.initializeMetrics( solrMetricsContext, - Attributes.builder().put(HANDLER_ATTR, "/authentication/pki").build(), - "/authentication/pki"); + Attributes.builder().put(HANDLER_ATTR, "/authentication/pki").build()); fileStore = new DistribFileStore(this); registerV2ApiIfEnabled(ClusterFileStore.class); @@ -901,23 +893,15 @@ private void loadInternal() { metricsHandler = new MetricsHandler(this); containerHandlers.put(METRICS_PATH, metricsHandler); - // TODO SOLR-17458: Add Otel metricsHandler.initializeMetrics( - solrMetricsContext, - Attributes.builder().put(HANDLER_ATTR, METRICS_PATH).build(), - METRICS_PATH); + solrMetricsContext, Attributes.builder().put(HANDLER_ATTR, METRICS_PATH).build()); containerHandlers.put(AUTHZ_PATH, securityConfHandler); - // TODO SOLR-17458: Add Otel securityConfHandler.initializeMetrics( - solrMetricsContext, Attributes.builder().put(HANDLER_ATTR, AUTHZ_PATH).build(), AUTHZ_PATH); + solrMetricsContext, Attributes.builder().put(HANDLER_ATTR, AUTHZ_PATH).build()); containerHandlers.put(AUTHC_PATH, securityConfHandler); PluginInfo[] metricReporters = cfg.getMetricsConfig().getMetricReporters(); - metricManager.loadReporters(metricReporters, loader, this, null, null, SolrInfoBean.Group.node); - metricManager.loadReporters(metricReporters, loader, this, null, null, SolrInfoBean.Group.jvm); - metricManager.loadReporters( - metricReporters, loader, this, null, null, SolrInfoBean.Group.jetty); containerProperties.putAll(cfg.getSolrProperties()); @@ -925,7 +909,7 @@ private void loadInternal() { Attributes.builder().put(CATEGORY_ATTR, SolrInfoBean.Category.CONTAINER.toString()).build(); // initialize gauges for reporting the number of cores and disk total/free - solrCores.initializeMetrics(solrMetricsContext, containerAttrs, ""); + solrCores.initializeMetrics(solrMetricsContext, containerAttrs); Path dataHome = cfg.getSolrDataHome() != null ? cfg.getSolrDataHome() : cfg.getCoreRootDirectory(); @@ -953,13 +937,7 @@ private void loadInternal() { SolrFieldCacheBean fieldCacheBean = new SolrFieldCacheBean(); fieldCacheBean.initializeMetrics( - solrMetricsContext, - Attributes.of(CATEGORY_ATTR, SolrInfoBean.Category.CACHE.toString()), - ""); - - if (isZooKeeperAware()) { - metricManager.loadClusterReporters(metricReporters, this); - } + solrMetricsContext, Attributes.of(CATEGORY_ATTR, SolrInfoBean.Category.CACHE.toString())); // setup executor to load cores in parallel coreLoadExecutor = @@ -1271,28 +1249,12 @@ public void shutdown() { customThreadPool.execute(replayUpdatesExecutor::shutdownAndAwaitTermination); if (metricManager != null) { - metricManager.closeReporters(SolrMetricManager.getRegistryName(SolrInfoBean.Group.node)); - metricManager.closeReporters(SolrMetricManager.getRegistryName(SolrInfoBean.Group.jvm)); - metricManager.closeReporters(SolrMetricManager.getRegistryName(SolrInfoBean.Group.jetty)); - - metricManager.unregisterGauges( - SolrMetricManager.getRegistryName(SolrInfoBean.Group.node), metricTag); - metricManager.unregisterGauges( - SolrMetricManager.getRegistryName(SolrInfoBean.Group.jvm), metricTag); - metricManager.unregisterGauges( - SolrMetricManager.getRegistryName(SolrInfoBean.Group.jetty), metricTag); - // Close all OTEL meter providers and metrics metricManager.closeAllRegistries(); } if (isZooKeeperAware()) { cancelCoreRecoveries(); - - if (metricManager != null) { - metricManager.closeReporters( - SolrMetricManager.getRegistryName(SolrInfoBean.Group.cluster)); - } } try { @@ -1796,8 +1758,7 @@ private SolrCore processCoreCreateException( private void resetIndexDirectory(CoreDescriptor dcore, ConfigSet coreConfig) { SolrConfig config = coreConfig.getSolrConfig(); - String registryName = - SolrMetricManager.getRegistryName(SolrInfoBean.Group.core, dcore.getName()); + String registryName = SolrMetricManager.enforcePrefix(dcore.getName()); DirectoryFactory df = DirectoryFactory.loadDirectoryFactory(config, this, registryName); String dataDir = SolrCore.findDataDir(df, null, config, dcore); @@ -2285,7 +2246,7 @@ protected T createHandler(String path, String handlerClass, Class clazz) if (handler instanceof SolrMetricProducer) { ((SolrMetricProducer) handler) .initializeMetrics( - solrMetricsContext, Attributes.builder().put(HANDLER_ATTR, path).build(), path); + solrMetricsContext, Attributes.builder().put(HANDLER_ATTR, path).build()); } return handler; } diff --git a/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java b/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java index 68207965e48..43edb25ca82 100644 --- a/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java +++ b/solr/core/src/java/org/apache/solr/core/HttpSolrClientProvider.java @@ -21,7 +21,6 @@ import java.util.concurrent.TimeUnit; import org.apache.solr.client.solrj.impl.Http2SolrClient; import org.apache.solr.common.util.IOUtils; -import org.apache.solr.metrics.SolrMetricManager; import org.apache.solr.metrics.SolrMetricsContext; import org.apache.solr.security.HttpClientBuilderPlugin; import org.apache.solr.update.UpdateShardHandlerConfig; @@ -67,10 +66,7 @@ private InstrumentedHttpListenerFactory.NameStrategy getNameStrategy( private void initializeMetrics(SolrMetricsContext parentContext) { var solrMetricsContext = parentContext.getChildContext(this); - String expandedScope = - SolrMetricManager.mkName(METRIC_SCOPE_NAME, SolrInfoBean.Category.HTTP.name()); - // TODO SOLR-17458: Add Otel - trackHttpSolrMetrics.initializeMetrics(solrMetricsContext, Attributes.empty(), expandedScope); + trackHttpSolrMetrics.initializeMetrics(solrMetricsContext, Attributes.empty()); } Http2SolrClient getSolrClient() { diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java index 970309b7944..bfd1ef68c92 100644 --- a/solr/core/src/java/org/apache/solr/core/SolrCore.java +++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java @@ -1107,7 +1107,6 @@ protected SolrCore( // Initialize the metrics manager this.coreMetricManager = initCoreMetricManager(solrConfig); this.solrMetricsContext = coreMetricManager.getSolrMetricsContext(); - this.coreMetricManager.loadReporters(); if (updateHandler == null) { directoryFactory = initDirectoryFactory(); @@ -1132,7 +1131,7 @@ protected SolrCore( initCoreAttributes(); // initialize core metrics - initializeMetrics(solrMetricsContext, coreAttributes, ""); + initializeMetrics(solrMetricsContext, coreAttributes); // init pluggable circuit breakers, after metrics because some circuit breakers use metrics initPlugins(null, CircuitBreaker.class); @@ -1142,8 +1141,7 @@ protected SolrCore( // also register it here for back-compat solrFieldCacheBean.initializeMetrics( solrMetricsContext, - coreAttributes.toBuilder().put(CATEGORY_ATTR, Category.CACHE.toString()).build(), - ""); + coreAttributes.toBuilder().put(CATEGORY_ATTR, Category.CACHE.toString()).build()); infoRegistry.put("fieldCache", solrFieldCacheBean); this.maxWarmingSearchers = solrConfig.maxWarmingSearchers; @@ -1220,8 +1218,7 @@ protected SolrCore( // Allow the directory factory to report metrics if (directoryFactory instanceof SolrMetricProducer) { ((SolrMetricProducer) directoryFactory) - // TODO SOLR-17458: Add Otel - .initializeMetrics(solrMetricsContext, Attributes.empty(), "directoryFactory"); + .initializeMetrics(solrMetricsContext, Attributes.empty()); } bufferUpdatesIfConstructing(coreDescriptor); @@ -1334,8 +1331,7 @@ private SolrCoreMetricManager initCoreMetricManager(SolrConfig config) { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { final List observables = new ArrayList<>(); Attributes baseSearcherAttributes = @@ -1690,7 +1686,7 @@ public StatsCache createStatsCache() { } cache = new LocalStatsCache(); } - cache.initializeMetrics(solrMetricsContext, coreAttributes, null); + cache.initializeMetrics(solrMetricsContext, coreAttributes); return cache; } diff --git a/solr/core/src/java/org/apache/solr/core/SolrCores.java b/solr/core/src/java/org/apache/solr/core/SolrCores.java index 104ca9b34c1..45d7a651c27 100644 --- a/solr/core/src/java/org/apache/solr/core/SolrCores.java +++ b/solr/core/src/java/org/apache/solr/core/SolrCores.java @@ -492,8 +492,7 @@ public void queueCoreToClose(SolrCore coreToClose) { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { parentContext.observableLongGauge( "solr_cores_loaded", "Number of Solr cores loaded by CoreContainer", diff --git a/solr/core/src/java/org/apache/solr/core/ZkContainer.java b/solr/core/src/java/org/apache/solr/core/ZkContainer.java index eb0497a64bc..29efbf888ba 100644 --- a/solr/core/src/java/org/apache/solr/core/ZkContainer.java +++ b/solr/core/src/java/org/apache/solr/core/ZkContainer.java @@ -154,7 +154,7 @@ public void initZooKeeper(final CoreContainer cc, CloudConfig config) { @Override public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + SolrMetricsContext parentContext, Attributes attributes) { final List observables = new ArrayList<>(); ctx = parentContext.getChildContext(this); diff --git a/solr/core/src/java/org/apache/solr/handler/ExportHandler.java b/solr/core/src/java/org/apache/solr/handler/ExportHandler.java index 6a83eb78783..acab3531950 100644 --- a/solr/core/src/java/org/apache/solr/handler/ExportHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/ExportHandler.java @@ -85,12 +85,11 @@ public ExportHandlerStreamFactory() { } } - // TODO SOLR-17458: Migrate to Otel @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { - super.initializeMetrics(parentContext, attributes, scope); - this.writerMetricsPath = SolrMetricManager.mkName("writer", getCategory().toString(), scope); + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { + super.initializeMetrics(parentContext, attributes); + this.writerMetricsPath = + SolrMetricManager.mkName("writer", getCategory().toString(), "/export"); } @Override diff --git a/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java b/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java index 010d1090e48..a1781fddddd 100644 --- a/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java @@ -842,14 +842,13 @@ private CommitVersionInfo getIndexVersion() { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { Attributes replicationAttributes = Attributes.builder() .putAll(attributes) .put(CATEGORY_ATTR, Category.REPLICATION.toString()) .build(); - super.initializeMetrics(parentContext, replicationAttributes, scope); + super.initializeMetrics(parentContext, replicationAttributes); ObservableLongMeasurement indexSizeMetric = solrMetricsContext.longGaugeMeasurement( diff --git a/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java b/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java index f2407a4273e..b76a9778d11 100644 --- a/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java +++ b/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java @@ -163,8 +163,7 @@ public SolrMetricsContext getSolrMetricsContext() { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { this.solrMetricsContext = parentContext.getChildContext(this); metrics = @@ -178,7 +177,7 @@ public void initializeMetrics( public static class HandlerMetrics { public static final HandlerMetrics NO_OP = new HandlerMetrics( - new SolrMetricsContext(new SolrMetricManager(null), "NO_OP", "NO_OP"), + new SolrMetricsContext(new SolrMetricManager(null), "NO_OP"), Attributes.empty(), false); diff --git a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java index 41306919693..34fce3584e8 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java @@ -128,9 +128,8 @@ public final void init(NamedList args) { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { - super.initializeMetrics(parentContext, attributes, scope); + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { + super.initializeMetrics(parentContext, attributes); coreAdminAsyncTracker.standardExecutor = MetricUtils.instrumentedExecutorService( coreAdminAsyncTracker.standardExecutor, diff --git a/solr/core/src/java/org/apache/solr/handler/admin/MetricsCollectorHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/MetricsCollectorHandler.java deleted file mode 100644 index 61f3f35b5af..00000000000 --- a/solr/core/src/java/org/apache/solr/handler/admin/MetricsCollectorHandler.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * 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.solr.handler.admin; - -import com.codahale.metrics.MetricRegistry; -import java.io.IOException; -import java.lang.invoke.MethodHandles; -import java.util.HashMap; -import java.util.Map; -import org.apache.solr.common.SolrException; -import org.apache.solr.common.SolrInputDocument; -import org.apache.solr.common.params.ModifiableSolrParams; -import org.apache.solr.common.params.SolrParams; -import org.apache.solr.common.util.ContentStream; -import org.apache.solr.common.util.NamedList; -import org.apache.solr.core.CoreContainer; -import org.apache.solr.handler.RequestHandlerBase; -import org.apache.solr.handler.loader.CSVLoader; -import org.apache.solr.handler.loader.ContentStreamLoader; -import org.apache.solr.handler.loader.JavabinLoader; -import org.apache.solr.handler.loader.JsonLoader; -import org.apache.solr.handler.loader.XMLLoader; -import org.apache.solr.metrics.AggregateMetric; -import org.apache.solr.metrics.SolrMetricManager; -import org.apache.solr.metrics.reporters.solr.SolrReporter; -import org.apache.solr.request.SolrQueryRequest; -import org.apache.solr.response.SolrQueryResponse; -import org.apache.solr.security.AuthorizationContext; -import org.apache.solr.update.AddUpdateCommand; -import org.apache.solr.update.CommitUpdateCommand; -import org.apache.solr.update.DeleteUpdateCommand; -import org.apache.solr.update.MergeIndexesCommand; -import org.apache.solr.update.RollbackUpdateCommand; -import org.apache.solr.update.processor.UpdateRequestProcessor; -import org.apache.solr.util.stats.MetricUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Handler to collect and aggregate metric reports. Each report indicates the target registry where - * metrics values should be collected and aggregated. Metrics with the same names are aggregated - * using {@link AggregateMetric} instances, which track the source of updates and their count, as - * well as providing simple statistics over collected values. - * - *

Each report consists of {@link SolrInputDocument}-s that are expected to contain the following - * fields: - * - *

    - *
  • {@link SolrReporter#GROUP_ID} - (required) specifies target registry name where metrics - * will be grouped. - *
  • {@link SolrReporter#REPORTER_ID} - (required) id of the reporter that sent this update. - * This can be eg. node name or replica name or other id that uniquely identifies the source - * of metrics values. - *
  • {@link MetricUtils#METRIC_NAME} - (required) metric name (in the source registry) - *
  • {@link SolrReporter#LABEL_ID} - (optional) label to prepend to metric names in the target - * registry. - *
  • {@link SolrReporter#REGISTRY_ID} - (optional) name of the source registry. - *
- * - * Remaining fields are assumed to be single-valued, and to contain metric attributes and their - * values. Example: - * - *
- *   <doc>
- *     <field name="_group_">solr.core.collection1.shard1.leader</field>
- *     <field name="_reporter_">core_node3</field>
- *     <field name="metric">INDEX.merge.errors</field>
- *     <field name="value">0</field>
- *   </doc>
- * 
- */ -public class MetricsCollectorHandler extends RequestHandlerBase { - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - public static final String HANDLER_PATH = "/admin/metrics/collector"; - - private final CoreContainer coreContainer; - private final SolrMetricManager metricManager; - private final Map loaders = new HashMap<>(); - private SolrParams params; - - public MetricsCollectorHandler(final CoreContainer coreContainer) { - this.coreContainer = coreContainer; - this.metricManager = coreContainer.getMetricManager(); - } - - @Override - public void init(NamedList initArgs) { - super.init(initArgs); - if (initArgs != null) { - params = initArgs.toSolrParams(); - } else { - params = new ModifiableSolrParams(); - } - loaders.put("application/xml", new XMLLoader().init(params)); - loaders.put("application/json", new JsonLoader().init(params)); - loaders.put("application/csv", new CSVLoader().init(params)); - loaders.put("application/javabin", new JavabinLoader().init(params)); - loaders.put("text/csv", loaders.get("application/csv")); - loaders.put("text/xml", loaders.get("application/xml")); - loaders.put("text/json", loaders.get("application/json")); - } - - @Override - public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { - if (coreContainer == null || coreContainer.isShutDown()) { - // silently drop request - return; - } - // log.info("#### {}", req); - if (req.getContentStreams() == null) { // no content - return; - } - for (ContentStream cs : req.getContentStreams()) { - if (cs.getContentType() == null) { - log.warn("Missing content type - ignoring"); - continue; - } - ContentStreamLoader loader = loaders.get(cs.getContentType()); - if (loader == null) { - throw new SolrException( - SolrException.ErrorCode.UNSUPPORTED_MEDIA_TYPE, - "Unsupported content type for stream: " - + cs.getSourceInfo() - + ", contentType=" - + cs.getContentType()); - } - loader.load(req, rsp, cs, new MetricUpdateProcessor(metricManager)); - } - } - - @Override - public String getDescription() { - return "Handler for collecting and aggregating SolrCloud metric reports."; - } - - @Override - public Name getPermissionName(AuthorizationContext request) { - return Name.METRICS_READ_PERM; - } - - private static class MetricUpdateProcessor extends UpdateRequestProcessor { - private final SolrMetricManager metricManager; - - public MetricUpdateProcessor(SolrMetricManager metricManager) { - super(null); - this.metricManager = metricManager; - } - - @Override - public void processAdd(AddUpdateCommand cmd) throws IOException { - SolrInputDocument doc = cmd.solrDoc; - if (doc == null) { - return; - } - String metricName = (String) doc.getFieldValue(MetricUtils.METRIC_NAME); - if (metricName == null) { - log.warn("Missing {} field in document, skipping: {}", MetricUtils.METRIC_NAME, doc); - return; - } - doc.remove(MetricUtils.METRIC_NAME); - // XXX we could modify keys by using this original registry name - doc.remove(SolrReporter.REGISTRY_ID); - String groupId = (String) doc.getFieldValue(SolrReporter.GROUP_ID); - if (groupId == null) { - log.warn("Missing {} field in document, skipping: {}", SolrReporter.GROUP_ID, doc); - return; - } - doc.remove(SolrReporter.GROUP_ID); - String reporterId = (String) doc.getFieldValue(SolrReporter.REPORTER_ID); - if (reporterId == null) { - log.warn("Missing {} field in document, skipping: {}", SolrReporter.REPORTER_ID, doc); - return; - } - doc.remove(SolrReporter.REPORTER_ID); - String labelId = (String) doc.getFieldValue(SolrReporter.LABEL_ID); - doc.remove(SolrReporter.LABEL_ID); - doc.forEach( - f -> { - String key; - if (doc.size() == 1 && f.getName().equals(MetricUtils.VALUE)) { - // only one "value" field - skip the unnecessary field name - key = MetricRegistry.name(labelId, metricName); - } else { - key = MetricRegistry.name(labelId, metricName, f.getName()); - } - MetricRegistry registry = metricManager.registry(groupId); - AggregateMetric metric = getOrCreate(registry, key); - Object o = f.getFirstValue(); - if (o != null) { - metric.set(reporterId, o); - } else { - // remove missing values - metric.clear(reporterId); - } - }); - } - - private AggregateMetric getOrCreate(MetricRegistry registry, String name) { - AggregateMetric existing = (AggregateMetric) registry.getMetrics().get(name); - if (existing != null) { - return existing; - } - AggregateMetric add = new AggregateMetric(); - try { - registry.register(name, add); - return add; - } catch (IllegalArgumentException e) { - // someone added before us - existing = (AggregateMetric) registry.getMetrics().get(name); - if (existing == null) { // now, that is weird... - throw new IllegalArgumentException("Inconsistent metric status, " + name); - } - return existing; - } - } - - @Override - public void processDelete(DeleteUpdateCommand cmd) throws IOException { - throw new UnsupportedOperationException("processDelete"); - } - - @Override - public void processMergeIndexes(MergeIndexesCommand cmd) throws IOException { - throw new UnsupportedOperationException("processMergeIndexes"); - } - - @Override - public void processCommit(CommitUpdateCommand cmd) throws IOException { - throw new UnsupportedOperationException("processCommit"); - } - - @Override - public void processRollback(RollbackUpdateCommand cmd) throws IOException { - throw new UnsupportedOperationException("processRollback"); - } - } -} diff --git a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java index 143cf453f41..a35ededf7b0 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java @@ -17,14 +17,6 @@ package org.apache.solr.handler.admin; -import com.codahale.metrics.Counter; -import com.codahale.metrics.Gauge; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.Meter; -import com.codahale.metrics.Metric; -import com.codahale.metrics.MetricFilter; -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.Timer; import io.prometheus.metrics.model.snapshots.CounterSnapshot; import io.prometheus.metrics.model.snapshots.GaugeSnapshot; import io.prometheus.metrics.model.snapshots.HistogramSnapshot; @@ -32,28 +24,18 @@ import io.prometheus.metrics.model.snapshots.MetricSnapshot; import io.prometheus.metrics.model.snapshots.MetricSnapshots; import java.util.ArrayList; -import java.util.Collections; -import java.util.EnumSet; import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; -import java.util.TreeSet; import java.util.function.BiConsumer; -import java.util.function.Predicate; import java.util.regex.Pattern; -import java.util.stream.Collectors; -import org.apache.solr.common.MapWriter; import org.apache.solr.common.SolrException; import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.CommonTestInjection; -import org.apache.solr.common.util.NamedList; -import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.common.util.StrUtils; import org.apache.solr.core.CoreContainer; import org.apache.solr.handler.RequestHandlerBase; @@ -64,7 +46,6 @@ import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.security.AuthorizationContext; import org.apache.solr.security.PermissionNameProvider; -import org.apache.solr.util.stats.MetricUtils; /** Request handler to return metrics */ public class MetricsHandler extends RequestHandlerBase implements PermissionNameProvider { @@ -89,7 +70,6 @@ public class MetricsHandler extends RequestHandlerBase implements PermissionName private static final Set labelFilterKeys = Set.of(CATEGORY_PARAM, CORE_PARAM, COLLECTION_PARAM, SHARD_PARAM, REPLICA_PARAM); - // NOCOMMIT: This wt=prometheus will be removed as it will become the default for /admin/metrics public static final String PROMETHEUS_METRICS_WT = "prometheus"; public static final String OPEN_METRICS_WT = "openmetrics"; @@ -129,6 +109,18 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw SolrException.ErrorCode.INVALID_STATE, "SolrMetricManager instance not initialized"); } + SolrParams params = req.getParams(); + String format = params.get(CommonParams.WT); + + if (format == null) { + req.setParams(SolrParams.wrapDefaults(params, SolrParams.of("wt", "prometheus"))); + } else if (!PROMETHEUS_METRICS_WT.equals(format) && !OPEN_METRICS_WT.equals(format)) { + throw new SolrException( + SolrException.ErrorCode.BAD_REQUEST, + "Only Prometheus and OpenMetrics metric formats supported. Unsupported format requested: " + + format); + } + if (cc != null && AdminHandlersProxy.maybeProxyToNodes(req, rsp, cc)) { return; // Request was proxied to other node } @@ -141,37 +133,11 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw } private void handleRequest(SolrParams params, BiConsumer consumer) { - NamedList response; - if (!enabled) { consumer.accept("error", "metrics collection is disabled"); return; } - // NOCOMMIT SOLR-17458: Make this the default option after dropwizard removal - if (PROMETHEUS_METRICS_WT.equals(params.get(CommonParams.WT)) - || OPEN_METRICS_WT.equals(params.get(CommonParams.WT))) { - handlePrometheusRequest(params, consumer); - return; - } - - String[] keys = params.getParams(KEY_PARAM); - if (keys != null && keys.length > 0) { - handleKeyRequest(keys, consumer); - return; - } - String[] exprs = params.getParams(EXPR_PARAM); - if (exprs != null && exprs.length > 0) { - handleExprRequest(exprs, consumer); - return; - } - - response = handleDropwizardRegistry(params); - - consumer.accept("metrics", response); - } - - private void handlePrometheusRequest(SolrParams params, BiConsumer consumer) { Set metricNames = readParamsAsSet(params, METRIC_NAME_PARAM); SortedMap> labelFilters = labelFilters(params); @@ -223,355 +189,6 @@ private Set readParamsAsSet(SolrParams params, String paramName) { return Set.copyOf(paramSet); } - private NamedList handleDropwizardRegistry(SolrParams params) { - boolean compact = params.getBool(COMPACT_PARAM, true); - MetricFilter mustMatchFilter = parseMustMatchFilter(params); - Predicate propertyFilter = parsePropertyFilter(params); - List metricTypes = parseMetricTypes(params); - List metricFilters = - metricTypes.stream().map(MetricType::asMetricFilter).collect(Collectors.toList()); - Set requestedRegistries = parseRegistries(params); - - NamedList response = new SimpleOrderedMap<>(); - for (String registryName : requestedRegistries) { - MetricRegistry registry = metricManager.registry(registryName); - SimpleOrderedMap result = new SimpleOrderedMap<>(); - - MetricUtils.toMaps( - registry, - metricFilters, - mustMatchFilter, - propertyFilter, - false, - false, - compact, - false, - (k, v) -> result.add(k, v)); - if (result.size() > 0) { - response.add(registryName, result); - } - } - return response; - } - - // NOCOMMIT: Remove this filtering logic - private static class MetricsExpr { - Pattern registryRegex; - MetricFilter metricFilter; - Predicate propertyFilter; - } - - private void handleExprRequest(String[] exprs, BiConsumer consumer) { - SimpleOrderedMap result = new SimpleOrderedMap<>(); - SimpleOrderedMap errors = new SimpleOrderedMap<>(); - List metricsExprs = new ArrayList<>(); - - for (String key : exprs) { - if (key == null || key.isEmpty()) { - continue; - } - String[] parts = KEY_SPLIT_REGEX.split(key); - if (parts.length < 2 || parts.length > 3) { - errors.add(key, "at least two and at most three colon-separated parts must be provided"); - continue; - } - MetricsExpr me = new MetricsExpr(); - me.registryRegex = Pattern.compile(unescape(parts[0])); - me.metricFilter = new SolrMetricManager.RegexFilter(unescape(parts[1])); - String propertyPart = parts.length > 2 ? unescape(parts[2]) : null; - if (propertyPart == null) { - me.propertyFilter = name -> true; - } else { - me.propertyFilter = - new Predicate<>() { - final Pattern pattern = Pattern.compile(propertyPart); - - @Override - public boolean test(CharSequence charSequence) { - return pattern.matcher(charSequence).matches(); - } - }; - } - metricsExprs.add(me); - } - // find matching registries first, to avoid scanning non-matching registries - Set matchingRegistries = new TreeSet<>(); - metricsExprs.forEach( - me -> { - metricManager - .registryNames() - .forEach( - name -> { - if (me.registryRegex.matcher(name).matches()) { - matchingRegistries.add(name); - } - }); - }); - for (String registryName : matchingRegistries) { - MetricRegistry registry = metricManager.registry(registryName); - for (MetricsExpr me : metricsExprs) { - @SuppressWarnings("unchecked") - SimpleOrderedMap perRegistryResult = - (SimpleOrderedMap) result.get(registryName); - final SimpleOrderedMap perRegistryTemp = new SimpleOrderedMap<>(); - // skip processing if not a matching registry - if (!me.registryRegex.matcher(registryName).matches()) { - continue; - } - MetricUtils.toMaps( - registry, - Collections.singletonList(MetricFilter.ALL), - me.metricFilter, - me.propertyFilter, - false, - false, - true, - false, - (k, v) -> perRegistryTemp.add(k, v)); - // extracted some metrics and there's no entry for this registry yet - if (perRegistryTemp.size() > 0) { - if (perRegistryResult == null) { // new results for this registry - result.add(registryName, perRegistryTemp); - } else { - // merge if needed - for (Iterator> it = perRegistryTemp.iterator(); - it.hasNext(); ) { - Map.Entry entry = it.next(); - Object existing = perRegistryResult.get(entry.getKey()); - if (existing == null) { - perRegistryResult.add(entry.getKey(), entry.getValue()); - } - } - } - } - } - } - consumer.accept("metrics", result); - if (errors.size() > 0) { - consumer.accept("errors", errors); - } - } - - private void handleKeyRequest(String[] keys, BiConsumer consumer) { - SimpleOrderedMap result = new SimpleOrderedMap<>(); - SimpleOrderedMap errors = new SimpleOrderedMap<>(); - for (String key : keys) { - if (key == null || key.isEmpty()) { - continue; - } - String[] parts = KEY_SPLIT_REGEX.split(key); - if (parts.length < 2 || parts.length > 3) { - errors.add(key, "at least two and at most three colon-separated parts must be provided"); - continue; - } - final String registryName = unescape(parts[0]); - final String metricName = unescape(parts[1]); - final String propertyName = parts.length > 2 ? unescape(parts[2]) : null; - if (!metricManager.hasDropwizardRegistry(registryName)) { - errors.add(key, "registry '" + registryName + "' not found"); - continue; - } - MetricRegistry registry = metricManager.registry(registryName); - Metric m = registry.getMetrics().get(metricName); - if (m == null) { - errors.add(key, "metric '" + metricName + "' not found"); - continue; - } - Predicate propertyFilter = MetricUtils.ALL_PROPERTIES; - if (propertyName != null) { - propertyFilter = propertyName::contentEquals; - // use escaped versions - key = parts[0] + ":" + parts[1]; - } - if (injectedSysProps != null - && SolrMetricManager.JVM_REGISTRY.equals(registryName) - && "system.properties".equals(metricName) - && injectedSysProps.containsKey(propertyName)) { - result.add( - registryName + ":" + metricName + ":" + propertyName, - injectedSysProps.get(propertyName)); - continue; - } - MetricUtils.convertMetric( - key, - m, - propertyFilter, - false, - true, - true, - false, - ":", - (k, v) -> { - if ((v instanceof Map) && propertyName != null) { - ((Map) v).forEach((k1, v1) -> result.add(k + ":" + k1, v1)); - } else if ((v instanceof MapWriter) && propertyName != null) { - ((MapWriter) v)._forEachEntry((k1, v1) -> result.add(k + ":" + k1, v1)); - } else { - result.add(k, v); - } - }); - } - consumer.accept("metrics", result); - if (errors.size() > 0) { - consumer.accept("errors", errors); - } - } - - private static String unescape(String s) { - if (s.indexOf('\\') == -1) { - return s; - } - StringBuilder sb = new StringBuilder(s.length()); - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - if (c == '\\') { - if (i < s.length() - 1 && s.charAt(i + 1) == ':') { - continue; - } - } - sb.append(c); - } - return sb.toString(); - } - - private MetricFilter parseMustMatchFilter(SolrParams params) { - String[] prefixes = params.getParams(PREFIX_PARAM); - MetricFilter prefixFilter = null; - if (prefixes != null && prefixes.length > 0) { - Set prefixSet = new HashSet<>(); - for (String prefix : prefixes) { - prefixSet.addAll(StrUtils.splitSmart(prefix, ',')); - } - prefixFilter = new SolrMetricManager.PrefixFilter(prefixSet); - } - String[] regexes = params.getParams(REGEX_PARAM); - MetricFilter regexFilter = null; - if (regexes != null && regexes.length > 0) { - regexFilter = new SolrMetricManager.RegexFilter(regexes); - } - MetricFilter mustMatchFilter; - if (prefixFilter == null && regexFilter == null) { - mustMatchFilter = MetricFilter.ALL; - } else { - if (prefixFilter == null) { - mustMatchFilter = regexFilter; - } else if (regexFilter == null) { - mustMatchFilter = prefixFilter; - } else { - mustMatchFilter = new SolrMetricManager.OrFilter(prefixFilter, regexFilter); - } - } - return mustMatchFilter; - } - - private Predicate parsePropertyFilter(SolrParams params) { - String[] props = params.getParams(PROPERTY_PARAM); - if (props == null || props.length == 0) { - return MetricUtils.ALL_PROPERTIES; - } - final Set filter = new HashSet<>(); - for (String prop : props) { - if (prop != null && !prop.trim().isEmpty()) { - filter.add(prop.trim()); - } - } - if (filter.isEmpty()) { - return MetricUtils.ALL_PROPERTIES; - } else { - return (name) -> filter.contains(name.toString()); - } - } - - private Set parseRegistries(SolrParams params) { - String[] groupStr = params.getParams(GROUP_PARAM); - String[] registryStr = params.getParams(REGISTRY_PARAM); - return parseRegistries(groupStr, registryStr); - } - - public Set parseRegistries(String[] groupStr, String[] registryStr) { - if ((groupStr == null || groupStr.length == 0) - && (registryStr == null || registryStr.length == 0)) { - // return all registries - return metricManager.registryNames(); - } - boolean allRegistries = false; - Set initialPrefixes = Collections.emptySet(); - if (groupStr != null && groupStr.length > 0) { - initialPrefixes = new HashSet<>(); - for (String g : groupStr) { - List split = StrUtils.splitSmart(g, ','); - for (String s : split) { - if (s.trim().equals(ALL)) { - allRegistries = true; - break; - } - initialPrefixes.add(SolrMetricManager.enforcePrefix(s.trim())); - } - if (allRegistries) { - return metricManager.registryNames(); - } - } - } - - if (registryStr != null && registryStr.length > 0) { - if (initialPrefixes.isEmpty()) { - initialPrefixes = new HashSet<>(); - } - for (String r : registryStr) { - List split = StrUtils.splitSmart(r, ','); - for (String s : split) { - if (s.trim().equals(ALL)) { - allRegistries = true; - break; - } - initialPrefixes.add(SolrMetricManager.enforcePrefix(s.trim())); - } - if (allRegistries) { - return metricManager.registryNames(); - } - } - } - Set validRegistries = new HashSet<>(); - for (String r : metricManager.registryNames()) { - for (String prefix : initialPrefixes) { - if (r.startsWith(prefix)) { - validRegistries.add(r); - break; - } - } - } - return validRegistries; - } - - private List parseMetricTypes(SolrParams params) { - String[] typeStr = params.getParams(TYPE_PARAM); - List types = Collections.emptyList(); - if (typeStr != null && typeStr.length > 0) { - types = new ArrayList<>(); - for (String type : typeStr) { - types.addAll(StrUtils.splitSmart(type, ',')); - } - } - - // include all metrics by default - List metricTypes = Collections.singletonList(MetricType.all); - try { - if (types.size() > 0) { - metricTypes = - types.stream().map(String::trim).map(MetricType::valueOf).collect(Collectors.toList()); - } - } catch (IllegalArgumentException e) { - throw new SolrException( - SolrException.ErrorCode.BAD_REQUEST, - "Invalid metric type in: " - + types - + " specified. Must be one of " - + MetricType.SUPPORTED_TYPES_MSG, - e); - } - return metricTypes; - } - /** * Merge a collection of individual {@link MetricSnapshot} instances into one {@link * MetricSnapshots}. This is necessary because we create a {@link @@ -664,25 +281,4 @@ public String getDescription() { public Category getCategory() { return Category.ADMIN; } - - enum MetricType { - histogram(Histogram.class), - meter(Meter.class), - timer(Timer.class), - counter(Counter.class), - gauge(Gauge.class), - all(null); - - public static final String SUPPORTED_TYPES_MSG = EnumSet.allOf(MetricType.class).toString(); - - private final Class klass; - - MetricType(Class klass) { - this.klass = klass; - } - - public MetricFilter asMetricFilter() { - return (name, metric) -> klass == null || klass.isInstance(metric); - } - } } diff --git a/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java index a0544d98b81..ff7af6e45c0 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java @@ -18,12 +18,17 @@ import static org.apache.solr.common.params.CommonParams.NAME; -import com.codahale.metrics.Gauge; +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; import java.io.IOException; import java.lang.invoke.MethodHandles; import java.lang.management.ManagementFactory; import java.lang.management.OperatingSystemMXBean; +import java.lang.management.PlatformManagedObject; import java.lang.management.RuntimeMXBean; +import java.lang.reflect.Method; import java.net.InetAddress; import java.nio.file.Path; import java.text.DecimalFormat; @@ -34,6 +39,9 @@ import java.util.List; import java.util.Locale; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.function.BiConsumer; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.lucene.util.Version; @@ -80,6 +88,13 @@ public class SystemInfoHandler extends RequestHandlerBase { private static final String REVERSE_DNS_OF_LOCALHOST_SYSPROP = "solr.admin.handler.systeminfo.dns.reverse.lookup.enabled"; + /** + * Local cache for BeanInfo instances that are created to scan for system metrics. List of + * properties is not supposed to change for the JVM lifespan, so we can keep already create + * BeanInfo instance for future calls. + */ + private static final ConcurrentMap, BeanInfo> beanInfos = new ConcurrentHashMap<>(); + // on some platforms, resolving canonical hostname can cause the thread // to block for several seconds if nameservices aren't available // so resolve this once per handler instance @@ -98,6 +113,76 @@ public SystemInfoHandler(CoreContainer cc) { initHostname(); } + /** + * Iterates over properties of the given MXBean and invokes the provided consumer with each + * property name and its current value. + * + * @param obj an instance of MXBean + * @param interfaces interfaces that it may implement. Each interface will be tried in turn, and + * only if it exists and if it contains unique properties then they will be added as metrics. + * @param consumer consumer for each property name and value + * @param formal type + */ + public static void forEachGetterValue( + T obj, String[] interfaces, BiConsumer consumer) { + for (String clazz : interfaces) { + try { + final Class intf = + Class.forName(clazz).asSubclass(PlatformManagedObject.class); + forEachGetterValue(obj, intf, consumer); + } catch (ClassNotFoundException e) { + // ignore + } + } + } + + /** + * Iterates over properties of the given MXBean and invokes the provided consumer with each + * property name and its current value. + * + * @param obj an instance of MXBean + * @param intf MXBean interface, one of {@link PlatformManagedObject}-s + * @param consumer consumer for each property name and value + * @param formal type + */ + public static void forEachGetterValue( + T obj, Class intf, BiConsumer consumer) { + if (intf.isInstance(obj)) { + BeanInfo beanInfo = + beanInfos.computeIfAbsent( + intf, + clazz -> { + try { + return Introspector.getBeanInfo( + clazz, clazz.getSuperclass(), Introspector.IGNORE_ALL_BEANINFO); + + } catch (IntrospectionException e) { + log.warn("Unable to fetch properties of MXBean {}", obj.getClass().getName()); + return null; + } + }); + + // if BeanInfo retrieval failed, return early + if (beanInfo == null) { + return; + } + for (final PropertyDescriptor desc : beanInfo.getPropertyDescriptors()) { + try { + Method readMethod = desc.getReadMethod(); + if (readMethod == null) { + continue; // skip properties without a read method + } + + final String name = desc.getName(); + Object value = readMethod.invoke(obj); + consumer.accept(name, value); + } catch (Exception e) { + // didn't work, skip it... + } + } + } + } + private void initHostname() { if (!EnvUtils.getPropertyAsBool(REVERSE_DNS_OF_LOCALHOST_SYSPROP, true)) { log.info( @@ -217,15 +302,15 @@ public static SimpleOrderedMap getSystemInfo() { OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean(); info.add(NAME, os.getName()); // add at least this one + // add remaining ones dynamically using Java Beans API // also those from JVM implementation-specific classes - MetricUtils.addMXBeanMetrics( + forEachGetterValue( os, MetricUtils.OS_MXBEAN_CLASSES, - null, - (name, metric) -> { + (name, value) -> { if (info.get(name) == null) { - info.add(name, ((Gauge) metric).getValue()); + info.add(name, value); } }); diff --git a/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java b/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java index 87c18486ba7..f404bf512dd 100644 --- a/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java +++ b/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java @@ -55,7 +55,6 @@ import org.apache.solr.core.PluginInfo; import org.apache.solr.core.SolrCore; import org.apache.solr.core.SolrInfoBean; -import org.apache.solr.metrics.SolrMetricManager; import org.apache.solr.metrics.SolrMetricProducer; import org.apache.solr.metrics.SolrMetricsContext; import org.apache.solr.request.SolrQueryRequest; @@ -440,11 +439,9 @@ private String buildUrl(String url) { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { solrMetricsContext = parentContext.getChildContext(this); - String expandedScope = SolrMetricManager.mkName(scope, SolrInfoBean.Category.QUERY.name()); - httpListenerFactory.initializeMetrics(solrMetricsContext, Attributes.empty(), expandedScope); + httpListenerFactory.initializeMetrics(solrMetricsContext, Attributes.empty()); commExecutor = MetricUtils.instrumentedExecutorService( commExecutor, solrMetricsContext, SolrInfoBean.Category.QUERY, "httpShardExecutor"); diff --git a/solr/core/src/java/org/apache/solr/handler/component/SearchComponent.java b/solr/core/src/java/org/apache/solr/handler/component/SearchComponent.java index de041a7220e..615726056e9 100644 --- a/solr/core/src/java/org/apache/solr/handler/component/SearchComponent.java +++ b/solr/core/src/java/org/apache/solr/handler/component/SearchComponent.java @@ -104,10 +104,8 @@ public SolrMetricsContext getSolrMetricsContext() { return solrMetricsContext; } - // TODO SOLR-17458: Update with Otel @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { // By default don't register any metrics - but prepare a child context this.solrMetricsContext = parentContext.getChildContext(this); } diff --git a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java index cc7ad157651..e126a495b5b 100644 --- a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java @@ -27,7 +27,6 @@ import static org.apache.solr.request.SolrRequestInfo.getQueryLimits; import static org.apache.solr.response.SolrQueryResponse.RESPONSE_HEADER_PARTIAL_RESULTS_DETAILS_KEY; -import com.codahale.metrics.Counter; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import java.io.IOException; @@ -42,7 +41,6 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; @@ -122,7 +120,6 @@ public class SearchHandler extends RequestHandlerBase Boolean.getBoolean("solr.disableRequestId"); private HandlerMetrics metricsShard = HandlerMetrics.NO_OP; - private final Map shardPurposes = new ConcurrentHashMap<>(); protected volatile List components; private ShardHandlerFactory shardHandlerFactory; @@ -156,12 +153,9 @@ public void init(PluginInfo info) { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { super.initializeMetrics( - parentContext, - Attributes.builder().putAll(attributes).put(INTERNAL_ATTR, false).build(), - scope); + parentContext, Attributes.builder().putAll(attributes).put(INTERNAL_ATTR, false).build()); metricsShard = new HandlerMetrics( // will register various metrics in the context solrMetricsContext, @@ -402,12 +396,6 @@ protected boolean checkCircuitBreakers( @Override public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { - if (req.getParams().getBool(ShardParams.IS_SHARD, false)) { - int purpose = req.getParams().getInt(ShardParams.SHARDS_PURPOSE, 0); - SolrPluginUtils.forEachRequestPurpose( - purpose, n -> shardPurposes.computeIfAbsent(n, name -> new Counter()).inc()); - } - List components = getComponents(); ResponseBuilder rb = newResponseBuilder(req, rsp, components); if (rb.requestInfo != null) { diff --git a/solr/core/src/java/org/apache/solr/handler/component/SuggestComponent.java b/solr/core/src/java/org/apache/solr/handler/component/SuggestComponent.java index 2702f79e58e..5a82e1088b0 100644 --- a/solr/core/src/java/org/apache/solr/handler/component/SuggestComponent.java +++ b/solr/core/src/java/org/apache/solr/handler/component/SuggestComponent.java @@ -386,9 +386,8 @@ public String getDescription() { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { - super.initializeMetrics(parentContext, attributes, scope); + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { + super.initializeMetrics(parentContext, attributes); var suggesterAttributes = attributes.toBuilder().put(CATEGORY_ATTR, getCategory().toString()).build(); this.toClose = diff --git a/solr/core/src/java/org/apache/solr/jersey/RequestContextKeys.java b/solr/core/src/java/org/apache/solr/jersey/RequestContextKeys.java index 273b191b50c..e12484b12a6 100644 --- a/solr/core/src/java/org/apache/solr/jersey/RequestContextKeys.java +++ b/solr/core/src/java/org/apache/solr/jersey/RequestContextKeys.java @@ -17,7 +17,6 @@ package org.apache.solr.jersey; -import com.codahale.metrics.Timer; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.ws.rs.container.ContainerRequestContext; @@ -27,6 +26,7 @@ import org.apache.solr.core.PluginBag; import org.apache.solr.core.SolrCore; import org.apache.solr.handler.RequestHandlerBase; +import org.apache.solr.metrics.otel.instruments.AttributedLongTimer; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.security.AuthorizationContext; @@ -50,7 +50,7 @@ public interface RequestContextKeys { String SOLR_PARAMS = SolrParams.class.getName(); String COLLECTION_LIST = "collection_name_list"; String HANDLER_METRICS = RequestHandlerBase.HandlerMetrics.class.getName(); - String TIMER = Timer.Context.class.getName(); + String TIMER = AttributedLongTimer.MetricTimer.class.getName(); String SOLR_JERSEY_RESPONSE = SolrJerseyResponse.class.getName(); /** diff --git a/solr/core/src/java/org/apache/solr/metrics/AggregateMetric.java b/solr/core/src/java/org/apache/solr/metrics/AggregateMetric.java deleted file mode 100644 index 638f2ebc644..00000000000 --- a/solr/core/src/java/org/apache/solr/metrics/AggregateMetric.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * 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.solr.metrics; - -import com.codahale.metrics.Metric; -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * This class is used for keeping several partial named values and providing useful statistics over - * them. - */ -public class AggregateMetric implements Metric { - - /** Simple class to represent current value and how many times it was set. */ - public static class Update { - public Object value; - public final AtomicInteger updateCount = new AtomicInteger(); - - public Update(Object value) { - update(value); - } - - public void update(Object value) { - this.value = value; - updateCount.incrementAndGet(); - } - - @Override - public String toString() { - return "Update{" + "value=" + value + ", updateCount=" + updateCount + '}'; - } - } - - private final Map values = new ConcurrentHashMap<>(); - - public void set(String name, Object value) { - final Update existing = values.get(name); - if (existing == null) { - final Update created = new Update(value); - final Update raced = values.putIfAbsent(name, created); - if (raced != null) { - raced.update(value); - } - } else { - existing.update(value); - } - } - - public void clear(String name) { - values.remove(name); - } - - public void clear() { - values.clear(); - } - - public int size() { - return values.size(); - } - - public boolean isEmpty() { - return values.isEmpty(); - } - - public Map getValues() { - return Collections.unmodifiableMap(values); - } - - // --------- stats --------- - public double getMax() { - if (values.isEmpty()) { - return 0; - } - Double res = null; - for (Update u : values.values()) { - if (!(u.value instanceof Number n)) { - continue; - } - if (res == null) { - res = n.doubleValue(); - continue; - } - if (n.doubleValue() > res) { - res = n.doubleValue(); - } - } - if (res == null) { - return 0; - } - return res; - } - - public double getMin() { - if (values.isEmpty()) { - return 0; - } - Double res = null; - for (Update u : values.values()) { - if (!(u.value instanceof Number n)) { - continue; - } - if (res == null) { - res = n.doubleValue(); - continue; - } - if (n.doubleValue() < res) { - res = n.doubleValue(); - } - } - if (res == null) { - return 0; - } - return res; - } - - public double getMean() { - if (values.isEmpty()) { - return 0; - } - double total = 0; - for (Update u : values.values()) { - if (!(u.value instanceof Number n)) { - continue; - } - total += n.doubleValue(); - } - return total / values.size(); - } - - public double getStdDev() { - int size = values.size(); - if (size < 2) { - return 0; - } - final double mean = getMean(); - double sum = 0; - int count = 0; - for (Update u : values.values()) { - if (!(u.value instanceof Number n)) { - continue; - } - count++; - final double diff = n.doubleValue() - mean; - sum += diff * diff; - } - if (count < 2) { - return 0; - } - final double variance = sum / (count - 1); - return Math.sqrt(variance); - } - - public double getSum() { - if (values.isEmpty()) { - return 0; - } - double res = 0; - for (Update u : values.values()) { - if (!(u.value instanceof Number n)) { - continue; - } - res += n.doubleValue(); - } - return res; - } - - @Override - public String toString() { - return "AggregateMetric{" - + "size=" - + size() - + ", max=" - + getMax() - + ", min=" - + getMin() - + ", mean=" - + getMean() - + ", stddev=" - + getStdDev() - + ", sum=" - + getSum() - + ", values=" - + values - + '}'; - } -} diff --git a/solr/core/src/java/org/apache/solr/metrics/DelegateRegistryCounter.java b/solr/core/src/java/org/apache/solr/metrics/DelegateRegistryCounter.java deleted file mode 100644 index c8cc2352818..00000000000 --- a/solr/core/src/java/org/apache/solr/metrics/DelegateRegistryCounter.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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.solr.metrics; - -import com.codahale.metrics.Counter; - -/** - * A counter implementation that is aware of both primary and delegate metrics belonging to - * different registries and able to update metrics in multiple registries - * - * @see SolrDelegateRegistryMetricsContext - */ -public class DelegateRegistryCounter extends Counter { - - private final Counter primaryCounter; - private final Counter delegateCounter; - - public DelegateRegistryCounter(Counter primaryCounter, Counter delegateCounter) { - this.primaryCounter = primaryCounter; - this.delegateCounter = delegateCounter; - } - - @Override - public void inc() { - primaryCounter.inc(); - delegateCounter.inc(); - } - - @Override - public void inc(long n) { - primaryCounter.inc(n); - delegateCounter.inc(n); - } - - @Override - public void dec() { - primaryCounter.dec(); - delegateCounter.dec(); - } - - @Override - public void dec(long n) { - primaryCounter.dec(n); - delegateCounter.dec(n); - } - - @Override - public long getCount() { - return primaryCounter.getCount(); - } - - public Counter getPrimaryCounter() { - return primaryCounter; - } - - public Counter getDelegateCounter() { - return delegateCounter; - } -} diff --git a/solr/core/src/java/org/apache/solr/metrics/DelegateRegistryHistogram.java b/solr/core/src/java/org/apache/solr/metrics/DelegateRegistryHistogram.java deleted file mode 100644 index 900641244ce..00000000000 --- a/solr/core/src/java/org/apache/solr/metrics/DelegateRegistryHistogram.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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.solr.metrics; - -import com.codahale.metrics.Histogram; -import com.codahale.metrics.Snapshot; - -/** - * A meter implementation that is aware of both primary and delegate metrics belonging to different - * registries and able to update metrics in multiple registries - * - * @see SolrDelegateRegistryMetricsContext - */ -public class DelegateRegistryHistogram extends Histogram { - - private final Histogram primaryHistogram; - private final Histogram delegateHistogram; - - public DelegateRegistryHistogram(Histogram primaryHistogram, Histogram delegateHistogram) { - super(null); - this.primaryHistogram = primaryHistogram; - this.delegateHistogram = delegateHistogram; - } - - @Override - public void update(int value) { - primaryHistogram.update(value); - delegateHistogram.update(value); - } - - @Override - public void update(long value) { - primaryHistogram.update(value); - delegateHistogram.update(value); - } - - @Override - public long getCount() { - return primaryHistogram.getCount(); - } - - @Override - public Snapshot getSnapshot() { - return primaryHistogram.getSnapshot(); - } - - public Histogram getPrimaryHistogram() { - return primaryHistogram; - } - - public Histogram getDelegateHistogram() { - return delegateHistogram; - } -} diff --git a/solr/core/src/java/org/apache/solr/metrics/DelegateRegistryMeter.java b/solr/core/src/java/org/apache/solr/metrics/DelegateRegistryMeter.java deleted file mode 100644 index 20903cc7f12..00000000000 --- a/solr/core/src/java/org/apache/solr/metrics/DelegateRegistryMeter.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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.solr.metrics; - -import com.codahale.metrics.Meter; - -/** - * A meter implementation that is aware of both primary and delegate metrics belonging to different - * registries and able to update metrics in multiple registries - * - * @see SolrDelegateRegistryMetricsContext - */ -public class DelegateRegistryMeter extends Meter { - - private final Meter primaryMeter; - private final Meter delegateMeter; - - public DelegateRegistryMeter(Meter primaryMeter, Meter delegateMeter) { - this.primaryMeter = primaryMeter; - this.delegateMeter = delegateMeter; - } - - @Override - public void mark() { - primaryMeter.mark(); - delegateMeter.mark(); - } - - @Override - public void mark(long n) { - primaryMeter.mark(n); - delegateMeter.mark(n); - } - - @Override - public long getCount() { - return primaryMeter.getCount(); - } - - @Override - public double getFifteenMinuteRate() { - return primaryMeter.getFifteenMinuteRate(); - } - - @Override - public double getFiveMinuteRate() { - return primaryMeter.getFiveMinuteRate(); - } - - @Override - public double getMeanRate() { - return primaryMeter.getMeanRate(); - } - - @Override - public double getOneMinuteRate() { - return primaryMeter.getOneMinuteRate(); - } - - public Meter getPrimaryMeter() { - return primaryMeter; - } - - public Meter getDelegateMeter() { - return delegateMeter; - } -} diff --git a/solr/core/src/java/org/apache/solr/metrics/DelegateRegistryTimer.java b/solr/core/src/java/org/apache/solr/metrics/DelegateRegistryTimer.java deleted file mode 100644 index 3519ee55cef..00000000000 --- a/solr/core/src/java/org/apache/solr/metrics/DelegateRegistryTimer.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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.solr.metrics; - -import com.codahale.metrics.Clock; -import com.codahale.metrics.Snapshot; -import com.codahale.metrics.Timer; -import java.time.Duration; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; - -/** - * A timer implementation that is aware of both primary and delegate metrics belonging to different - * registries and able to update metrics in multiple registries - * - * @see SolrDelegateRegistryMetricsContext - */ -public class DelegateRegistryTimer extends Timer { - - private final Timer primaryTimer; - private final Timer delegateTimer; - private final Clock clock; - - public DelegateRegistryTimer(Clock clock, Timer primaryTimer, Timer delegateTimer) { - this.primaryTimer = primaryTimer; - this.delegateTimer = delegateTimer; - this.clock = clock; - } - - @Override - public void update(long duration, TimeUnit unit) { - primaryTimer.update(duration, unit); - delegateTimer.update(duration, unit); - } - - @Override - public void update(Duration duration) { - primaryTimer.update(duration); - delegateTimer.update(duration); - } - - @Override - public T time(Callable event) throws Exception { - final long startTime = clock.getTick(); - try { - return event.call(); - } finally { - update(clock.getTick() - startTime, TimeUnit.NANOSECONDS); - } - } - - @Override - public T timeSupplier(Supplier event) { - final long startTime = clock.getTick(); - try { - return event.get(); - } finally { - update(clock.getTick() - startTime, TimeUnit.NANOSECONDS); - } - } - - @Override - public void time(Runnable event) { - final long startTime = clock.getTick(); - try { - event.run(); - } finally { - update(clock.getTick() - startTime, TimeUnit.NANOSECONDS); - } - } - - @Override - public Context time() { - return super.time(); - } - - @Override - public long getCount() { - return primaryTimer.getCount(); - } - - @Override - public double getFifteenMinuteRate() { - return primaryTimer.getFifteenMinuteRate(); - } - - @Override - public double getFiveMinuteRate() { - return primaryTimer.getFiveMinuteRate(); - } - - @Override - public double getMeanRate() { - return primaryTimer.getMeanRate(); - } - - @Override - public double getOneMinuteRate() { - return primaryTimer.getOneMinuteRate(); - } - - @Override - public Snapshot getSnapshot() { - return primaryTimer.getSnapshot(); - } - - public Timer getPrimaryTimer() { - return primaryTimer; - } - - public Timer getDelegateTimer() { - return delegateTimer; - } -} diff --git a/solr/core/src/java/org/apache/solr/metrics/FilteringSolrMetricReporter.java b/solr/core/src/java/org/apache/solr/metrics/FilteringSolrMetricReporter.java deleted file mode 100644 index acdfc3b0b84..00000000000 --- a/solr/core/src/java/org/apache/solr/metrics/FilteringSolrMetricReporter.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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.solr.metrics; - -import com.codahale.metrics.MetricFilter; -import java.util.ArrayList; -import java.util.List; - -/** A {@link SolrMetricReporter} that supports (prefix) filters. */ -public abstract class FilteringSolrMetricReporter extends SolrMetricReporter { - - protected List filters = new ArrayList<>(); - - public FilteringSolrMetricReporter(SolrMetricManager metricManager, String registryName) { - super(metricManager, registryName); - } - - public void setFilter(List filters) { - if (filters == null || filters.isEmpty()) { - return; - } - this.filters.addAll(filters); - } - - public void setFilter(String filter) { - if (filter != null && !filter.isEmpty()) { - this.filters.add(filter); - } - } - - /** - * Report only metrics with names matching any of the prefix filters. If the filters list is empty - * then all names will match. - */ - protected MetricFilter newMetricFilter() { - final MetricFilter filter; - if (!filters.isEmpty()) { - filter = new SolrMetricManager.PrefixFilter(filters); - } else { - filter = MetricFilter.ALL; - } - return filter; - } -} diff --git a/solr/core/src/java/org/apache/solr/metrics/MetricSuppliers.java b/solr/core/src/java/org/apache/solr/metrics/MetricSuppliers.java deleted file mode 100644 index e128fbd5fc8..00000000000 --- a/solr/core/src/java/org/apache/solr/metrics/MetricSuppliers.java +++ /dev/null @@ -1,580 +0,0 @@ -/* - * 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.solr.metrics; - -import com.codahale.metrics.Clock; -import com.codahale.metrics.Counter; -import com.codahale.metrics.ExponentiallyDecayingReservoir; -import com.codahale.metrics.Gauge; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.Meter; -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.Reservoir; -import com.codahale.metrics.SlidingTimeWindowReservoir; -import com.codahale.metrics.SlidingWindowReservoir; -import com.codahale.metrics.Timer; -import com.codahale.metrics.UniformReservoir; -import java.lang.invoke.MethodHandles; -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadMXBean; -import java.time.Duration; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; -import org.apache.solr.core.MetricsConfig; -import org.apache.solr.core.PluginInfo; -import org.apache.solr.core.SolrResourceLoader; -import org.apache.solr.util.SolrPluginUtils; -import org.apache.solr.util.plugin.PluginInfoInitialized; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Helper class for constructing instances of {@link - * com.codahale.metrics.MetricRegistry.MetricSupplier} based on plugin configuration. This allows us - * to customize eg. {@link com.codahale.metrics.Reservoir} implementations and parameters for timers - * and histograms. - * - *

Custom supplier implementations must provide a zero-args constructor, and may optionally - * implement {@link org.apache.solr.util.plugin.PluginInfoInitialized} interface for configuration - - * if they don't then {@link org.apache.solr.util.SolrPluginUtils#invokeSetters(Object, Iterable, - * boolean)} will be used for initialization. - */ -public class MetricSuppliers { - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - /** Default {@link Counter} supplier. No configuration available. */ - public static final class DefaultCounterSupplier - implements MetricRegistry.MetricSupplier { - @Override - public Counter newMetric() { - return new Counter(); - } - } - - // back-compat implementation, no longer present in metrics-4 - private static final class CpuTimeClock extends Clock { - private static final ThreadMXBean THREAD_MX_BEAN = ManagementFactory.getThreadMXBean(); - - @Override - public long getTick() { - return THREAD_MX_BEAN.getCurrentThreadCpuTime(); - } - } - - private static final Clock CPU_CLOCK = new CpuTimeClock(); - private static final Clock USER_CLOCK = new Clock.UserTimeClock(); - - /** Clock type parameter. */ - public static final String CLOCK = "clock"; - - /** User-time clock. */ - public static final String CLOCK_USER = "user"; - - /** CPU-time clock. */ - public static final String CLOCK_CPU = "cpu"; - - /** - * Default {@link Meter} supplier. The following configuration is available, either as attribute - * or initArgs: - * - *

    - *
  • clock - (string) can be set to {@link #CLOCK_USER} for {@link - * com.codahale.metrics.Clock.UserTimeClock} or {@link #CLOCK_CPU} for {@link CpuTimeClock}. - * If not set then the value of {@link Clock#defaultClock()} will be used. - *
- */ - public static final class DefaultMeterSupplier - implements MetricRegistry.MetricSupplier, PluginInfoInitialized { - - public Clock clk = Clock.defaultClock(); - - @Override - public void init(PluginInfo info) { - clk = getClock(info, CLOCK); - } - - @Override - public Meter newMetric() { - return new Meter(clk); - } - } - - public static Clock getClock(PluginInfo info, String param) { - if (info == null) { - return Clock.defaultClock(); - } - String clock = null; - if (info.attributes != null) { - clock = info.attributes.get(param); - } - if (clock == null && info.initArgs != null) { - clock = (String) info.initArgs.get(param); - } - Clock clk = Clock.defaultClock(); - if (clock != null) { - if (clock.equalsIgnoreCase(CLOCK_USER)) { - clk = USER_CLOCK; - } else if (clock.equalsIgnoreCase(CLOCK_CPU)) { - clk = CPU_CLOCK; - } - } - return clk; - } - - /** - * Implementation class, must implement {@link Reservoir}. Supports non-standard configuration of - * the implementations available in metrics-core. - */ - public static final String RESERVOIR = "reservoir"; - - /** Size of reservoir. */ - public static final String RESERVOIR_SIZE = "size"; - - /** Alpha parameter of {@link ExponentiallyDecayingReservoir}. */ - public static final String RESERVOIR_EDR_ALPHA = "alpha"; - - /** Time window in seconds of {@link SlidingTimeWindowReservoir}. */ - public static final String RESERVOIR_WINDOW = "window"; - - private static final String EDR_CLAZZ = ExponentiallyDecayingReservoir.class.getName(); - private static final String UNI_CLAZZ = UniformReservoir.class.getName(); - private static final String STW_CLAZZ = SlidingTimeWindowReservoir.class.getName(); - private static final String SW_CLAZZ = SlidingWindowReservoir.class.getName(); - - private static final int DEFAULT_SIZE = 1028; - private static final double DEFAULT_ALPHA = 0.015; - private static final long DEFAULT_WINDOW = 300; - - private static final Reservoir getReservoir(SolrResourceLoader loader, PluginInfo info) { - if (info == null) { - return new ExponentiallyDecayingReservoir(); - } - Clock clk = getClock(info, CLOCK); - String clazz = ExponentiallyDecayingReservoir.class.getName(); - int size = -1; - double alpha = -1; - long window = -1; - if (info.initArgs != null) { - if (info.initArgs.get(RESERVOIR) != null) { - String val = String.valueOf(info.initArgs.get(RESERVOIR)).trim(); - if (!val.isEmpty()) { - clazz = val; - } - } - Number n = (Number) info.initArgs.get(RESERVOIR_SIZE); - if (n != null) { - size = n.intValue(); - } - n = (Number) info.initArgs.get(RESERVOIR_EDR_ALPHA); - if (n != null) { - alpha = n.doubleValue(); - } - n = (Number) info.initArgs.get(RESERVOIR_WINDOW); - if (n != null) { - window = n.longValue(); - } - } - if (size <= 0) { - size = DEFAULT_SIZE; - } - if (alpha <= 0) { - alpha = DEFAULT_ALPHA; - } - // special case for core implementations - if (clazz.equals(EDR_CLAZZ)) { - return new ExponentiallyDecayingReservoir(size, alpha, clk); - } else if (clazz.equals(UNI_CLAZZ)) { - return new UniformReservoir(size); - } else if (clazz.equals(STW_CLAZZ)) { - if (window <= 0) { - window = DEFAULT_WINDOW; // 5 minutes, comparable to EDR - } - return new SlidingTimeWindowReservoir(window, TimeUnit.SECONDS); - } else if (clazz.equals(SW_CLAZZ)) { - return new SlidingWindowReservoir(size); - } else { // custom reservoir - Reservoir reservoir; - if (loader == null) { - return new ExponentiallyDecayingReservoir(size, alpha, clk); - } else { - try { - reservoir = loader.newInstance(clazz, Reservoir.class); - if (reservoir instanceof PluginInfoInitialized) { - ((PluginInfoInitialized) reservoir).init(info); - } else { - SolrPluginUtils.invokeSetters(reservoir, info.initArgs, true); - } - return reservoir; - } catch (Exception e) { - log.warn( - "Error initializing custom Reservoir implementation (will use default): {}", info, e); - return new ExponentiallyDecayingReservoir(size, alpha, clk); - } - } - } - } - - /** - * Default supplier of {@link Timer} instances, with configurable clock and reservoir. See {@link - * DefaultMeterSupplier} for clock configuration. Reservoir configuration uses {@link #RESERVOIR}, - * {@link #RESERVOIR_EDR_ALPHA}, {@link #RESERVOIR_SIZE} and {@link #RESERVOIR_WINDOW}. - */ - public static final class DefaultTimerSupplier - implements MetricRegistry.MetricSupplier, PluginInfoInitialized { - - public Clock clk = Clock.defaultClock(); - private PluginInfo info; - private SolrResourceLoader loader; - - public DefaultTimerSupplier(SolrResourceLoader loader) { - this.loader = loader; - } - - @Override - public void init(PluginInfo info) { - clk = getClock(info, CLOCK); - this.info = info; - } - - public Reservoir getReservoir() { - return MetricSuppliers.getReservoir(loader, info); - } - - @Override - public Timer newMetric() { - return new Timer(getReservoir(), clk); - } - } - - /** Default supplier of {@link Histogram} instances, with configurable reservoir. */ - public static final class DefaultHistogramSupplier - implements MetricRegistry.MetricSupplier, PluginInfoInitialized { - - private PluginInfo info; - private SolrResourceLoader loader; - - public DefaultHistogramSupplier(SolrResourceLoader loader) { - this.loader = loader; - } - - @Override - public void init(PluginInfo info) { - this.info = info; - } - - public Reservoir getReservoir() { - return MetricSuppliers.getReservoir(loader, info); - } - - @Override - public Histogram newMetric() { - return new Histogram(getReservoir()); - } - } - - /** - * Create a {@link Counter} supplier. - * - * @param loader resource loader - * @param info plugin configuration, or null for default - * @return configured supplier instance, or default instance if configuration was invalid - */ - @SuppressWarnings({"unchecked"}) - public static MetricRegistry.MetricSupplier counterSupplier( - SolrResourceLoader loader, PluginInfo info) { - if (info == null || info.className == null || info.className.trim().isEmpty()) { - return new DefaultCounterSupplier(); - } - if (MetricsConfig.NOOP_IMPL_CLASS.equals(info.className)) { - return NoOpCounterSupplier.INSTANCE; - } - MetricRegistry.MetricSupplier supplier; - if (loader == null) { - supplier = new DefaultCounterSupplier(); - } else { - try { - supplier = loader.newInstance(info.className, MetricRegistry.MetricSupplier.class); - } catch (Exception e) { - log.warn("Error creating custom Counter supplier (will use default): {}", info, e); - supplier = new DefaultCounterSupplier(); - } - } - if (supplier instanceof PluginInfoInitialized) { - ((PluginInfoInitialized) supplier).init(info); - } else { - SolrPluginUtils.invokeSetters(supplier, info.initArgs, true); - } - return supplier; - } - - /** - * Create a {@link Meter} supplier. - * - * @param loader resource loader - * @param info plugin configuration, or null for default - * @return configured supplier instance, or default instance if configuration was invalid - */ - @SuppressWarnings({"unchecked"}) - public static MetricRegistry.MetricSupplier meterSupplier( - SolrResourceLoader loader, PluginInfo info) { - MetricRegistry.MetricSupplier supplier; - if (info == null || info.className == null || info.className.isEmpty()) { - supplier = new DefaultMeterSupplier(); - } else { - if (MetricsConfig.NOOP_IMPL_CLASS.equals(info.className)) { - return NoOpMeterSupplier.INSTANCE; - } - if (loader == null) { - supplier = new DefaultMeterSupplier(); - } else { - try { - supplier = loader.newInstance(info.className, MetricRegistry.MetricSupplier.class); - } catch (Exception e) { - log.warn("Error creating custom Meter supplier (will use default): {}", info, e); - supplier = new DefaultMeterSupplier(); - } - } - } - if (supplier instanceof PluginInfoInitialized) { - ((PluginInfoInitialized) supplier).init(info); - } else { - SolrPluginUtils.invokeSetters(supplier, info.initArgs, true); - } - return supplier; - } - - /** - * Create a {@link Timer} supplier. - * - * @param loader resource loader - * @param info plugin configuration, or null for default - * @return configured supplier instance, or default instance if configuration was invalid - */ - @SuppressWarnings({"unchecked"}) - public static MetricRegistry.MetricSupplier timerSupplier( - SolrResourceLoader loader, PluginInfo info) { - MetricRegistry.MetricSupplier supplier; - if (info == null || info.className == null || info.className.isEmpty()) { - supplier = new DefaultTimerSupplier(loader); - } else { - if (MetricsConfig.NOOP_IMPL_CLASS.equals(info.className)) { - return NoOpTimerSupplier.INSTANCE; - } - if (loader == null) { - supplier = new DefaultTimerSupplier(null); - } else { - try { - supplier = loader.newInstance(info.className, MetricRegistry.MetricSupplier.class); - } catch (Exception e) { - log.warn("Error creating custom Timer supplier (will use default): {}", info, e); - supplier = new DefaultTimerSupplier(loader); - } - } - } - if (supplier instanceof PluginInfoInitialized) { - ((PluginInfoInitialized) supplier).init(info); - } else { - SolrPluginUtils.invokeSetters(supplier, info.initArgs, true); - } - return supplier; - } - - /** - * Create a {@link Histogram} supplier. - * - * @param info plugin configuration, or null for default - * @return configured supplier instance, or default instance if configuration was invalid - */ - @SuppressWarnings({"unchecked"}) - public static MetricRegistry.MetricSupplier histogramSupplier( - SolrResourceLoader loader, PluginInfo info) { - MetricRegistry.MetricSupplier supplier; - if (info == null || info.className == null || info.className.isEmpty()) { - supplier = new DefaultHistogramSupplier(loader); - } else { - if (MetricsConfig.NOOP_IMPL_CLASS.equals(info.className)) { - return NoOpHistogramSupplier.INSTANCE; - } - if (loader == null) { - supplier = new DefaultHistogramSupplier(null); - } else { - try { - supplier = loader.newInstance(info.className, MetricRegistry.MetricSupplier.class); - } catch (Exception e) { - log.warn("Error creating custom Histogram supplier (will use default): {}", info, e); - supplier = new DefaultHistogramSupplier(loader); - } - } - } - if (supplier instanceof PluginInfoInitialized) { - ((PluginInfoInitialized) supplier).init(info); - } else { - SolrPluginUtils.invokeSetters(supplier, info.initArgs, true); - } - return supplier; - } - - // NO-OP implementations. These can be used to effectively "turn off" the metrics - // collection, or rather eliminate the overhead of the metrics accounting and their - // memory footprint. - - /** Marker interface for all no-op metrics. */ - public interface NoOpMetric {} - - /** No-op implementation of {@link Counter} supplier. */ - public static final class NoOpCounterSupplier implements MetricRegistry.MetricSupplier { - public static final NoOpCounterSupplier INSTANCE = new NoOpCounterSupplier(); - - private static final class NoOpCounter extends Counter implements NoOpMetric { - @Override - public void inc() { - // no-op - } - - @Override - public void inc(long n) { - // no-op - } - - @Override - public void dec() { - // no-op - } - - @Override - public void dec(long n) { - // no-op - } - } - - private static final Counter METRIC = new NoOpCounter(); - - @Override - public Counter newMetric() { - return METRIC; - } - } - - /** No-op implementation of {@link Histogram} supplier. */ - public static final class NoOpHistogramSupplier - implements MetricRegistry.MetricSupplier { - public static final NoOpHistogramSupplier INSTANCE = new NoOpHistogramSupplier(); - - private static final class NoOpHistogram extends Histogram implements NoOpMetric { - - public NoOpHistogram() { - super(new UniformReservoir(1)); - } - - @Override - public void update(int value) { - // no-op - } - - @Override - public void update(long value) { - // no-op - } - } - - private static final NoOpHistogram METRIC = new NoOpHistogram(); - - @Override - public Histogram newMetric() { - return METRIC; - } - } - - /** No-op implementation of {@link Meter} supplier. */ - public static final class NoOpMeterSupplier implements MetricRegistry.MetricSupplier { - public static final NoOpMeterSupplier INSTANCE = new NoOpMeterSupplier(); - - private static final class NoOpMeter extends Meter implements NoOpMetric { - @Override - public void mark() { - // no-op - } - - @Override - public void mark(long n) { - // no-op - } - } - - private static final NoOpMeter METRIC = new NoOpMeter(); - - @Override - public Meter newMetric() { - return METRIC; - } - } - - /** No-op implementation of {@link Timer} supplier. */ - public static final class NoOpTimerSupplier implements MetricRegistry.MetricSupplier { - public static final NoOpTimerSupplier INSTANCE = new NoOpTimerSupplier(); - - private static final class NoOpTimer extends Timer implements NoOpMetric { - @Override - public void update(long duration, TimeUnit unit) { - // no-op - } - - @Override - public void update(Duration duration) { - // no-op - } - - @Override - public T time(Callable event) throws Exception { - return event.call(); - } - - @Override - public T timeSupplier(Supplier event) { - return event.get(); - } - - @Override - public void time(Runnable event) { - event.run(); - } - } - - private static final NoOpTimer METRIC = new NoOpTimer(); - - @Override - public Timer newMetric() { - return METRIC; - } - } - - /** No-op implementation of {@link Gauge}. */ - public static final class NoOpGauge implements Gauge, NoOpMetric { - public static final NoOpGauge INSTANCE = new NoOpGauge(); - - @Override - public Object getValue() { - return null; - } - } - - @SuppressWarnings("unchecked") - public static Gauge getNoOpGauge(Gauge actual) { - return (Gauge) NoOpGauge.INSTANCE; - } -} diff --git a/solr/core/src/java/org/apache/solr/metrics/MetricsMap.java b/solr/core/src/java/org/apache/solr/metrics/MetricsMap.java deleted file mode 100644 index 1d667cf556b..00000000000 --- a/solr/core/src/java/org/apache/solr/metrics/MetricsMap.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * 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.solr.metrics; - -import com.codahale.metrics.Gauge; -import com.codahale.metrics.Metric; -import java.io.IOException; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.function.BiConsumer; -import javax.management.Attribute; -import javax.management.AttributeList; -import javax.management.AttributeNotFoundException; -import javax.management.DynamicMBean; -import javax.management.InvalidAttributeValueException; -import javax.management.MBeanAttributeInfo; -import javax.management.MBeanException; -import javax.management.MBeanInfo; -import javax.management.ReflectionException; -import javax.management.openmbean.OpenMBeanAttributeInfoSupport; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import org.apache.lucene.store.AlreadyClosedException; -import org.apache.solr.common.MapWriter; -import org.apache.solr.common.SolrException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Dynamically constructed map of metrics, intentionally different from {@link - * com.codahale.metrics.MetricSet} where each metric had to be known in advance and registered - * separately in {@link com.codahale.metrics.MetricRegistry}. - * - *

Note: this awkwardly extends {@link Gauge} and not {@link Metric} because awkwardly {@link - * Metric} instances are not supported by {@link com.codahale.metrics.MetricRegistryListener} :( - * - *

Note 2: values added to this metric map should belong to the list of types supported by JMX: - * {@link javax.management.openmbean.OpenType#ALLOWED_CLASSNAMES_LIST}, otherwise only their - * toString() representation will be shown in JConsole. - */ -// NOCOMMIT: This MetricMap appears to be a shim for MapWriter for responses and a way to shim -// gauges into Dropwizard and JXM which is being removed. This should be removed completely as it is -// no longer needed with OTEL -public class MetricsMap implements Gauge>, MapWriter, DynamicMBean { - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - // set to true to use cached statistics between getMBeanInfo calls to work - // around over calling getStatistics on MBeanInfos when iterating over all attributes (SOLR-6586) - private final boolean useCachedStatsBetweenGetMBeanInfoCalls = - Boolean.getBoolean("useCachedStatsBetweenGetMBeanInfoCalls"); - - private BiConsumer> mapInitializer; - private MapWriter initializer; - private Map jmxAttributes; - private volatile Map cachedValue; - - /** - * Create an instance that reports values to a MapWriter. - * - * @param initializer function to populate the MapWriter result. - */ - public MetricsMap(MapWriter initializer) { - this.initializer = initializer; - } - - @Override - public Map getValue() { - return getValue(true); - } - - public Map getValue(boolean detailed) { - Map map = new HashMap<>(); - if (mapInitializer != null) { - mapInitializer.accept(detailed, map); - } else { - initializer.toMap(map); - } - return map; - } - - @Override - public String toString() { - return getValue().toString(); - } - - // lazy init - private synchronized void initJmxAttributes() { - if (jmxAttributes == null) { - jmxAttributes = new HashMap<>(); - } - } - - @Override - public Object getAttribute(String attribute) - throws AttributeNotFoundException, MBeanException, ReflectionException { - Object val; - // jmxAttributes override any real values - if (jmxAttributes != null) { - val = jmxAttributes.get(attribute); - if (val != null) { - return val; - } - } - Map stats = null; - if (useCachedStatsBetweenGetMBeanInfoCalls) { - Map cachedStats = this.cachedValue; - if (cachedStats != null) { - stats = cachedStats; - } - } - if (stats == null) { - stats = getValue(true); - } - val = stats.get(attribute); - - if (val != null) { - // It's String or one of the simple types, just return it as JMX suggests direct support for - // such types - for (String simpleTypeName : SimpleType.ALLOWED_CLASSNAMES_LIST) { - if (val.getClass().getName().equals(simpleTypeName)) { - return val; - } - } - // It's an arbitrary object which could be something complex and odd, return its toString, - // assuming that is a workable representation of the object - return val.toString(); - } - return null; - } - - @Override - public void setAttribute(Attribute attribute) - throws AttributeNotFoundException, - InvalidAttributeValueException, - MBeanException, - ReflectionException { - initJmxAttributes(); - jmxAttributes.put(attribute.getName(), String.valueOf(attribute.getValue())); - } - - @Override - public AttributeList getAttributes(String[] attributes) { - AttributeList list = new AttributeList(); - for (String attribute : attributes) { - try { - list.add(new Attribute(attribute, getAttribute(attribute))); - } catch (Exception e) { - log.warn("Could not get attribute {}", attribute); - } - } - return list; - } - - @Override - public AttributeList setAttributes(AttributeList attributes) { - throw new UnsupportedOperationException("Operation not Supported"); - } - - @Override - public Object invoke(String actionName, Object[] params, String[] signature) - throws MBeanException, ReflectionException { - throw new UnsupportedOperationException("Operation not Supported"); - } - - @Override - public MBeanInfo getMBeanInfo() { - ArrayList attrInfoList = new ArrayList<>(); - Map stats = getValue(true); - if (useCachedStatsBetweenGetMBeanInfoCalls) { - cachedValue = stats; - } - if (jmxAttributes != null) { - jmxAttributes.forEach( - (k, v) -> { - attrInfoList.add( - new MBeanAttributeInfo(k, String.class.getName(), null, true, false, false)); - }); - } - try { - stats.forEach( - (k, v) -> { - if (jmxAttributes != null && jmxAttributes.containsKey(k)) { - return; - } - Class type = v.getClass(); - OpenType typeBox = determineType(type); - if (type.equals(String.class) || typeBox == null) { - attrInfoList.add( - new MBeanAttributeInfo(k, String.class.getName(), null, true, false, false)); - } else { - attrInfoList.add( - new OpenMBeanAttributeInfoSupport(k, k, typeBox, true, false, false)); - } - }); - } catch (Exception e) { - // don't log issue if the core is closing - if (!(SolrException.getRootCause(e) instanceof AlreadyClosedException)) - log.warn("Could not get attributes of MetricsMap: {}", this, e); - } - MBeanAttributeInfo[] attrInfoArr = attrInfoList.toArray(new MBeanAttributeInfo[0]); - return new MBeanInfo(getClass().getName(), "MetricsMap", attrInfoArr, null, null, null); - } - - private OpenType determineType(Class type) { - try { - for (Field field : SimpleType.class.getFields()) { - if (field.getType().equals(SimpleType.class)) { - SimpleType candidate = (SimpleType) field.get(SimpleType.class); - if (candidate.getTypeName().equals(type.getName())) { - return candidate; - } - } - } - } catch (Exception e) { - throw new RuntimeException(e); - } - return null; - } - - @Override - public void writeMap(EntryWriter ew) throws IOException { - if (mapInitializer != null) { - Map value = getValue(); - value.forEach((k, v) -> ew.putNoEx(k, v)); - } else { - initializer.writeMap(ew); - } - } -} diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrCoreContainerReporter.java b/solr/core/src/java/org/apache/solr/metrics/SolrCoreContainerReporter.java deleted file mode 100644 index 7f235b62fbd..00000000000 --- a/solr/core/src/java/org/apache/solr/metrics/SolrCoreContainerReporter.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.solr.metrics; - -import org.apache.solr.core.CoreContainer; -import org.apache.solr.core.PluginInfo; - -/** A {@link SolrMetricReporter} that has access to its {@link CoreContainer}. */ -public abstract class SolrCoreContainerReporter extends SolrMetricReporter { - - protected CoreContainer coreContainer; - - protected SolrCoreContainerReporter(SolrMetricManager metricManager, String registryName) { - super(metricManager, registryName); - } - - @Override - public final void init(PluginInfo pluginInfo) { - throw new UnsupportedOperationException( - getClass().getCanonicalName() - + ".init(PluginInfo) is not supported, use init(PluginInfo,CoreContainer) instead."); - } - - public void init(PluginInfo pluginInfo, CoreContainer coreContainer) { - super.init(pluginInfo); - this.coreContainer = coreContainer; - } - - public CoreContainer getCoreContainer() { - return coreContainer; - } -} diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrCoreMetricManager.java b/solr/core/src/java/org/apache/solr/metrics/SolrCoreMetricManager.java index 9d859d4f5a9..ec0fc589ef9 100644 --- a/solr/core/src/java/org/apache/solr/metrics/SolrCoreMetricManager.java +++ b/solr/core/src/java/org/apache/solr/metrics/SolrCoreMetricManager.java @@ -16,7 +16,6 @@ */ package org.apache.solr.metrics; -import com.codahale.metrics.MetricRegistry; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import java.io.Closeable; @@ -25,15 +24,11 @@ import java.util.List; import org.apache.solr.cloud.CloudDescriptor; import org.apache.solr.common.util.Utils; -import org.apache.solr.core.CoreContainer; -import org.apache.solr.core.NodeConfig; -import org.apache.solr.core.PluginInfo; import org.apache.solr.core.SolrCore; -import org.apache.solr.core.SolrInfoBean; /** - * Helper class for managing registration of {@link SolrMetricProducer}'s and {@link - * SolrMetricReporter}'s specific to a {@link SolrCore} instance. + * Helper class for managing registration of {@link SolrMetricProducer}'s specific to a {@link + * SolrCore} instance. */ public class SolrCoreMetricManager implements Closeable { @@ -49,7 +44,6 @@ public class SolrCoreMetricManager implements Closeable { private String collectionName; private String shardName; private String replicaName; - private String leaderRegistryName; private boolean cloudMode; // Track all metric producers registered for this core so we can re-initialize them during core @@ -69,8 +63,7 @@ public SolrCoreMetricManager(SolrCore core) { metricManager = core.getCoreContainer().getMetricManager(); String registryName = createRegistryName(cloudMode, collectionName, shardName, replicaName, core.getName()); - solrMetricsContext = new SolrMetricsContext(metricManager, registryName, core.getMetricTag()); - leaderRegistryName = createLeaderRegistryName(cloudMode, collectionName, shardName); + solrMetricsContext = new SolrMetricsContext(metricManager, registryName); } private void initCloudMode() { @@ -88,28 +81,6 @@ private void initCloudMode() { } } - /** - * Load reporters configured globally and specific to {@link - * org.apache.solr.core.SolrInfoBean.Group#core} group or with a registry name specific to this - * core. - */ - public void loadReporters() { - CoreContainer coreContainer = core.getCoreContainer(); - NodeConfig nodeConfig = coreContainer.getConfig(); - PluginInfo[] pluginInfos = nodeConfig.getMetricsConfig().getMetricReporters(); - metricManager.loadReporters( - pluginInfos, - core.getResourceLoader(), - coreContainer, - core, - solrMetricsContext.getTag(), - SolrInfoBean.Group.core, - solrMetricsContext.getRegistryName()); - if (cloudMode) { - metricManager.loadShardReporters(pluginInfos, core); - } - } - /** * Re-register all metric producers associated with this core. This recreates the metric registry * resetting its state and recreating its attributes for all tracked registered producers. @@ -118,23 +89,20 @@ public void reregisterCoreMetrics() { this.solrMetricsContext = new SolrMetricsContext( metricManager, - createRegistryName(cloudMode, collectionName, shardName, replicaName, core.getName()), - solrMetricsContext.getTag()); + createRegistryName(cloudMode, collectionName, shardName, replicaName, core.getName())); metricManager.removeRegistry(solrMetricsContext.getRegistryName()); - if (leaderRegistryName != null) metricManager.removeRegistry(leaderRegistryName); // TODO: We are going to recreate the attributes and re-initialize/reregister metrics from // tracked producers. // There is some possible improvement that can be done here to not have to duplicate code in // registerMetricProducer - core.initializeMetrics(solrMetricsContext, core.getCoreAttributes(), core.getName()); + core.initializeMetrics(solrMetricsContext, core.getCoreAttributes()); registeredProducers.forEach( metricProducer -> { metricProducer.producer.initializeMetrics( solrMetricsContext, - metricProducer.attributes.toBuilder().putAll(core.getCoreAttributes()).build(), - ""); + metricProducer.attributes.toBuilder().putAll(core.getCoreAttributes()).build()); }); } @@ -164,16 +132,7 @@ public void registerMetricProducer(SolrMetricProducer producer, Attributes attri // There is some possible improvement that can be done here to not have to duplicate code in // reregisterCoreMetrics producer.initializeMetrics( - solrMetricsContext, attributes.toBuilder().putAll(core.getCoreAttributes()).build(), ""); - } - - /** Return the registry used by this SolrCore. */ - public MetricRegistry getRegistry() { - if (solrMetricsContext != null) { - return solrMetricsContext.getMetricRegistry(); - } else { - return null; - } + solrMetricsContext, attributes.toBuilder().putAll(core.getCoreAttributes()).build()); } /** @@ -181,12 +140,7 @@ public MetricRegistry getRegistry() { */ @Override public void close() throws IOException { - metricManager.closeReporters(solrMetricsContext.getRegistryName(), solrMetricsContext.getTag()); - if (getLeaderRegistryName() != null) { - metricManager.closeReporters(getLeaderRegistryName(), solrMetricsContext.getTag()); - } - metricManager.unregisterGauges( - solrMetricsContext.getRegistryName(), solrMetricsContext.getTag()); + solrMetricsContext.unregister(); } public SolrMetricsContext getSolrMetricsContext() { @@ -216,27 +170,13 @@ public String getRegistryName() { return solrMetricsContext != null ? solrMetricsContext.getRegistryName() : null; } - /** - * Metric registry name for leader metrics. This is null if not in cloud mode. - * - * @return metric registry name for leader metrics - */ - public String getLeaderRegistryName() { - return leaderRegistryName; - } - - /** Return a tag specific to this instance. */ - public String getTag() { - return solrMetricsContext.getTag(); - } - public static String createRegistryName( boolean cloud, String collectionName, String shardName, String replicaName, String coreName) { if (cloud) { // build registry name from logical names - return SolrMetricManager.getRegistryName( - SolrInfoBean.Group.core, collectionName, shardName, replicaName); + return SolrMetricManager.enforcePrefix( + "core." + collectionName + "." + shardName + "." + replicaName); } else { - return SolrMetricManager.getRegistryName(SolrInfoBean.Group.core, coreName); + return SolrMetricManager.enforcePrefix("core." + coreName); } } @@ -260,14 +200,4 @@ public static String createRegistryName(SolrCore aCore, String coreName) { replicaName, coreName); } - - public static String createLeaderRegistryName( - boolean cloud, String collectionName, String shardName) { - if (cloud) { - return SolrMetricManager.getRegistryName( - SolrInfoBean.Group.collection, collectionName, shardName, "leader"); - } else { - return null; - } - } } diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrCoreReporter.java b/solr/core/src/java/org/apache/solr/metrics/SolrCoreReporter.java deleted file mode 100644 index 2970b34998d..00000000000 --- a/solr/core/src/java/org/apache/solr/metrics/SolrCoreReporter.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.solr.metrics; - -import org.apache.solr.core.PluginInfo; -import org.apache.solr.core.SolrCore; - -/** A {@link FilteringSolrMetricReporter} that has access to its {@link SolrCore}. */ -public abstract class SolrCoreReporter extends FilteringSolrMetricReporter { - - protected SolrCore core; - - public SolrCoreReporter(SolrMetricManager metricManager, String registryName) { - super(metricManager, registryName); - } - - @Override - public final void init(PluginInfo pluginInfo) { - throw new UnsupportedOperationException( - getClass().getCanonicalName() - + ".init(PluginInfo) is not supported, use init(PluginInfo,SolrCore) instead."); - } - - public void init(PluginInfo pluginInfo, SolrCore core) { - super.init(pluginInfo); - this.core = core; - } - - public SolrCore getCore() { - return core; - } -} diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrDelegateRegistryMetricsContext.java b/solr/core/src/java/org/apache/solr/metrics/SolrDelegateRegistryMetricsContext.java deleted file mode 100644 index bfab5f40b92..00000000000 --- a/solr/core/src/java/org/apache/solr/metrics/SolrDelegateRegistryMetricsContext.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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.solr.metrics; - -import com.codahale.metrics.Counter; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.Meter; -import com.codahale.metrics.Timer; - -/** - * This class represents a metrics context that is delegate aware in that it is aware of multiple - * metric registries, a primary and a delegate. This enables creating metrics that are tracked at - * multiple levels, i.e. core-level and node-level. This class will create instances of new Timer, - * Meter, Counter, Histogram implementations that hold references to both primary and delegate - * implementations of corresponding classes. The DelegateRegistry* metric classes are just - * pass-through to two different implementations. As such the DelegateRegistry* metric classes do - * not hold any metric data themselves. - * - * @see org.apache.solr.metrics.SolrMetricsContext - */ -public class SolrDelegateRegistryMetricsContext extends SolrMetricsContext { - - private final String delegateRegistry; - - public SolrDelegateRegistryMetricsContext( - SolrMetricManager metricManager, String registry, String tag, String delegateRegistry) { - super(metricManager, registry, tag); - this.delegateRegistry = delegateRegistry; - } - - @Override - public Meter meter(String metricName, String... metricPath) { - return new DelegateRegistryMeter( - super.meter(metricName, metricPath), - getMetricManager().meter(this, delegateRegistry, metricName, metricPath)); - } - - @Override - public Counter counter(String metricName, String... metricPath) { - return new DelegateRegistryCounter( - super.counter(metricName, metricPath), - getMetricManager().counter(this, delegateRegistry, metricName, metricPath)); - } - - @Override - public Timer timer(String metricName, String... metricPath) { - return new DelegateRegistryTimer( - MetricSuppliers.getClock( - getMetricManager().getMetricsConfig().getTimerSupplier(), MetricSuppliers.CLOCK), - super.timer(metricName, metricPath), - getMetricManager().timer(this, delegateRegistry, metricName, metricPath)); - } - - @Override - public Histogram histogram(String metricName, String... metricPath) { - return new DelegateRegistryHistogram( - super.histogram(metricName, metricPath), - getMetricManager().histogram(this, delegateRegistry, metricName, metricPath)); - } - - @Override - public SolrMetricsContext getChildContext(Object child) { - return new SolrDelegateRegistryMetricsContext( - getMetricManager(), - getRegistryName(), - SolrMetricProducer.getUniqueMetricTag(child, getTag()), - delegateRegistry); - } -} diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrMetricInfo.java b/solr/core/src/java/org/apache/solr/metrics/SolrMetricInfo.java index a016fab7827..d01dd8f8b31 100644 --- a/solr/core/src/java/org/apache/solr/metrics/SolrMetricInfo.java +++ b/solr/core/src/java/org/apache/solr/metrics/SolrMetricInfo.java @@ -16,7 +16,6 @@ */ package org.apache.solr.metrics; -import com.codahale.metrics.MetricRegistry; import java.util.Objects; import org.apache.solr.core.SolrInfoBean; @@ -66,17 +65,6 @@ public static SolrMetricInfo of(String fullName) { return new SolrMetricInfo(category, scope, name); } - /** - * Returns the metric name defined by this object. For example, if the name is `Requests`, scope - * is `/admin/ping`, and category is `QUERY`, then the metric name is - * `QUERY./admin/ping.Requests`. - * - * @return the metric name defined by this object - */ - public String getMetricName() { - return MetricRegistry.name(category.toString(), scope, name); - } - @Override public String toString() { return "SolrMetricInfo{" diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java b/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java index e5e908d7393..a8b256e0cce 100644 --- a/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java +++ b/solr/core/src/java/org/apache/solr/metrics/SolrMetricManager.java @@ -19,16 +19,6 @@ import static org.apache.solr.metrics.otel.MetricExporterFactory.OTLP_EXPORTER_ENABLED; import static org.apache.solr.metrics.otel.MetricExporterFactory.OTLP_EXPORTER_INTERVAL; -import com.codahale.metrics.Counter; -import com.codahale.metrics.Gauge; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.Meter; -import com.codahale.metrics.Metric; -import com.codahale.metrics.MetricFilter; -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.MetricSet; -import com.codahale.metrics.SharedMetricRegistries; -import com.codahale.metrics.Timer; import io.opentelemetry.api.metrics.BatchCallback; import io.opentelemetry.api.metrics.DoubleCounter; import io.opentelemetry.api.metrics.DoubleCounterBuilder; @@ -64,69 +54,56 @@ import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; -import java.io.IOException; import java.lang.invoke.MethodHandles; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; import java.util.stream.Collectors; import org.apache.solr.common.SolrException; import org.apache.solr.common.util.IOUtils; -import org.apache.solr.common.util.NamedList; -import org.apache.solr.core.CoreContainer; import org.apache.solr.core.MetricsConfig; -import org.apache.solr.core.PluginInfo; import org.apache.solr.core.SolrCore; import org.apache.solr.core.SolrInfoBean; import org.apache.solr.core.SolrResourceLoader; -import org.apache.solr.logging.MDCLoggingContext; import org.apache.solr.metrics.otel.FilterablePrometheusMetricReader; import org.apache.solr.metrics.otel.MetricExporterFactory; import org.apache.solr.metrics.otel.OtelUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.slf4j.MDC; /** - * This class maintains a repository of named {@link MetricRegistry} instances, and provides several - * helper methods for managing various aspects of metrics reporting: + * This class maintains a repository of named {@link SdkMeterProvider} instances. It provides + * utility to create, manage, record and export metrics through OpenTelemetry's APIs as well as + * managing the lifecycle of these MeterProviders. * - *

    - *
  • registry creation, clearing and removal, - *
  • creation of most common metric implementations, - *
  • management of {@link SolrMetricReporter}-s specific to a named registry. - *
+ *

Solr creates 2 main {@link SdkMeterProvider}'s (solr.jvm, solr.node) as well as an additional + * provider for every {@link SolrCore} JVM metrics and registry are collected from {@link + * io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics} * - * {@link MetricRegistry} instances are automatically created when first referenced by name. - * Similarly, instances of {@link Metric} implementations, such as {@link Meter}, {@link Counter}, - * {@link Timer} and {@link Histogram} are automatically created and registered under hierarchical - * names, in a specified registry, when {@link #meter(SolrMetricsContext, String, String, - * String...)} and other similar methods are called. + *

The SolrMetricManager acts as a bridge between Solr and OpenTelemetry SDK providing the + * following: * - *

This class enforces a common prefix ({@link #REGISTRY_NAME_PREFIX}) in all registry names. + *

    + *
  • MeterProvider creation and removal. + *
  • Access to metric instruments such as {@link LongCounter}, {@link LongUpDownCounter}, {@link + * LongGauge}, {@link LongHistogram} and observable instruments to a specific MeterProvider + * instances + *
  • {@link FilterablePrometheusMetricReader} for reading and fitlering OpenTelemetry metrics in + * Prometheus Format from all MeterProviders + *
  • Enablement of optional OTLP exporter + *
* - *

Solr uses several different registries for collecting metrics belonging to different groups, - * using {@link org.apache.solr.core.SolrInfoBean.Group} as the main name of the registry (plus the - * above-mentioned prefix). Instances of {@link SolrMetricManager} are created for each {@link - * org.apache.solr.core.CoreContainer}, and most registries are local to each instance, with the - * exception of two global registries: solr.jetty and solr.jvm, which are - * shared between all {@link org.apache.solr.core.CoreContainer}-s + *

Instances of {@code SolrMetricManager} are intended to be owned per {@link + * org.apache.solr.core.CoreContainer} and automatically manage JVM-wide MeterProviders. */ public class SolrMetricManager { @@ -137,13 +114,6 @@ public class SolrMetricManager { /** Common prefix for all registry names that Solr uses. */ public static final String REGISTRY_NAME_PREFIX = "solr."; - /** - * Registry name for Jetty-specific metrics. This name is also subject to overrides controlled by - * system properties. This registry is shared between instances of {@link SolrMetricManager}. - */ - public static final String JETTY_REGISTRY = - REGISTRY_NAME_PREFIX + SolrInfoBean.Group.jetty.toString(); - /** * Registry name for JVM-specific metrics. This name is also subject to overrides controlled by * system properties. This registry is shared between instances of {@link SolrMetricManager}. @@ -151,9 +121,8 @@ public class SolrMetricManager { public static final String JVM_REGISTRY = REGISTRY_NAME_PREFIX + SolrInfoBean.Group.jvm.toString(); - private final ConcurrentMap registries = new ConcurrentHashMap<>(); - - private final Map> reporters = new HashMap<>(); + public static final String NODE_REGISTRY = + REGISTRY_NAME_PREFIX + SolrInfoBean.Group.node.toString(); private final Lock reportersLock = new ReentrantLock(); private final Lock swapLock = new ReentrantLock(); @@ -161,10 +130,6 @@ public class SolrMetricManager { public static final int DEFAULT_CLOUD_REPORTER_PERIOD = 60; private final MetricsConfig metricsConfig; - private final MetricRegistry.MetricSupplier counterSupplier; - private final MetricRegistry.MetricSupplier meterSupplier; - private final MetricRegistry.MetricSupplier timerSupplier; - private final MetricRegistry.MetricSupplier histogramSupplier; private final ConcurrentMap meterProviderAndReaders = new ConcurrentHashMap<>(); @@ -192,23 +157,12 @@ public class SolrMetricManager { public SolrMetricManager(MetricExporter exporter) { metricsConfig = new MetricsConfig.MetricsConfigBuilder().build(); metricExporter = exporter; - counterSupplier = MetricSuppliers.counterSupplier(null, null); - meterSupplier = MetricSuppliers.meterSupplier(null, null); - timerSupplier = MetricSuppliers.timerSupplier(null, null); - histogramSupplier = MetricSuppliers.histogramSupplier(null, null); } public SolrMetricManager(SolrResourceLoader loader, MetricsConfig metricsConfig) { this.metricsConfig = metricsConfig; this.metricExporter = loadMetricExporter(loader); - counterSupplier = MetricSuppliers.counterSupplier(loader, metricsConfig.getCounterSupplier()); - meterSupplier = MetricSuppliers.meterSupplier(loader, metricsConfig.getMeterSupplier()); - timerSupplier = MetricSuppliers.timerSupplier(loader, metricsConfig.getTimerSupplier()); - histogramSupplier = - MetricSuppliers.histogramSupplier(loader, metricsConfig.getHistogramSupplier()); - this.otelRuntimeJvmMetrics = - new OtelRuntimeJvmMetrics() - .initialize(this, SolrMetricManager.getRegistryName(SolrInfoBean.Group.jvm)); + this.otelRuntimeJvmMetrics = new OtelRuntimeJvmMetrics().initialize(this, JVM_REGISTRY); } public LongCounter longCounter( @@ -475,258 +429,6 @@ private DoubleCounterBuilder doubleCounterBuilder( return builder; } - // for unit tests - public MetricRegistry.MetricSupplier getCounterSupplier() { - return counterSupplier; - } - - public MetricRegistry.MetricSupplier getMeterSupplier() { - return meterSupplier; - } - - public MetricRegistry.MetricSupplier getTimerSupplier() { - return timerSupplier; - } - - public MetricRegistry.MetricSupplier getHistogramSupplier() { - return histogramSupplier; - } - - /** Return an object used for representing a null (missing) numeric value. */ - public Object nullNumber() { - return metricsConfig.getNullNumber(); - } - - /** Return an object used for representing a "Not A Number" (NaN) value. */ - public Object notANumber() { - return metricsConfig.getNotANumber(); - } - - /** Return an object used for representing a null (missing) string value. */ - public Object nullString() { - return metricsConfig.getNullString(); - } - - /** Return an object used for representing a null (missing) object value. */ - public Object nullObject() { - return metricsConfig.getNullObject(); - } - - /** - * An implementation of {@link MetricFilter} that selects metrics with names that start with one - * of prefixes. - */ - public static class PrefixFilter implements MetricFilter { - private final Set prefixes = new HashSet<>(); - private final Set matched = new HashSet<>(); - private boolean allMatch = false; - - /** - * Create a filter that uses the provided prefixes. - * - * @param prefixes prefixes to use, must not be null. If empty then any name will match, if not - * empty then match on any prefix will succeed (logical OR). - */ - public PrefixFilter(String... prefixes) { - Objects.requireNonNull(prefixes); - if (prefixes.length > 0) { - this.prefixes.addAll(Arrays.asList(prefixes)); - } - if (this.prefixes.isEmpty()) { - allMatch = true; - } - } - - public PrefixFilter(Collection prefixes) { - Objects.requireNonNull(prefixes); - this.prefixes.addAll(prefixes); - if (this.prefixes.isEmpty()) { - allMatch = true; - } - } - - @Override - public boolean matches(String name, Metric metric) { - if (allMatch) { - matched.add(name); - return true; - } - for (String prefix : prefixes) { - if (name.startsWith(prefix)) { - matched.add(name); - return true; - } - } - return false; - } - - /** - * Return the set of names that matched this filter. - * - * @return matching names - */ - public Set getMatched() { - return Collections.unmodifiableSet(matched); - } - - /** Clear the set of names that matched. */ - public void reset() { - matched.clear(); - } - - @Override - public String toString() { - return "PrefixFilter{" + "prefixes=" + prefixes + '}'; - } - } - - /** - * An implementation of {@link MetricFilter} that selects metrics with names that match regular - * expression patterns. - */ - public static class RegexFilter implements MetricFilter { - private final Set compiledPatterns = new HashSet<>(); - private final Set matched = new HashSet<>(); - private boolean allMatch = false; - - /** - * Create a filter that uses the provided prefix. - * - * @param patterns regex patterns to use, must not be null. If empty then any name will match, - * if not empty then match on any pattern will succeed (logical OR). - */ - public RegexFilter(String... patterns) throws PatternSyntaxException { - this(patterns != null ? Arrays.asList(patterns) : Collections.emptyList()); - } - - public RegexFilter(Collection patterns) throws PatternSyntaxException { - Objects.requireNonNull(patterns); - if (patterns.isEmpty()) { - allMatch = true; - return; - } - patterns.forEach( - p -> { - Pattern pattern = Pattern.compile(p); - compiledPatterns.add(pattern); - }); - if (patterns.isEmpty()) { - allMatch = true; - } - } - - @Override - public boolean matches(String name, Metric metric) { - if (allMatch) { - matched.add(name); - return true; - } - for (Pattern p : compiledPatterns) { - if (p.matcher(name).matches()) { - matched.add(name); - return true; - } - } - return false; - } - - /** - * Return the set of names that matched this filter. - * - * @return matching names - */ - public Set getMatched() { - return Collections.unmodifiableSet(matched); - } - - /** Clear the set of names that matched. */ - public void reset() { - matched.clear(); - } - - @Override - public String toString() { - return "RegexFilter{" + "compiledPatterns=" + compiledPatterns + '}'; - } - } - - /** - * An implementation of {@link MetricFilter} that selects metrics that match any filter in a list - * of filters. - */ - public static class OrFilter implements MetricFilter { - List filters = new ArrayList<>(); - - public OrFilter(Collection filters) { - if (filters != null) { - this.filters.addAll(filters); - } - } - - public OrFilter(MetricFilter... filters) { - if (filters != null) { - for (MetricFilter filter : filters) { - if (filter != null) { - this.filters.add(filter); - } - } - } - } - - @Override - public boolean matches(String s, Metric metric) { - for (MetricFilter filter : filters) { - if (filter.matches(s, metric)) { - return true; - } - } - return false; - } - } - - /** - * An implementation of {@link MetricFilter} that selects metrics that match all filters in a list - * of filters. - */ - public static class AndFilter implements MetricFilter { - List filters = new ArrayList<>(); - - public AndFilter(Collection filters) { - if (filters != null) { - this.filters.addAll(filters); - } - } - - public AndFilter(MetricFilter... filters) { - if (filters != null) { - for (MetricFilter filter : filters) { - if (filter != null) { - this.filters.add(filter); - } - } - } - } - - @Override - public boolean matches(String s, Metric metric) { - for (MetricFilter filter : filters) { - if (!filter.matches(s, metric)) { - return false; - } - } - return true; - } - } - - /** Return a set of existing registry names. */ - // NOCOMMIT: Remove for OTEL - public Set registryNames() { - Set set = new HashSet<>(); - set.addAll(registries.keySet()); - set.addAll(SharedMetricRegistries.names()); - return set; - } - /** * Check whether a registry with a given name already exists. * @@ -737,99 +439,6 @@ public boolean hasRegistry(String name) { return meterProviderAndReaders.containsKey(enforcePrefix(name)); } - // NOCOMMIT: Used in filtering. Will remove later - public boolean hasDropwizardRegistry(String name) { - Set names = registryNames(); - name = enforcePrefix(name); - return names.contains(name); - } - - /** - * Return set of existing registry names that match a regex pattern - * - * @param patterns regex patterns. NOTE: users need to make sure that patterns that don't start - * with a wildcard use the full registry name starting with {@link #REGISTRY_NAME_PREFIX} - * @return set of existing registry names where at least one pattern matched. - */ - // TODO SOLR-17458: We may not need? Maybe make a custom OTEL metric reader instead - public Set registryNames(String... patterns) throws PatternSyntaxException { - if (patterns == null || patterns.length == 0) { - return registryNames(); - } - List compiled = new ArrayList<>(); - for (String pattern : patterns) { - compiled.add(Pattern.compile(pattern)); - } - return registryNames(compiled.toArray(new Pattern[0])); - } - - public Set registryNames(Pattern... patterns) { - Set allNames = registryNames(); - if (patterns == null || patterns.length == 0) { - return allNames; - } - return allNames.stream() - .filter( - s -> { - for (Pattern p : patterns) { - if (p.matcher(s).matches()) { - return true; - } - } - return false; - }) - .collect(Collectors.toSet()); - } - - /** - * Check for predefined shared registry names. This compares the input name with normalized names - * of predefined shared registries - {@link #JVM_REGISTRY} and {@link #JETTY_REGISTRY}. - * - * @param registry already normalized name - * @return true if the name matches one of shared registries - */ - // TODO SOLR-17458: We may not need - private static boolean isSharedRegistry(String registry) { - return JETTY_REGISTRY.equals(registry) || JVM_REGISTRY.equals(registry); - } - - /** - * Get (or create if not present) a named registry. This method always creates and persists a new - * registry in case it does not already exist. - * - * @param registry name of the registry - * @return existing or newly created registry - */ - // NOCOMMIT SOLR-17458: We may not need - public MetricRegistry registry(String registry) { - return registry(registry, true); - } - - /** - * Get (or create if not present) a named registry. - * - * @param registry name of the registry. - * @param create When false and the registry does not exist, we return null instead of creating a - * new one. - */ - public MetricRegistry registry(String registry, boolean create) { - registry = enforcePrefix(registry); - if (isSharedRegistry(registry)) { - return SharedMetricRegistries.getOrCreate(registry); - } else { - swapLock.lock(); - try { - if (create) { - return getOrCreateRegistry(registries, registry); - } else { - return registries.get(registry); - } - } finally { - swapLock.unlock(); - } - } - } - /** * Get (or create if not present) a named {@link SdkMeterProvider}. * @@ -867,21 +476,11 @@ public SdkMeterProvider meterProvider(String providerName) { .sdkMeterProvider(); } - // TODO SOLR-17458: We may not need - private static MetricRegistry getOrCreateRegistry( - ConcurrentMap map, String registry) { - final MetricRegistry existing = map.get(registry); - if (existing == null) { - final MetricRegistry created = new MetricRegistry(); - final MetricRegistry raced = map.putIfAbsent(registry, created); - if (raced == null) { - return created; - } else { - return raced; - } - } else { - return existing; - } + /** Return a set of existing registry names. */ + public Set registryNames() { + Set set = new HashSet<>(); + set.addAll(meterProviderAndReaders.keySet()); + return set; } /** @@ -890,7 +489,6 @@ private static MetricRegistry getOrCreateRegistry( * * @param registry name of the registry to remove */ - // NOCOMMIT: Remove this public void removeRegistry(String registry) { String key = enforcePrefix(registry); MeterProviderAndReaders mpr = meterProviderAndReaders.remove(key); @@ -913,327 +511,6 @@ public void closeAllRegistries() { } } - /** - * Potential conflict resolution strategies when attempting to register a new metric that already - * exists - */ - // TODO SOLR-17458: Don't think we need - public enum ResolutionStrategy { - /** - * The existing metric will be kept and the new metric will be ignored. If no metric exists, - * then the new metric will be registered. - */ - IGNORE, - /** The existing metric will be removed and replaced with the new metric */ - REPLACE, - /** An exception will be thrown. This is the default implementation behavior. */ - ERROR - } - - /** - * Register all metrics in the provided {@link MetricSet}, optionally skipping those that already - * exist. - * - * @param registry registry name - * @param metrics metric set to register - * @param strategy the conflict resolution strategy to use if the named metric already exists. - * @param metricPath (optional) additional top-most metric name path elements - * @throws Exception if a metric with this name already exists. - */ - // I don't think we do something like this for OTEL? - public void registerAll( - String registry, MetricSet metrics, ResolutionStrategy strategy, String... metricPath) - throws Exception { - MetricRegistry metricRegistry = registry(registry); - synchronized (metricRegistry) { - Map existingMetrics = metricRegistry.getMetrics(); - for (Map.Entry entry : metrics.getMetrics().entrySet()) { - String fullName = mkName(entry.getKey(), metricPath); - if (strategy == ResolutionStrategy.REPLACE) { - metricRegistry.remove(fullName); - } else if (strategy == ResolutionStrategy.IGNORE && existingMetrics.containsKey(fullName)) { - continue; - } // strategy == ERROR will fail when we try to register - metricRegistry.register(fullName, entry.getValue()); - } - } - } - - /** - * Remove all metrics from a specified registry. - * - * @param registry registry name - */ - // TODO SOLR-17458: Don't think we need - public void clearRegistry(String registry) { - registry(registry).removeMatching(MetricFilter.ALL); - } - - /** - * Remove some metrics from a named registry - * - * @param registry registry name - * @param metricPath (optional) top-most metric name path elements. If empty then this is - * equivalent to calling {@link #clearRegistry(String)}, otherwise non-empty elements will be - * joined using dotted notation to form a fully-qualified prefix. Metrics with names that - * start with the prefix will be removed. - * @return set of metrics names that have been removed. - */ - // NOCOMMIT SOLR-17458: This is not supported in otel. Metrics are immutable. We can at best - // filter - // them or delete the meterProvider entirely - public Set clearMetrics(String registry, String... metricPath) { - PrefixFilter filter; - if (metricPath == null || metricPath.length == 0) { - filter = new PrefixFilter(""); - } else { - String prefix = MetricRegistry.name("", metricPath); - filter = new PrefixFilter(prefix); - } - registry(registry).removeMatching(filter); - return filter.getMatched(); - } - - /** - * Retrieve matching metrics and their names. - * - * @param registry registry name. - * @param metricFilter filter (null is equivalent to {@link MetricFilter#ALL}). - * @return map of matching names and metrics - */ - // TODO SOLR-17458: We will create an OTEL metric reader for this instead. For tests, we can - // create an in-memory metric reader - public Map getMetrics(String registry, MetricFilter metricFilter) { - if (metricFilter == null || metricFilter == MetricFilter.ALL) { - return registry(registry).getMetrics(); - } - return registry(registry).getMetrics().entrySet().stream() - .filter(entry -> metricFilter.matches(entry.getKey(), entry.getValue())) - .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue())); - } - - /** - * Create or get an existing named {@link Meter} - * - * @param registry registry name - * @param metricName metric name, either final name or a fully-qualified name using dotted - * notation - * @param metricPath (optional) additional top-most metric name path elements - * @return existing or a newly created {@link Meter} - */ - // TODO SOLR-17458: Don't need this - public Meter meter( - SolrMetricsContext context, String registry, String metricName, String... metricPath) { - final String name = mkName(metricName, metricPath); - if (context != null) { - context.registerMetricName(name); - } - return registry(registry).meter(name, meterSupplier); - } - - /** - * Create or get an existing named {@link Timer} - * - * @param registry registry name - * @param metricName metric name, either final name or a fully-qualified name using dotted - * notation - * @param metricPath (optional) additional top-most metric name path elements - * @return existing or a newly created {@link Timer} - */ - // TODO SOLR-17458: Don't need this - public Timer timer( - SolrMetricsContext context, String registry, String metricName, String... metricPath) { - final String name = mkName(metricName, metricPath); - if (context != null) { - context.registerMetricName(name); - } - return registry(registry).timer(name, timerSupplier); - } - - /** - * Create or get an existing named {@link Counter} - * - * @param registry registry name - * @param metricName metric name, either final name or a fully-qualified name using dotted - * notation - * @param metricPath (optional) additional top-most metric name path elements - * @return existing or a newly created {@link Counter} - */ - // TODO SOLR-17458: Don't need this - public Counter counter( - SolrMetricsContext context, String registry, String metricName, String... metricPath) { - final String name = mkName(metricName, metricPath); - if (context != null) { - context.registerMetricName(name); - } - return registry(registry).counter(name, counterSupplier); - } - - /** - * Create or get an existing named {@link Histogram} - * - * @param registry registry name - * @param metricName metric name, either final name or a fully-qualified name using dotted - * notation - * @param metricPath (optional) additional top-most metric name path elements - * @return existing or a newly created {@link Histogram} - */ - // TODO SOLR-17458: Don't need this - public Histogram histogram( - SolrMetricsContext context, String registry, String metricName, String... metricPath) { - final String name = mkName(metricName, metricPath); - if (context != null) { - context.registerMetricName(name); - } - return registry(registry).histogram(name, histogramSupplier); - } - - /** - * @deprecated use {@link #registerMetric(SolrMetricsContext, String, Metric, ResolutionStrategy, - * String, String...)} - */ - // TODO SOLR-17458: Don't need this - @Deprecated - public void registerMetric( - SolrMetricsContext context, - String registry, - Metric metric, - boolean force, - String metricName, - String... metricPath) { - registerMetric( - context, - registry, - metric, - force ? ResolutionStrategy.REPLACE : ResolutionStrategy.IGNORE, - metricName, - metricPath); - } - - /** - * Register an instance of {@link Metric}. - * - * @param registry registry name - * @param metric metric instance - * @param strategy the conflict resolution strategy to use if the named metric already exists. - * @param metricName metric name, either final name or a fully-qualified name using dotted - * notation - * @param metricPath (optional) additional top-most metric name path elements - */ - // TODO SOLR-17458: Don't need this - public void registerMetric( - SolrMetricsContext context, - String registry, - Metric metric, - ResolutionStrategy strategy, - String metricName, - String... metricPath) { - MetricRegistry metricRegistry = registry(registry); - String fullName = mkName(metricName, metricPath); - if (context != null) { - context.registerMetricName(fullName); - } - synchronized (metricRegistry) { // prevent race; register() throws if metric is already present - if (strategy == ResolutionStrategy.REPLACE) { // must remove any existing one if present - metricRegistry.remove(fullName); - } else if (strategy == ResolutionStrategy.IGNORE - && metricRegistry.getMetrics().containsKey(fullName)) { - return; - } // strategy == ERROR will fail when we try to register - metricRegistry.register(fullName, metric); - } - } - - /** - * This is a wrapper for {@link Gauge} metrics, which are usually implemented as lambdas that - * often keep a reference to their parent instance. In order to make sure that all such metrics - * are removed when their parent instance is removed / closed the metric is associated with an - * instance tag, which can be used then to remove wrappers with the matching tag using {@link - * #unregisterGauges(String, String)}. - */ - public static class GaugeWrapper implements Gauge { - private final Gauge gauge; - private final String tag; - - public GaugeWrapper(Gauge gauge, String tag) { - this.gauge = gauge; - this.tag = tag; - } - - @Override - public T getValue() { - return gauge.getValue(); - } - - public String getTag() { - return tag; - } - - public Gauge getGauge() { - return gauge; - } - } - - /** - * @deprecated use {@link #registerGauge(SolrMetricsContext, String, Gauge, String, - * ResolutionStrategy, String, String...)} - */ - @Deprecated - public void registerGauge( - SolrMetricsContext context, - String registry, - Gauge gauge, - String tag, - boolean force, - String metricName, - String... metricPath) { - registerGauge( - context, - registry, - gauge, - tag, - force ? ResolutionStrategy.REPLACE : ResolutionStrategy.ERROR, - metricName, - metricPath); - } - - public void registerGauge( - SolrMetricsContext context, - String registry, - Gauge gauge, - String tag, - ResolutionStrategy strategy, - String metricName, - String... metricPath) { - if (!metricsConfig.isEnabled()) { - gauge = MetricSuppliers.getNoOpGauge(gauge); - } - registerMetric( - context, registry, new GaugeWrapper<>(gauge, tag), strategy, metricName, metricPath); - } - - // NOCOMMIT: No longer need - public int unregisterGauges(String registryName, String tagSegment) { - if (tagSegment == null) { - return 0; - } - MetricRegistry registry = registry(registryName, false); - if (registry == null) return 0; - AtomicInteger removed = new AtomicInteger(); - registry.removeMatching( - (name, metric) -> { - if (metric instanceof GaugeWrapper wrapper) { - boolean toRemove = wrapper.getTag().contains(tagSegment); - if (toRemove) { - removed.incrementAndGet(); - } - return toRemove; - } - return false; - }); - return removed.get(); - } - /** * This method creates a hierarchical name with arbitrary levels of hierarchy * @@ -1287,477 +564,6 @@ public static String enforcePrefix(String name) { } } - /** - * Helper method to construct a properly prefixed registry name based on the group. - * - * @param group reporting group - * @param names optional child elements of the registry name. If exactly one element is provided - * and it already contains the required prefix and group name then this value will be used, - * and the group parameter will be ignored. - * @return fully-qualified and prefixed registry name, with overrides applied. - */ - public static String getRegistryName(SolrInfoBean.Group group, String... names) { - String fullName; - String prefix = REGISTRY_NAME_PREFIX + group.name() + '.'; - // check for existing prefix and group - if (names != null && names.length > 0 && names[0] != null && names[0].startsWith(prefix)) { - // assume the first segment already was expanded - if (names.length > 1) { - String[] newNames = new String[names.length - 1]; - System.arraycopy(names, 1, newNames, 0, newNames.length); - fullName = MetricRegistry.name(names[0], newNames); - } else { - fullName = MetricRegistry.name(names[0]); - } - } else { - fullName = MetricRegistry.name(group.toString(), names); - } - return enforcePrefix(fullName); - } - - // reporter management - - /** - * Create and register {@link SolrMetricReporter}-s specific to a {@link - * org.apache.solr.core.SolrInfoBean.Group}. Note: reporters that specify neither "group" nor - * "registry" attributes are treated as universal - they will always be loaded for any group. - * These two attributes may also contain multiple comma- or whitespace-separated values, in which - * case the reporter will be loaded for any matching value from the list. If both attributes are - * present then only "group" attribute will be processed. - * - * @param pluginInfos plugin configurations - * @param loader resource loader - * @param coreContainer core container - * @param solrCore optional solr core - * @param tag optional tag for the reporters, to distinguish reporters logically created for - * different parent component instances. - * @param group selected group, not null - * @param registryNames optional child registry name elements - */ - // NOCOMMIT: Come back and cleanup and remove all reporters code - public void loadReporters( - PluginInfo[] pluginInfos, - SolrResourceLoader loader, - CoreContainer coreContainer, - SolrCore solrCore, - String tag, - SolrInfoBean.Group group, - String... registryNames) { - if (pluginInfos == null || pluginInfos.length == 0) { - return; - } - String registryName = getRegistryName(group, registryNames); - for (PluginInfo info : pluginInfos) { - String target = info.attributes.get("group"); - if (target == null) { // no "group" - target = info.attributes.get("registry"); - if (target != null) { - String[] targets = target.split("[\\s,]+"); - boolean found = false; - for (String t : targets) { - t = enforcePrefix(t); - if (registryName.equals(t)) { - found = true; - break; - } - } - if (!found) { - continue; - } - } else { - // neither group nor registry specified. - // always register this plugin for all groups and registries - } - } else { // check groups - String[] targets = target.split("[\\s,]+"); - boolean found = false; - for (String t : targets) { - if (group.toString().equals(t)) { - found = true; - break; - } - } - if (!found) { - continue; - } - } - try { - loadReporter(registryName, loader, coreContainer, solrCore, info, tag); - } catch (Exception e) { - log.warn("Error loading metrics reporter, plugin info: {}", info, e); - } - } - } - - /** - * Convenience wrapper for {@link SolrMetricManager#loadReporter(String, SolrResourceLoader, - * CoreContainer, SolrCore, PluginInfo, String)} passing {@link SolrCore#getResourceLoader()} and - * {@link SolrCore#getCoreContainer()} as the extra parameters. - */ - public void loadReporter(String registry, SolrCore solrCore, PluginInfo pluginInfo, String tag) - throws Exception { - loadReporter( - registry, - solrCore.getResourceLoader(), - solrCore.getCoreContainer(), - solrCore, - pluginInfo, - tag); - } - - /** - * Convenience wrapper for {@link SolrMetricManager#loadReporter(String, SolrResourceLoader, - * CoreContainer, SolrCore, PluginInfo, String)} passing {@link CoreContainer#getResourceLoader()} - * and null solrCore and tag. - */ - public void loadReporter(String registry, CoreContainer coreContainer, PluginInfo pluginInfo) - throws Exception { - loadReporter( - registry, coreContainer.getResourceLoader(), coreContainer, null, pluginInfo, null); - } - - /** - * Create and register an instance of {@link SolrMetricReporter}. - * - * @param registry reporter is associated with this registry - * @param loader loader to use when creating an instance of the reporter - * @param coreContainer core container - * @param solrCore optional solr core - * @param pluginInfo plugin configuration. Plugin "name" and "class" attributes are required. - * @param tag optional tag for the reporter, to distinguish reporters logically created for - * different parent component instances. - * @throws Exception if any argument is missing or invalid - */ - public void loadReporter( - String registry, - SolrResourceLoader loader, - CoreContainer coreContainer, - SolrCore solrCore, - PluginInfo pluginInfo, - String tag) - throws Exception { - if (registry == null - || pluginInfo == null - || pluginInfo.name == null - || pluginInfo.className == null) { - throw new IllegalArgumentException( - "loadReporter called with missing arguments: " - + "registry=" - + registry - + ", loader=" - + loader - + ", pluginInfo=" - + pluginInfo); - } - // make sure we use a name with prefix - registry = enforcePrefix(registry); - SolrMetricReporter reporter = - loader.newInstance( - pluginInfo.className, - SolrMetricReporter.class, - new String[0], - new Class[] {SolrMetricManager.class, String.class}, - new Object[] {this, registry}); - // prepare MDC for plugins that want to use its properties - MDCLoggingContext.setCoreDescriptor( - coreContainer, solrCore == null ? null : solrCore.getCoreDescriptor()); - if (tag != null) { - // add instance tag to MDC - MDC.put("tag", "t:" + tag); - } - try { - if (reporter instanceof SolrCoreReporter) { - ((SolrCoreReporter) reporter).init(pluginInfo, solrCore); - } else if (reporter instanceof SolrCoreContainerReporter) { - ((SolrCoreContainerReporter) reporter).init(pluginInfo, coreContainer); - } else { - reporter.init(pluginInfo); - } - } catch (IllegalStateException e) { - throw new IllegalArgumentException("reporter init failed: " + pluginInfo, e); - } finally { - MDCLoggingContext.clear(); - MDC.remove("tag"); - } - registerReporter(registry, pluginInfo.name, tag, reporter); - } - - private void registerReporter( - String registry, String name, String tag, SolrMetricReporter reporter) throws Exception { - try { - if (!reportersLock.tryLock(10, TimeUnit.SECONDS)) { - throw new Exception("Could not obtain lock to modify reporters registry: " + registry); - } - } catch (InterruptedException e) { - throw new Exception( - "Interrupted while trying to obtain lock to modify reporters registry: " + registry); - } - try { - Map perRegistry = reporters.get(registry); - if (perRegistry == null) { - perRegistry = new HashMap<>(); - reporters.put(registry, perRegistry); - } - if (tag != null && !tag.isEmpty()) { - name = name + "@" + tag; - } - SolrMetricReporter oldReporter = perRegistry.get(name); - if (oldReporter != null) { // close it - log.info( - "Replacing existing reporter '{}' in registry'{}': {}", name, registry, oldReporter); - oldReporter.close(); - } - perRegistry.put(name, reporter); - - } finally { - reportersLock.unlock(); - } - } - - /** - * Close and unregister a named {@link SolrMetricReporter} for a registry. - * - * @param registry registry name - * @param name reporter name - * @param tag optional tag for the reporter, to distinguish reporters logically created for - * different parent component instances. - * @return true if a named reporter existed and was closed. - */ - public boolean closeReporter(String registry, String name, String tag) { - // make sure we use a name with prefix - registry = enforcePrefix(registry); - try { - if (!reportersLock.tryLock(10, TimeUnit.SECONDS)) { - log.warn("Could not obtain lock to modify reporters registry: {}", registry); - return false; - } - } catch (InterruptedException e) { - log.warn( - "Interrupted while trying to obtain lock to modify reporters registry: {}", registry); - return false; - } - try { - Map perRegistry = reporters.get(registry); - if (perRegistry == null) { - return false; - } - if (tag != null && !tag.isEmpty()) { - name = name + "@" + tag; - } - SolrMetricReporter reporter = perRegistry.remove(name); - if (reporter == null) { - return false; - } - try { - reporter.close(); - } catch (Exception e) { - log.warn("Error closing metric reporter, registry={}, name={}", registry, name, e); - } - return true; - } finally { - reportersLock.unlock(); - } - } - - /** - * Close and unregister all {@link SolrMetricReporter}-s for a registry. - * - * @param registry registry name - * @return names of closed reporters - */ - public Set closeReporters(String registry) { - return closeReporters(registry, null); - } - - /** - * Close and unregister all {@link SolrMetricReporter}-s for a registry. - * - * @param registry registry name - * @param tag optional tag for the reporter, to distinguish reporters logically created for - * different parent component instances. - * @return names of closed reporters - */ - public Set closeReporters(String registry, String tag) { - // make sure we use a name with prefix - registry = enforcePrefix(registry); - try { - if (!reportersLock.tryLock(10, TimeUnit.SECONDS)) { - log.warn("Could not obtain lock to modify reporters registry: {}", registry); - return Collections.emptySet(); - } - } catch (InterruptedException e) { - log.warn( - "Interrupted while trying to obtain lock to modify reporters registry: {}", registry); - return Collections.emptySet(); - } - try { - log.info("Closing metric reporters for registry={} tag={}", registry, tag); - Map perRegistry = reporters.get(registry); - if (perRegistry != null) { - Set names = new HashSet<>(perRegistry.keySet()); - Set removed = new HashSet<>(); - names.forEach( - name -> { - if (tag != null && !tag.isEmpty() && !name.endsWith("@" + tag)) { - return; - } - SolrMetricReporter reporter = perRegistry.remove(name); - try { - reporter.close(); - } catch (IOException ioe) { - log.warn("Exception closing reporter {}", reporter, ioe); - } - removed.add(name); - }); - if (removed.size() == names.size()) { - reporters.remove(registry); - } - return removed; - } else { - return Collections.emptySet(); - } - } finally { - reportersLock.unlock(); - if (log.isDebugEnabled()) { - log.debug("Finished closing registry={}, tag={}", registry, tag); - } - } - } - - /** - * Get a map of reporters for a registry. Keys are reporter names, values are reporter instances. - * - * @param registry registry name - * @return map of reporters and their names, may be empty but never null - */ - public Map getReporters(String registry) { - // make sure we use a name with prefix - registry = enforcePrefix(registry); - try { - if (!reportersLock.tryLock(10, TimeUnit.SECONDS)) { - log.warn("Could not obtain lock to modify reporters registry: {}", registry); - return Collections.emptyMap(); - } - } catch (InterruptedException e) { - log.warn( - "Interrupted while trying to obtain lock to modify reporters registry: {}", registry); - return Collections.emptyMap(); - } - try { - Map perRegistry = reporters.get(registry); - if (perRegistry == null) { - return Collections.emptyMap(); - } else { - // defensive copy - the original map may change after we release the lock - return Collections.unmodifiableMap(new HashMap<>(perRegistry)); - } - } finally { - reportersLock.unlock(); - } - } - - private List prepareCloudPlugins( - PluginInfo[] pluginInfos, - String group, - Map defaultAttributes, - Map defaultInitArgs) { - List result = new ArrayList<>(); - if (pluginInfos == null) { - pluginInfos = new PluginInfo[0]; - } - for (PluginInfo info : pluginInfos) { - String groupAttr = info.attributes.get("group"); - if (!group.equals(groupAttr)) { - continue; - } - info = preparePlugin(info, defaultAttributes, defaultInitArgs); - if (info != null) { - result.add(info); - } - } - return result; - } - - @SuppressWarnings("unchecked") - private PluginInfo preparePlugin( - PluginInfo info, Map defaultAttributes, Map defaultInitArgs) { - if (info == null) { - return null; - } - String classNameAttr = info.attributes.get("class"); - - Map attrs = new HashMap<>(info.attributes); - defaultAttributes.forEach( - (k, v) -> { - if (!attrs.containsKey(k)) { - attrs.put(k, v); - } - }); - attrs.put("class", classNameAttr); - Map initArgs = new HashMap<>(); - if (info.initArgs != null) { - initArgs.putAll(info.initArgs.asMap(10)); - } - defaultInitArgs.forEach( - (k, v) -> { - if (!initArgs.containsKey(k)) { - initArgs.put(k, v); - } - }); - return new PluginInfo(info.type, attrs, new NamedList<>(initArgs), null); - } - - public void loadShardReporters(PluginInfo[] pluginInfos, SolrCore core) { - // don't load for non-cloud cores - if (core.getCoreDescriptor().getCloudDescriptor() == null) { - return; - } - // prepare default plugin if none present in the config - Map attrs = new HashMap<>(); - attrs.put("name", "shardDefault"); - attrs.put("group", SolrInfoBean.Group.shard.toString()); - Map initArgs = new HashMap<>(); - initArgs.put("period", DEFAULT_CLOUD_REPORTER_PERIOD); - - String registryName = core.getCoreMetricManager().getRegistryName(); - // collect infos and normalize - List infos = - prepareCloudPlugins(pluginInfos, SolrInfoBean.Group.shard.toString(), attrs, initArgs); - for (PluginInfo info : infos) { - try { - loadReporter(registryName, core, info, core.getMetricTag()); - } catch (Exception e) { - log.warn("Could not load shard reporter, pluginInfo={}", info, e); - } - } - } - - public void loadClusterReporters(PluginInfo[] pluginInfos, CoreContainer cc) { - // don't load for non-cloud instances - if (!cc.isZooKeeperAware()) { - return; - } - Map attrs = new HashMap<>(); - attrs.put("name", "clusterDefault"); - attrs.put("group", SolrInfoBean.Group.cluster.toString()); - Map initArgs = new HashMap<>(); - initArgs.put("period", DEFAULT_CLOUD_REPORTER_PERIOD); - List infos = - prepareCloudPlugins(pluginInfos, SolrInfoBean.Group.cluster.toString(), attrs, initArgs); - String registryName = getRegistryName(SolrInfoBean.Group.cluster); - for (PluginInfo info : infos) { - try { - loadReporter(registryName, cc, info); - } catch (Exception e) { - log.warn("Could not load cluster reporter, pluginInfo={}", info, e); - } - } - } - - public MetricsConfig getMetricsConfig() { - return metricsConfig; - } - /** Get a shallow copied map of {@link FilterablePrometheusMetricReader}. */ public Map getPrometheusMetricReaders() { return meterProviderAndReaders.entrySet().stream() diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrMetricProducer.java b/solr/core/src/java/org/apache/solr/metrics/SolrMetricProducer.java index ea046b8fda5..9631c5bedfd 100644 --- a/solr/core/src/java/org/apache/solr/metrics/SolrMetricProducer.java +++ b/solr/core/src/java/org/apache/solr/metrics/SolrMetricProducer.java @@ -50,16 +50,18 @@ static String getUniqueMetricTag(Object o, String parentName) { } /** - * NOCOMMIT SOLR-17458: The Scope parameter will be removed with Dropwizard + * Implementation should initialize all metrics to a {@link SolrMetricsContext} + * Registry/MeterProvider with {@link Attributes} as the common set of attributes that will be + * attached to every metric that is initialized for that class/component * - *

{@link Attributes} passed is the base or common set of attributes that should be attached to - * every metric that will be initialized + * @param parentContext The registry that the component will initialize metrics to + * @param attributes Base set of attributes that will be bound to all metrics for that component */ - void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes, String scope); + void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes); /** * Implementations should return the context used in {@link #initializeMetrics(SolrMetricsContext, - * Attributes, String)} to ensure proper cleanup of metrics at the end of the life-cycle of this + * Attributes)} to ensure proper cleanup of metrics at the end of the life-cycle of this * component. This should be the child context if one was created, or null if the parent context * was used. */ @@ -78,9 +80,7 @@ static String getUniqueMetricTag(Object o, String parentName) { @Override default void close() throws IOException { SolrMetricsContext context = getSolrMetricsContext(); - if (context == null) { - return; - } else { + if (context != null) { context.unregister(); } } diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrMetricReporter.java b/solr/core/src/java/org/apache/solr/metrics/SolrMetricReporter.java deleted file mode 100644 index 61a1a0881fb..00000000000 --- a/solr/core/src/java/org/apache/solr/metrics/SolrMetricReporter.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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.solr.metrics; - -import java.io.Closeable; -import java.lang.invoke.MethodHandles; -import org.apache.solr.core.PluginInfo; -import org.apache.solr.util.SolrPluginUtils; -import org.apache.solr.util.plugin.PluginInfoInitialized; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** Interface for 'pluggable' metric reporters. */ -public abstract class SolrMetricReporter implements Closeable, PluginInfoInitialized { - - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - protected final String registryName; - protected final SolrMetricManager metricManager; - protected PluginInfo pluginInfo; - protected boolean enabled = true; - protected int period = SolrMetricManager.DEFAULT_CLOUD_REPORTER_PERIOD; - - /** - * Create a reporter for metrics managed in a named registry. - * - * @param registryName registry to use, one of registries managed by {@link SolrMetricManager} - */ - protected SolrMetricReporter(SolrMetricManager metricManager, String registryName) { - this.registryName = registryName; - this.metricManager = metricManager; - } - - /** - * Initializes a {@link SolrMetricReporter} with the plugin's configuration. - * - * @param pluginInfo the plugin's configuration - */ - @Override - @SuppressWarnings("unchecked") - public void init(PluginInfo pluginInfo) { - if (pluginInfo != null) { - this.pluginInfo = pluginInfo.copy(); - if (this.pluginInfo.initArgs != null) { - SolrPluginUtils.invokeSetters(this, this.pluginInfo.initArgs); - } - } - validate(); - if (!enabled) { - log.info("Reporter disabled for registry {}", registryName); - return; - } - log.debug("Initializing for registry {}", registryName); - doInit(); - } - - /** Reporter initialization implementation. */ - protected abstract void doInit(); - - /** - * Enable reporting, defaults to true. {@link #init(PluginInfo)} checks this flag before calling - * {@link #doInit()} to initialize reporting. - * - * @param enabled - whether or not reporting is to be enabled - */ - public void setEnabled(Boolean enabled) { - if (enabled != null) { - this.enabled = enabled; - } - } - - /** - * @param period - in seconds - */ - public void setPeriod(int period) { - this.period = period; - } - - /** - * @return period, in seconds - */ - public int getPeriod() { - return period; - } - - /** - * Get the effective {@link PluginInfo} instance that was used for initialization of this plugin. - * - * @return plugin info, or null if not yet initialized. - */ - public PluginInfo getPluginInfo() { - return pluginInfo; - } - - /** - * Validates that the reporter has been correctly configured. - * - * @throws IllegalStateException if the reporter is not properly configured - */ - protected abstract void validate() throws IllegalStateException; - - @Override - public String toString() { - return getClass().getName() - + "{" - + "registryName='" - + registryName - + '\'' - + ", pluginInfo=" - + pluginInfo - + '}'; - } -} diff --git a/solr/core/src/java/org/apache/solr/metrics/SolrMetricsContext.java b/solr/core/src/java/org/apache/solr/metrics/SolrMetricsContext.java index 05df56eba88..ddd069bdfeb 100644 --- a/solr/core/src/java/org/apache/solr/metrics/SolrMetricsContext.java +++ b/solr/core/src/java/org/apache/solr/metrics/SolrMetricsContext.java @@ -17,12 +17,6 @@ package org.apache.solr.metrics; -import com.codahale.metrics.Counter; -import com.codahale.metrics.Gauge; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.Meter; -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.Timer; import io.opentelemetry.api.metrics.BatchCallback; import io.opentelemetry.api.metrics.DoubleCounter; import io.opentelemetry.api.metrics.DoubleGauge; @@ -39,12 +33,11 @@ import io.opentelemetry.api.metrics.ObservableLongGauge; import io.opentelemetry.api.metrics.ObservableLongMeasurement; import io.opentelemetry.api.metrics.ObservableMeasurement; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; +import java.util.ArrayList; +import java.util.List; import java.util.function.Consumer; +import org.apache.solr.common.util.IOUtils; import org.apache.solr.metrics.otel.OtelUnit; -import org.apache.solr.util.stats.MetricUtils; /** * This class represents a metrics context that ties together components with the same life-cycle @@ -56,47 +49,14 @@ public class SolrMetricsContext { private final String registryName; private final SolrMetricManager metricManager; - private final String tag; - private final Set metricNames = ConcurrentHashMap.newKeySet(); + private final List closeables = new ArrayList<>(); - public SolrMetricsContext(SolrMetricManager metricManager, String registryName, String tag) { + public SolrMetricsContext(SolrMetricManager metricManager, String registryName) { this.registryName = registryName; this.metricManager = metricManager; - this.tag = tag; - } - - /** See {@link SolrMetricManager#nullNumber()}. */ - // TODO Remove - public Object nullNumber() { - return metricManager.nullNumber(); - } - - /** See {@link SolrMetricManager#notANumber()}. */ - // TODO Remove - public Object notANumber() { - return metricManager.notANumber(); - } - - /** See {@link SolrMetricManager#nullString()}. */ - // TODO Remove - public Object nullString() { - return metricManager.nullString(); - } - - /** See {@link SolrMetricManager#nullObject()}. */ - // TODO Remove - public Object nullObject() { - return metricManager.nullObject(); - } - - /** Metrics tag that represents objects with the same life-cycle. */ - // TODO Remove - public String getTag() { - return tag; } /** Return metric registry name used in this context. */ - // TODO Change this to OTEL Scope public String getRegistryName() { return registryName; } @@ -106,23 +66,6 @@ public SolrMetricManager getMetricManager() { return metricManager; } - /** Return a modifiable set of metric names that this component registers. */ - public Set getMetricNames() { - return metricNames; - } - - /** - * Unregister all {@link Gauge} metrics that use this context's tag. - * - *

NOTE: This method MUST be called at the end of a life-cycle (typically in close() - * ) of components that register gauge metrics with references to the current object's - * instance. Failure to do so may result in hard-to-debug memory leaks. - */ - // TODO don't need this - public void unregister() { - metricManager.unregisterGauges(registryName, tag); - } - /** * Get a context with the same registry name but a tag that represents a parent-child * relationship. Since it's a different tag than the parent's context it is assumed that the @@ -130,32 +73,11 @@ public void unregister() { * * @param child child object that produces metrics with a different life-cycle than the parent. */ - // TODO We shouldn't need child context anymore public SolrMetricsContext getChildContext(Object child) { - SolrMetricsContext childContext = - new SolrMetricsContext( - metricManager, registryName, SolrMetricProducer.getUniqueMetricTag(child, tag)); + SolrMetricsContext childContext = new SolrMetricsContext(metricManager, registryName); return childContext; } - /** - * Register a metric name that this component reports. This method is called by various metric - * registration methods in {@link org.apache.solr.metrics.SolrMetricManager} in order to capture - * what metric names are reported from this component (which in turn is called from {@link - * SolrMetricProducer#initializeMetrics(SolrMetricsContext, - * io.opentelemetry.api.common.Attributes, String)}). - */ - // TODO We can continue to register metric names - public void registerMetricName(String name) { - metricNames.add(name); - } - - /** Return a snapshot of metric values that this component reports. */ - // TODO Don't think this is needed anymore - public Map getMetricsSnapshot() { - return MetricUtils.convertMetrics(getMetricRegistry(), metricNames); - } - public LongCounter longCounter(String metricName, String description) { return longCounter(metricName, description, null); } @@ -223,7 +145,9 @@ public DoubleGauge doubleGauge(String metricName, String description, OtelUnit u public ObservableLongGauge observableLongGauge( String metricName, String description, Consumer callback) { - return observableLongGauge(metricName, description, callback, null); + var observableLongGauge = observableLongGauge(metricName, description, callback, null); + closeables.add(observableLongGauge); + return observableLongGauge; } public ObservableLongGauge observableLongGauge( @@ -236,7 +160,9 @@ public ObservableLongGauge observableLongGauge( public ObservableDoubleGauge observableDoubleGauge( String metricName, String description, Consumer callback) { - return observableDoubleGauge(metricName, description, callback, null); + var observableDoubleGauge = observableDoubleGauge(metricName, description, callback, null); + closeables.add(observableDoubleGauge); + return observableDoubleGauge; } public ObservableDoubleGauge observableDoubleGauge( @@ -250,7 +176,9 @@ public ObservableDoubleGauge observableDoubleGauge( public ObservableLongCounter observableLongCounter( String metricName, String description, Consumer callback) { - return observableLongCounter(metricName, description, callback, null); + var observableLongCounter = observableLongCounter(metricName, description, callback, null); + closeables.add(observableLongCounter); + return observableLongCounter; } public ObservableLongCounter observableLongCounter( @@ -264,7 +192,9 @@ public ObservableLongCounter observableLongCounter( public ObservableDoubleCounter observableDoubleCounter( String metricName, String description, Consumer callback) { - return observableDoubleCounter(metricName, description, callback, null); + var observableDoubleCounter = observableDoubleCounter(metricName, description, callback, null); + closeables.add(observableDoubleCounter); + return observableDoubleCounter; } public ObservableDoubleCounter observableDoubleCounter( @@ -317,68 +247,14 @@ public BatchCallback batchCallback( Runnable callback, ObservableMeasurement measurement, ObservableMeasurement... additionalMeasurements) { - return metricManager.batchCallback(registryName, callback, measurement, additionalMeasurements); + var batchCallback = + metricManager.batchCallback(registryName, callback, measurement, additionalMeasurements); + closeables.add(batchCallback); + return batchCallback; } - /** - * Convenience method for {@link SolrMetricManager#meter(SolrMetricsContext, String, String, - * String...)}. - */ - // TODO Remove - public Meter meter(String metricName, String... metricPath) { - return metricManager.meter(this, registryName, metricName, metricPath); - } - - /** - * Convenience method for {@link SolrMetricManager#counter(SolrMetricsContext, String, String, - * String...)}. - */ - // TODO Remove - public Counter counter(String metricName, String... metricPath) { - return metricManager.counter(this, registryName, metricName, metricPath); - } - - /** - * Convenience method for {@link SolrMetricManager#registerGauge(SolrMetricsContext, String, - * Gauge, String, SolrMetricManager.ResolutionStrategy, String, String...)}. - */ - // TODO Remove - public void gauge(Gauge gauge, boolean force, String metricName, String... metricPath) { - metricManager.registerGauge( - this, - registryName, - gauge, - tag, - force - ? SolrMetricManager.ResolutionStrategy.REPLACE - : SolrMetricManager.ResolutionStrategy.ERROR, - metricName, - metricPath); - } - - /** - * Convenience method for {@link SolrMetricManager#meter(SolrMetricsContext, String, String, - * String...)}. - */ - // TODO Remove - public Timer timer(String metricName, String... metricPath) { - return metricManager.timer(this, registryName, metricName, metricPath); - } - - /** - * Convenience method for {@link SolrMetricManager#histogram(SolrMetricsContext, String, String, - * String...)}. - */ - // TODO Remove - public Histogram histogram(String metricName, String... metricPath) { - return metricManager.histogram(this, registryName, metricName, metricPath); - } - - /** - * Get the {@link MetricRegistry} instance that is used for registering metrics in this context. - */ - // TODO Change this to OTEL Scope? - public MetricRegistry getMetricRegistry() { - return metricManager.registry(registryName); + public void unregister() { + IOUtils.closeQuietly(closeables); + closeables.clear(); } } diff --git a/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedInstrumentFactory.java b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedInstrumentFactory.java index a443eab92b0..0f2c05f848e 100644 --- a/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedInstrumentFactory.java +++ b/solr/core/src/java/org/apache/solr/metrics/otel/instruments/AttributedInstrumentFactory.java @@ -60,7 +60,7 @@ public AttributedInstrumentFactory( this.primaryIsNodeRegistry = primaryMetricsContext .getRegistryName() - .equals(SolrMetricManager.getRegistryName(SolrInfoBean.Group.node)); + .equals(SolrMetricManager.NODE_REGISTRY); // Only create node registry if we want dual registry mode AND primary is not already a node // registry @@ -68,8 +68,7 @@ public AttributedInstrumentFactory( this.nodeMetricsContext = new SolrMetricsContext( primaryMetricsContext.getMetricManager(), - SolrMetricManager.getRegistryName(SolrInfoBean.Group.node), - null); + SolrMetricManager.NODE_REGISTRY); this.nodeAttributes = createNodeAttributes(primaryAttributes); } } diff --git a/solr/core/src/java/org/apache/solr/metrics/package-info.java b/solr/core/src/java/org/apache/solr/metrics/package-info.java index 8f8a37d2df3..b2dceaaa97d 100644 --- a/solr/core/src/java/org/apache/solr/metrics/package-info.java +++ b/solr/core/src/java/org/apache/solr/metrics/package-info.java @@ -17,7 +17,6 @@ /** * The {@link org.apache.solr.metrics.SolrCoreMetricManager} is responsible for collecting metrics - * from {@link org.apache.solr.metrics.SolrMetricProducer}'s and exposing metrics to {@link - * org.apache.solr.metrics.SolrMetricReporter}'s. + * from {@link org.apache.solr.metrics.SolrMetricProducer}'s. */ package org.apache.solr.metrics; diff --git a/solr/core/src/java/org/apache/solr/metrics/reporters/ReporterClientCache.java b/solr/core/src/java/org/apache/solr/metrics/reporters/ReporterClientCache.java deleted file mode 100644 index b6465d11022..00000000000 --- a/solr/core/src/java/org/apache/solr/metrics/reporters/ReporterClientCache.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.solr.metrics.reporters; - -import java.io.Closeable; -import java.lang.invoke.MethodHandles; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Simple cache for reusable service clients used by some implementations of {@link - * org.apache.solr.metrics.SolrMetricReporter}. - */ -public class ReporterClientCache implements Closeable { - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - private final Map cache = new ConcurrentHashMap<>(); - - /** - * Provide an instance of service client. - * - * @param formal type - */ - public interface ClientProvider { - /** - * Get an instance of a service client. It's not specified that each time this method is invoked - * a new client instance should be returned. - * - * @return client instance - * @throws Exception when client creation encountered an error. - */ - T get() throws Exception; - } - - /** - * Get existing or register a new client. - * - * @param id client id - * @param clientProvider provider of new client instances - */ - public synchronized T getOrCreate(String id, ClientProvider clientProvider) { - T item = cache.get(id); - if (item == null) { - try { - item = clientProvider.get(); - cache.put(id, item); - } catch (Exception e) { - log.warn("Error providing a new client for id={}", id, e); - item = null; - } - } - return item; - } - - /** Empty this cache, and close all clients that are {@link Closeable}. */ - @Override - public void close() { - for (T client : cache.values()) { - if (client instanceof Closeable) { - try { - ((Closeable) client).close(); - } catch (Exception e) { - log.warn("Error closing client {}, ignoring...", client, e); - } - } - } - cache.clear(); - } -} diff --git a/solr/core/src/java/org/apache/solr/metrics/reporters/package-info.java b/solr/core/src/java/org/apache/solr/metrics/reporters/package-info.java deleted file mode 100644 index e8ee9b97554..00000000000 --- a/solr/core/src/java/org/apache/solr/metrics/reporters/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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. - */ - -/** - * This package houses 'pluggable' metric reporters that inherit from the {@link - * org.apache.solr.metrics.SolrMetricReporter} class. - */ -package org.apache.solr.metrics.reporters; diff --git a/solr/core/src/java/org/apache/solr/metrics/reporters/solr/SolrReporter.java b/solr/core/src/java/org/apache/solr/metrics/reporters/solr/SolrReporter.java deleted file mode 100644 index b66b94bc4df..00000000000 --- a/solr/core/src/java/org/apache/solr/metrics/reporters/solr/SolrReporter.java +++ /dev/null @@ -1,496 +0,0 @@ -/* - * 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.solr.metrics.reporters.solr; - -import com.codahale.metrics.Counter; -import com.codahale.metrics.Gauge; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.Meter; -import com.codahale.metrics.MetricFilter; -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.ScheduledReporter; -import com.codahale.metrics.Timer; -import java.lang.invoke.MethodHandles; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; -import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.io.SolrClientCache; -import org.apache.solr.client.solrj.request.UpdateRequest; -import org.apache.solr.common.params.ModifiableSolrParams; -import org.apache.solr.common.params.SolrParams; -import org.apache.solr.handler.admin.MetricsCollectorHandler; -import org.apache.solr.metrics.SolrMetricManager; -import org.apache.solr.util.stats.MetricUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Implementation of {@link ScheduledReporter} that reports metrics from selected registries and - * sends them periodically as update requests to a selected Solr collection and to a configured - * handler. - */ -public class SolrReporter extends ScheduledReporter { - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - public static final String REGISTRY_ID = "_registry_"; - public static final String REPORTER_ID = "_reporter_"; - public static final String GROUP_ID = "_group_"; - public static final String LABEL_ID = "_label_"; - - /** Specification of what registries and what metrics to send. */ - public static final class Report { - public String groupPattern; - public String labelPattern; - public String registryPattern; - public Set metricFilters = new HashSet<>(); - - /** - * Create a report specification - * - * @param groupPattern logical group for these metrics. This is used in {@link - * MetricsCollectorHandler} to select the target registry for metrics to aggregate. Must not - * be null or empty. It may contain back-references to capture groups from {@code - * registryPattern} - * @param labelPattern name of this group of metrics. This is used in {@link - * MetricsCollectorHandler} to prefix metric names. May be null or empty. It may contain - * back-references to capture groups from {@code registryPattern}. - * @param registryPattern pattern for selecting matching registries, see {@link - * SolrMetricManager#registryNames(String...)} - * @param metricFilters patterns for selecting matching metrics, see {@link - * org.apache.solr.metrics.SolrMetricManager.RegexFilter} - */ - public Report( - String groupPattern, - String labelPattern, - String registryPattern, - Collection metricFilters) { - this.groupPattern = groupPattern; - this.labelPattern = labelPattern; - this.registryPattern = registryPattern; - if (metricFilters != null) { - this.metricFilters.addAll(metricFilters); - } - } - - @SuppressWarnings({"unchecked"}) - public static Report fromMap(Map map) { - String groupPattern = (String) map.get("group"); - String labelPattern = (String) map.get("label"); - String registryPattern = (String) map.get("registry"); - Object oFilters = map.get("filter"); - Collection metricFilters = Collections.emptyList(); - if (oFilters != null) { - if (oFilters instanceof String) { - metricFilters = Collections.singletonList((String) oFilters); - } else if (oFilters instanceof Collection) { - metricFilters = (Collection) oFilters; - } else { - log.warn("Invalid report filters, ignoring: {}", oFilters); - } - } - if (groupPattern == null || registryPattern == null) { - log.warn("Invalid report configuration, group and registry required!: {}", map); - return null; - } - return new Report(groupPattern, labelPattern, registryPattern, metricFilters); - } - } - - /** Builder for the {@link SolrReporter} class. */ - public static class Builder { - private final SolrMetricManager metricManager; - private final List reports; - private String reporterId; - private TimeUnit rateUnit; - private TimeUnit durationUnit; - private String handler; - private boolean skipHistograms; - private boolean skipAggregateValues; - private boolean cloudClient; - private boolean compact; - private SolrParams params; - - /** - * Create a builder for SolrReporter. - * - * @param metricManager metric manager that is the source of metrics - * @param reports report definitions - * @return builder - */ - public static Builder forReports(SolrMetricManager metricManager, List reports) { - return new Builder(metricManager, reports); - } - - private Builder(SolrMetricManager metricManager, List reports) { - this.metricManager = metricManager; - this.reports = reports; - this.rateUnit = TimeUnit.SECONDS; - this.durationUnit = TimeUnit.MILLISECONDS; - this.skipHistograms = false; - this.skipAggregateValues = false; - this.cloudClient = false; - this.compact = true; - this.params = null; - } - - /** - * Additional {@link SolrParams} to add to every request. - * - * @param params additional params - * @return {@code this} - */ - public Builder withSolrParams(SolrParams params) { - this.params = params; - return this; - } - - /** - * If true then use {@link org.apache.solr.client.solrj.impl.CloudSolrClient} for communication. - * Default is false. - * - * @param cloudClient use CloudSolrClient when true, {@link - * org.apache.solr.client.solrj.impl.Http2SolrClient} otherwise. - * @return {@code this} - */ - public Builder cloudClient(boolean cloudClient) { - this.cloudClient = cloudClient; - return this; - } - - /** - * If true then use "compact" data representation. - * - * @param compact compact representation. - * @return {@code this} - */ - public Builder setCompact(boolean compact) { - this.compact = compact; - return this; - } - - /** - * Histograms are difficult / impossible to aggregate, so it may not be worth to report them. - * - * @param skipHistograms when true then skip histograms from reports - * @return {@code this} - */ - public Builder skipHistograms(boolean skipHistograms) { - this.skipHistograms = skipHistograms; - return this; - } - - /** - * Individual values from {@link org.apache.solr.metrics.AggregateMetric} may not be worth to - * report. - * - * @param skipAggregateValues when tru then skip reporting individual values from the metric - * @return {@code this} - */ - public Builder skipAggregateValues(boolean skipAggregateValues) { - this.skipAggregateValues = skipAggregateValues; - return this; - } - - /** - * Handler name to use at the remote end. - * - * @param handler handler name, eg. "/admin/metricsCollector" - * @return {@code this} - */ - public Builder withHandler(String handler) { - this.handler = handler; - return this; - } - - /** - * Use this id to identify metrics from this instance. - * - * @param reporterId reporter id - * @return {@code this} - */ - public Builder withReporterId(String reporterId) { - this.reporterId = reporterId; - return this; - } - - /** - * Convert rates to the given time unit. - * - * @param rateUnit a unit of time - * @return {@code this} - */ - public Builder convertRatesTo(TimeUnit rateUnit) { - this.rateUnit = rateUnit; - return this; - } - - /** - * Convert durations to the given time unit. - * - * @param durationUnit a unit of time - * @return {@code this} - */ - public Builder convertDurationsTo(TimeUnit durationUnit) { - this.durationUnit = durationUnit; - return this; - } - - /** - * Build it. - * - * @param solrClientCache an instance of {@link SolrClientCache} to be used for making calls. - * @param urlProvider function that returns the base URL of Solr instance to target. May return - * null to indicate that reporting should be skipped. Note: this function will be called - * every time just before report is sent. - * @return configured instance of reporter - */ - public SolrReporter build(SolrClientCache solrClientCache, Supplier urlProvider) { - return new SolrReporter( - solrClientCache, - false, - urlProvider, - metricManager, - reports, - handler, - reporterId, - rateUnit, - durationUnit, - params, - skipHistograms, - skipAggregateValues, - cloudClient, - compact); - } - } - - private String reporterId; - private String handler; - private Supplier urlProvider; - private SolrClientCache clientCache; - private boolean closeClientCache; - private List compiledReports; - private SolrMetricManager metricManager; - private boolean skipHistograms; - private boolean skipAggregateValues; - private boolean cloudClient; - private boolean compact; - private ModifiableSolrParams params; - private Map metadata; - - private static final class CompiledReport { - String group; - String label; - Pattern registryPattern; - MetricFilter filter; - - CompiledReport(Report report) throws PatternSyntaxException { - this.group = report.groupPattern; - this.label = report.labelPattern; - this.registryPattern = Pattern.compile(report.registryPattern); - this.filter = new SolrMetricManager.RegexFilter(report.metricFilters); - } - - @Override - public String toString() { - return "CompiledReport{" - + "group='" - + group - + '\'' - + ", label='" - + label - + '\'' - + ", registryPattern=" - + registryPattern - + ", filter=" - + filter - + '}'; - } - } - - // Recent dropwizard (found with version 4.1.2) requires that you _must_ call the superclass with - // a non-null registry. - // We delegate to registries anyway, so having a dummy registry is harmless. - private static final MetricRegistry dummyRegistry = new MetricRegistry(); - - /** - * Create a SolrReporter instance. - * - * @param solrClientCache client cache to use for constructing SolrClient instances. - * @param urlProvider what URL to send to. - * @param metricManager metric manager - * @param metrics metric specifications to report - * @param handler handler name to report to - * @param reporterId my reporter id - * @param rateUnit rate unit - * @param durationUnit duration unit - * @param params request parameters - * @param skipHistograms if true then don't send histogram metrics - * @param skipAggregateValues if true then don't send aggregate metrics' individual values - * @param cloudClient if true then use CloudSolrClient, plain HttpSolrClient otherwise. - * @param compact if true then use compact representation. - */ - public SolrReporter( - SolrClientCache solrClientCache, - boolean closeClientCache, - Supplier urlProvider, - SolrMetricManager metricManager, - List metrics, - String handler, - String reporterId, - TimeUnit rateUnit, - TimeUnit durationUnit, - SolrParams params, - boolean skipHistograms, - boolean skipAggregateValues, - boolean cloudClient, - boolean compact) { - super(dummyRegistry, "solr-reporter", MetricFilter.ALL, rateUnit, durationUnit, null, true); - - this.metricManager = metricManager; - this.urlProvider = urlProvider; - this.reporterId = reporterId; - if (handler == null) { - handler = MetricsCollectorHandler.HANDLER_PATH; - } - this.handler = handler; - this.clientCache = solrClientCache; - this.closeClientCache = closeClientCache; - this.compiledReports = new ArrayList<>(); - metrics.forEach( - report -> { - MetricFilter filter = new SolrMetricManager.RegexFilter(report.metricFilters); - try { - CompiledReport cs = new CompiledReport(report); - compiledReports.add(cs); - } catch (PatternSyntaxException e) { - log.warn("Skipping report with invalid registryPattern: {}", report.registryPattern, e); - } - }); - this.skipHistograms = skipHistograms; - this.skipAggregateValues = skipAggregateValues; - this.cloudClient = cloudClient; - this.compact = compact; - this.params = new ModifiableSolrParams(); - this.params.set(REPORTER_ID, reporterId); - // allow overrides to take precedence - if (params != null) { - this.params.add(params); - } - metadata = new HashMap<>(); - metadata.put(REPORTER_ID, reporterId); - } - - @Override - public void close() { - if (closeClientCache) { - clientCache.close(); - } - super.close(); - } - - @Override - public void report() { - String url = urlProvider.get(); - // if null then suppress reporting - if (url == null) { - return; - } - - SolrClient solr; - if (cloudClient) { - solr = clientCache.getCloudSolrClient(url); - } else { - solr = clientCache.getHttpSolrClient(url); - } - UpdateRequest req = new UpdateRequest(handler); - req.setParams(params); - compiledReports.forEach( - report -> { - Set registryNames = metricManager.registryNames(report.registryPattern); - registryNames.forEach( - registryName -> { - String label = report.label; - if (label != null && label.indexOf('$') != -1) { - // label with back-references - Matcher m = report.registryPattern.matcher(registryName); - label = m.replaceFirst(label); - } - final String effectiveLabel = label; - String group = report.group; - if (group.indexOf('$') != -1) { - // group with back-references - Matcher m = report.registryPattern.matcher(registryName); - group = m.replaceFirst(group); - } - final String effectiveGroup = group; - MetricUtils.toSolrInputDocuments( - metricManager.registry(registryName), - Collections.singletonList(report.filter), - MetricFilter.ALL, - MetricUtils.ALL_PROPERTIES, - skipHistograms, - skipAggregateValues, - compact, - metadata, - doc -> { - doc.setField(REGISTRY_ID, registryName); - doc.setField(GROUP_ID, effectiveGroup); - if (effectiveLabel != null) { - doc.setField(LABEL_ID, effectiveLabel); - } - req.add(doc); - }); - }); - }); - - // if no docs added then don't send a report - if (req.getDocuments() == null || req.getDocuments().isEmpty()) { - return; - } - try { - // log.info("%%% sending to " + url + ": " + req.getParams()); - solr.request(req); - } catch (Exception e) { - if (log.isDebugEnabled()) { - log.debug("Error sending metric report: {}", e); - } - } - } - - @Override - @SuppressWarnings("rawtypes") // super uses raw Gauge, so we're stuck with it - public void report( - SortedMap gauges, - SortedMap counters, - SortedMap histograms, - SortedMap meters, - SortedMap timers) { - // no-op - we do all the work in report() - } -} diff --git a/solr/core/src/java/org/apache/solr/metrics/reporters/solr/package-info.java b/solr/core/src/java/org/apache/solr/metrics/reporters/solr/package-info.java deleted file mode 100644 index a8fbb1676a8..00000000000 --- a/solr/core/src/java/org/apache/solr/metrics/reporters/solr/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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. - */ - -/** - * This package contains {@link org.apache.solr.metrics.SolrMetricReporter} implementations specific - * to SolrCloud reporting. - */ -package org.apache.solr.metrics.reporters.solr; diff --git a/solr/core/src/java/org/apache/solr/search/CaffeineCache.java b/solr/core/src/java/org/apache/solr/search/CaffeineCache.java index 601bdf80e11..1ccf30145d0 100644 --- a/solr/core/src/java/org/apache/solr/search/CaffeineCache.java +++ b/solr/core/src/java/org/apache/solr/search/CaffeineCache.java @@ -16,10 +16,6 @@ */ package org.apache.solr.search; -import static org.apache.solr.metrics.SolrMetricProducer.CATEGORY_ATTR; -import static org.apache.solr.metrics.SolrMetricProducer.OPERATION_ATTR; -import static org.apache.solr.metrics.SolrMetricProducer.RESULT_ATTR; - import com.github.benmanes.caffeine.cache.AsyncCache; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; @@ -475,11 +471,15 @@ public String toString() { } @Override + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { + initializeMetrics(parentContext, attributes, "solr_caffeine_cache"); + } + public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String metricName) { + SolrMetricsContext solrMetricsContext, Attributes attributes, String metricName) { Attributes cacheAttributes = attributes.toBuilder().put(CATEGORY_ATTR, getCategory().toString()).build(); - solrMetricsContext = parentContext.getChildContext(this); + this.solrMetricsContext = solrMetricsContext.getChildContext(this); ObservableLongMeasurement cacheLookupsMetric = solrMetricsContext.longCounterMeasurement( diff --git a/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java b/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java index 3289d42cf25..883dcaf66a0 100644 --- a/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java +++ b/solr/core/src/java/org/apache/solr/search/SolrFieldCacheBean.java @@ -56,8 +56,7 @@ public SolrMetricsContext getSolrMetricsContext() { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { this.solrMetricsContext = parentContext; var solrCacheStats = solrMetricsContext.longGaugeMeasurement( diff --git a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java index 14e44b4fcc0..5ca8c7bbe0a 100644 --- a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java +++ b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java @@ -18,7 +18,6 @@ import static org.apache.solr.search.CpuAllowedLimit.TIMING_CONTEXT; -import com.codahale.metrics.Gauge; import io.opentelemetry.api.common.Attributes; import java.io.Closeable; import java.io.IOException; @@ -83,7 +82,6 @@ import org.apache.lucene.search.TotalHitCountCollector; import org.apache.lucene.search.TotalHits; import org.apache.lucene.search.TotalHits.Relation; -import org.apache.lucene.store.AlreadyClosedException; import org.apache.lucene.store.Directory; import org.apache.lucene.util.Bits; import org.apache.lucene.util.BytesRef; @@ -611,12 +609,14 @@ public void register() { } this.solrMetricsContext = core.getSolrMetricsContext().getChildContext(this); for (SolrCache cache : cacheList) { - cache.initializeMetrics( - solrMetricsContext, - core.getCoreAttributes().toBuilder().put(NAME_ATTR, cache.name()).build(), - "solr_searcher_cache"); + if (cache instanceof CaffeineCache caffeineCache) { + caffeineCache.initializeMetrics( + solrMetricsContext, + core.getCoreAttributes().toBuilder().put(NAME_ATTR, cache.name()).build(), + "solr_searcher_cache"); + } } - initializeMetrics(solrMetricsContext, core.getCoreAttributes(), STATISTICS_KEY); + initializeMetrics(solrMetricsContext, core.getCoreAttributes()); registerTime = new Date(); } @@ -2616,8 +2616,7 @@ public SolrMetricsContext getSolrMetricsContext() { } @Override - public void initializeMetrics( - SolrMetricsContext solrMetricsContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext solrMetricsContext, Attributes attributes) { var baseAttributes = attributes.toBuilder().put(CATEGORY_ATTR, Category.SEARCHER.toString()).build(); @@ -2695,20 +2694,6 @@ public void initializeMetrics( })); } - /** - * wraps a gauge (related to an IndexReader) and swallows any {@link AlreadyClosedException} that - * might be thrown, returning the specified default in it's place. - */ - private Gauge rgauge(T closedDefault, Gauge g) { - return () -> { - try { - return g.getValue(); - } catch (AlreadyClosedException ignore) { - return closedDefault; - } - }; - } - public long getWarmupTime() { return warmupTime; } diff --git a/solr/core/src/java/org/apache/solr/search/stats/StatsCache.java b/solr/core/src/java/org/apache/solr/search/stats/StatsCache.java index 44dc7aca40e..5f163e842af 100644 --- a/solr/core/src/java/org/apache/solr/search/stats/StatsCache.java +++ b/solr/core/src/java/org/apache/solr/search/stats/StatsCache.java @@ -328,8 +328,7 @@ public SolrMetricsContext getSolrMetricsContext() { } @Override - public void initializeMetrics( - SolrMetricsContext solrMetricsContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext solrMetricsContext, Attributes attributes) { this.solrMetricsContext = solrMetricsContext; var cacheBaseAttribute = attributes.toBuilder() diff --git a/solr/core/src/java/org/apache/solr/security/AuditLoggerPlugin.java b/solr/core/src/java/org/apache/solr/security/AuditLoggerPlugin.java index 89a6c923f7a..fb810895abd 100644 --- a/solr/core/src/java/org/apache/solr/security/AuditLoggerPlugin.java +++ b/solr/core/src/java/org/apache/solr/security/AuditLoggerPlugin.java @@ -262,8 +262,7 @@ public void setFormatter(AuditEventFormatter formatter) { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, final String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { solrMetricsContext = parentContext.getChildContext(this); String className = this.getClass().getSimpleName(); log.debug("Initializing metrics for {}", className); diff --git a/solr/core/src/java/org/apache/solr/security/AuthenticationPlugin.java b/solr/core/src/java/org/apache/solr/security/AuthenticationPlugin.java index f68c0dc0397..99c1b091eac 100644 --- a/solr/core/src/java/org/apache/solr/security/AuthenticationPlugin.java +++ b/solr/core/src/java/org/apache/solr/security/AuthenticationPlugin.java @@ -144,8 +144,7 @@ public SolrMetricsContext getSolrMetricsContext() { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { this.solrMetricsContext = parentContext.getChildContext(this); Attributes attrsWithCategory = Attributes.builder() diff --git a/solr/core/src/java/org/apache/solr/security/MultiAuthPlugin.java b/solr/core/src/java/org/apache/solr/security/MultiAuthPlugin.java index 7c7e5a4b5df..87664c0dcce 100644 --- a/solr/core/src/java/org/apache/solr/security/MultiAuthPlugin.java +++ b/solr/core/src/java/org/apache/solr/security/MultiAuthPlugin.java @@ -194,15 +194,12 @@ private void addWWWAuthenticateHeaders(HttpServletResponse response) { } } - // TODO SOLR-17458: Migrate to Otel @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { for (AuthenticationPlugin plugin : pluginMap.values()) { - // TODO SOLR-17458: Add Otel - plugin.initializeMetrics(parentContext, Attributes.empty(), scope); + plugin.initializeMetrics(parentContext, Attributes.empty()); } - super.initializeMetrics(parentContext, attributes, scope); + super.initializeMetrics(parentContext, attributes); } private String getSchemeFromAuthHeader(final String authHeader) { diff --git a/solr/core/src/java/org/apache/solr/security/MultiDestinationAuditLogger.java b/solr/core/src/java/org/apache/solr/security/MultiDestinationAuditLogger.java index 13d3ea48cd2..b617362210f 100644 --- a/solr/core/src/java/org/apache/solr/security/MultiDestinationAuditLogger.java +++ b/solr/core/src/java/org/apache/solr/security/MultiDestinationAuditLogger.java @@ -130,10 +130,9 @@ public void inform(ResourceLoader loader) { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { - super.initializeMetrics(parentContext, attributes, scope); - plugins.forEach(p -> p.initializeMetrics(parentContext, Attributes.empty(), scope)); + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { + super.initializeMetrics(parentContext, attributes); + plugins.forEach(p -> p.initializeMetrics(parentContext, Attributes.empty())); } @Override diff --git a/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java b/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java index dc802afc2b7..76970a990cb 100644 --- a/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java +++ b/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java @@ -223,8 +223,7 @@ public DirectUpdateHandler2(SolrCore core, UpdateHandler updateHandler) { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { this.solrMetricsContext = parentContext.getChildContext(this); var baseAttributes = diff --git a/solr/core/src/java/org/apache/solr/update/PeerSync.java b/solr/core/src/java/org/apache/solr/update/PeerSync.java index 90fdb7674aa..f049ba851fd 100644 --- a/solr/core/src/java/org/apache/solr/update/PeerSync.java +++ b/solr/core/src/java/org/apache/solr/update/PeerSync.java @@ -145,8 +145,7 @@ public SolrMetricsContext getSolrMetricsContext() { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { this.solrMetricsContext = parentContext.getChildContext(this); var baseAttributes = attributes.toBuilder() diff --git a/solr/core/src/java/org/apache/solr/update/PeerSyncWithLeader.java b/solr/core/src/java/org/apache/solr/update/PeerSyncWithLeader.java index d01a5bf51cd..49027b1665c 100644 --- a/solr/core/src/java/org/apache/solr/update/PeerSyncWithLeader.java +++ b/solr/core/src/java/org/apache/solr/update/PeerSyncWithLeader.java @@ -99,10 +99,8 @@ public SolrMetricsContext getSolrMetricsContext() { return solrMetricsContext; } - // TODO SOLR-17458: Migrate to Otel @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { this.solrMetricsContext = parentContext.getChildContext(this); var baseAttributes = attributes.toBuilder() diff --git a/solr/core/src/java/org/apache/solr/update/SolrIndexWriter.java b/solr/core/src/java/org/apache/solr/update/SolrIndexWriter.java index fd29f7ddf04..b17c5ecd74e 100644 --- a/solr/core/src/java/org/apache/solr/update/SolrIndexWriter.java +++ b/solr/core/src/java/org/apache/solr/update/SolrIndexWriter.java @@ -261,8 +261,7 @@ private void initMetrics(final SolrCore core) { "solr_indexwriter_merges", "Number of total merge operations, " + descSuffix); mergeDocsCounter = solrMetricsContext.longCounter( - "solr_indexwriter_merge_docs", - "Number of documents involved in merge, " + descSuffix); + "solr_indexwriter_merge_docs", "Number of documents involved in merge, " + descSuffix); mergeSegmentsCounter = solrMetricsContext.longCounter( "solr_indexwriter_merge_segments", diff --git a/solr/core/src/java/org/apache/solr/update/UpdateLog.java b/solr/core/src/java/org/apache/solr/update/UpdateLog.java index e427582718a..464c47cc53e 100644 --- a/solr/core/src/java/org/apache/solr/update/UpdateLog.java +++ b/solr/core/src/java/org/apache/solr/update/UpdateLog.java @@ -627,8 +627,7 @@ protected void initTlogDir(SolrCore core) { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { final List observables = new ArrayList<>(); solrMetricsContext = parentContext.getChildContext(this); @@ -661,7 +660,6 @@ public void initializeMetrics( toClose = Collections.unmodifiableList(observables); - solrMetricsContext.gauge(() -> state.getValue(), true, "state", scope); observables.add( solrMetricsContext.observableLongGauge( "solr_core_update_log_state", diff --git a/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java b/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java index c0d4715154a..eef6d04f762 100644 --- a/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java +++ b/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java @@ -32,7 +32,6 @@ import org.apache.solr.common.util.IOUtils; import org.apache.solr.common.util.SolrNamedThreadFactory; import org.apache.solr.core.SolrInfoBean; -import org.apache.solr.metrics.SolrMetricManager; import org.apache.solr.metrics.SolrMetricsContext; import org.apache.solr.security.HttpClientBuilderPlugin; import org.apache.solr.update.processor.DistributedUpdateProcessor; @@ -164,11 +163,9 @@ public String getName() { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { solrMetricsContext = parentContext.getChildContext(this); - String expandedScope = SolrMetricManager.mkName(scope, getCategory().name()); - trackHttpSolrMetrics.initializeMetrics(solrMetricsContext, Attributes.empty(), expandedScope); + trackHttpSolrMetrics.initializeMetrics(solrMetricsContext, Attributes.empty()); updateExecutor = MetricUtils.instrumentedExecutorService( updateExecutor, solrMetricsContext, getCategory(), "updateOnlyExecutor"); diff --git a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java index 68436cfe76d..e31e02b85d2 100644 --- a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java +++ b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpListenerFactory.java @@ -19,7 +19,6 @@ import static org.apache.solr.metrics.SolrMetricManager.mkName; -import com.codahale.metrics.Timer; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; import java.util.Locale; @@ -29,6 +28,8 @@ import org.apache.solr.common.util.CollectionUtil; import org.apache.solr.metrics.SolrMetricProducer; import org.apache.solr.metrics.SolrMetricsContext; +import org.apache.solr.metrics.otel.OtelUnit; +import org.apache.solr.metrics.otel.instruments.AttributedLongTimer; import org.apache.solr.util.tracing.TraceUtils; import org.eclipse.jetty.client.Request; import org.eclipse.jetty.client.Result; @@ -77,6 +78,7 @@ public interface NameStrategy { protected SolrMetricsContext solrMetricsContext; protected String scope; protected NameStrategy nameStrategy; + private AttributedLongTimer requestTimer; public InstrumentedHttpListenerFactory(NameStrategy nameStrategy) { this.nameStrategy = nameStrategy; @@ -89,7 +91,7 @@ private static String methodNameString(Request request) { @Override public RequestResponseListener get() { return new RequestResponseListener() { - Timer.Context timerContext; + AttributedLongTimer.MetricTimer timerContext; Span span = Span.getInvalid(); @Override @@ -101,8 +103,8 @@ public void onQueued(Request request) { @Override public void onBegin(Request request) { - if (solrMetricsContext != null) { - timerContext = timer(request).time(); + if (requestTimer != null) { + timerContext = requestTimer.start(); } if (span.isRecording()) { span.addEvent("Client Send"); // perhaps delayed a bit after the span started in enqueue @@ -121,16 +123,16 @@ public void onComplete(Result result) { }; } - private Timer timer(Request request) { - return solrMetricsContext.timer(nameStrategy.getNameFor(scope, request)); - } - - // TODO SOLR-17458: Add Otel @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { this.solrMetricsContext = parentContext; - this.scope = scope; + this.requestTimer = + new AttributedLongTimer( + solrMetricsContext.longHistogram( + "solr_client_request_duration", + "HTTP client request duration", + OtelUnit.MILLISECONDS), + attributes); } @Override diff --git a/solr/core/src/java/org/apache/solr/util/stats/MetricUtils.java b/solr/core/src/java/org/apache/solr/util/stats/MetricUtils.java index 3447e3e6f0a..23e6ca33ff2 100644 --- a/solr/core/src/java/org/apache/solr/util/stats/MetricUtils.java +++ b/solr/core/src/java/org/apache/solr/util/stats/MetricUtils.java @@ -16,45 +16,15 @@ */ package org.apache.solr.util.stats; -import com.codahale.metrics.Counter; -import com.codahale.metrics.Gauge; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.Meter; -import com.codahale.metrics.Metric; -import com.codahale.metrics.MetricFilter; -import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Snapshot; import com.codahale.metrics.Timer; -import java.beans.BeanInfo; -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.io.IOException; import java.lang.invoke.MethodHandles; import java.lang.management.OperatingSystemMXBean; -import java.lang.management.PlatformManagedObject; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.SortedSet; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; -import java.util.function.BiConsumer; -import java.util.function.Consumer; import java.util.function.Predicate; -import org.apache.solr.common.ConditionalKeyMapWriter; -import org.apache.solr.common.IteratorWriter; -import org.apache.solr.common.MapWriter; -import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.util.NamedList; import org.apache.solr.core.SolrInfoBean; -import org.apache.solr.metrics.AggregateMetric; -import org.apache.solr.metrics.SolrMetricManager; import org.apache.solr.metrics.SolrMetricsContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -91,13 +61,6 @@ public class MetricUtils { public static final Predicate ALL_PROPERTIES = (name) -> true; - /** - * Local cache for BeanInfo instances that are created to scan for system metrics. List of - * properties is not supposed to change for the JVM lifespan, so we can keep already create - * BeanInfo instance for future calls. - */ - private static final ConcurrentMap, BeanInfo> beanInfos = new ConcurrentHashMap<>(); - /** * Adds metrics from a Timer to a NamedList, using well-known back-compat names. * @@ -127,369 +90,6 @@ public static double nsToMs(double ns) { return ns / TimeUnit.MILLISECONDS.toNanos(1); } - /** - * Provides a representation of the given metric registry as {@link SolrInputDocument}-s. Only - * those metrics are converted which match at least one of the given MetricFilter instances. - * - * @param registry the {@link MetricRegistry} to be converted - * @param shouldMatchFilters a list of {@link MetricFilter} instances. A metric must match any - * one of the filters from this list to be included in the output - * @param mustMatchFilter a {@link MetricFilter}. A metric must match this filter to be - * included in the output. - * @param propertyFilter limit what properties of a metric are returned - * @param skipHistograms discard any {@link Histogram}-s and histogram parts of {@link Timer}-s. - * @param skipAggregateValues discard internal values of {@link AggregateMetric}-s. - * @param compact use compact representation for counters and gauges. - * @param metadata optional metadata. If not null and not empty then this map will be added under - * a {@code _metadata_} key. - * @param consumer consumer that accepts produced {@link SolrInputDocument}-s - */ - public static void toSolrInputDocuments( - MetricRegistry registry, - List shouldMatchFilters, - MetricFilter mustMatchFilter, - Predicate propertyFilter, - boolean skipHistograms, - boolean skipAggregateValues, - boolean compact, - Map metadata, - Consumer consumer) { - boolean addMetadata = metadata != null && !metadata.isEmpty(); - toMaps( - registry, - shouldMatchFilters, - mustMatchFilter, - propertyFilter, - skipHistograms, - skipAggregateValues, - compact, - false, - (k, v) -> { - SolrInputDocument doc = new SolrInputDocument(); - doc.setField(METRIC_NAME, k); - toSolrInputDocument(null, doc, v); - if (addMetadata) { - toSolrInputDocument(null, doc, metadata); - } - consumer.accept(doc); - }); - } - - /** - * Fill in a SolrInputDocument with values from a converted metric, recursively. - * - * @param prefix prefix to add to generated field names, or null if none. - * @param doc document to fill - * @param o an instance of converted metric, either a Map or a flat Object - */ - static void toSolrInputDocument(String prefix, SolrInputDocument doc, Object o) { - final BiConsumer consumer = - (k, v) -> { - if ((v instanceof Map) || (v instanceof MapWriter) || (v instanceof IteratorWriter)) { - toSolrInputDocument(k.toString(), doc, v); - } else { - String key = prefix != null ? prefix + "." + k : k.toString(); - doc.addField(key, v); - } - }; - if (o instanceof MapWriter writer) { - writer._forEachEntry(consumer); - } else if (o instanceof Map) { - @SuppressWarnings({"unchecked"}) - Map map = (Map) o; - for (Map.Entry entry : map.entrySet()) { - consumer.accept(entry.getKey(), entry.getValue()); - } - } else if (o instanceof IteratorWriter writer) { - final String name = prefix != null ? prefix : "value"; - try { - writer.writeIter( - new IteratorWriter.ItemWriter() { - @Override - public IteratorWriter.ItemWriter add(Object o) { - consumer.accept(name, o); - return this; - } - }); - } catch (IOException e) { - throw new RuntimeException("this should never happen", e); - } - } else { - String key = prefix != null ? prefix : VALUE; - doc.addField(key, o); - } - } - - /** - * Convert selected metrics to maps or to flattened objects. - * - * @param registry source of metrics - * @param shouldMatchFilters metrics must match any of these filters - * @param mustMatchFilter metrics must match this filter - * @param propertyFilter limit what properties of a metric are returned - * @param skipHistograms discard any {@link Histogram}-s and histogram parts of {@link Timer}-s. - * @param skipAggregateValues discard internal values of {@link AggregateMetric}-s. - * @param compact use compact representation for counters and gauges. - * @param simple use simplified representation for complex metrics - instead of a (name, map) only - * the selected (name "." key, value) pairs will be produced. - * @param consumer consumer that accepts produced objects - */ - public static void toMaps( - MetricRegistry registry, - List shouldMatchFilters, - MetricFilter mustMatchFilter, - Predicate propertyFilter, - boolean skipHistograms, - boolean skipAggregateValues, - boolean compact, - boolean simple, - BiConsumer consumer) { - final Map metrics = registry.getMetrics(); - final SortedSet names = registry.getNames(); - names.stream() - .filter( - s -> - shouldMatchFilters.stream() - .anyMatch(metricFilter -> metricFilter.matches(s, metrics.get(s)))) - .filter(s -> mustMatchFilter.matches(s, metrics.get(s))) - .forEach( - n -> { - Metric metric = metrics.get(n); - convertMetric( - n, - metric, - propertyFilter, - skipHistograms, - skipAggregateValues, - compact, - simple, - ".", - consumer); - }); - } - - /** - * Convert selected metrics from a registry into a map, with metrics in a compact AND simple - * format. - * - * @param registry registry - * @param names metric names - * @return map where keys are metric names (if they were present in the registry) and values are - * converted metrics in simplified format. - */ - public static Map convertMetrics( - MetricRegistry registry, Collection names) { - final Map metrics = new HashMap<>(); - convertMetrics(registry, names, false, true, true, true, (k, v) -> metrics.put(k, v)); - return metrics; - } - - /** - * Convert selected metrics from a registry into maps (when compact==false) or - * flattened objects. - * - * @param registry registry - * @param names metric names - * @param skipHistograms discard any {@link Histogram}-s and histogram parts of {@link Timer}-s. - * @param skipAggregateValues discard internal values of {@link AggregateMetric}-s. - * @param compact use compact representation for counters and gauges. - * @param simple use simplified representation for complex metrics - instead of a (name, map) only - * the selected (name "." key, value) pairs will be produced. - * @param consumer consumer that accepts produced objects - */ - public static void convertMetrics( - MetricRegistry registry, - Collection names, - boolean skipHistograms, - boolean skipAggregateValues, - boolean compact, - boolean simple, - BiConsumer consumer) { - final Map metrics = registry.getMetrics(); - names.stream() - .forEach( - n -> { - Metric metric = metrics.get(n); - convertMetric( - n, - metric, - (s) -> true, - skipHistograms, - skipAggregateValues, - compact, - simple, - ".", - consumer); - }); - } - - /** - * Convert a single instance of metric into a map or flattened object. - * - * @param n metric name - * @param metric metric instance - * @param propertyFilter limit what properties of a metric are returned - * @param skipHistograms discard any {@link Histogram}-s and histogram parts of {@link Timer}-s. - * @param skipAggregateValues discard internal values of {@link AggregateMetric}-s. - * @param compact use compact representation for counters and gauges. - * @param simple use simplified representation for complex metrics - instead of a (name, map) only - * the selected (name "." key, value) pairs will be produced. - * @param consumer consumer that accepts produced objects - */ - public static void convertMetric( - String n, - Metric metric, - Predicate propertyFilter, - boolean skipHistograms, - boolean skipAggregateValues, - boolean compact, - boolean simple, - String separator, - BiConsumer consumer) { - if (metric instanceof Counter counter) { - convertCounter(n, counter, propertyFilter, compact, consumer); - } else if (metric instanceof Gauge gauge) { - // unwrap if needed - if (gauge instanceof SolrMetricManager.GaugeWrapper) { - gauge = ((SolrMetricManager.GaugeWrapper) gauge).getGauge(); - } - try { - if (gauge instanceof MapWriter) { - convertMapWriter( - n, (MapWriter) gauge, propertyFilter, simple, compact, separator, consumer); - } else { - convertGauge(n, gauge, propertyFilter, simple, compact, separator, consumer); - } - } catch (InternalError ie) { - if (n.startsWith("memory.") && ie.getMessage().contains("Memory Pool not found")) { - log.warn("Error converting gauge '{}', possible JDK bug: SOLR-10362", n, ie); - consumer.accept(n, null); - } else { - throw ie; - } - } - } else if (metric instanceof Meter meter) { - convertMeter(n, meter, propertyFilter, simple, separator, consumer); - } else if (metric instanceof Timer timer) { - convertTimer(n, timer, propertyFilter, skipHistograms, simple, separator, consumer); - } else if (metric instanceof Histogram) { - if (!skipHistograms) { - Histogram histogram = (Histogram) metric; - convertHistogram(n, histogram, propertyFilter, simple, separator, consumer); - } - } else if (metric instanceof AggregateMetric) { - convertAggregateMetric( - n, - (AggregateMetric) metric, - propertyFilter, - skipAggregateValues, - simple, - separator, - consumer); - } - } - - /** - * Convert an instance of {@link AggregateMetric}. - * - * @param name metric name - * @param metric an instance of {@link AggregateMetric} - * @param propertyFilter limit what properties of a metric are returned - * @param skipAggregateValues discard internal values of {@link AggregateMetric}-s. - * @param simple use simplified representation for complex metrics - instead of a (name, map) only - * the selected (name "." key, value) pairs will be produced. - * @param consumer consumer that accepts produced objects - */ - static void convertAggregateMetric( - String name, - AggregateMetric metric, - Predicate propertyFilter, - boolean skipAggregateValues, - boolean simple, - String separator, - BiConsumer consumer) { - if (simple) { - if (propertyFilter.test(MEAN)) { - consumer.accept(name + separator + MEAN, metric.getMean()); - } - } else { - MapWriter writer = - ew -> { - BiConsumer filter = - (k, v) -> { - if (propertyFilter.test(k)) { - ew.putNoEx(k, v); - } - }; - filter.accept("count", metric.size()); - filter.accept(MAX, metric.getMax()); - filter.accept(MIN, metric.getMin()); - filter.accept(MEAN, metric.getMean()); - filter.accept(STDDEV, metric.getStdDev()); - filter.accept(SUM, metric.getSum()); - if (!(metric.isEmpty() || skipAggregateValues)) { - ew.putNoEx( - VALUES, - (MapWriter) - ew1 -> { - metric - .getValues() - .forEach( - (k, v) -> { - ew1.putNoEx( - k, - (MapWriter) - ew2 -> { - ew2.putNoEx("value", v.value); - ew2.putNoEx("updateCount", v.updateCount.get()); - }); - }); - }); - } - }; - if (writer._size() > 0) { - consumer.accept(name, writer); - } - } - } - - /** - * Convert an instance of {@link Histogram}. NOTE: it's assumed that histogram contains non-time - * based values that don't require unit conversion. - * - * @param name metric name - * @param histogram an instance of {@link Histogram} - * @param propertyFilter limit what properties of a metric are returned - * @param simple use simplified representation for complex metrics - instead of a (name, map) only - * the selected (name "." key, value) pairs will be produced. - * @param consumer consumer that accepts produced objects - */ - static void convertHistogram( - String name, - Histogram histogram, - Predicate propertyFilter, - boolean simple, - String separator, - BiConsumer consumer) { - Snapshot snapshot = histogram.getSnapshot(); - if (simple) { - if (propertyFilter.test(MEAN)) { - consumer.accept(name + separator + MEAN, snapshot.getMean()); - } - } else { - MapWriter writer = - ew -> { - String prop = "count"; - if (propertyFilter.test(prop)) { - ew.putNoEx(prop, histogram.getCount()); - } - // non-time based values - addSnapshot(ew, snapshot, propertyFilter, false); - }; - consumer.accept(name, writer); - } - } - // optionally convert ns to ms static double nsToMs(boolean convert, double value) { if (convert) { @@ -499,312 +99,6 @@ static double nsToMs(boolean convert, double value) { } } - // some snapshots represent time in ns, other snapshots represent raw values (eg. chunk size) - static void addSnapshot( - MapWriter.EntryWriter ew, - Snapshot snapshot, - Predicate propertyFilter, - boolean ms) { - BiConsumer filter = - (k, v) -> { - if (propertyFilter.test(k)) { - ew.putNoEx(k, v); - } - }; - filter.accept((ms ? MIN_MS : MIN), nsToMs(ms, (double) snapshot.getMin())); - filter.accept((ms ? MAX_MS : MAX), nsToMs(ms, (double) snapshot.getMax())); - filter.accept((ms ? MEAN_MS : MEAN), nsToMs(ms, snapshot.getMean())); - filter.accept((ms ? MEDIAN_MS : MEDIAN), nsToMs(ms, snapshot.getMedian())); - filter.accept((ms ? STDDEV_MS : STDDEV), nsToMs(ms, snapshot.getStdDev())); - filter.accept((ms ? P75_MS : P75), nsToMs(ms, snapshot.get75thPercentile())); - filter.accept((ms ? P95_MS : P95), nsToMs(ms, snapshot.get95thPercentile())); - filter.accept((ms ? P99_MS : P99), nsToMs(ms, snapshot.get99thPercentile())); - filter.accept((ms ? P999_MS : P999), nsToMs(ms, snapshot.get999thPercentile())); - } - - /** - * Convert a {@link Timer} to a map. - * - * @param name metric name - * @param timer timer instance - * @param propertyFilter limit what properties of a metric are returned - * @param skipHistograms if true then discard the histogram part of the timer. - * @param simple use simplified representation for complex metrics - instead of a (name, map) only - * the selected (name "." key, value) pairs will be produced. - * @param consumer consumer that accepts produced objects - */ - public static void convertTimer( - String name, - Timer timer, - Predicate propertyFilter, - boolean skipHistograms, - boolean simple, - String separator, - BiConsumer consumer) { - if (simple) { - String prop = "meanRate"; - if (propertyFilter.test(prop)) { - consumer.accept(name + separator + prop, timer.getMeanRate()); - } - } else { - MapWriter writer = - ew -> { - BiConsumer filter = - (k, v) -> { - if (propertyFilter.test(k)) { - ew.putNoEx(k, v); - } - }; - filter.accept("count", timer.getCount()); - filter.accept("meanRate", timer.getMeanRate()); - filter.accept("1minRate", timer.getOneMinuteRate()); - filter.accept("5minRate", timer.getFiveMinuteRate()); - filter.accept("15minRate", timer.getFifteenMinuteRate()); - if (!skipHistograms) { - // time-based values in nanoseconds - addSnapshot(ew, timer.getSnapshot(), propertyFilter, true); - } - }; - if (writer._size() > 0) { - consumer.accept(name, writer); - } - } - } - - /** - * Convert a {@link Meter} to a map. - * - * @param name metric name - * @param meter meter instance - * @param propertyFilter limit what properties of a metric are returned - * @param simple use simplified representation for complex metrics - instead of a (name, map) only - * the selected (name "." key, value) pairs will be produced. - * @param consumer consumer that accepts produced objects - */ - static void convertMeter( - String name, - Meter meter, - Predicate propertyFilter, - boolean simple, - String separator, - BiConsumer consumer) { - if (simple) { - if (propertyFilter.test("count")) { - consumer.accept(name + separator + "count", meter.getCount()); - } - } else { - MapWriter writer = - ew -> { - BiConsumer filter = - (k, v) -> { - if (propertyFilter.test(k)) { - ew.putNoEx(k, v); - } - }; - filter.accept("count", meter.getCount()); - filter.accept("meanRate", meter.getMeanRate()); - filter.accept("1minRate", meter.getOneMinuteRate()); - filter.accept("5minRate", meter.getFiveMinuteRate()); - filter.accept("15minRate", meter.getFifteenMinuteRate()); - }; - if (writer._size() > 0) { - consumer.accept(name, writer); - } - } - } - - static void convertMapWriter( - String name, - MapWriter metric, - Predicate propertyFilter, - boolean simple, - boolean compact, - String separator, - BiConsumer consumer) { - ConditionalKeyMapWriter filteredMetric = new ConditionalKeyMapWriter(metric, propertyFilter); - if (compact || simple) { - if (simple) { - filteredMetric._forEachEntry((k, v) -> consumer.accept(name + separator + k, v)); - } else { - if (filteredMetric._size() > 0) { - consumer.accept(name, filteredMetric); - } - } - } else { - if (filteredMetric._size() > 0) { - consumer.accept(name, (MapWriter) ew -> ew.putNoEx("value", filteredMetric)); - } - } - } - - /** - * Convert a {@link Gauge}. - * - * @param name metric name - * @param gauge gauge instance - * @param propertyFilter limit what properties of a metric are returned - * @param simple use simplified representation for complex metrics - instead of a (name, map) only - * the selected (name "." key, value) pairs will be produced. - * @param compact if true then only return {@link Gauge#getValue()}. If false then return a map - * with a "value" field. - * @param consumer consumer that accepts produced objects - */ - static void convertGauge( - String name, - Gauge gauge, - Predicate propertyFilter, - boolean simple, - boolean compact, - String separator, - BiConsumer consumer) { - if (compact || simple) { - Object o = gauge.getValue(); - if (o instanceof Map) { - if (simple) { - for (Map.Entry entry : ((Map) o).entrySet()) { - String prop = entry.getKey().toString(); - if (propertyFilter.test(prop)) { - consumer.accept(name + separator + prop, entry.getValue()); - } - } - } else { - boolean notEmpty = - ((Map) o) - .entrySet().stream() - .anyMatch(entry -> propertyFilter.test(entry.getKey().toString())); - MapWriter writer = - ew -> { - for (Map.Entry entry : ((Map) o).entrySet()) { - String prop = entry.getKey().toString(); - if (propertyFilter.test(prop)) { - ew.putNoEx(prop, entry.getValue()); - } - } - }; - if (notEmpty) { - consumer.accept(name, writer); - } - } - } else { - consumer.accept(name, o); - } - } else { - Object o = gauge.getValue(); - if (o instanceof Map) { - boolean notEmpty = - ((Map) o) - .entrySet().stream() - .anyMatch(entry -> propertyFilter.test(entry.getKey().toString())); - if (notEmpty) { - consumer.accept( - name, - (MapWriter) - ew -> { - ew.putNoEx( - "value", - (MapWriter) - ew1 -> { - for (Map.Entry entry : ((Map) o).entrySet()) { - String prop = entry.getKey().toString(); - if (propertyFilter.test(prop)) { - ew1.put(prop, entry.getValue()); - } - } - }); - }); - } - } else { - if (propertyFilter.test("value")) { - consumer.accept(name, (MapWriter) ew -> ew.putNoEx("value", o)); - } - } - } - } - - /** - * Convert a {@link Counter} - * - * @param counter counter instance - * @param propertyFilter limit what properties of a metric are returned - * @param compact if true then only return {@link Counter#getCount()}. If false then return a map - * with a "count" field. - */ - static void convertCounter( - String name, - Counter counter, - Predicate propertyFilter, - boolean compact, - BiConsumer consumer) { - if (compact) { - consumer.accept(name, counter.getCount()); - } else { - if (propertyFilter.test("count")) { - consumer.accept(name, (MapWriter) ew -> ew.putNoEx("count", counter.getCount())); - } - } - } - - /** - * Creates a set of metrics (gauges) that correspond to available bean properties for the provided - * MXBean. - * - * @param obj an instance of MXBean - * @param intf MXBean interface, one of {@link PlatformManagedObject}-s - * @param consumer consumer for created names and metrics - * @param formal type - */ - public static void addMXBeanMetrics( - T obj, Class intf, String prefix, BiConsumer consumer) { - if (intf.isInstance(obj)) { - BeanInfo beanInfo = - beanInfos.computeIfAbsent( - intf, - clazz -> { - try { - return Introspector.getBeanInfo( - clazz, clazz.getSuperclass(), Introspector.IGNORE_ALL_BEANINFO); - - } catch (IntrospectionException e) { - log.warn("Unable to fetch properties of MXBean {}", obj.getClass().getName()); - return null; - } - }); - - // if BeanInfo retrieval failed, return early - if (beanInfo == null) { - return; - } - for (final PropertyDescriptor desc : beanInfo.getPropertyDescriptors()) { - try { - Method readMethod = desc.getReadMethod(); - if (readMethod == null) { - continue; // skip properties without a read method - } - - final String name = desc.getName(); - // test if it works at all - readMethod.invoke(obj); - // worked - consume it - final Gauge gauge = - () -> { - try { - return readMethod.invoke(obj); - } catch (InvocationTargetException ite) { - // ignore (some properties throw UOE) - return null; - } catch (IllegalAccessException e) { - return null; - } - }; - String metricName = MetricRegistry.name(prefix, name); - consumer.accept(metricName, gauge); - } catch (Exception e) { - // didn't work, skip it... - } - } - } - } - /** * These are well-known implementations of {@link java.lang.management.OperatingSystemMXBean}. * Some of them provide additional useful properties beyond those declared by the interface. @@ -825,28 +119,4 @@ public static ExecutorService instrumentedExecutorService( String name) { return new OtelInstrumentedExecutorService(delegate, ctx, category, name); } - - /** - * Creates a set of metrics (gauges) that correspond to available bean properties for the provided - * MXBean. - * - * @param obj an instance of MXBean - * @param interfaces interfaces that it may implement. Each interface will be tried in turn, and - * only if it exists and if it contains unique properties then they will be added as metrics. - * @param prefix optional prefix for metric names - * @param consumer consumer for created names and metrics - * @param formal type - */ - public static void addMXBeanMetrics( - T obj, String[] interfaces, String prefix, BiConsumer consumer) { - for (String clazz : interfaces) { - try { - final Class intf = - Class.forName(clazz).asSubclass(PlatformManagedObject.class); - MetricUtils.addMXBeanMetrics(obj, intf, prefix, consumer); - } catch (ClassNotFoundException e) { - // ignore - } - } - } } diff --git a/solr/core/src/java/org/apache/solr/util/stats/OtelInstrumentedExecutorService.java b/solr/core/src/java/org/apache/solr/util/stats/OtelInstrumentedExecutorService.java index 2823826d4b5..b0d76fcc43c 100644 --- a/solr/core/src/java/org/apache/solr/util/stats/OtelInstrumentedExecutorService.java +++ b/solr/core/src/java/org/apache/solr/util/stats/OtelInstrumentedExecutorService.java @@ -43,8 +43,8 @@ import org.apache.solr.metrics.otel.instruments.AttributedLongUpDownCounter; /** - * OTEL instrumentation wrapper around {@link ExecutorService}. Based on {@link - * com.codahale.metrics.InstrumentedExecutorService}. + * OTEL instrumentation wrapper around {@link ExecutorService}. Based on + * com.codahale.metrics.InstrumentedExecutorService. */ public class OtelInstrumentedExecutorService implements ExecutorService { public static final AttributeKey EXECUTOR_NAME_ATTR = diff --git a/solr/core/src/test/org/apache/solr/SolrInfoBeanTest.java b/solr/core/src/test/org/apache/solr/SolrInfoBeanTest.java index e8e61bc5fe5..8b3c75bbaa1 100644 --- a/solr/core/src/test/org/apache/solr/SolrInfoBeanTest.java +++ b/solr/core/src/test/org/apache/solr/SolrInfoBeanTest.java @@ -25,7 +25,6 @@ import java.util.Enumeration; import java.util.List; import java.util.stream.Stream; -import org.apache.lucene.tests.util.TestUtil; import org.apache.solr.core.SolrInfoBean; import org.apache.solr.handler.admin.LukeRequestHandler; import org.apache.solr.handler.component.SearchComponent; @@ -59,14 +58,12 @@ public void testCallMBeanInfo() throws Exception { int checked = 0; SolrMetricManager metricManager = h.getCoreContainer().getMetricManager(); String registry = h.getCore().getCoreMetricManager().getRegistryName(); - SolrMetricsContext solrMetricsContext = new SolrMetricsContext(metricManager, registry, "foo"); - String scope = TestUtil.randomSimpleString(random(), 2, 10); + SolrMetricsContext solrMetricsContext = new SolrMetricsContext(metricManager, registry); for (Class clazz : classes) { if (SolrInfoBean.class.isAssignableFrom(clazz)) { try { SolrInfoBean info = clazz.asSubclass(SolrInfoBean.class).getConstructor().newInstance(); - // TODO SOLR-17458: Fix test later - info.initializeMetrics(solrMetricsContext, Attributes.empty(), scope); + info.initializeMetrics(solrMetricsContext, Attributes.empty()); // System.out.println( info.getClass() ); assertNotNull(info.getClass().getCanonicalName(), info.getName()); diff --git a/solr/core/src/test/org/apache/solr/blockcache/BufferStoreTest.java b/solr/core/src/test/org/apache/solr/blockcache/BufferStoreTest.java index f42067715a0..01687589ccb 100644 --- a/solr/core/src/test/org/apache/solr/blockcache/BufferStoreTest.java +++ b/solr/core/src/test/org/apache/solr/blockcache/BufferStoreTest.java @@ -41,9 +41,8 @@ public void setup() { metrics = new Metrics(); metricManager = new SolrMetricManager(null); registry = TestUtil.randomSimpleString(random(), 2, 10); - String scope = TestUtil.randomSimpleString(random(), 2, 10); - SolrMetricsContext solrMetricsContext = new SolrMetricsContext(metricManager, registry, "foo"); - metrics.initializeMetrics(solrMetricsContext, Attributes.empty(), scope); + SolrMetricsContext solrMetricsContext = new SolrMetricsContext(metricManager, registry); + metrics.initializeMetrics(solrMetricsContext, Attributes.empty()); BufferStore.initNewBuffer(blockSize, blockSize, metrics); store = BufferStore.instance(blockSize); } diff --git a/solr/core/src/test/org/apache/solr/cloud/CloudExitableDirectoryReaderTest.java b/solr/core/src/test/org/apache/solr/cloud/CloudExitableDirectoryReaderTest.java index 6ccce2788c9..8eb6daf2ceb 100644 --- a/solr/core/src/test/org/apache/solr/cloud/CloudExitableDirectoryReaderTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/CloudExitableDirectoryReaderTest.java @@ -23,8 +23,7 @@ import static org.apache.solr.cloud.TrollingIndexReaderFactory.catchTrace; import com.carrotsearch.randomizedtesting.annotations.Repeat; -import com.codahale.metrics.Metered; -import com.codahale.metrics.MetricRegistry; +import io.prometheus.metrics.model.snapshots.CounterSnapshot; import java.lang.invoke.MethodHandles; import java.util.LinkedHashMap; import java.util.Map; @@ -34,7 +33,6 @@ import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.request.UpdateRequest; import org.apache.solr.client.solrj.response.QueryResponse; -import org.apache.solr.cloud.MiniSolrCloudCluster.JettySolrRunnerWithMetrics; import org.apache.solr.common.cloud.DocCollection; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.SolrParams; @@ -58,7 +56,7 @@ public class CloudExitableDirectoryReaderTest extends SolrCloudTestCase { private static final String sleep = "2"; private static final String COLLECTION = "exitable"; - private static Map fiveHundredsByNode; + private static Map fiveHundredsByNode; /** * Client used for all test requests. @@ -100,23 +98,40 @@ public static void setupCluster() throws Exception { fiveHundredsByNode = new LinkedHashMap<>(); long httpOk = 0; for (JettySolrRunner jetty : cluster.getJettySolrRunners()) { - MetricRegistry metricRegistry = ((JettySolrRunnerWithMetrics) jetty).getMetricRegistry(); - - httpOk += - ((Metered) - metricRegistry - .getMetrics() - .get("org.eclipse.jetty.ee10.servlet.ServletContextHandler.2xx-responses")) - .getCount(); - - Metered old = - fiveHundredsByNode.put( - jetty.getNodeName(), - (Metered) - metricRegistry - .getMetrics() - .get("org.eclipse.jetty.ee10.servlet.ServletContextHandler.5xx-responses")); + var reader = + jetty.getCoreContainer().getMetricManager().getPrometheusMetricReader("solr.node"); + + var errorsSnapshots = reader.collect((name) -> name.equals("solr_node_requests_errors")); + long errorCount = 0L; + + if (errorsSnapshots.size() > 0) { + var errorSnapshot = + errorsSnapshots.stream().map(CounterSnapshot.class::cast).findFirst().orElse(null); + if (errorSnapshot != null) { + errorCount = + errorSnapshot.getDataPoints().stream() + .mapToLong((value) -> (long) value.getValue()) + .sum(); + } + } + + Long old = fiveHundredsByNode.put(jetty.getNodeName(), errorCount); assertNull("expecting uniq nodenames", old); + + var requestsSnapshots = reader.collect((name) -> name.equals("solr_node_requests")); + + if (requestsSnapshots.size() > 0) { + var requestsSnapshot = + requestsSnapshots.stream().map(CounterSnapshot.class::cast).findFirst().orElse(null); + if (requestsSnapshot != null) { + long totalRequests = (long) requestsSnapshot.getDataPoints().getFirst().getValue(); + // Calculate successful requests (total - errors) + long successfulRequests = totalRequests - errorCount; + httpOk += successfulRequests; + } + } + + assertTrue(reader.collect().size() > 0); } assertTrue("expecting some http activity during collection creation", httpOk > 0); indexDocs(); @@ -350,7 +365,8 @@ public boolean isPartial(QueryResponse rsp) { } public void assertNo500s(String msg) { - assertTrue(msg, fiveHundredsByNode.values().stream().allMatch((m) -> m.getCount() == 0)); + assertTrue( + msg, fiveHundredsByNode.values().stream().allMatch((errorCount) -> errorCount == 0L)); } /** execute a request, verify that we get an expected error */ diff --git a/solr/core/src/test/org/apache/solr/cloud/MigrateReplicasTest.java b/solr/core/src/test/org/apache/solr/cloud/MigrateReplicasTest.java index 296dcf001a5..b65643ca0f5 100644 --- a/solr/core/src/test/org/apache/solr/cloud/MigrateReplicasTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/MigrateReplicasTest.java @@ -19,7 +19,6 @@ import static java.nio.charset.StandardCharsets.UTF_8; -import com.codahale.metrics.Metric; import java.io.IOException; import java.lang.invoke.MethodHandles; import java.util.ArrayList; @@ -49,9 +48,10 @@ import org.apache.solr.common.cloud.ZkStateReader; import org.apache.solr.common.util.StrUtils; import org.apache.solr.common.util.Utils; +import org.apache.solr.core.CoreContainer; +import org.apache.solr.core.SolrInfoBean; import org.apache.solr.embedded.JettySolrRunner; -import org.apache.solr.metrics.MetricsMap; -import org.apache.solr.metrics.SolrMetricManager; +import org.apache.solr.util.SolrMetricTestUtils; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -203,37 +203,27 @@ public void test() throws Exception { // No cores on this node, ignore it continue; } - SolrMetricManager metricManager = jetty.getCoreContainer().getMetricManager(); - String registryName = null; - for (String name : metricManager.registryNames()) { - if (name.startsWith("solr.core.")) { - registryName = name; + + CoreContainer coreContainer = jetty.getCoreContainer(); + List coreNames = jetty.getCoreContainer().getAllCoreNames(); + for (String coreName : coreNames) { + try (var core = coreContainer.getCore(coreName)) { + var dp = + SolrMetricTestUtils.getGaugeDatapoint( + core, + "solr_replication_is_replicating", + SolrMetricTestUtils.newCloudLabelsBuilder(core) + .label("category", SolrInfoBean.Category.REPLICATION.toString()) + .label("handler", "/replication") + .build()); + if (dp == null) continue; + + double isReplicating = dp.getValue(); + assertTrue( + "solr_replication_is_replicating should be 0 or 1, got: " + isReplicating, + isReplicating == 0.0 || isReplicating == 1.0); } } - Map metrics = metricManager.registry(registryName).getMetrics(); - if (!metrics.containsKey("REPLICATION./replication.fetcher")) { - continue; - } - MetricsMap fetcherGauge = - (MetricsMap) - ((SolrMetricManager.GaugeWrapper) metrics.get("REPLICATION./replication.fetcher")) - .getGauge(); - assertNotNull("no IndexFetcher gauge in metrics", fetcherGauge); - Map value = fetcherGauge.getValue(); - if (value.isEmpty()) { - continue; - } - assertNotNull("isReplicating missing: " + value, value.get("isReplicating")); - assertTrue( - "isReplicating should be a boolean: " + value, - value.get("isReplicating") instanceof Boolean); - if (value.get("indexReplicatedAt") == null) { - continue; - } - assertNotNull("timesIndexReplicated missing: " + value, value.get("timesIndexReplicated")); - assertTrue( - "timesIndexReplicated should be a number: " + value, - value.get("timesIndexReplicated") instanceof Number); } } diff --git a/solr/core/src/test/org/apache/solr/cloud/PeerSyncReplicationTest.java b/solr/core/src/test/org/apache/solr/cloud/PeerSyncReplicationTest.java index 63637289262..c24bcba8481 100644 --- a/solr/core/src/test/org/apache/solr/cloud/PeerSyncReplicationTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/PeerSyncReplicationTest.java @@ -20,7 +20,7 @@ import static java.util.Collections.singletonList; import com.carrotsearch.randomizedtesting.generators.RandomStrings; -import com.codahale.metrics.MetricRegistry; +import io.opentelemetry.api.metrics.MeterProvider; import java.io.IOException; import java.lang.invoke.MethodHandles; import java.nio.file.Files; @@ -177,10 +177,10 @@ public void test() throws Exception { // assert metrics SolrMetricManager manager = nodePeerSynced.jetty.getCoreContainer().getMetricManager(); - MetricRegistry registry = null; + MeterProvider registry = null; for (String name : manager.registryNames()) { if (name.startsWith("solr.core.collection1")) { - registry = manager.registry(name); + registry = manager.meterProvider(name); break; } } diff --git a/solr/core/src/test/org/apache/solr/cloud/ReplaceNodeTest.java b/solr/core/src/test/org/apache/solr/cloud/ReplaceNodeTest.java index cb3305d92f7..d031196754b 100644 --- a/solr/core/src/test/org/apache/solr/cloud/ReplaceNodeTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/ReplaceNodeTest.java @@ -20,13 +20,11 @@ import static org.apache.solr.common.params.CollectionParams.SOURCE_NODE; import static org.apache.solr.common.params.CollectionParams.TARGET_NODE; -import com.codahale.metrics.Metric; import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.apache.solr.client.solrj.SolrClient; @@ -43,9 +41,10 @@ import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.StrUtils; +import org.apache.solr.core.CoreContainer; +import org.apache.solr.core.SolrInfoBean; import org.apache.solr.embedded.JettySolrRunner; -import org.apache.solr.metrics.MetricsMap; -import org.apache.solr.metrics.SolrMetricManager; +import org.apache.solr.util.SolrMetricTestUtils; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -183,37 +182,26 @@ public void test() throws Exception { // No cores on this node, ignore it continue; } - SolrMetricManager metricManager = jetty.getCoreContainer().getMetricManager(); - String registryName = null; - for (String name : metricManager.registryNames()) { - if (name.startsWith("solr.core.")) { - registryName = name; + CoreContainer coreContainer = jetty.getCoreContainer(); + List coreNames = jetty.getCoreContainer().getAllCoreNames(); + for (String coreName : coreNames) { + try (var core = coreContainer.getCore(coreName)) { + var dp = + SolrMetricTestUtils.getGaugeDatapoint( + core, + "solr_replication_is_replicating", + SolrMetricTestUtils.newCloudLabelsBuilder(core) + .label("category", SolrInfoBean.Category.REPLICATION.toString()) + .label("handler", "/replication") + .build()); + if (dp == null) continue; + + double isReplicating = dp.getValue(); + assertTrue( + "solr_replication_is_replicating should be 0 or 1, got: " + isReplicating, + isReplicating == 0.0 || isReplicating == 1.0); } } - Map metrics = metricManager.registry(registryName).getMetrics(); - if (!metrics.containsKey("REPLICATION./replication.fetcher")) { - continue; - } - MetricsMap fetcherGauge = - (MetricsMap) - ((SolrMetricManager.GaugeWrapper) metrics.get("REPLICATION./replication.fetcher")) - .getGauge(); - assertNotNull("no IndexFetcher gauge in metrics", fetcherGauge); - Map value = fetcherGauge.getValue(); - if (value.isEmpty()) { - continue; - } - assertNotNull("isReplicating missing: " + value, value.get("isReplicating")); - assertTrue( - "isReplicating should be a boolean: " + value, - value.get("isReplicating") instanceof Boolean); - if (value.get("indexReplicatedAt") == null) { - continue; - } - assertNotNull("timesIndexReplicated missing: " + value, value.get("timesIndexReplicated")); - assertTrue( - "timesIndexReplicated should be a number: " + value, - value.get("timesIndexReplicated") instanceof Number); } } diff --git a/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java b/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java index 09c700cfee1..438b693e2ee 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java @@ -269,7 +269,6 @@ static void assertUlogPresence(DocCollection collection) { } } - @SuppressWarnings("unchecked") public void testAddDocs() throws Exception { int numPullReplicas = 1 + random().nextInt(3); CollectionAdminRequest.createCollection(collectionName, "conf", 1, 1, 0, numPullReplicas) diff --git a/solr/core/src/test/org/apache/solr/cluster/placement/impl/PlacementPluginIntegrationTest.java b/solr/core/src/test/org/apache/solr/cluster/placement/impl/PlacementPluginIntegrationTest.java index e8997c0a0d2..0c81722721c 100644 --- a/solr/core/src/test/org/apache/solr/cluster/placement/impl/PlacementPluginIntegrationTest.java +++ b/solr/core/src/test/org/apache/solr/cluster/placement/impl/PlacementPluginIntegrationTest.java @@ -385,8 +385,6 @@ public void testWithCollectionIntegration() throws Exception { // this functionality relies on System.getProperty which we cannot set on individual // nodes in a mini cluster. For this reason this test is very basic - see // AffinityPlacementFactoryTest for a more comprehensive test. - // NOCOMMIT: This test fails because of CollectionMetricsBuilder. Need to dive deeper into what - // this is and if we need to shim otel into this metrics map. @Test public void testNodeTypeIntegration() throws Exception { // this functionality relies on System.getProperty which we cannot set on individual diff --git a/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java b/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java index 3c3105923bf..29a1844869f 100644 --- a/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java +++ b/solr/core/src/test/org/apache/solr/core/TestHttpSolrClientProvider.java @@ -18,9 +18,8 @@ import static org.apache.solr.SolrTestCaseJ4.assumeWorkingMockito; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; +import io.opentelemetry.api.metrics.LongHistogram; import org.apache.solr.SolrTestCase; import org.apache.solr.client.solrj.impl.SolrHttpConstants; import org.apache.solr.metrics.SolrMetricsContext; @@ -39,6 +38,10 @@ public void setUp() throws Exception { super.setUp(); assumeWorkingMockito(); parentSolrMetricCtx = Mockito.mock(SolrMetricsContext.class); + SolrMetricsContext childContext = Mockito.mock(SolrMetricsContext.class); + LongHistogram mockHistogram = Mockito.mock(LongHistogram.class); + Mockito.when(parentSolrMetricCtx.getChildContext(any())).thenReturn(childContext); + Mockito.when(childContext.longHistogram(any(), any(), any())).thenReturn(mockHistogram); } @Test @@ -59,16 +62,4 @@ public void test_when_updateShardHandler_cfg_is_not_null() { assertEquals(httpSolrClientProvider.getSolrClient().getIdleTimeout(), idleTimeout); } } - - @Test - public void test_closing_solr_metric_context() { - SolrMetricsContext childSolrMetricContext = Mockito.mock(SolrMetricsContext.class); - Mockito.when(parentSolrMetricCtx.getChildContext(any(HttpSolrClientProvider.class))) - .thenReturn(childSolrMetricContext); - try (var httpSolrClientProvider = new HttpSolrClientProvider(null, parentSolrMetricCtx)) { - assertNotNull(httpSolrClientProvider.getSolrClient()); - } finally { - verify(childSolrMetricContext, times(1)).unregister(); - } - } } diff --git a/solr/core/src/test/org/apache/solr/handler/RequestHandlerBaseTest.java b/solr/core/src/test/org/apache/solr/handler/RequestHandlerBaseTest.java index 2320b526b08..b1a88291a2d 100644 --- a/solr/core/src/test/org/apache/solr/handler/RequestHandlerBaseTest.java +++ b/solr/core/src/test/org/apache/solr/handler/RequestHandlerBaseTest.java @@ -27,9 +27,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import com.codahale.metrics.Counter; -import com.codahale.metrics.Meter; -import com.codahale.metrics.Timer; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongCounter; @@ -189,9 +186,6 @@ private RequestHandlerBase.HandlerMetrics createHandlerMetrics() { final SolrMetricsContext metricsContext = mock(SolrMetricsContext.class); when(metricsContext.getRegistryName()).thenReturn("solr.core"); - when(metricsContext.timer(any(), any())).thenReturn(mock(Timer.class)); - when(metricsContext.meter(any(), any())).then(invocation -> mock(Meter.class)); - when(metricsContext.counter(any(), any())).thenReturn(mock(Counter.class)); when(metricsContext.longCounter(any(), any())).thenReturn(mockLongCounter); when(metricsContext.longHistogram(any(), any())).thenReturn(mockLongHistogram); diff --git a/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java b/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java index cdc9ca26494..14c03db7650 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java @@ -71,20 +71,6 @@ public void proxySystemInfoHandlerAllNodes() throws IOException, SolrServerExcep assertEquals(nl.getName(2), ((NamedList) nl.get(nl.getName(2))).get("node")); } - @Test - public void proxyMetricsHandlerAllNodes() throws IOException, SolrServerException { - MapSolrParams params = new MapSolrParams(Collections.singletonMap("nodes", "all")); - GenericSolrRequest req = - new GenericSolrRequest( - SolrRequest.METHOD.GET, "/admin/metrics", SolrRequest.SolrRequestType.ADMIN, params); - SimpleSolrResponse rsp = req.process(solrClient, null); - NamedList nl = rsp.getResponse(); - assertEquals(3, nl.size()); - assertTrue(nl.getName(1).endsWith("_solr")); - assertTrue(nl.getName(2).endsWith("_solr")); - assertNotNull(((NamedList) nl.get(nl.getName(1))).get("metrics")); - } - @Test(expected = SolrException.class) public void proxySystemInfoHandlerNonExistingNode() throws IOException, SolrServerException { MapSolrParams params = diff --git a/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java b/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java index 6cb09d3d95d..f2ea61a9fb5 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java @@ -25,7 +25,6 @@ import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.params.CommonParams; import org.apache.solr.handler.RequestHandlerBase; -import org.apache.solr.metrics.MetricsMap; import org.apache.solr.metrics.SolrMetricsContext; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.SolrQueryResponse; @@ -277,11 +276,8 @@ public String getDescription() { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { - super.initializeMetrics(parentContext, attributes, scope); - MetricsMap metrics = new MetricsMap(map -> gaugevals.forEach((k, v) -> map.putNoEx(k, v))); - solrMetricsContext.gauge(metrics, true, "dumphandlergauge", getCategory().toString(), scope); + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { + super.initializeMetrics(parentContext, attributes); } @Override diff --git a/solr/core/src/test/org/apache/solr/handler/admin/SystemInfoHandlerTest.java b/solr/core/src/test/org/apache/solr/handler/admin/SystemInfoHandlerTest.java index d9998ee109f..363de728439 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/SystemInfoHandlerTest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/SystemInfoHandlerTest.java @@ -16,13 +16,11 @@ */ package org.apache.solr.handler.admin; -import com.codahale.metrics.Gauge; import java.lang.management.ManagementFactory; import java.lang.management.OperatingSystemMXBean; import java.util.Arrays; import org.apache.solr.SolrTestCase; import org.apache.solr.common.util.SimpleOrderedMap; -import org.apache.solr.util.stats.MetricUtils; public class SystemInfoHandlerTest extends SolrTestCase { @@ -38,13 +36,7 @@ public void testMagickGetter() { // make another using MetricUtils.addMXBeanMetrics() SimpleOrderedMap info2 = new SimpleOrderedMap<>(); - MetricUtils.addMXBeanMetrics( - os, - OperatingSystemMXBean.class, - null, - (k, v) -> { - info2.add(k, ((Gauge) v).getValue()); - }); + SystemInfoHandler.forEachGetterValue(os, OperatingSystemMXBean.class, info2::add); // make sure they got the same thing for (String p : Arrays.asList("name", "version", "arch")) { diff --git a/solr/core/src/test/org/apache/solr/metrics/DelegateRegistryTimerTest.java b/solr/core/src/test/org/apache/solr/metrics/DelegateRegistryTimerTest.java deleted file mode 100644 index 71e816fa4f3..00000000000 --- a/solr/core/src/test/org/apache/solr/metrics/DelegateRegistryTimerTest.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * 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.solr.metrics; - -import com.codahale.metrics.Clock; -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.Timer; -import java.time.Duration; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; -import org.apache.solr.SolrTestCase; -import org.junit.Test; - -public class DelegateRegistryTimerTest extends SolrTestCase { - - MetricRegistry.MetricSupplier timerSupplier = - new MetricSuppliers.DefaultTimerSupplier(null); - - @Test - public void update() { - DelegateRegistryTimer delegateRegistryTimer = - new DelegateRegistryTimer( - Clock.defaultClock(), timerSupplier.newMetric(), timerSupplier.newMetric()); - delegateRegistryTimer.update(Duration.ofNanos(100)); - assertEquals(1, delegateRegistryTimer.getPrimaryTimer().getCount()); - assertEquals(100.0, delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMean(), 0.0); - assertEquals(100.0, delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMedian(), 0.0); - assertEquals(100L, delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMax()); - assertEquals(100.0, delegateRegistryTimer.getSnapshot().getMean(), 0.0); - assertEquals(100.0, delegateRegistryTimer.getSnapshot().getMedian(), 0.0); - assertEquals(100L, delegateRegistryTimer.getSnapshot().getMax()); - assertEquals(1, delegateRegistryTimer.getDelegateTimer().getCount()); - assertEquals(100.0, delegateRegistryTimer.getDelegateTimer().getSnapshot().getMean(), 0.0); - assertEquals(100.0, delegateRegistryTimer.getDelegateTimer().getSnapshot().getMedian(), 0.0); - assertEquals(100L, delegateRegistryTimer.getDelegateTimer().getSnapshot().getMax()); - - delegateRegistryTimer.update(Duration.ofNanos(200)); - delegateRegistryTimer.update(Duration.ofNanos(300)); - assertEquals(3, delegateRegistryTimer.getPrimaryTimer().getCount()); - assertEquals(200.0, delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMean(), 0.0); - assertEquals(200.0, delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMedian(), 0.0); - assertEquals(300L, delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMax()); - assertEquals(200.0, delegateRegistryTimer.getSnapshot().getMean(), 0.0); - assertEquals(200.0, delegateRegistryTimer.getSnapshot().getMedian(), 0.0); - assertEquals(300L, delegateRegistryTimer.getSnapshot().getMax()); - assertEquals(3, delegateRegistryTimer.getDelegateTimer().getCount()); - assertEquals(200.0, delegateRegistryTimer.getDelegateTimer().getSnapshot().getMean(), 0.0); - assertEquals(200.0, delegateRegistryTimer.getDelegateTimer().getSnapshot().getMedian(), 0.0); - assertEquals(300L, delegateRegistryTimer.getDelegateTimer().getSnapshot().getMax()); - } - - @Test - public void testUpdate() { - DelegateRegistryTimer delegateRegistryTimer = - new DelegateRegistryTimer( - Clock.defaultClock(), timerSupplier.newMetric(), timerSupplier.newMetric()); - delegateRegistryTimer.update(100, TimeUnit.NANOSECONDS); - assertEquals(1, delegateRegistryTimer.getPrimaryTimer().getCount()); - assertEquals(100, delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMean(), 0.0); - assertEquals(100, delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMedian(), 0.0); - assertEquals(100L, delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMax()); - assertEquals(100, delegateRegistryTimer.getSnapshot().getMean(), 0.0); - assertEquals(100, delegateRegistryTimer.getSnapshot().getMedian(), 0.0); - assertEquals(100L, delegateRegistryTimer.getSnapshot().getMax()); - assertEquals(1, delegateRegistryTimer.getDelegateTimer().getCount()); - assertEquals(100, delegateRegistryTimer.getDelegateTimer().getSnapshot().getMean(), 0.0); - assertEquals(100, delegateRegistryTimer.getDelegateTimer().getSnapshot().getMedian(), 0.0); - assertEquals(100L, delegateRegistryTimer.getDelegateTimer().getSnapshot().getMax()); - - delegateRegistryTimer.update(200, TimeUnit.NANOSECONDS); - delegateRegistryTimer.update(300, TimeUnit.NANOSECONDS); - assertEquals(3, delegateRegistryTimer.getPrimaryTimer().getCount()); - assertEquals(200, delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMean(), 0.0); - assertEquals(200, delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMedian(), 0.0); - assertEquals(300L, delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMax()); - assertEquals(200, delegateRegistryTimer.getSnapshot().getMean(), 0.0); - assertEquals(200, delegateRegistryTimer.getSnapshot().getMedian(), 0.0); - assertEquals(300L, delegateRegistryTimer.getSnapshot().getMax()); - assertEquals(3, delegateRegistryTimer.getDelegateTimer().getCount()); - assertEquals(200, delegateRegistryTimer.getDelegateTimer().getSnapshot().getMean(), 0.0); - assertEquals(200, delegateRegistryTimer.getDelegateTimer().getSnapshot().getMedian(), 0.0); - assertEquals(300L, delegateRegistryTimer.getDelegateTimer().getSnapshot().getMax()); - } - - @Test - public void timeContext() throws InterruptedException { - DelegateRegistryTimer delegateRegistryTimer = - new DelegateRegistryTimer( - Clock.defaultClock(), timerSupplier.newMetric(), timerSupplier.newMetric()); - Timer.Context time = delegateRegistryTimer.time(); - Thread.sleep(100); - time.close(); - assertTrue(delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMean() > 100000); - assertTrue(delegateRegistryTimer.getDelegateTimer().getSnapshot().getMean() > 100000); - assertEquals( - delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMean(), - delegateRegistryTimer.getDelegateTimer().getSnapshot().getMean(), - 0.0); - assertEquals( - delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMean(), - delegateRegistryTimer.getSnapshot().getMean(), - 0.0); - } - - @Test - public void timeSupplier() { - DelegateRegistryTimer delegateRegistryTimer = - new DelegateRegistryTimer( - Clock.defaultClock(), timerSupplier.newMetric(), timerSupplier.newMetric()); - AtomicLong timeTaken = new AtomicLong(); - Long supplierResult = - delegateRegistryTimer.timeSupplier( - () -> { - timeTaken.getAndSet(System.nanoTime()); - for (int i = 0; i < 100; i++) { - // Just loop - } - timeTaken.getAndSet(System.nanoTime() - timeTaken.get()); - return 1L; - }); - assertEquals(Long.valueOf(1L), supplierResult); - assertEquals(1, delegateRegistryTimer.getPrimaryTimer().getCount()); - assertEquals(1, delegateRegistryTimer.getDelegateTimer().getCount()); - assertTrue(delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMean() > timeTaken.get()); - assertTrue(delegateRegistryTimer.getDelegateTimer().getSnapshot().getMean() > timeTaken.get()); - assertEquals( - delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMean(), - delegateRegistryTimer.getDelegateTimer().getSnapshot().getMean(), - 0.0); - assertEquals( - delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMean(), - delegateRegistryTimer.getSnapshot().getMean(), - 0.0); - } - - @Test - public void testTimeCallable() throws Exception { - DelegateRegistryTimer delegateRegistryTimer = - new DelegateRegistryTimer( - Clock.defaultClock(), timerSupplier.newMetric(), timerSupplier.newMetric()); - AtomicLong timeTaken = new AtomicLong(); - Long callableResult = - delegateRegistryTimer.time( - () -> { - timeTaken.getAndSet(System.nanoTime()); - for (int i = 0; i < 100; i++) { - // Just loop - } - timeTaken.getAndSet(System.nanoTime() - timeTaken.get()); - return 1L; - }); - assertEquals(Long.valueOf(1L), callableResult); - assertEquals(1, delegateRegistryTimer.getPrimaryTimer().getCount()); - assertEquals(1, delegateRegistryTimer.getDelegateTimer().getCount()); - assertTrue(delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMean() > timeTaken.get()); - assertTrue(delegateRegistryTimer.getDelegateTimer().getSnapshot().getMean() > timeTaken.get()); - assertEquals( - delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMean(), - delegateRegistryTimer.getDelegateTimer().getSnapshot().getMean(), - 0.0); - assertEquals( - delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMean(), - delegateRegistryTimer.getSnapshot().getMean(), - 0.0); - } - - @Test - public void testTimeRunnable() { - DelegateRegistryTimer delegateRegistryTimer = - new DelegateRegistryTimer( - Clock.defaultClock(), timerSupplier.newMetric(), timerSupplier.newMetric()); - AtomicLong timeTaken = new AtomicLong(); - delegateRegistryTimer.time( - () -> { - timeTaken.getAndSet(System.nanoTime()); - for (int i = 0; i < 100; i++) { - // Just loop - } - timeTaken.getAndSet(System.nanoTime() - timeTaken.get()); - }); - assertEquals(1, delegateRegistryTimer.getPrimaryTimer().getCount()); - assertEquals(1, delegateRegistryTimer.getDelegateTimer().getCount()); - assertTrue(delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMean() > timeTaken.get()); - assertTrue(delegateRegistryTimer.getDelegateTimer().getSnapshot().getMean() > timeTaken.get()); - assertEquals( - delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMean(), - delegateRegistryTimer.getDelegateTimer().getSnapshot().getMean(), - 0.0); - assertEquals( - delegateRegistryTimer.getPrimaryTimer().getSnapshot().getMean(), - delegateRegistryTimer.getSnapshot().getMean(), - 0.0); - } -} diff --git a/solr/core/src/test/org/apache/solr/metrics/MetricsConfigTest.java b/solr/core/src/test/org/apache/solr/metrics/MetricsConfigTest.java deleted file mode 100644 index eff63f4db72..00000000000 --- a/solr/core/src/test/org/apache/solr/metrics/MetricsConfigTest.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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.solr.metrics; - -import com.codahale.metrics.Clock; -import com.codahale.metrics.ExponentiallyDecayingReservoir; -import com.codahale.metrics.Reservoir; -import com.codahale.metrics.SlidingTimeWindowReservoir; -import com.codahale.metrics.UniformReservoir; -import java.io.InputStream; -import java.util.Map; -import java.util.Properties; -import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.core.NodeConfig; -import org.apache.solr.core.SolrXmlConfig; -import org.junit.Test; - -/** */ -public class MetricsConfigTest extends SolrTestCaseJ4 { - @Test - public void testDefaults() { - NodeConfig cfg = loadNodeConfig("solr-metricsconfig.xml"); - SolrMetricManager mgr = - new SolrMetricManager(cfg.getSolrResourceLoader(), cfg.getMetricsConfig()); - assertTrue(mgr.getCounterSupplier() instanceof MetricSuppliers.DefaultCounterSupplier); - assertTrue(mgr.getMeterSupplier() instanceof MetricSuppliers.DefaultMeterSupplier); - assertTrue(mgr.getTimerSupplier() instanceof MetricSuppliers.DefaultTimerSupplier); - assertTrue(mgr.getHistogramSupplier() instanceof MetricSuppliers.DefaultHistogramSupplier); - Clock clk = ((MetricSuppliers.DefaultTimerSupplier) mgr.getTimerSupplier()).clk; - assertTrue(clk instanceof Clock.UserTimeClock); - Reservoir rsv = ((MetricSuppliers.DefaultTimerSupplier) mgr.getTimerSupplier()).getReservoir(); - assertTrue(rsv instanceof ExponentiallyDecayingReservoir); - } - - @Test - public void testCustomReservoir() { - System.setProperty("timer.reservoir", UniformReservoir.class.getName()); - System.setProperty("histogram.size", "2048"); - System.setProperty("histogram.window", "600"); - System.setProperty("histogram.reservoir", SlidingTimeWindowReservoir.class.getName()); - NodeConfig cfg = loadNodeConfig("solr-metricsconfig.xml"); - SolrMetricManager mgr = - new SolrMetricManager(cfg.getSolrResourceLoader(), cfg.getMetricsConfig()); - assertTrue(mgr.getCounterSupplier() instanceof MetricSuppliers.DefaultCounterSupplier); - assertTrue(mgr.getMeterSupplier() instanceof MetricSuppliers.DefaultMeterSupplier); - assertTrue(mgr.getTimerSupplier() instanceof MetricSuppliers.DefaultTimerSupplier); - assertTrue(mgr.getHistogramSupplier() instanceof MetricSuppliers.DefaultHistogramSupplier); - Reservoir rsv = ((MetricSuppliers.DefaultTimerSupplier) mgr.getTimerSupplier()).getReservoir(); - assertTrue(rsv instanceof UniformReservoir); - rsv = ((MetricSuppliers.DefaultHistogramSupplier) mgr.getHistogramSupplier()).getReservoir(); - assertTrue(rsv instanceof SlidingTimeWindowReservoir); - } - - @Test - public void testCustomSupplier() { - System.setProperty("counter.class", MockCounterSupplier.class.getName()); - System.setProperty("meter.class", MockMeterSupplier.class.getName()); - System.setProperty("timer.class", MockTimerSupplier.class.getName()); - System.setProperty("histogram.class", MockHistogramSupplier.class.getName()); - NodeConfig cfg = loadNodeConfig("solr-metricsconfig.xml"); - SolrMetricManager mgr = - new SolrMetricManager(cfg.getSolrResourceLoader(), cfg.getMetricsConfig()); - assertTrue(mgr.getCounterSupplier() instanceof MockCounterSupplier); - assertTrue(mgr.getMeterSupplier() instanceof MockMeterSupplier); - assertTrue(mgr.getTimerSupplier() instanceof MockTimerSupplier); - assertTrue(mgr.getHistogramSupplier() instanceof MockHistogramSupplier); - - // assert setter-based configuration - MockCounterSupplier mockCounterSupplier = ((MockCounterSupplier) mgr.getCounterSupplier()); - assertEquals("bar", mockCounterSupplier.foo); - MockMeterSupplier mockMeterSupplier = ((MockMeterSupplier) mgr.getMeterSupplier()); - assertEquals("bar", mockMeterSupplier.foo); - MockTimerSupplier mockTimerSupplier = ((MockTimerSupplier) mgr.getTimerSupplier()); - assertTrue(mockTimerSupplier.boolParam); - assertEquals("strParam", mockTimerSupplier.strParam); - assertEquals(-100, mockTimerSupplier.intParam); - - // assert PluginInfoInitialized-based configuration - MockHistogramSupplier mockHistogramSupplier = - ((MockHistogramSupplier) mgr.getHistogramSupplier()); - assertNotNull(mockHistogramSupplier.info); - } - - @Test - public void testDisabledMetrics() { - System.setProperty("metricsEnabled", "false"); - NodeConfig cfg = loadNodeConfig("solr-metricsconfig.xml"); - SolrMetricManager mgr = - new SolrMetricManager(cfg.getSolrResourceLoader(), cfg.getMetricsConfig()); - assertTrue(mgr.getCounterSupplier() instanceof MetricSuppliers.NoOpCounterSupplier); - assertTrue(mgr.getMeterSupplier() instanceof MetricSuppliers.NoOpMeterSupplier); - assertTrue(mgr.getTimerSupplier() instanceof MetricSuppliers.NoOpTimerSupplier); - assertTrue(mgr.getHistogramSupplier() instanceof MetricSuppliers.NoOpHistogramSupplier); - } - - @Test - public void testMissingValuesConfig() { - NodeConfig cfg = loadNodeConfig("solr-metricsconfig1.xml"); - SolrMetricManager mgr = - new SolrMetricManager(cfg.getSolrResourceLoader(), cfg.getMetricsConfig()); - assertNull("nullNumber", mgr.nullNumber()); - assertEquals("notANumber", -1, mgr.notANumber()); - assertEquals("nullNumber", "", mgr.nullString()); - assertTrue("nullObject", mgr.nullObject() instanceof Map); - @SuppressWarnings("unchecked") - Map map = (Map) mgr.nullObject(); - assertEquals("missing", map.get("value")); - } - - private NodeConfig loadNodeConfig(String config) { - InputStream is = MetricsConfigTest.class.getResourceAsStream("/solr/" + config); - return SolrXmlConfig.fromInputStream(TEST_PATH(), is, new Properties()); // TODO pass in props - } -} diff --git a/solr/core/src/test/org/apache/solr/metrics/MetricsDisabledCloudTest.java b/solr/core/src/test/org/apache/solr/metrics/MetricsDisabledCloudTest.java deleted file mode 100644 index 2b3f50b0a4d..00000000000 --- a/solr/core/src/test/org/apache/solr/metrics/MetricsDisabledCloudTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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.solr.metrics; - -import com.codahale.metrics.MetricRegistry; -import org.apache.solr.client.solrj.request.CollectionAdminRequest; -import org.apache.solr.cloud.SolrCloudTestCase; -import org.apache.solr.core.MetricsConfig; -import org.apache.solr.core.NodeConfig; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; - -/** */ -public class MetricsDisabledCloudTest extends SolrCloudTestCase { - - @BeforeClass - public static void startCluster() throws Exception { - System.setProperty("metricsEnabled", "false"); - configureCluster(2).configure(); - CollectionAdminRequest.createCollection("test", "config", 1, 2); - } - - @Test - public void testBasic() { - NodeConfig cfg = cluster.getRandomJetty(random()).getCoreContainer().getNodeConfig(); - MetricsConfig metricsConfig = cfg.getMetricsConfig(); - assertFalse("metrics should be disabled", metricsConfig.isEnabled()); - SolrMetricManager metricManager = - cluster.getRandomJetty(random()).getCoreContainer().getMetricManager(); - assertTrue( - "wrong type of supplier: " + metricManager.getCounterSupplier(), - metricManager.getCounterSupplier() instanceof MetricSuppliers.NoOpCounterSupplier); - assertTrue( - "wrong type of supplier: " + metricManager.getHistogramSupplier(), - metricManager.getHistogramSupplier() instanceof MetricSuppliers.NoOpHistogramSupplier); - assertTrue( - "wrong type of supplier: " + metricManager.getTimerSupplier(), - metricManager.getTimerSupplier() instanceof MetricSuppliers.NoOpTimerSupplier); - assertTrue( - "wrong type of supplier: " + metricManager.getMeterSupplier(), - metricManager.getMeterSupplier() instanceof MetricSuppliers.NoOpMeterSupplier); - for (String registryName : metricManager.registryNames()) { - if (!registryName.startsWith("solr.core.")) { - continue; - } - MetricRegistry registry = metricManager.registry(registryName); - registry - .getMetrics() - .forEach( - (name, metric) -> { - assertTrue( - "should be NoOpMetric but was: " - + name - + "=" - + metric - + "(" - + metric.getClass() - + ")", - metric instanceof MetricSuppliers.NoOpMetric); - }); - } - } - - @AfterClass - public static void stopCluster() throws Exception { - shutdownCluster(); - } -} diff --git a/solr/core/src/test/org/apache/solr/metrics/MockCounterSupplier.java b/solr/core/src/test/org/apache/solr/metrics/MockCounterSupplier.java deleted file mode 100644 index 702a390d73e..00000000000 --- a/solr/core/src/test/org/apache/solr/metrics/MockCounterSupplier.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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.solr.metrics; - -import com.codahale.metrics.Counter; -import com.codahale.metrics.MetricRegistry; - -/** */ -public class MockCounterSupplier implements MetricRegistry.MetricSupplier { - public String foo; - - public void setFoo(String foo) { - this.foo = foo; - } - - @Override - public Counter newMetric() { - return new Counter(); - } -} diff --git a/solr/core/src/test/org/apache/solr/metrics/MockHistogramSupplier.java b/solr/core/src/test/org/apache/solr/metrics/MockHistogramSupplier.java deleted file mode 100644 index 4bba36842cc..00000000000 --- a/solr/core/src/test/org/apache/solr/metrics/MockHistogramSupplier.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.solr.metrics; - -import com.codahale.metrics.ExponentiallyDecayingReservoir; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.MetricRegistry; -import org.apache.solr.core.PluginInfo; -import org.apache.solr.util.plugin.PluginInfoInitialized; - -/** */ -public class MockHistogramSupplier - implements MetricRegistry.MetricSupplier, PluginInfoInitialized { - public PluginInfo info; - - @Override - public Histogram newMetric() { - return new Histogram(new ExponentiallyDecayingReservoir()); - } - - @Override - public void init(PluginInfo info) { - this.info = info; - } -} diff --git a/solr/core/src/test/org/apache/solr/metrics/MockMeterSupplier.java b/solr/core/src/test/org/apache/solr/metrics/MockMeterSupplier.java deleted file mode 100644 index eca764d6e31..00000000000 --- a/solr/core/src/test/org/apache/solr/metrics/MockMeterSupplier.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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.solr.metrics; - -import com.codahale.metrics.Meter; -import com.codahale.metrics.MetricRegistry; - -/** */ -public class MockMeterSupplier implements MetricRegistry.MetricSupplier { - public String foo; - - public void setFoo(String foo) { - this.foo = foo; - } - - @Override - public Meter newMetric() { - return new Meter(); - } -} diff --git a/solr/core/src/test/org/apache/solr/metrics/MockTimerSupplier.java b/solr/core/src/test/org/apache/solr/metrics/MockTimerSupplier.java deleted file mode 100644 index 599abc7ef89..00000000000 --- a/solr/core/src/test/org/apache/solr/metrics/MockTimerSupplier.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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.solr.metrics; - -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.Timer; - -/** */ -public class MockTimerSupplier implements MetricRegistry.MetricSupplier { - public boolean boolParam; - public String strParam; - public int intParam; - - public void setBoolParam(boolean boolParam) { - this.boolParam = boolParam; - } - - public void setStrParam(String strParam) { - this.strParam = strParam; - } - - public void setIntParam(int intParam) { - this.intParam = intParam; - } - - @Override - public Timer newMetric() { - return new Timer(); - } -} diff --git a/solr/core/src/test/org/apache/solr/metrics/SolrCoreMetricManagerTest.java b/solr/core/src/test/org/apache/solr/metrics/SolrCoreMetricManagerTest.java index a124ad26e11..cc317633daf 100644 --- a/solr/core/src/test/org/apache/solr/metrics/SolrCoreMetricManagerTest.java +++ b/solr/core/src/test/org/apache/solr/metrics/SolrCoreMetricManagerTest.java @@ -16,55 +16,42 @@ */ package org.apache.solr.metrics; -import com.codahale.metrics.Counter; -import com.codahale.metrics.Metric; -import com.codahale.metrics.MetricRegistry; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.prometheus.metrics.model.snapshots.CounterSnapshot; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Random; -import java.util.stream.Collectors; -import org.apache.lucene.tests.util.TestUtil; import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.common.params.CoreAdminParams; import org.apache.solr.common.params.MapSolrParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.params.UpdateParams; import org.apache.solr.core.CoreContainer; -import org.apache.solr.core.PluginInfo; import org.apache.solr.core.SolrCore; import org.apache.solr.core.SolrInfoBean; -import org.apache.solr.metrics.reporters.MockMetricReporter; import org.apache.solr.request.SolrQueryRequestBase; -import org.apache.solr.schema.FieldType; import org.apache.solr.update.CommitUpdateCommand; import org.apache.solr.util.SolrMetricTestUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; -// NOCOMMIT: Need to fix up these tests to use the new SolrMetricTestUtils once we move off of -// Dropwizard public class SolrCoreMetricManagerTest extends SolrTestCaseJ4 { private static final int MAX_ITERATIONS = 100; private SolrCoreMetricManager coreMetricManager; - private SolrMetricManager metricManager; @Before public void beforeTest() throws Exception { initCore("solrconfig-basic.xml", "schema.xml"); coreMetricManager = h.getCore().getCoreMetricManager(); - metricManager = h.getCore().getCoreContainer().getMetricManager(); } @After public void afterTest() throws IOException { if (null != coreMetricManager) { coreMetricManager.close(); - assertTrue(metricManager.getReporters(coreMetricManager.getRegistryName()).isEmpty()); deleteCore(); } } @@ -72,90 +59,36 @@ public void afterTest() throws IOException { @Test public void testRegisterMetrics() { Random random = random(); - - String scope = SolrMetricTestUtils.getRandomScope(random); SolrInfoBean.Category category = SolrMetricTestUtils.getRandomCategory(random); - Map metrics = SolrMetricTestUtils.getRandomMetrics(random); - SolrMetricProducer producer = SolrMetricTestUtils.getProducerOf(category, scope, metrics); - try { - coreMetricManager.registerMetricProducer(producer, Attributes.empty()); - assertNotNull(scope); - assertNotNull(category); - assertRegistered(scope, metrics, coreMetricManager); - } catch (final IllegalArgumentException e) { - assertTrue( - "expected at least one null but got: scope=" + scope + ", category=" + category, - (scope == null || category == null)); - assertRegistered(scope, new HashMap<>(), coreMetricManager); - } - } - - @Test - public void testLoadReporter() throws Exception { - Random random = random(); - - String className = MockMetricReporter.class.getName(); - String reporterName = TestUtil.randomUnicodeString(random); - String taggedName = reporterName + "@" + coreMetricManager.getTag(); - - Map attrs = new HashMap<>(); - attrs.put(FieldType.CLASS_NAME, className); - attrs.put(CoreAdminParams.NAME, reporterName); - - boolean shouldDefineConfigurable = random.nextBoolean(); - String configurable = TestUtil.randomUnicodeString(random); - if (shouldDefineConfigurable) attrs.put("configurable", configurable); - - boolean shouldDefinePlugin = random.nextBoolean(); - PluginInfo pluginInfo = - shouldDefinePlugin ? new PluginInfo(TestUtil.randomUnicodeString(random), attrs) : null; - - try { - metricManager.loadReporter( - coreMetricManager.getRegistryName(), - coreMetricManager.getCore(), - pluginInfo, - coreMetricManager.getTag()); - assertNotNull(pluginInfo); - Map reporters = - metricManager.getReporters(coreMetricManager.getRegistryName()); - assertTrue( - "reporters.size should be > 0, but was + " + reporters.size(), reporters.size() > 0); - assertNotNull( - "reporter " + reporterName + " not present among " + reporters, - reporters.get(taggedName)); - assertTrue( - "wrong reporter class: " + reporters.get(taggedName), - reporters.get(taggedName) instanceof MockMetricReporter); - } catch (IllegalArgumentException e) { - assertTrue(pluginInfo == null || attrs.get("configurable") == null); - assertNull(metricManager.getReporters(coreMetricManager.getRegistryName()).get(taggedName)); - } + Map metrics = + SolrMetricTestUtils.getRandomPrometheusMetricsWithReplacements(random, new HashMap<>()); + SolrMetricTestUtils.TestSolrMetricProducer producer = + new SolrMetricTestUtils.TestSolrMetricProducer("coll", metrics); + coreMetricManager.registerMetricProducer(producer, Attributes.empty()); + assertNotNull(category); + assertRegistered(metrics, coreMetricManager); } private void assertRegistered( - String scope, Map newMetrics, SolrCoreMetricManager coreMetricManager) { - if (scope == null || newMetrics == null) { + Map newMetrics, SolrCoreMetricManager coreMetricManager) { + if (newMetrics == null) { return; } - String filter = "." + scope + "."; - MetricRegistry registry = metricManager.registry(coreMetricManager.getRegistryName()); - assertEquals( - newMetrics.size(), - registry.getMetrics().keySet().stream().filter(s -> s.contains(filter)).count()); - - Map registeredMetrics = - registry.getMetrics().entrySet().stream() - .filter(e -> e.getKey() != null && e.getKey().contains(filter)) - .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())); - for (Map.Entry entry : registeredMetrics.entrySet()) { - String name = entry.getKey(); - Metric expectedMetric = entry.getValue(); - - Metric actualMetric = registry.getMetrics().get(name); - - assertNotNull(actualMetric); - assertEquals(expectedMetric, actualMetric); + var reader = + coreMetricManager + .getSolrMetricsContext() + .getMetricManager() + .getPrometheusMetricReader(coreMetricManager.getRegistryName()); + + // Check every metric that registered appears in the PrometheusMetricReader + for (Map.Entry entry : newMetrics.entrySet()) { + var metricSnapshots = reader.collect(name -> entry.getKey().equals(name)); + assertNotNull(metricSnapshots); + var counterSnapshot = (CounterSnapshot) metricSnapshots.get(0); + assertEquals( + counterSnapshot.getDataPoints().getFirst().getValue(), + newMetrics.get(counterSnapshot.getMetadata().getPrometheusName()), + 0.0); } } @@ -205,10 +138,8 @@ public void testReregisterMetrics() { @Test public void testNonCloudRegistryName() { String registryName = h.getCore().getCoreMetricManager().getRegistryName(); - String leaderRegistryName = h.getCore().getCoreMetricManager().getLeaderRegistryName(); assertNotNull(registryName); assertEquals("solr.core.collection1", registryName); - assertNull(leaderRegistryName); } /** Check the metric registry specific to a core is removed once the core is unloaded. */ diff --git a/solr/core/src/test/org/apache/solr/metrics/SolrMetricManagerTest.java b/solr/core/src/test/org/apache/solr/metrics/SolrMetricManagerTest.java index 4af0a5f3809..fa15ea4cb9a 100644 --- a/solr/core/src/test/org/apache/solr/metrics/SolrMetricManagerTest.java +++ b/solr/core/src/test/org/apache/solr/metrics/SolrMetricManagerTest.java @@ -17,9 +17,6 @@ package org.apache.solr.metrics; -import com.codahale.metrics.Counter; -import com.codahale.metrics.Metric; -import com.codahale.metrics.MetricRegistry; import com.google.common.util.concurrent.AtomicDouble; import io.opentelemetry.api.metrics.DoubleCounter; import io.opentelemetry.api.metrics.DoubleGauge; @@ -38,21 +35,12 @@ import io.prometheus.metrics.model.snapshots.MetricSnapshot; import io.prometheus.metrics.model.snapshots.MetricSnapshots; import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Random; -import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.DoubleAdder; import java.util.concurrent.atomic.LongAdder; -import org.apache.lucene.tests.util.TestUtil; import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.RetryUtil; -import org.apache.solr.core.PluginInfo; -import org.apache.solr.core.SolrInfoBean; -import org.apache.solr.util.SolrMetricTestUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -77,130 +65,11 @@ public void tearDown() throws Exception { super.tearDown(); } - // NOCOMMIT: Migration of this to OTEL isn't possible. You can't register instruments to a - // meterprovider that the provider itself didn't create - @Test - public void testRegisterAll() throws Exception { - Random r = random(); - - Map metrics = SolrMetricTestUtils.getRandomMetrics(r, true); - MetricRegistry mr = new MetricRegistry(); - for (Map.Entry entry : metrics.entrySet()) { - mr.register(entry.getKey(), entry.getValue()); - } - - String registryName = TestUtil.randomSimpleString(r, 1, 10); - assertEquals(0, metricManager.registry(registryName).getMetrics().size()); - // There is nothing registered so we should be error-free on the first pass - metricManager.registerAll(registryName, mr, SolrMetricManager.ResolutionStrategy.ERROR); - // this should simply skip existing names - metricManager.registerAll(registryName, mr, SolrMetricManager.ResolutionStrategy.IGNORE); - // this should re-register everything, and no errors - metricManager.registerAll(registryName, mr, SolrMetricManager.ResolutionStrategy.REPLACE); - // this should produce error - expectThrows( - IllegalArgumentException.class, - () -> - metricManager.registerAll( - registryName, mr, SolrMetricManager.ResolutionStrategy.ERROR)); - } - - // NOCOMMIT: Migration of this to OTEL isn't possible. You can only delete the whole - // sdkMeterProvider and all it's recorded metrics - @Test - public void testClearMetrics() { - Random r = random(); - - Map metrics = SolrMetricTestUtils.getRandomMetrics(r, true); - String registryName = TestUtil.randomSimpleString(r, 1, 10); - - for (Map.Entry entry : metrics.entrySet()) { - metricManager.registerMetric( - null, registryName, entry.getValue(), false, entry.getKey(), "foo", "bar"); - } - for (Map.Entry entry : metrics.entrySet()) { - metricManager.registerMetric( - null, registryName, entry.getValue(), false, entry.getKey(), "foo", "baz"); - } - for (Map.Entry entry : metrics.entrySet()) { - metricManager.registerMetric( - null, registryName, entry.getValue(), false, entry.getKey(), "foo"); - } - - assertEquals(metrics.size() * 3, metricManager.registry(registryName).getMetrics().size()); - - // clear all metrics with prefix "foo.bar." - Set removed = metricManager.clearMetrics(registryName, "foo", "bar."); - assertEquals(metrics.size(), removed.size()); - for (String s : removed) { - assertTrue(s.startsWith("foo.bar.")); - } - removed = metricManager.clearMetrics(registryName, "foo", "baz."); - assertEquals(metrics.size(), removed.size()); - for (String s : removed) { - assertTrue(s.startsWith("foo.baz.")); - } - // perhaps surprisingly, this works too - see PrefixFilter docs - removed = metricManager.clearMetrics(registryName, "fo"); - assertEquals(metrics.size(), removed.size()); - for (String s : removed) { - assertTrue(s.startsWith("foo.")); - } - } - - @Test - public void testSimpleMetrics() { - Random r = random(); - - String registryName = TestUtil.randomSimpleString(r, 1, 10); - - metricManager.counter(null, registryName, "simple_counter", "foo", "bar"); - metricManager.timer(null, registryName, "simple_timer", "foo", "bar"); - metricManager.meter(null, registryName, "simple_meter", "foo", "bar"); - metricManager.histogram(null, registryName, "simple_histogram", "foo", "bar"); - Map metrics = metricManager.registry(registryName).getMetrics(); - assertEquals(4, metrics.size()); - for (Map.Entry entry : metrics.entrySet()) { - assertTrue(entry.getKey().startsWith("foo.bar.simple_")); - } - } - - @Test - public void testRegistryName() { - Random r = random(); - - String name = TestUtil.randomSimpleString(r, 1, 10); - - String result = SolrMetricManager.getRegistryName(SolrInfoBean.Group.core, name, "collection1"); - assertEquals("solr.core." + name + ".collection1", result); - // try it with already prefixed name - group will be ignored - result = SolrMetricManager.getRegistryName(SolrInfoBean.Group.core, result); - assertEquals("solr.core." + name + ".collection1", result); - // try it with already prefixed name but with additional segments - result = - SolrMetricManager.getRegistryName(SolrInfoBean.Group.core, result, "shard1", "replica1"); - assertEquals("solr.core." + name + ".collection1.shard1.replica1", result); - } - @Test public void testDefaultCloudReporterPeriodUnchanged() { assertEquals(60, SolrMetricManager.DEFAULT_CLOUD_REPORTER_PERIOD); } - private PluginInfo createPluginInfo(String name, String group, String registry) { - Map attrs = new HashMap<>(); - attrs.put("name", name); - if (group != null) { - attrs.put("group", group); - } - if (registry != null) { - attrs.put("registry", registry); - } - NamedList initArgs = new NamedList<>(); - initArgs.add("configurable", "true"); - return new PluginInfo("SolrMetricReporter", attrs, initArgs, null); - } - @Test public void testLongCounter() { LongCounter counter = diff --git a/solr/core/src/test/org/apache/solr/metrics/SolrMetricReporterTest.java b/solr/core/src/test/org/apache/solr/metrics/SolrMetricReporterTest.java deleted file mode 100644 index b9dd45e467c..00000000000 --- a/solr/core/src/test/org/apache/solr/metrics/SolrMetricReporterTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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.solr.metrics; - -import java.util.HashMap; -import java.util.Map; -import java.util.Random; -import org.apache.lucene.tests.util.TestUtil; -import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.common.params.CoreAdminParams; -import org.apache.solr.core.PluginInfo; -import org.apache.solr.metrics.reporters.MockMetricReporter; -import org.apache.solr.schema.FieldType; -import org.junit.Test; - -public class SolrMetricReporterTest extends SolrTestCaseJ4 { - - @Test - public void testInit() throws Exception { - Random random = random(); - - SolrMetricManager metricManager = new SolrMetricManager(null); - - final String registryName = TestUtil.randomSimpleString(random); - final MockMetricReporter reporter = new MockMetricReporter(metricManager, registryName); - - Map attrs = new HashMap<>(); - attrs.put(FieldType.CLASS_NAME, MockMetricReporter.class.getName()); - attrs.put(CoreAdminParams.NAME, TestUtil.randomUnicodeString(random)); - attrs.put("enabled", random.nextBoolean()); - - boolean shouldDefineConfigurable = random.nextBoolean(); - String configurable = TestUtil.randomUnicodeString(random); - if (shouldDefineConfigurable) attrs.put("configurable", configurable); - - boolean shouldDefinePlugin = random.nextBoolean(); - String type = TestUtil.randomUnicodeString(random); - PluginInfo pluginInfo = shouldDefinePlugin ? new PluginInfo(type, attrs) : null; - - try { - reporter.init(pluginInfo); - assertNotNull(pluginInfo); - assertEquals(configurable, attrs.get("configurable")); - assertTrue(reporter.didValidate); - assertNotNull(reporter.configurable); - assertEquals(configurable, reporter.configurable); - } catch (IllegalStateException e) { - assertTrue(pluginInfo == null || attrs.get("configurable") == null); - assertTrue(reporter.didValidate); - assertNull(reporter.configurable); - } finally { - reporter.close(); - } - } -} diff --git a/solr/core/src/test/org/apache/solr/metrics/reporters/MockMetricReporter.java b/solr/core/src/test/org/apache/solr/metrics/reporters/MockMetricReporter.java deleted file mode 100644 index e2c251c444b..00000000000 --- a/solr/core/src/test/org/apache/solr/metrics/reporters/MockMetricReporter.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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.solr.metrics.reporters; - -import com.codahale.metrics.Metric; -import com.codahale.metrics.MetricRegistry; -import java.util.Locale; -import java.util.NoSuchElementException; -import org.apache.solr.metrics.SolrMetricManager; -import org.apache.solr.metrics.SolrMetricReporter; - -public class MockMetricReporter extends SolrMetricReporter { - - public String configurable; - - public boolean didInit = false; - public boolean didClose = false; - public boolean didValidate = false; - - public MockMetricReporter(SolrMetricManager metricManager, String registryName) { - super(metricManager, registryName); - } - - @Override - protected void doInit() { - didInit = true; - } - - @Override - public void close() { - didClose = true; - } - - @Override - protected void validate() throws IllegalStateException { - didValidate = true; - if (configurable == null) { - throw new IllegalStateException("MockMetricReporter::configurable not defined."); - } - if (period < 1) { - throw new IllegalStateException( - "Init argument 'period' is in time unit 'seconds' and must be at least 1."); - } - } - - public void setConfigurable(String configurable) { - this.configurable = configurable; - } - - public Metric reportMetric(String metricName) throws NoSuchElementException { - MetricRegistry registry = metricManager.registry(registryName); - Metric metric = registry.getMetrics().get(metricName); - if (metric == null) { - throw new NoSuchElementException("Metric was not found for metric name = " + metricName); - } - - return metric; - } - - @Override - public String toString() { - return String.format( - Locale.ENGLISH, - "[%s@%s: configurable = %s, didInit = %b, didValidate = %b, didClose = %b]", - getClass().getName(), - Integer.toHexString(hashCode()), - configurable, - didInit, - didValidate, - didClose); - } -} diff --git a/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriter.java b/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriter.java index 71545ea6628..570d03758c6 100644 --- a/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriter.java +++ b/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriter.java @@ -16,7 +16,8 @@ */ package org.apache.solr.response; -import com.codahale.metrics.SharedMetricRegistries; +import static org.apache.solr.client.solrj.impl.InputStreamResponseParser.STREAM_KEY; + import java.io.InputStream; import java.lang.invoke.MethodHandles; import java.nio.charset.StandardCharsets; @@ -50,8 +51,6 @@ public class TestPrometheusResponseWriter extends SolrTestCaseJ4 { @BeforeClass public static void beforeClass() throws Exception { - SharedMetricRegistries.clear(); - solrClientTestRule.startSolr(LuceneTestCase.createTempDir()); solrClientTestRule .newCollection("core1") @@ -127,15 +126,14 @@ public void testAcceptHeaderOpenMetricsFormat() throws Exception { ModifiableSolrParams params = new ModifiableSolrParams(); var req = new GenericSolrRequest(METHOD.GET, "/admin/metrics", SolrRequestType.ADMIN, params); - // NOCOMMIT: Remove this prometheus writer type after Dropwizard is removed - req.setResponseParser(new InputStreamResponseParser("prometheus")); + req.setResponseParser(new InputStreamResponseParser(null)); req.addHeader("Accept", "application/openmetrics-text;version=1.0.0"); try (SolrClient adminClient = getHttpSolrClient(solrClientTestRule.getBaseUrl())) { NamedList res = adminClient.request(req); - try (InputStream in = (InputStream) res.get("stream")) { + try (InputStream in = (InputStream) res.get(STREAM_KEY)) { String output = new String(in.readAllBytes(), StandardCharsets.UTF_8); assertTrue( "Should use OpenMetrics format when Accept header is set", @@ -148,15 +146,16 @@ public void testAcceptHeaderOpenMetricsFormat() throws Exception { public void testWtParameterOpenMetricsFormat() throws Exception { ModifiableSolrParams params = new ModifiableSolrParams(); var req = new GenericSolrRequest(METHOD.GET, "/admin/metrics", SolrRequestType.ADMIN, params); + req.setResponseParser(new InputStreamResponseParser("openmetrics")); try (SolrClient adminClient = getHttpSolrClient(solrClientTestRule.getBaseUrl())) { NamedList res = adminClient.request(req); - try (InputStream in = (InputStream) res.get("stream")) { + try (InputStream in = (InputStream) res.get(STREAM_KEY)) { String output = new String(in.readAllBytes(), StandardCharsets.UTF_8); assertTrue( - "Should use OpenMetrics format when Accept header is set", + "Should use OpenMetrics format when wt=openmetrics is set", output.trim().endsWith("# EOF")); } } @@ -166,18 +165,50 @@ public void testWtParameterOpenMetricsFormat() throws Exception { public void testDefaultPrometheusFormat() throws Exception { ModifiableSolrParams params = new ModifiableSolrParams(); var req = new GenericSolrRequest(METHOD.GET, "/admin/metrics", SolrRequestType.ADMIN, params); - // NOCOMMIT: Remove this prometheus writer type after Dropwizard is removed + req.setResponseParser(new InputStreamResponseParser("prometheus")); try (SolrClient adminClient = getHttpSolrClient(solrClientTestRule.getBaseUrl())) { NamedList res = adminClient.request(req); - try (InputStream in = (InputStream) res.get("stream")) { + try (InputStream in = (InputStream) res.get(STREAM_KEY)) { String output = new String(in.readAllBytes(), StandardCharsets.UTF_8); assertFalse( - "Should default to Prometheus format when no Accept header or wt=openmetrics is set", + "Should use Prometheus format when wt=prometheus is set", output.trim().endsWith("# EOF")); } } } + + @Test + public void testDefaultPrometheusFormatNoWtParam() throws Exception { + ModifiableSolrParams params = new ModifiableSolrParams(); + var req = new GenericSolrRequest(METHOD.GET, "/admin/metrics", SolrRequestType.ADMIN, params); + + req.setResponseParser(new InputStreamResponseParser(null)); + + try (SolrClient adminClient = getHttpSolrClient(solrClientTestRule.getBaseUrl())) { + NamedList res = adminClient.request(req); + + try (InputStream in = (InputStream) res.get(STREAM_KEY)) { + String output = new String(in.readAllBytes(), StandardCharsets.UTF_8); + assertFalse( + "Should default to Prometheus format when no wt parameter is set", + output.trim().endsWith("# EOF")); + } + } + } + + @Test + public void testUnsupportedMetricsFormat() throws Exception { + ModifiableSolrParams params = new ModifiableSolrParams(); + var req = new GenericSolrRequest(METHOD.GET, "/admin/metrics", SolrRequestType.ADMIN, params); + + req.setResponseParser(new InputStreamResponseParser("unknownFormat")); + + try (SolrClient adminClient = getHttpSolrClient(solrClientTestRule.getBaseUrl())) { + NamedList res = adminClient.request(req); + assertEquals(400, res.get("responseStatus")); + } + } } diff --git a/solr/core/src/test/org/apache/solr/search/TestCaffeineCache.java b/solr/core/src/test/org/apache/solr/search/TestCaffeineCache.java index d045a1d46de..f458f06717a 100644 --- a/solr/core/src/test/org/apache/solr/search/TestCaffeineCache.java +++ b/solr/core/src/test/org/apache/solr/search/TestCaffeineCache.java @@ -56,7 +56,7 @@ public void testSimple() throws IOException { String lfuCacheName = scope + "-1"; String newLfuCacheName = scope + "-2"; - SolrMetricsContext solrMetricsContext = new SolrMetricsContext(metricManager, registry, "foo"); + SolrMetricsContext solrMetricsContext = new SolrMetricsContext(metricManager, registry); lfuCache.initializeMetrics( solrMetricsContext, Attributes.of(NAME_ATTR, lfuCacheName), "solr_cache"); diff --git a/solr/core/src/test/org/apache/solr/search/TestRecovery.java b/solr/core/src/test/org/apache/solr/search/TestRecovery.java index 60bde7493bd..928e8dd73c7 100644 --- a/solr/core/src/test/org/apache/solr/search/TestRecovery.java +++ b/solr/core/src/test/org/apache/solr/search/TestRecovery.java @@ -20,8 +20,6 @@ import static org.apache.solr.update.processor.DistributingUpdateProcessorFactory.DISTRIB_UPDATE_PARAM; import static org.apache.solr.util.SolrMatchers.subListMatches; -import com.codahale.metrics.Metric; -import com.codahale.metrics.MetricRegistry; import java.io.RandomAccessFile; import java.lang.invoke.MethodHandles; import java.nio.charset.StandardCharsets; @@ -43,7 +41,6 @@ import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.util.TimeSource; import org.apache.solr.common.util.Utils; -import org.apache.solr.metrics.SolrMetricManager; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.schema.IndexSchema; import org.apache.solr.update.UpdateHandler; @@ -100,13 +97,6 @@ public void afterTest() { deleteCore(); } - private Map getMetrics() { - SolrMetricManager manager = h.getCoreContainer().getMetricManager(); - MetricRegistry registry = - manager.registry(h.getCore().getCoreMetricManager().getRegistryName()); - return registry.getMetrics(); - } - @Test public void stressLogReplay() throws Exception { final int NUM_UPDATES = 150; diff --git a/solr/core/src/test/org/apache/solr/search/TestSolrCachePerf.java b/solr/core/src/test/org/apache/solr/search/TestSolrCachePerf.java index ff676ef4956..141ed14d085 100644 --- a/solr/core/src/test/org/apache/solr/search/TestSolrCachePerf.java +++ b/solr/core/src/test/org/apache/solr/search/TestSolrCachePerf.java @@ -111,9 +111,7 @@ private void doTestGetPutCompute( Object o = cache.init(params, null, cr); cache.setState(SolrCache.State.LIVE); cache.initializeMetrics( - new SolrMetricsContext(metricManager, "foo", "bar"), - Attributes.of(NAME_ATTR, "foo"), - "foo"); + new SolrMetricsContext(metricManager, "foo"), Attributes.of(NAME_ATTR, "foo")); AtomicBoolean stop = new AtomicBoolean(); SummaryStatistics perImplRatio = ratioStats.computeIfAbsent(clazz.getSimpleName(), c -> new SummaryStatistics()); diff --git a/solr/core/src/test/org/apache/solr/search/TestSolrFieldCacheBean.java b/solr/core/src/test/org/apache/solr/search/TestSolrFieldCacheBean.java index d39411ad5d8..726d42d2c70 100644 --- a/solr/core/src/test/org/apache/solr/search/TestSolrFieldCacheBean.java +++ b/solr/core/src/test/org/apache/solr/search/TestSolrFieldCacheBean.java @@ -88,14 +88,11 @@ private void assertEntryList(boolean bytesMetricIncluded) { private FieldCacheMetrics getFieldCacheMetrics() { String registryName = TestUtil.randomSimpleString(random(), 1, 10); SolrMetricManager metricManager = h.getCoreContainer().getMetricManager(); - SolrMetricsContext solrMetricsContext = - new SolrMetricsContext(metricManager, registryName, "foo"); + SolrMetricsContext solrMetricsContext = new SolrMetricsContext(metricManager, registryName); try (SolrFieldCacheBean mbean = new SolrFieldCacheBean()) { mbean.initializeMetrics( - solrMetricsContext, - Attributes.of(CATEGORY_ATTR, SolrInfoBean.Category.CACHE.toString()), - null); + solrMetricsContext, Attributes.of(CATEGORY_ATTR, SolrInfoBean.Category.CACHE.toString())); var metrics = metricManager.getPrometheusMetricReader(registryName).collect(); diff --git a/solr/core/src/test/org/apache/solr/search/TestThinCache.java b/solr/core/src/test/org/apache/solr/search/TestThinCache.java index ff174290d65..55717b7d015 100644 --- a/solr/core/src/test/org/apache/solr/search/TestThinCache.java +++ b/solr/core/src/test/org/apache/solr/search/TestThinCache.java @@ -16,6 +16,9 @@ */ package org.apache.solr.search; +import static org.apache.solr.metrics.SolrMetricProducer.CATEGORY_ATTR; +import static org.apache.solr.metrics.SolrMetricProducer.NAME_ATTR; + import io.opentelemetry.api.common.Attributes; import io.prometheus.metrics.model.snapshots.Labels; import java.nio.file.Files; @@ -25,6 +28,7 @@ import java.util.Map; import org.apache.lucene.tests.util.TestUtil; import org.apache.solr.SolrTestCaseJ4; +import org.apache.solr.core.SolrInfoBean; import org.apache.solr.metrics.SolrMetricManager; import org.apache.solr.metrics.SolrMetricsContext; import org.apache.solr.util.EmbeddedSolrServerTestRule; @@ -93,14 +97,24 @@ public void testSimple() { Object cacheScope = new Object(); ThinCache.NodeLevelCache backing = new ThinCache.NodeLevelCache<>(); ThinCache lfuCache = new ThinCache<>(); + String lfuCacheName = "lfu_cache"; lfuCache.setBacking(cacheScope, backing); - SolrMetricsContext solrMetricsContext = new SolrMetricsContext(metricManager, registry, "foo"); - lfuCache.initializeMetrics(solrMetricsContext, Attributes.empty(), scope + "-1"); + SolrMetricsContext solrMetricsContext = new SolrMetricsContext(metricManager, registry); + lfuCache.initializeMetrics( + solrMetricsContext, + Attributes.of( + CATEGORY_ATTR, SolrInfoBean.Category.CACHE.toString(), NAME_ATTR, lfuCacheName), + "solr_node_cache"); Object cacheScope2 = new Object(); ThinCache newLFUCache = new ThinCache<>(); + String newLfuCacheName = "new_lfu_cache"; newLFUCache.setBacking(cacheScope2, backing); - newLFUCache.initializeMetrics(solrMetricsContext, Attributes.empty(), scope + "-2"); + newLFUCache.initializeMetrics( + solrMetricsContext, + Attributes.of( + CATEGORY_ATTR, SolrInfoBean.Category.CACHE.toString(), NAME_ATTR, newLfuCacheName), + "solr_node_cache"); Map params = new HashMap<>(); params.put("size", "100"); @@ -117,10 +131,13 @@ public void testSimple() { assertEquals("15", lfuCache.get(15)); assertEquals("75", lfuCache.get(75)); assertNull(lfuCache.get(110)); - Map nl = lfuCache.getMetricsMap().getValue(); - assertEquals(3L, nl.get("lookups")); - assertEquals(2L, nl.get("hits")); - assertEquals(101L, nl.get("inserts")); + + var hits = getNodeCacheLookups(metricManager, registry, lfuCacheName, "hit"); + var miss = getNodeCacheLookups(metricManager, registry, lfuCacheName, "miss"); + var inserts = getNodeCacheOp(metricManager, registry, lfuCacheName, "inserts"); + assertEquals(3L, hits + miss); + assertEquals(2L, hits); + assertEquals(101L, inserts); assertNull(lfuCache.get(1)); // first item put in should be the first out @@ -133,15 +150,15 @@ public void testSimple() { assertEquals("15", newLFUCache.get(15)); assertEquals("75", newLFUCache.get(75)); assertNull(newLFUCache.get(50)); - nl = newLFUCache.getMetricsMap().getValue(); - assertEquals(3L, nl.get("lookups")); - assertEquals(2L, nl.get("hits")); - assertEquals(1L, nl.get("inserts")); - assertEquals(0L, nl.get("evictions")); - - assertEquals(7L, nl.get("cumulative_lookups")); - assertEquals(4L, nl.get("cumulative_hits")); - assertEquals(102L, nl.get("cumulative_inserts")); + + var newhits = getNodeCacheLookups(metricManager, registry, newLfuCacheName, "hit"); + var newmiss = getNodeCacheLookups(metricManager, registry, newLfuCacheName, "miss"); + var newinserts = getNodeCacheOp(metricManager, registry, newLfuCacheName, "inserts"); + var evictions = getNodeCacheOp(metricManager, registry, newLfuCacheName, "evictions"); + assertEquals(7L, newhits + newmiss); + assertEquals(4L, newhits); + assertEquals(102L, newinserts); + assertEquals(0L, evictions); } @Test @@ -156,21 +173,24 @@ public void testInitCore() throws Exception { assertQ(req("q", "*:*", "fq", "id:0")); assertQ(req("q", "*:*", "fq", "id:1")); + var metricManager = h.getCoreContainer().getMetricManager(); assertEquals( 3L, - getNodeCacheLookups(thinCacheName, "hit") - + getNodeCacheLookups(thinCacheName, "miss")); // total lookups - assertEquals(1L, getNodeCacheLookups(thinCacheName, "hit")); - assertEquals(2L, getNodeCacheOp(thinCacheName, "inserts")); + getNodeCacheLookups(metricManager, "solr.node", thinCacheName, "hit") + + getNodeCacheLookups( + metricManager, "solr.node", thinCacheName, "miss")); // total lookups + assertEquals(1L, getNodeCacheLookups(metricManager, "solr.node", thinCacheName, "hit")); + assertEquals(2L, getNodeCacheOp(metricManager, "solr.node", thinCacheName, "inserts")); - assertEquals(2, getNodeCacheSize(thinCacheName)); + assertEquals(2, getNodeCacheSize(metricManager, "solr.node", thinCacheName)); // for the other node-level cache, simply check that metrics are accessible - assertEquals(0, getNodeCacheSize(nodeCacheName)); + assertEquals(0, getNodeCacheSize(metricManager, "solr.node", nodeCacheName)); } - private long getNodeCacheOp(String cacheName, String operation) { - var reader = h.getCoreContainer().getMetricManager().getPrometheusMetricReader("solr.node"); + private long getNodeCacheOp( + SolrMetricManager metricManager, String registry, String cacheName, String operation) { + var reader = metricManager.getPrometheusMetricReader(registry); return (long) SolrMetricTestUtils.getCounterDatapoint( reader, @@ -184,8 +204,9 @@ private long getNodeCacheOp(String cacheName, String operation) { .getValue(); } - private long getNodeCacheLookups(String cacheName, String result) { - var reader = h.getCoreContainer().getMetricManager().getPrometheusMetricReader("solr.node"); + private long getNodeCacheLookups( + SolrMetricManager metricManager, String registry, String cacheName, String result) { + var reader = metricManager.getPrometheusMetricReader(registry); var builder = Labels.builder() .label("category", "CACHE") @@ -198,8 +219,9 @@ private long getNodeCacheLookups(String cacheName, String result) { .getValue(); } - private long getNodeCacheSize(String cacheName) { - var reader = h.getCoreContainer().getMetricManager().getPrometheusMetricReader("solr.node"); + private long getNodeCacheSize( + SolrMetricManager metricManager, String registry, String cacheName) { + var reader = metricManager.getPrometheusMetricReader(registry); return (long) SolrMetricTestUtils.getGaugeDatapoint( reader, diff --git a/solr/core/src/test/org/apache/solr/search/ThinCache.java b/solr/core/src/test/org/apache/solr/search/ThinCache.java index c39ae8b30cc..c8123a899ed 100644 --- a/solr/core/src/test/org/apache/solr/search/ThinCache.java +++ b/solr/core/src/test/org/apache/solr/search/ThinCache.java @@ -20,6 +20,7 @@ import com.github.benmanes.caffeine.cache.RemovalListener; import com.google.common.annotations.VisibleForTesting; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.ObservableLongMeasurement; import java.io.IOException; import java.lang.invoke.MethodHandles; import java.lang.ref.WeakReference; @@ -35,8 +36,9 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.LongAdder; import org.apache.lucene.util.Accountable; -import org.apache.solr.metrics.MetricsMap; +import org.apache.solr.common.util.IOUtils; import org.apache.solr.metrics.SolrMetricsContext; +import org.apache.solr.metrics.otel.OtelUnit; import org.apache.solr.util.IOFunction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -75,6 +77,7 @@ public class ThinCache extends SolrCacheBase implements SolrCache, Accountable, RemovalListener { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + private AutoCloseable toClose; private static final class ScopedKey { public final S scope; @@ -277,7 +280,6 @@ public Object init(Map args, Object persistence, CacheRegenerato return persistence; } - private MetricsMap cacheMap; private SolrMetricsContext solrMetricsContext; private final LongAdder hits = new LongAdder(); @@ -292,46 +294,65 @@ public Object init(Map args, Object persistence, CacheRegenerato private long priorEvictions; @Override + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { + initializeMetrics(parentContext, attributes, "solr_thin_cache"); + } + public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { - solrMetricsContext = parentContext.getChildContext(this); - cacheMap = - new MetricsMap( - map -> { + SolrMetricsContext parentContext, Attributes attributes, String metricName) { + Attributes cacheAttributes = + attributes.toBuilder().put(CATEGORY_ATTR, getCategory().toString()).build(); + this.solrMetricsContext = parentContext.getChildContext(this); + + ObservableLongMeasurement cacheLookupsMetric = + solrMetricsContext.longCounterMeasurement( + metricName + "_lookups", "Number of cumulative cache lookup results (hits and misses)"); + + ObservableLongMeasurement cacheOperationMetric = + solrMetricsContext.longCounterMeasurement( + metricName + "_ops", "Number of cumulative cache operations (inserts and evictions)"); + + ObservableLongMeasurement sizeMetric = + solrMetricsContext.longGaugeMeasurement( + metricName + "_size", "Current number cache entries"); + + ObservableLongMeasurement ramBytesUsedMetric = + solrMetricsContext.longGaugeMeasurement( + metricName + "_ram_used", "RAM bytes used by cache", OtelUnit.BYTES); + + ObservableLongMeasurement warmupTimeMetric = + solrMetricsContext.longGaugeMeasurement( + metricName + "_warmup_time", "Cache warmup time (most recent)", OtelUnit.MILLISECONDS); + + this.toClose = + solrMetricsContext.batchCallback( + () -> { long hitCount = hits.sum(); - long insertCount = inserts.sum(); long lookupCount = lookups.sum(); - long evictionCount = evictions.sum(); - - map.put(LOOKUPS_PARAM, lookupCount); - map.put(HITS_PARAM, hitCount); - map.put(HIT_RATIO_PARAM, hitRate(hitCount, lookupCount)); - map.put(INSERTS_PARAM, insertCount); - map.put(EVICTIONS_PARAM, evictionCount); - map.put(SIZE_PARAM, local.size()); - map.put("warmupTime", warmupTimeMillis); - map.put(RAM_BYTES_USED_PARAM, ramBytesUsed()); - map.put(MAX_RAM_MB_PARAM, getMaxRamMB()); - + long insertCount = inserts.sum(); + sizeMetric.record(local.size(), cacheAttributes); + ramBytesUsedMetric.record(ramBytesUsed(), cacheAttributes); + warmupTimeMetric.record(warmupTimeMillis, cacheAttributes); long cumLookups = priorLookups + lookupCount; long cumHits = priorHits + hitCount; - map.put("cumulative_lookups", cumLookups); - map.put("cumulative_hits", cumHits); - map.put("cumulative_hitratio", hitRate(cumHits, cumLookups)); - map.put("cumulative_inserts", priorInserts + insertCount); - map.put("cumulative_evictions", priorEvictions + evictionCount); - }); - solrMetricsContext.gauge(cacheMap, true, scope, getCategory().toString()); - } - - @VisibleForTesting - MetricsMap getMetricsMap() { - return cacheMap; - } - // TODO: refactor this common method out of here and `CaffeineCache` - private static double hitRate(long hitCount, long lookupCount) { - return lookupCount == 0 ? 1.0 : (double) hitCount / lookupCount; + cacheLookupsMetric.record( + cumHits, cacheAttributes.toBuilder().put(RESULT_ATTR, "hit").build()); + cacheLookupsMetric.record( + cumLookups - cumHits, + cacheAttributes.toBuilder().put(RESULT_ATTR, "miss").build()); + cacheOperationMetric.record( + priorInserts + insertCount, + cacheAttributes.toBuilder().put(OPERATION_ATTR, "inserts").build()); + cacheOperationMetric.record( + priorEvictions + evictions.sum(), + cacheAttributes.toBuilder().put(OPERATION_ATTR, "evictions").build()); + }, + cacheLookupsMetric, + cacheOperationMetric, + sizeMetric, + ramBytesUsedMetric, + warmupTimeMetric); } @Override @@ -342,6 +363,7 @@ public SolrMetricsContext getSolrMetricsContext() { @Override public void close() throws IOException { backing.unregister(scope); + IOUtils.closeQuietly(toClose); SolrCache.super.close(); } @@ -370,7 +392,8 @@ public void onRemoval(K key, V value, RemovalCause cause) { @Override public String toString() { - return name() + (cacheMap != null ? cacheMap.getValue().toString() : ""); + String cacheName = name(); + return cacheName != null ? cacheName : getClass().getSimpleName(); } @Override diff --git a/solr/core/src/test/org/apache/solr/security/AuditLoggerIntegrationTest.java b/solr/core/src/test/org/apache/solr/security/AuditLoggerIntegrationTest.java index f774abbbd58..ad5c047775e 100644 --- a/solr/core/src/test/org/apache/solr/security/AuditLoggerIntegrationTest.java +++ b/solr/core/src/test/org/apache/solr/security/AuditLoggerIntegrationTest.java @@ -27,7 +27,6 @@ import static org.apache.solr.security.AuditEvent.RequestType.SEARCH; import static org.apache.solr.security.Sha256AuthenticationProvider.getSaltedHashedValue; -import com.codahale.metrics.MetricRegistry; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import io.opentelemetry.exporter.prometheus.PrometheusMetricReader; @@ -439,20 +438,6 @@ private static void assertAuditEvent( } } - private ArrayList getMetricsRegistries(MiniSolrCloudCluster cluster) { - ArrayList registries = new ArrayList<>(); - cluster - .getJettySolrRunners() - .forEach( - r -> { - MetricRegistry registry = - r.getCoreContainer().getMetricManager().registry("solr.node"); - assertNotNull(registry); - registries.add(registry); - }); - return registries; - } - /** * @see #assertThreeTestAdminEvents */ diff --git a/solr/core/src/test/org/apache/solr/security/AuditLoggerPluginTest.java b/solr/core/src/test/org/apache/solr/security/AuditLoggerPluginTest.java index 1de35430800..32dec177433 100644 --- a/solr/core/src/test/org/apache/solr/security/AuditLoggerPluginTest.java +++ b/solr/core/src/test/org/apache/solr/security/AuditLoggerPluginTest.java @@ -136,7 +136,7 @@ public void setUp() throws Exception { config.put("async", false); plugin.init(config); SolrMetricsContext mockSolrMetricsContext = MockSolrMetricsContextFactory.create(); - plugin.initializeMetrics(mockSolrMetricsContext, Attributes.empty(), "solr.test"); + plugin.initializeMetrics(mockSolrMetricsContext, Attributes.empty()); } @Override diff --git a/solr/core/src/test/org/apache/solr/security/CertAuthPluginTest.java b/solr/core/src/test/org/apache/solr/security/CertAuthPluginTest.java index db37c071ec5..42a596ba9e7 100644 --- a/solr/core/src/test/org/apache/solr/security/CertAuthPluginTest.java +++ b/solr/core/src/test/org/apache/solr/security/CertAuthPluginTest.java @@ -60,8 +60,8 @@ public void setUp() throws Exception { String registryName = "solr.core.collection1"; plugin = new CertAuthPlugin(); SolrMetricsContext solrMetricsContext = - new SolrMetricsContext(coreContainer.getMetricManager(), registryName, "foo"); - plugin.initializeMetrics(solrMetricsContext, Attributes.empty(), null); + new SolrMetricsContext(coreContainer.getMetricManager(), registryName); + plugin.initializeMetrics(solrMetricsContext, Attributes.empty()); plugin.init(Collections.emptyMap()); } diff --git a/solr/core/src/test/org/apache/solr/security/MockSolrMetricsContextFactory.java b/solr/core/src/test/org/apache/solr/security/MockSolrMetricsContextFactory.java index 679e14af67d..2703b8b2737 100644 --- a/solr/core/src/test/org/apache/solr/security/MockSolrMetricsContextFactory.java +++ b/solr/core/src/test/org/apache/solr/security/MockSolrMetricsContextFactory.java @@ -5,7 +5,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import com.codahale.metrics.Counter; import com.codahale.metrics.Timer; import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.LongGauge; @@ -27,12 +26,6 @@ public static SolrMetricsContext create() { Timer mockTimer = mock(Timer.class); Timer.Context mockTimerContext = mock(Timer.Context.class); when(mockTimer.time()).thenReturn(mockTimerContext); - when(mockChildContext.timer(anyString(), anyString(), anyString(), anyString())) - .thenReturn(mockTimer); - - Counter mockCounter = mock(Counter.class); - when(mockChildContext.counter(anyString(), anyString(), anyString(), anyString())) - .thenReturn(mockCounter); LongHistogram mockLongHistogram = mock(LongHistogram.class); when(mockChildContext.longHistogram(anyString(), anyString(), any(OtelUnit.class))) diff --git a/solr/core/src/test/org/apache/solr/security/MultiDestinationAuditLoggerTest.java b/solr/core/src/test/org/apache/solr/security/MultiDestinationAuditLoggerTest.java index fe6c30070b0..f667a226c22 100644 --- a/solr/core/src/test/org/apache/solr/security/MultiDestinationAuditLoggerTest.java +++ b/solr/core/src/test/org/apache/solr/security/MultiDestinationAuditLoggerTest.java @@ -55,7 +55,7 @@ public void init() throws IOException { al.init(config); SolrMetricsContext mockSolrMetricsContext = MockSolrMetricsContextFactory.create(); - al.initializeMetrics(mockSolrMetricsContext, Attributes.empty(), "solr.test"); + al.initializeMetrics(mockSolrMetricsContext, Attributes.empty()); al.doAudit(new AuditEvent(AuditEvent.EventType.ANONYMOUS).setUsername("me")); assertEquals( diff --git a/solr/core/src/test/org/apache/solr/security/SolrLogAuditLoggerPluginTest.java b/solr/core/src/test/org/apache/solr/security/SolrLogAuditLoggerPluginTest.java index 15242a166ec..baf106bb045 100644 --- a/solr/core/src/test/org/apache/solr/security/SolrLogAuditLoggerPluginTest.java +++ b/solr/core/src/test/org/apache/solr/security/SolrLogAuditLoggerPluginTest.java @@ -41,7 +41,7 @@ public void setUp() throws Exception { config = new HashMap<>(); config.put("async", false); SolrMetricsContext mockSolrMetricsContext = MockSolrMetricsContextFactory.create(); - plugin.initializeMetrics(mockSolrMetricsContext, Attributes.empty(), "solr.test"); + plugin.initializeMetrics(mockSolrMetricsContext, Attributes.empty()); } @Test(expected = SolrException.class) diff --git a/solr/core/src/test/org/apache/solr/security/TestPKIAuthenticationPlugin.java b/solr/core/src/test/org/apache/solr/security/TestPKIAuthenticationPlugin.java index 42e1800274f..9d5fed99204 100644 --- a/solr/core/src/test/org/apache/solr/security/TestPKIAuthenticationPlugin.java +++ b/solr/core/src/test/org/apache/solr/security/TestPKIAuthenticationPlugin.java @@ -133,7 +133,7 @@ private static void mockMetrics(MockPKIAuthenticationPlugin mock) { LongHistogram longHistogramMock = mock(LongHistogram.class); when(smcMock.longCounter(any(), any())).thenReturn(longCounterMock); when(smcMock.longHistogram(any(), any(), any())).thenReturn(longHistogramMock); - mock.initializeMetrics(smcMock, Attributes.empty(), ""); + mock.initializeMetrics(smcMock, Attributes.empty()); } @Override diff --git a/solr/core/src/test/org/apache/solr/util/stats/MetricUtilsTest.java b/solr/core/src/test/org/apache/solr/util/stats/MetricUtilsTest.java deleted file mode 100644 index df6f8c991e9..00000000000 --- a/solr/core/src/test/org/apache/solr/util/stats/MetricUtilsTest.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * 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.solr.util.stats; - -import com.codahale.metrics.Counter; -import com.codahale.metrics.Gauge; -import com.codahale.metrics.Histogram; -import com.codahale.metrics.Meter; -import com.codahale.metrics.MetricFilter; -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.Snapshot; -import com.codahale.metrics.Timer; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.common.MapWriter; -import org.apache.solr.common.util.NamedList; -import org.apache.solr.metrics.AggregateMetric; -import org.apache.solr.metrics.MetricsMap; -import org.apache.solr.metrics.SolrMetricManager; -import org.junit.Test; - -public class MetricUtilsTest extends SolrTestCaseJ4 { - - @Test - public void testSolrTimerGetSnapshot() { - // create a timer with up to 100 data points - final Timer timer = new Timer(); - final int iterations = random().nextInt(100); - for (int i = 0; i < iterations; ++i) { - timer.update(random().nextInt(Integer.MAX_VALUE - 1) + 1, TimeUnit.NANOSECONDS); - } - // obtain timer metrics - Map map = new HashMap<>(); - MetricUtils.convertTimer( - "", - timer, - MetricUtils.ALL_PROPERTIES, - false, - false, - ".", - (k, v) -> { - ((MapWriter) v).toMap(map); - }); - NamedList lst = new NamedList<>(map); - // check that expected metrics were obtained - assertEquals(14, lst.size()); - final Snapshot snapshot = timer.getSnapshot(); - // cannot test avgRequestsPerMinute directly because mean rate changes as time increases! - // assertEquals(lst.get("avgRequestsPerSecond"), timer.getMeanRate()); - assertEquals(timer.getFiveMinuteRate(), lst.get("5minRate")); - assertEquals(timer.getFifteenMinuteRate(), lst.get("15minRate")); - assertEquals(MetricUtils.nsToMs(snapshot.getMean()), lst.get("mean_ms")); - assertEquals(MetricUtils.nsToMs(snapshot.getMedian()), lst.get("median_ms")); - assertEquals(MetricUtils.nsToMs(snapshot.get75thPercentile()), lst.get("p75_ms")); - assertEquals(MetricUtils.nsToMs(snapshot.get95thPercentile()), lst.get("p95_ms")); - assertEquals(MetricUtils.nsToMs(snapshot.get99thPercentile()), lst.get("p99_ms")); - assertEquals(MetricUtils.nsToMs(snapshot.get999thPercentile()), lst.get("p999_ms")); - } - - @Test - @SuppressWarnings({"unchecked"}) - public void testMetrics() throws Exception { - MetricRegistry registry = new MetricRegistry(); - Counter counter = registry.counter("counter"); - counter.inc(); - Timer timer = registry.timer("timer"); - Timer.Context ctx = timer.time(); - Thread.sleep(150); - ctx.stop(); - Meter meter = registry.meter("meter"); - meter.mark(); - Histogram histogram = registry.histogram("histogram"); - histogram.update(10); - - // SOLR-14252: check that negative values are supported correctly - // NB a-d represent the same metric from multiple nodes - AggregateMetric am1 = new AggregateMetric(); - registry.register("aggregate1", am1); - am1.set("a", -10); - am1.set("b", 1); - am1.set("b", -2); - am1.set("c", -3); - am1.set("d", -5); - - // SOLR-14252: check that aggregation of non-Number metrics don't trigger NullPointerException - AggregateMetric am2 = new AggregateMetric(); - registry.register("aggregate2", am2); - am2.set("a", false); - am2.set("b", true); - - Gauge gauge = () -> "foobar"; - registry.register("gauge", gauge); - Gauge error = - () -> { - throw new InternalError("Memory Pool not found error"); - }; - registry.register("memory.expected.error", error); - - MetricsMap metricsMap = - new MetricsMap( - map -> { - map.putNoEx("foo", "bar"); - }); - registry.register("map", metricsMap); - - SolrMetricManager.GaugeWrapper> gaugeWrapper = - new SolrMetricManager.GaugeWrapper<>(metricsMap, "foo-tag"); - registry.register("wrappedGauge", gaugeWrapper); - - MetricUtils.toMaps( - registry, - Collections.singletonList(MetricFilter.ALL), - MetricFilter.ALL, - MetricUtils.ALL_PROPERTIES, - false, - false, - false, - false, - (k, o) -> { - Map v = new HashMap<>(); - if (o != null) { - ((MapWriter) o).toMap(v); - } - if (k.startsWith("counter")) { - assertEquals(1L, v.get("count")); - } else if (k.startsWith("gauge")) { - assertEquals("foobar", v.get("value")); - } else if (k.startsWith("timer")) { - assertEquals(1L, v.get("count")); - assertTrue(((Number) v.get("min_ms")).intValue() > 100); - } else if (k.startsWith("meter")) { - assertEquals(1L, v.get("count")); - } else if (k.startsWith("histogram")) { - assertEquals(1L, v.get("count")); - } else if (k.startsWith("aggregate1")) { - assertEquals(4, v.get("count")); - Map values = (Map) v.get("values"); - assertNotNull(values); - assertEquals(4, values.size()); - Map update = (Map) values.get("a"); - assertEquals(-10, update.get("value")); - assertEquals(1, update.get("updateCount")); - update = (Map) values.get("b"); - assertEquals(-2, update.get("value")); - assertEquals(2, update.get("updateCount")); - assertEquals(-10D, v.get("min")); - assertEquals(-2D, v.get("max")); - assertEquals(-5D, v.get("mean")); - } else if (k.startsWith("aggregate2")) { - // SOLR-14252: non-Number metric aggregations should return 0 rather than throwing NPE - assertEquals(2, v.get("count")); - assertEquals(0D, v.get("min")); - assertEquals(0D, v.get("max")); - assertEquals(0D, v.get("mean")); - } else if (k.startsWith("memory.expected.error")) { - assertTrue(v.isEmpty()); - } else if (k.startsWith("map") || k.startsWith("wrapped")) { - assertNotNull(v.toString(), v.get("value")); - assertTrue(v.toString(), v.get("value") instanceof Map); - assertEquals(v.toString(), "bar", ((Map) v.get("value")).get("foo")); - } - }); - // test compact format - MetricUtils.toMaps( - registry, - Collections.singletonList(MetricFilter.ALL), - MetricFilter.ALL, - MetricUtils.ALL_PROPERTIES, - false, - false, - true, - false, - (k, o) -> { - if (k.startsWith("counter")) { - assertTrue(o instanceof Long); - assertEquals(1L, o); - } else if (k.startsWith("gauge")) { - assertTrue(o instanceof String); - assertEquals("foobar", o); - } else if (k.startsWith("timer")) { - assertTrue(o instanceof MapWriter); - Map v = new HashMap<>(); - ((MapWriter) o).toMap(v); - assertEquals(1L, v.get("count")); - assertTrue(((Number) v.get("min_ms")).intValue() > 100); - } else if (k.startsWith("meter")) { - assertTrue(o instanceof MapWriter); - Map v = new HashMap<>(); - ((MapWriter) o).toMap(v); - assertEquals(1L, v.get("count")); - } else if (k.startsWith("histogram")) { - assertTrue(o instanceof MapWriter); - Map v = new HashMap<>(); - ((MapWriter) o).toMap(v); - assertEquals(1L, v.get("count")); - } else if (k.startsWith("aggregate1")) { - assertTrue(o instanceof MapWriter); - Map v = new HashMap<>(); - ((MapWriter) o).toMap(v); - assertEquals(4, v.get("count")); - Map values = (Map) v.get("values"); - assertNotNull(values); - assertEquals(4, values.size()); - Map update = (Map) values.get("a"); - assertEquals(-10, update.get("value")); - assertEquals(1, update.get("updateCount")); - update = (Map) values.get("b"); - assertEquals(-2, update.get("value")); - assertEquals(2, update.get("updateCount")); - } else if (k.startsWith("aggregate2")) { - assertTrue(o instanceof MapWriter); - Map v = new HashMap<>(); - ((MapWriter) o).toMap(v); - assertEquals(2, v.get("count")); - Map values = (Map) v.get("values"); - assertNotNull(values); - assertEquals(2, values.size()); - Map update = (Map) values.get("a"); - assertEquals(false, update.get("value")); - assertEquals(1, update.get("updateCount")); - update = (Map) values.get("b"); - assertEquals(true, update.get("value")); - assertEquals(1, update.get("updateCount")); - } else if (k.startsWith("memory.expected.error")) { - assertNull(o); - } else if (k.startsWith("map") || k.startsWith("wrapped")) { - assertTrue(o instanceof MapWriter); - MapWriter writer = (MapWriter) o; - assertEquals(1, writer._size()); - assertEquals("bar", writer._get("foo")); - } else { - assertTrue(o instanceof MapWriter); - Map v = new HashMap<>(); - ((MapWriter) o).toMap(v); - assertEquals(1L, v.get("count")); - } - }); - } -} diff --git a/solr/core/src/test/org/apache/solr/util/stats/OtelInstrumentedExecutorServiceTest.java b/solr/core/src/test/org/apache/solr/util/stats/OtelInstrumentedExecutorServiceTest.java index 550477620e0..8a024296a75 100644 --- a/solr/core/src/test/org/apache/solr/util/stats/OtelInstrumentedExecutorServiceTest.java +++ b/solr/core/src/test/org/apache/solr/util/stats/OtelInstrumentedExecutorServiceTest.java @@ -49,7 +49,7 @@ public class OtelInstrumentedExecutorServiceTest extends SolrTestCase { @Before public void setUpMetrics() { - metricsContext = new SolrMetricsContext(new SolrMetricManager(null), REGISTRY_NAME, TAG_NAME); + metricsContext = new SolrMetricsContext(new SolrMetricManager(null), REGISTRY_NAME); } @Test diff --git a/solr/cross-dc-manager/gradle.lockfile b/solr/cross-dc-manager/gradle.lockfile index 6bf0109d189..b68ba032e3d 100644 --- a/solr/cross-dc-manager/gradle.lockfile +++ b/solr/cross-dc-manager/gradle.lockfile @@ -47,16 +47,14 @@ commons-collections:commons-collections:3.2.2=jarValidation,runtimeClasspath,run commons-digester:commons-digester:2.1=jarValidation,runtimeClasspath,runtimeLibs,testRuntimeClasspath commons-io:commons-io:2.17.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath commons-validator:commons-validator:1.7=jarValidation,runtimeClasspath,runtimeLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath io.dropwizard.metrics:metrics-core:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath io.dropwizard.metrics:metrics-healthchecks:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-jakarta-servlets:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath io.dropwizard.metrics:metrics-json:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath +io.dropwizard.metrics:metrics-jvm:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath diff --git a/solr/modules/analysis-extras/gradle.lockfile b/solr/modules/analysis-extras/gradle.lockfile index aea208ebcbf..108fc89f756 100644 --- a/solr/modules/analysis-extras/gradle.lockfile +++ b/solr/modules/analysis-extras/gradle.lockfile @@ -35,13 +35,10 @@ com.tdunning:t-digest:3.3=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,s commons-cli:commons-cli:1.10.0=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-codec:commons-codec:1.19.0=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-io:commons-io:2.17.0=apiHelper,compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=apiHelper,compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.2.6.Final=apiHelper,compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath diff --git a/solr/modules/clustering/gradle.lockfile b/solr/modules/clustering/gradle.lockfile index 8c950bdd034..cab7bb569cd 100644 --- a/solr/modules/clustering/gradle.lockfile +++ b/solr/modules/clustering/gradle.lockfile @@ -33,13 +33,10 @@ com.tdunning:t-digest:3.3=jarValidation,runtimeClasspath,runtimeLibs,solrPlatfor commons-cli:commons-cli:1.10.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-codec:commons-codec:1.19.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-io:commons-io:2.17.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath diff --git a/solr/modules/cross-dc/gradle.lockfile b/solr/modules/cross-dc/gradle.lockfile index f54c28c5dfc..fb6b44255af 100644 --- a/solr/modules/cross-dc/gradle.lockfile +++ b/solr/modules/cross-dc/gradle.lockfile @@ -34,13 +34,10 @@ com.tdunning:t-digest:3.3=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,s commons-cli:commons-cli:1.10.0=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-codec:commons-codec:1.19.0=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-io:commons-io:2.17.0=apiHelper,compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath io.dropwizard.metrics:metrics-core:4.2.26=apiHelper,compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.2.6.Final=apiHelper,compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath diff --git a/solr/modules/extraction/gradle.lockfile b/solr/modules/extraction/gradle.lockfile index dfc67bbf342..db4d9bd1a37 100644 --- a/solr/modules/extraction/gradle.lockfile +++ b/solr/modules/extraction/gradle.lockfile @@ -61,13 +61,10 @@ edu.ucar:httpservices:4.5.5=compileClasspath,jarValidation,runtimeClasspath,runt edu.ucar:netcdf4:4.5.5=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath edu.ucar:udunits:4.5.5=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath edu.usc.ir:sentiment-analysis-parser:0.1=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath diff --git a/solr/modules/gcs-repository/gradle.lockfile b/solr/modules/gcs-repository/gradle.lockfile index 544c741d8ae..137765519b6 100644 --- a/solr/modules/gcs-repository/gradle.lockfile +++ b/solr/modules/gcs-repository/gradle.lockfile @@ -62,13 +62,10 @@ com.tdunning:t-digest:3.3=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,s commons-cli:commons-cli:1.10.0=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-codec:commons-codec:1.19.0=apiHelper,compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath commons-io:commons-io:2.17.0=apiHelper,compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=apiHelper,compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.grpc:grpc-alts:1.65.1=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath diff --git a/solr/modules/jwt-auth/build.gradle b/solr/modules/jwt-auth/build.gradle index be4ae8f38bc..25f46c46c0a 100644 --- a/solr/modules/jwt-auth/build.gradle +++ b/solr/modules/jwt-auth/build.gradle @@ -36,7 +36,6 @@ dependencies { implementation libs.bc.jose4j - implementation libs.dropwizard.metrics.core implementation libs.eclipse.jetty.client implementation libs.eclipse.jetty.http implementation libs.eclipse.jetty.toolchain.servletapi diff --git a/solr/modules/jwt-auth/gradle.lockfile b/solr/modules/jwt-auth/gradle.lockfile index bf36af6c0b0..35118bbe26e 100644 --- a/solr/modules/jwt-auth/gradle.lockfile +++ b/solr/modules/jwt-auth/gradle.lockfile @@ -43,13 +43,10 @@ com.tdunning:t-digest:3.3=jarValidation,runtimeClasspath,runtimeLibs,solrPlatfor commons-cli:commons-cli:1.10.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-codec:commons-codec:1.19.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath commons-io:commons-io:2.17.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.github.microutils:kotlin-logging-jvm:3.0.5=jarValidation,testRuntimeClasspath diff --git a/solr/modules/langid/gradle.lockfile b/solr/modules/langid/gradle.lockfile index 2b52e6abf02..4f6bff6891e 100644 --- a/solr/modules/langid/gradle.lockfile +++ b/solr/modules/langid/gradle.lockfile @@ -34,13 +34,10 @@ com.tdunning:t-digest:3.3=jarValidation,runtimeClasspath,runtimeLibs,solrPlatfor commons-cli:commons-cli:1.10.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-codec:commons-codec:1.19.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-io:commons-io:2.17.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath diff --git a/solr/modules/llm/gradle.lockfile b/solr/modules/llm/gradle.lockfile index eb0f21cf02d..ee3c1fce41e 100644 --- a/solr/modules/llm/gradle.lockfile +++ b/solr/modules/llm/gradle.lockfile @@ -48,13 +48,10 @@ dev.langchain4j:langchain4j-core:0.35.0=compileClasspath,jarValidation,runtimeCl dev.langchain4j:langchain4j-hugging-face:0.35.0=jarValidation,runtimeClasspath,runtimeLibs,testRuntimeClasspath dev.langchain4j:langchain4j-mistral-ai:0.35.0=jarValidation,runtimeClasspath,runtimeLibs,testRuntimeClasspath dev.langchain4j:langchain4j-open-ai:0.35.0=jarValidation,runtimeClasspath,runtimeLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath diff --git a/solr/modules/ltr/gradle.lockfile b/solr/modules/ltr/gradle.lockfile index 61a53133e8a..1e06f146eb8 100644 --- a/solr/modules/ltr/gradle.lockfile +++ b/solr/modules/ltr/gradle.lockfile @@ -33,13 +33,10 @@ com.tdunning:t-digest:3.3=jarValidation,runtimeClasspath,runtimeLibs,solrPlatfor commons-cli:commons-cli:1.10.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-codec:commons-codec:1.19.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-io:commons-io:2.17.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath diff --git a/solr/modules/opentelemetry/gradle.lockfile b/solr/modules/opentelemetry/gradle.lockfile index 934ef9815c7..fe99045d4f8 100644 --- a/solr/modules/opentelemetry/gradle.lockfile +++ b/solr/modules/opentelemetry/gradle.lockfile @@ -39,13 +39,10 @@ com.tdunning:t-digest:3.3=jarValidation,runtimeClasspath,runtimeLibs,solrPlatfor commons-cli:commons-cli:1.10.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-codec:commons-codec:1.19.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-io:commons-io:2.17.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.grpc:grpc-api:1.65.1=jarValidation,runtimeClasspath,runtimeLibs,testRuntimeClasspath diff --git a/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/TestDistributedTracing.java b/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/TestDistributedTracing.java index 4daba5c87a4..9e7c127f4f6 100644 --- a/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/TestDistributedTracing.java +++ b/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/TestDistributedTracing.java @@ -17,11 +17,14 @@ package org.apache.solr.opentelemetry; +import static org.apache.solr.handler.admin.MetricsHandler.PROMETHEUS_METRICS_WT; + import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; import io.opentelemetry.sdk.trace.data.SpanData; import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -32,6 +35,7 @@ import org.apache.solr.client.solrj.SolrRequest.SolrRequestType; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.CloudSolrClient; +import org.apache.solr.client.solrj.impl.InputStreamResponseParser; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.request.GenericSolrRequest; import org.apache.solr.client.solrj.request.V2Request; @@ -39,6 +43,7 @@ import org.apache.solr.client.solrj.response.V2Response; import org.apache.solr.cloud.SolrCloudTestCase; import org.apache.solr.common.SolrDocumentList; +import org.apache.solr.common.util.NamedList; import org.apache.solr.util.tracing.TraceUtils; import org.junit.AfterClass; import org.junit.Before; @@ -131,8 +136,11 @@ public void test() throws IOException, SolrServerException { public void testAdminApi() throws Exception { CloudSolrClient cloudClient = cluster.getSolrClient(); - cloudClient.request( - new GenericSolrRequest(SolrRequest.METHOD.GET, "/admin/metrics", SolrRequestType.ADMIN)); + GenericSolrRequest request = + new GenericSolrRequest(SolrRequest.METHOD.GET, "/admin/metrics", SolrRequestType.ADMIN); + request.setResponseParser(new InputStreamResponseParser(PROMETHEUS_METRICS_WT)); + NamedList rsp = cloudClient.request(request); + ((InputStream) rsp.get("stream")).close(); var finishedSpans = getAndClearSpans(); assertEquals("get:/admin/metrics", finishedSpans.get(0).getName()); diff --git a/solr/modules/s3-repository/gradle.lockfile b/solr/modules/s3-repository/gradle.lockfile index 7774a5b3a4f..3f1cd6aa22f 100644 --- a/solr/modules/s3-repository/gradle.lockfile +++ b/solr/modules/s3-repository/gradle.lockfile @@ -46,13 +46,10 @@ com.tdunning:t-digest:3.3=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,s commons-cli:commons-cli:1.10.0=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-codec:commons-codec:1.19.0=apiHelper,compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath commons-io:commons-io:2.17.0=apiHelper,compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=apiHelper,compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=apiHelper,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.micrometer:micrometer-commons:1.13.3=jarValidation,testCompileClasspath,testRuntimeClasspath diff --git a/solr/modules/scripting/gradle.lockfile b/solr/modules/scripting/gradle.lockfile index 8db04cfb975..ec325d05b00 100644 --- a/solr/modules/scripting/gradle.lockfile +++ b/solr/modules/scripting/gradle.lockfile @@ -33,13 +33,10 @@ com.tdunning:t-digest:3.3=jarValidation,runtimeClasspath,runtimeLibs,solrPlatfor commons-cli:commons-cli:1.10.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-codec:commons-codec:1.19.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-io:commons-io:2.17.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath diff --git a/solr/modules/sql/gradle.lockfile b/solr/modules/sql/gradle.lockfile index a4c455939e2..4363255d7c9 100644 --- a/solr/modules/sql/gradle.lockfile +++ b/solr/modules/sql/gradle.lockfile @@ -36,13 +36,10 @@ com.tdunning:t-digest:3.3=jarValidation,runtimeClasspath,runtimeLibs,solrPlatfor commons-cli:commons-cli:1.10.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-codec:commons-codec:1.19.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath commons-io:commons-io:2.17.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath diff --git a/solr/prometheus-exporter/build.gradle b/solr/prometheus-exporter/build.gradle deleted file mode 100644 index 26204db9487..00000000000 --- a/solr/prometheus-exporter/build.gradle +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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. - */ - -apply plugin: 'java-library' -// this is actually more of an 'application' but we don't want all of what Gradle adds - -description = 'Prometheus exporter for exposing metrics from Solr using Metrics API and Search API' - -dependencies { - implementation platform(project(':platform')) - implementation platform(libs.fasterxml.jackson.bom) - implementation project(':solr:solrj') - runtimeOnly project(':solr:solrj-zookeeper') - // ideally remove ZK dep - implementation(libs.apache.zookeeper.zookeeper, { - exclude group: "org.apache.yetus", module: "audience-annotations" - }) - - implementation(libs.prometheus.simpleclient, { - exclude group: "io.prometheus", module: "simpleclient_tracer_common" - exclude group: "io.prometheus", module: "simpleclient_tracer_otel" - exclude group: "io.prometheus", module: "simpleclient_tracer_otel_agent" - }) - implementation(libs.prometheus.simpleclient.httpserver, { - exclude group: "io.prometheus", module: "simpleclient_tracer_common" - exclude group: "io.prometheus", module: "simpleclient_tracer_otel" - exclude group: "io.prometheus", module: "simpleclient_tracer_otel_agent" - }) - implementation(libs.thisptr.jacksonjq, { - exclude group: "org.jruby.joni", module: "joni" - exclude group: "com.fasterxml.jackson.core", module: "jackson-databind" - }) - implementation libs.fasterxml.jackson.core.databind - implementation libs.commonscli.commonscli - implementation(libs.benmanes.caffeine) { transitive = false } - implementation libs.slf4j.api - implementation libs.commonscodec.commonscodec - - runtimeOnly libs.apache.log4j.api - runtimeOnly libs.apache.log4j.core - runtimeOnly libs.apache.log4j.slf4j2impl - runtimeOnly libs.lmax.disruptor - - testImplementation project(':solr:test-framework') - testImplementation project(':solr:solrj-zookeeper') - testImplementation libs.carrotsearch.randomizedtesting.runner - testImplementation libs.junit.junit - testImplementation libs.apache.lucene.testframework - - testImplementation libs.apache.httpcomponents.httpclient - testImplementation libs.apache.httpcomponents.httpcore -} - -ext { - mainClass = 'org.apache.solr.prometheus.exporter.SolrExporter' -} - -task run(type: JavaExec) { - group = 'application' - description = 'Run the main class with JavaExecTask' - mainClass = project.ext.mainClass - classpath = sourceSets.main.runtimeClasspath - systemProperties = ["log4j.configurationFile":"file:conf/log4j2.xml"] - args = ["-f", "conf/solr-exporter-config.xml"] -} - -jar { - manifest { - attributes('Main-Class': project.ext.mainClass) - } -} - -assemblePackaging { - // Add two folders to default packaging. - from(projectDir, { - include "bin/**" - include "conf/**" - }) -} diff --git a/solr/prometheus-exporter/gradle.lockfile b/solr/prometheus-exporter/gradle.lockfile deleted file mode 100644 index 3f224e849dc..00000000000 --- a/solr/prometheus-exporter/gradle.lockfile +++ /dev/null @@ -1,184 +0,0 @@ -# This is a Gradle generated file for dependency locking. -# Manual edits can break the build and are not advised. -# This file is expected to be part of source control. -com.carrotsearch.randomizedtesting:randomizedtesting-runner:2.8.3=jarValidation,testCompileClasspath,testRuntimeClasspath -com.carrotsearch:hppc:0.10.0=jarValidation,solrPlatformLibs,testRuntimeClasspath -com.fasterxml.jackson.core:jackson-annotations:2.20=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -com.fasterxml.jackson.core:jackson-core:2.20.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -com.fasterxml.jackson.core:jackson-databind:2.20.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.20.0=jarValidation,solrPlatformLibs,testRuntimeClasspath -com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.20.0=jarValidation,solrPlatformLibs,testRuntimeClasspath -com.fasterxml.jackson.module:jackson-module-jakarta-xmlbind-annotations:2.20.0=jarValidation,solrPlatformLibs,testRuntimeClasspath -com.fasterxml.jackson:jackson-bom:2.20.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -com.fasterxml.woodstox:woodstox-core:7.0.0=jarValidation,solrPlatformLibs,testRuntimeClasspath -com.github.ben-manes.caffeine:caffeine:3.2.2=annotationProcessor,compileClasspath,errorprone,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath -com.github.kevinstern:software-and-algorithms:1.0=annotationProcessor,errorprone,testAnnotationProcessor -com.google.auto.service:auto-service-annotations:1.0.1=annotationProcessor,errorprone,testAnnotationProcessor -com.google.auto.value:auto-value-annotations:1.11.0=annotationProcessor,errorprone,testAnnotationProcessor -com.google.auto:auto-common:1.2.2=annotationProcessor,errorprone,testAnnotationProcessor -com.google.errorprone:error_prone_annotation:2.41.0=annotationProcessor,errorprone,testAnnotationProcessor -com.google.errorprone:error_prone_annotations:2.41.0=annotationProcessor,errorprone,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath -com.google.errorprone:error_prone_check_api:2.41.0=annotationProcessor,errorprone,testAnnotationProcessor -com.google.errorprone:error_prone_core:2.41.0=annotationProcessor,errorprone,testAnnotationProcessor -com.google.googlejavaformat:google-java-format:1.27.0=annotationProcessor,errorprone,testAnnotationProcessor -com.google.guava:failureaccess:1.0.3=annotationProcessor,errorprone,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath -com.google.guava:guava:33.4.8-jre=annotationProcessor,errorprone,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath -com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,errorprone,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath -com.google.j2objc:j2objc-annotations:3.1=annotationProcessor,errorprone,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath -com.google.protobuf:protobuf-java:3.25.8=annotationProcessor,errorprone,testAnnotationProcessor -com.j256.simplemagic:simplemagic:1.17=jarValidation,solrPlatformLibs,testRuntimeClasspath -com.jayway.jsonpath:json-path:2.9.0=jarValidation,solrPlatformLibs,testRuntimeClasspath -com.lmax:disruptor:3.4.4=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -com.tdunning:t-digest:3.3=jarValidation,solrPlatformLibs,testRuntimeClasspath -commons-cli:commons-cli:1.10.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -commons-codec:commons-codec:1.19.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -commons-io:commons-io:2.17.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor -io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor -io.netty:netty-buffer:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.netty:netty-codec-base:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.netty:netty-common:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.netty:netty-handler:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.netty:netty-resolver:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.netty:netty-tcnative-boringssl-static:2.0.70.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.netty:netty-tcnative-classes:2.0.70.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.netty:netty-transport-classes-epoll:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.netty:netty-transport-native-epoll:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.netty:netty-transport-native-unix-common:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.netty:netty-transport:4.2.6.Final=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-incubator:2.11.0-alpha=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.opentelemetry.instrumentation:opentelemetry-instrumentation-api:2.11.0=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.opentelemetry.instrumentation:opentelemetry-runtime-telemetry-java17:2.11.0-alpha=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.opentelemetry.instrumentation:opentelemetry-runtime-telemetry-java8:2.11.0-alpha=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.opentelemetry.semconv:opentelemetry-semconv:1.29.0-alpha=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.opentelemetry:opentelemetry-api-incubator:1.45.0-alpha=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.opentelemetry:opentelemetry-api:1.53.0=jarValidation,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.opentelemetry:opentelemetry-common:1.53.0=jarValidation,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.opentelemetry:opentelemetry-context:1.53.0=jarValidation,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -io.opentelemetry:opentelemetry-exporter-common:1.50.0=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.opentelemetry:opentelemetry-exporter-prometheus:1.50.0-alpha=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.opentelemetry:opentelemetry-sdk-common:1.53.0=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi:1.50.0=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.opentelemetry:opentelemetry-sdk-logs:1.53.0=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.opentelemetry:opentelemetry-sdk-metrics:1.53.0=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.opentelemetry:opentelemetry-sdk-trace:1.53.0=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.opentelemetry:opentelemetry-sdk:1.53.0=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.prometheus:prometheus-metrics-config:1.3.6=jarValidation,testRuntimeClasspath -io.prometheus:prometheus-metrics-exporter-common:1.3.6=jarValidation,testRuntimeClasspath -io.prometheus:prometheus-metrics-exporter-httpserver:1.3.6=jarValidation,testRuntimeClasspath -io.prometheus:prometheus-metrics-exposition-formats:1.1.0=solrPlatformLibs -io.prometheus:prometheus-metrics-exposition-formats:1.3.6=jarValidation,testRuntimeClasspath -io.prometheus:prometheus-metrics-exposition-textformats:1.3.6=jarValidation,testRuntimeClasspath -io.prometheus:prometheus-metrics-model:1.1.0=solrPlatformLibs -io.prometheus:prometheus-metrics-model:1.3.6=jarValidation,testRuntimeClasspath -io.prometheus:simpleclient:0.16.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath -io.prometheus:simpleclient_common:0.16.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath -io.prometheus:simpleclient_httpserver:0.16.0=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath -io.sgr:s2-geometry-library-java:1.0.0=jarValidation,solrPlatformLibs,testRuntimeClasspath -io.swagger.core.v3:swagger-annotations-jakarta:2.2.22=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -jakarta.annotation:jakarta.annotation-api:2.1.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -jakarta.inject:jakarta.inject-api:2.0.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -jakarta.servlet:jakarta.servlet-api:6.0.0=jarValidation,testCompileClasspath,testRuntimeClasspath -jakarta.validation:jakarta.validation-api:3.0.2=jarValidation,solrPlatformLibs,testRuntimeClasspath -jakarta.ws.rs:jakarta.ws.rs-api:3.1.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -javax.inject:javax.inject:1=annotationProcessor,errorprone,testAnnotationProcessor -junit:junit:4.13.2=jarValidation,testCompileClasspath,testRuntimeClasspath -net.thisptr:jackson-jq:0.0.13=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,testCompileClasspath,testRuntimeClasspath -org.antlr:antlr4-runtime:4.13.2=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.commons:commons-exec:1.5.0=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.commons:commons-lang3:3.18.0=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.commons:commons-math3:3.6.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.curator:curator-client:5.9.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.apache.curator:curator-framework:5.9.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.apache.curator:curator-test:5.9.0=jarValidation,testRuntimeClasspath -org.apache.httpcomponents:httpclient:4.5.14=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.apache.httpcomponents:httpcore:4.4.16=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.apache.httpcomponents:httpmime:4.5.14=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -org.apache.logging.log4j:log4j-1.2-api:2.21.0=solrPlatformLibs -org.apache.logging.log4j:log4j-api:2.21.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -org.apache.logging.log4j:log4j-core:2.21.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -org.apache.logging.log4j:log4j-layout-template-json:2.21.0=solrPlatformLibs -org.apache.logging.log4j:log4j-slf4j2-impl:2.21.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -org.apache.logging.log4j:log4j-web:2.21.0=solrPlatformLibs -org.apache.lucene:lucene-analysis-common:10.2.1=jarValidation,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.apache.lucene:lucene-analysis-kuromoji:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-analysis-nori:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-analysis-phonetic:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-backward-codecs:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-classification:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-codecs:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-core:10.2.1=jarValidation,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.apache.lucene:lucene-expressions:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-facet:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-grouping:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-highlighter:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-join:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-memory:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-misc:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-queries:10.2.1=jarValidation,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.apache.lucene:lucene-queryparser:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-sandbox:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-spatial-extras:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-spatial3d:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-suggest:10.2.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.apache.lucene:lucene-test-framework:10.2.1=jarValidation,testCompileClasspath,testRuntimeClasspath -org.apache.zookeeper:zookeeper-jute:3.9.4=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.apache.zookeeper:zookeeper:3.9.4=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.apiguardian:apiguardian-api:1.1.2=jarValidation,testRuntimeClasspath -org.codehaus.woodstox:stax2-api:4.2.2=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.eclipse.jetty.ee10:jetty-ee10-servlet:12.0.19=jarValidation,testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty.http2:jetty-http2-client-transport:12.0.19=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -org.eclipse.jetty.http2:jetty-http2-client:12.0.19=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty.http2:jetty-http2-common:12.0.19=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty.http2:jetty-http2-hpack:12.0.19=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty.http2:jetty-http2-server:12.0.19=jarValidation,testRuntimeClasspath -org.eclipse.jetty.toolchain:jetty-jakarta-servlet-api:5.0.2=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.eclipse.jetty:jetty-alpn-client:12.0.19=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-alpn-java-client:12.0.19=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -org.eclipse.jetty:jetty-alpn-java-server:12.0.19=jarValidation,testRuntimeClasspath -org.eclipse.jetty:jetty-alpn-server:12.0.19=jarValidation,testRuntimeClasspath -org.eclipse.jetty:jetty-client:12.0.19=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -org.eclipse.jetty:jetty-http:12.0.19=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-io:12.0.19=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-rewrite:12.0.19=jarValidation,testRuntimeClasspath -org.eclipse.jetty:jetty-security:12.0.19=jarValidation,testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-server:12.0.19=jarValidation,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-session:12.0.19=jarValidation,testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-util:12.0.19=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.glassfish.hk2.external:aopalliance-repackaged:3.1.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.glassfish.hk2:hk2-api:3.1.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.glassfish.hk2:hk2-locator:3.1.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.glassfish.hk2:hk2-utils:3.1.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.glassfish.hk2:osgi-resource-locator:1.0.3=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.glassfish.jersey.containers:jersey-container-jetty-http:2.39.1=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.glassfish.jersey.core:jersey-client:3.1.11=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.glassfish.jersey.core:jersey-common:3.1.11=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.glassfish.jersey.core:jersey-server:3.1.11=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.glassfish.jersey.ext:jersey-entity-filtering:3.1.11=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.glassfish.jersey.inject:jersey-hk2:3.1.11=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.glassfish.jersey.media:jersey-media-json-jackson:3.1.11=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.hamcrest:hamcrest:3.0=jarValidation,testCompileClasspath,testRuntimeClasspath -org.javassist:javassist:3.30.2-GA=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.jspecify:jspecify:1.0.0=annotationProcessor,errorprone,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath -org.junit.jupiter:junit-jupiter-api:5.6.2=jarValidation,testRuntimeClasspath -org.junit.platform:junit-platform-commons:1.6.2=jarValidation,testRuntimeClasspath -org.junit:junit-bom:5.6.2=jarValidation,testRuntimeClasspath -org.locationtech.spatial4j:spatial4j:0.8=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.opentest4j:opentest4j:1.2.0=jarValidation,testRuntimeClasspath -org.ow2.asm:asm-commons:9.8=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.ow2.asm:asm-tree:9.8=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.ow2.asm:asm:9.8=jarValidation,solrPlatformLibs,testRuntimeClasspath -org.pcollections:pcollections:4.0.1=annotationProcessor,errorprone,testAnnotationProcessor -org.semver4j:semver4j:6.0.0=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -org.slf4j:jcl-over-slf4j:2.0.17=jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testRuntimeClasspath -org.slf4j:jul-to-slf4j:2.0.17=solrPlatformLibs -org.slf4j:slf4j-api:2.0.17=compileClasspath,jarValidation,runtimeClasspath,runtimeLibs,solrPlatformLibs,testCompileClasspath,testRuntimeClasspath -org.xerial.snappy:snappy-java:1.1.10.8=jarValidation,solrPlatformLibs,testRuntimeClasspath -empty=apiHelper,apiHelperTest,compileOnlyHelper,compileOnlyHelperTest,missingdoclet,packaging,permitAggregatorUse,permitTestAggregatorUse,permitTestUnusedDeclared,permitTestUsedUndeclared,permitUnusedDeclared,permitUsedUndeclared,signatures diff --git a/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/MetricsQuery.java b/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/MetricsQuery.java deleted file mode 100644 index d1b209d6921..00000000000 --- a/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/exporter/MetricsQuery.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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.solr.prometheus.exporter; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.regex.Matcher; -import net.thisptr.jackson.jq.JsonQuery; -import net.thisptr.jackson.jq.exception.JsonQueryException; -import org.apache.solr.common.params.ModifiableSolrParams; -import org.apache.solr.common.util.DOMUtil; -import org.apache.solr.common.util.NamedList; -import org.w3c.dom.Node; - -public class MetricsQuery { - - private final String path; - private final ModifiableSolrParams parameters; - private final String core; - private final String collection; - private final List jsonQueries; - - private MetricsQuery( - String path, - ModifiableSolrParams parameters, - String core, - String collection, - List jsonQueries) { - this.path = path; - this.parameters = parameters; - this.core = core; - this.collection = collection; - this.jsonQueries = jsonQueries; - } - - public MetricsQuery withCore(String core) { - return new MetricsQuery( - getPath(), getParameters(), core, getCollection().orElse(null), getJsonQueries()); - } - - public MetricsQuery withCollection(String collection) { - return new MetricsQuery( - getPath(), getParameters(), getCore().orElse(null), collection, getJsonQueries()); - } - - public String getPath() { - return path; - } - - public Optional getCore() { - return Optional.ofNullable(core); - } - - public Optional getCollection() { - return Optional.ofNullable(collection); - } - - public List getJsonQueries() { - return jsonQueries; - } - - public static List from(Node node, Map jqTemplates) - throws JsonQueryException { - List metricsQueries = new ArrayList<>(); - - NamedList config = DOMUtil.childNodesToNamedList(node); - @SuppressWarnings("unchecked") - List> requests = (List>) config.getAll("request"); - - for (NamedList request : requests) { - NamedList query = (NamedList) request.get("query"); - @SuppressWarnings("unchecked") - NamedList queryParameters = (NamedList) query.get("params"); - String path = (String) query.get("path"); - String core = (String) query.get("core"); - String collection = (String) query.get("collection"); - @SuppressWarnings("unchecked") - List jsonQueries = (ArrayList) request.get("jsonQueries"); - - ModifiableSolrParams params = new ModifiableSolrParams(); - if (queryParameters != null) { - for (Map.Entry entrySet : queryParameters.asShallowMap().entrySet()) { - if (entrySet.getValue() instanceof Collection) { - @SuppressWarnings("unchecked") - Collection values = (Collection) entrySet.getValue(); - for (Object value : values) { - params.add(entrySet.getKey(), String.valueOf(value)); - } - } else { - params.add(entrySet.getKey(), String.valueOf(entrySet.getValue())); - } - } - } - - List compiledQueries = new ArrayList<>(); - if (jsonQueries != null) { - for (String jsonQuery : jsonQueries) { - - // does this query refer to a reusable jq template to reduce boilerplate in the config? - final String jsonQueryCollapseWs = jsonQuery.replaceAll("\\s+", " ").trim(); - if (jsonQueryCollapseWs.startsWith("$jq:")) { - Optional maybeMatcher = MetricsQueryTemplate.matches(jsonQueryCollapseWs); - if (maybeMatcher.isPresent()) { - Matcher matcher = maybeMatcher.get(); - String templateName = matcher.group("TEMPLATE"); - MetricsQueryTemplate template = jqTemplates.get(templateName); - if (template == null) { - throw new IllegalStateException( - "jq template '" + matcher.group("TEMPLATE") + "' not found!"); - } - - jsonQuery = template.applyTemplate(matcher); - } - } - - JsonQuery compiledJsonQuery = JsonQuery.compile(jsonQuery); - compiledQueries.add(compiledJsonQuery); - } - } - - metricsQueries.add(new MetricsQuery(path, params, core, collection, compiledQueries)); - } - - return metricsQueries; - } - - public ModifiableSolrParams getParameters() { - return parameters; - } -} diff --git a/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/scraper/SolrScraper.java b/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/scraper/SolrScraper.java deleted file mode 100644 index e66b228c67d..00000000000 --- a/solr/prometheus-exporter/src/java/org/apache/solr/prometheus/scraper/SolrScraper.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * 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.solr.prometheus.scraper; - -import static org.apache.solr.common.params.CommonParams.ADMIN_PATHS; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.prometheus.client.Collector; -import io.prometheus.client.Counter; -import java.io.Closeable; -import java.io.IOException; -import java.lang.invoke.MethodHandles; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.function.Function; -import java.util.stream.Collectors; -import net.thisptr.jackson.jq.JsonQuery; -import net.thisptr.jackson.jq.exception.JsonQueryException; -import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.SolrRequest; -import org.apache.solr.client.solrj.SolrRequest.METHOD; -import org.apache.solr.client.solrj.SolrRequest.SolrRequestType; -import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.impl.CloudSolrClient; -import org.apache.solr.client.solrj.impl.Http2SolrClient; -import org.apache.solr.client.solrj.request.GenericSolrRequest; -import org.apache.solr.common.util.NamedList; -import org.apache.solr.prometheus.collector.MetricSamples; -import org.apache.solr.prometheus.exporter.MetricsQuery; -import org.apache.solr.prometheus.exporter.SolrExporter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public abstract class SolrScraper implements Closeable { - - private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - - protected static final String ZK_HOST_LABEL = "zk_host"; - protected static final String BASE_URL_LABEL = "base_url"; - protected static final String CLUSTER_ID_LABEL = "cluster_id"; - - private static final Counter scrapeErrorTotal = - Counter.build() - .name("solr_exporter_scrape_error_total") - .help("Number of scrape error.") - .labelNames(ZK_HOST_LABEL, BASE_URL_LABEL, CLUSTER_ID_LABEL) - .register(SolrExporter.defaultRegistry); - - protected static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - - protected final String clusterId; - - protected final ExecutorService executor; - - public abstract Map metricsForAllHosts(MetricsQuery query) - throws IOException; - - public abstract Map pingAllCores(MetricsQuery query) throws IOException; - - public abstract Map pingAllCollections(MetricsQuery query) - throws IOException; - - public abstract MetricSamples search(MetricsQuery query) throws IOException; - - public abstract MetricSamples collections(MetricsQuery metricsQuery) throws IOException; - - public SolrScraper(ExecutorService executor, String clusterId) { - this.executor = executor; - this.clusterId = clusterId; - } - - protected Map sendRequestsInParallel( - Collection items, Function samplesCallable) - throws IOException { - - Map result = new HashMap<>(); // sync on this when adding to it below - - try { - // invoke each samplesCallable with each item and putting the results in the above "result" - // map. - executor.invokeAll( - items.stream() - .map( - item -> - (Callable) - () -> { - try { - final MetricSamples samples = samplesCallable.apply(item); - synchronized (result) { - result.put(item, samples); - } - } catch (Exception e) { - // do NOT totally fail; just log and move on - log.warn("Error occurred during metrics collection", e); - } - return null; // not used - }) - .collect(Collectors.toList())); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException(e); - } - - return result; - } - - protected MetricSamples request(SolrClient client, MetricsQuery query) throws IOException { - MetricSamples samples = new MetricSamples(); - - String baseUrlLabelValue = ""; - String zkHostLabelValue = ""; - if (client instanceof Http2SolrClient) { - baseUrlLabelValue = ((Http2SolrClient) client).getBaseURL(); - } else if (client instanceof CloudSolrClient) { - zkHostLabelValue = ((CloudSolrClient) client).getClusterStateProvider().getQuorumHosts(); - } - - SolrRequest request; - if (ADMIN_PATHS.contains(query.getPath())) { - request = - new GenericSolrRequest( - METHOD.GET, query.getPath(), SolrRequestType.ADMIN, query.getParameters()); - } else { - request = - new GenericSolrRequest( - METHOD.GET, query.getPath(), SolrRequestType.UNSPECIFIED, query.getParameters()) - .setRequiresCollection(true); - } - - NamedList response; - try { - if (query.getCollection().isEmpty() && query.getCore().isEmpty()) { - response = client.request(request); - } else if (query.getCore().isPresent()) { - response = client.request(request, query.getCore().get()); - } else if (query.getCollection().isPresent()) { - response = client.request(request, query.getCollection().get()); - } else { - throw new AssertionError("Invalid configuration"); - } - if (response == null) { // ideally we'd make this impossible - throw new RuntimeException("no response from server"); - } - } catch (SolrServerException | IOException e) { - log.error("failed to request: {}", request.getPath(), e); - return samples; - } - - JsonNode jsonNode = OBJECT_MAPPER.readTree((String) response.get("response")); - - for (JsonQuery jsonQuery : query.getJsonQueries()) { - try { - List results = jsonQuery.apply(jsonNode); - for (JsonNode result : results) { - String type = result.get("type").textValue(); - String name = result.get("name").textValue(); - String help = result.get("help").textValue(); - double value = result.get("value").doubleValue(); - - List labelNames = new ArrayList<>(); - List labelValues = new ArrayList<>(); - - /* Labels in response */ - for (JsonNode item : result.get("label_names")) { - labelNames.add(item.textValue()); - } - - for (JsonNode item : result.get("label_values")) { - labelValues.add(item.textValue()); - } - - /* Labels due to client */ - if (!baseUrlLabelValue.isEmpty()) { - labelNames.add(BASE_URL_LABEL); - labelValues.add(baseUrlLabelValue); - } else if (!zkHostLabelValue.isEmpty()) { - labelNames.add(ZK_HOST_LABEL); - labelValues.add(zkHostLabelValue); - } - - // Add the unique cluster ID, either as specified on cmdline --cluster-id or - // baseUrl/zkHost - labelNames.add(CLUSTER_ID_LABEL); - labelValues.add(clusterId); - - // Deduce core if not there - if (labelNames.indexOf("core") < 0 - && labelNames.indexOf("collection") >= 0 - && labelNames.indexOf("shard") >= 0 - && labelNames.indexOf("replica") >= 0) { - labelNames.add("core"); - - String collection = labelValues.get(labelNames.indexOf("collection")); - String shard = labelValues.get(labelNames.indexOf("shard")); - String replica = labelValues.get(labelNames.indexOf("replica")); - - labelValues.add(collection + "_" + shard + "_" + replica); - } - - samples.addSamplesIfNotPresent( - name, - new Collector.MetricFamilySamples( - name, Collector.Type.valueOf(type), help, new ArrayList<>())); - - samples.addSampleIfMetricExists( - name, new Collector.MetricFamilySamples.Sample(name, labelNames, labelValues, value)); - } - } catch (JsonQueryException e) { - log.error("Error apply JSON query={} to result", jsonQuery, e); - scrapeErrorTotal.labels(zkHostLabelValue, baseUrlLabelValue, clusterId).inc(); - } - } - - return samples; - } -} diff --git a/solr/prometheus-exporter/src/test-files/solr/solr.xml b/solr/prometheus-exporter/src/test-files/solr/solr.xml deleted file mode 100644 index 057aee1b3f7..00000000000 --- a/solr/prometheus-exporter/src/test-files/solr/solr.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - ${shareSchema:false} - ${configSetBaseDir:configsets} - ${coreRootDirectory:.} - ${solr.tests.allowUrls:} - - - ${urlScheme:} - ${socketTimeout:90000} - ${connTimeout:15000} - - - - 127.0.0.1 - ${hostPort:8983} - ${solr.zookeeper.client.timeout:30000} - ${genericCoreNodeNames:true} - ${leaderVoteWait:10000} - ${distribUpdateConnTimeout:45000} - ${distribUpdateSoTimeout:340000} - - - diff --git a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/exporter/SolrExporterIntegrationTest.java b/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/exporter/SolrExporterIntegrationTest.java deleted file mode 100644 index 08b9e62d144..00000000000 --- a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/exporter/SolrExporterIntegrationTest.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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.solr.prometheus.exporter; - -import java.util.Map; -import java.util.stream.Collectors; -import org.junit.Before; -import org.junit.Test; - -public class SolrExporterIntegrationTest extends SolrExporterTestBase { - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - startMetricsExporterWithConfiguration( - "conf/prometheus-solr-exporter-integration-test-config.xml"); - } - - private Map metricsWithName( - Map allMetrics, String desiredMetricName) { - return allMetrics.entrySet().stream() - .filter(entry -> entry.getKey().startsWith(desiredMetricName)) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - } - - @Test - public void pingAllCollectionsAndCoresAreAvailable() throws Exception { - Map pingMetrics = metricsWithName(getAllMetrics(), "solr_ping"); - - assertEquals(5, pingMetrics.size()); - - for (Map.Entry metric : pingMetrics.entrySet()) { - assertEquals(1.0, metric.getValue(), 0.001); - } - } - - @Test - public void solrExporterDurationMetric() throws Exception { - Map durationHistogram = - metricsWithName(getAllMetrics(), "solr_exporter_duration"); - - assertTrue(durationHistogram.get("solr_exporter_duration_seconds_count") > 0); - assertTrue(durationHistogram.get("solr_exporter_duration_seconds_sum") > 0); - - // 18 = (15 buckets in the histogram) + (count metric) + (sum metric) + (created metric) - assertEquals(18, durationHistogram.size()); - } - - @Test - public void jsonFacetMetrics() throws Exception { - Map facetMetrics = metricsWithName(getAllMetrics(), "solr_facets_category"); - assertEquals(FACET_VALUES.size(), facetMetrics.size()); - } - - @Test - public void collectionMetrics() throws Exception { - Map allMetrics = getAllMetrics(); - Map liveNodeMetrics = - metricsWithName(allMetrics, "solr_collections_live_nodes"); - - assertEquals(1, liveNodeMetrics.size()); - liveNodeMetrics.forEach( - (metric, value) -> { - assertEquals((double) NUM_NODES, value, 0.001); - }); - - Map shardLeaderMetrics = - metricsWithName(allMetrics, "solr_collections_shard_leader"); - - assertEquals(NUM_NODES, shardLeaderMetrics.size()); - - double totalLeaderCount = - shardLeaderMetrics.values().stream().mapToDouble(Double::doubleValue).sum(); - - assertEquals(NUM_SHARDS, totalLeaderCount, 0.001); - } -} diff --git a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrCloudScraperTest.java b/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrCloudScraperTest.java deleted file mode 100644 index 1265314fb9e..00000000000 --- a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrCloudScraperTest.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * 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.solr.prometheus.scraper; - -import com.carrotsearch.randomizedtesting.annotations.ThreadLeakLingering; -import io.prometheus.client.Collector; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.stream.Collectors; -import org.apache.solr.common.cloud.ClusterState; -import org.apache.solr.common.cloud.DocCollection; -import org.apache.solr.common.cloud.Replica; -import org.apache.solr.common.cloud.Slice; -import org.apache.solr.common.util.ExecutorUtil; -import org.apache.solr.common.util.IOUtils; -import org.apache.solr.common.util.SolrNamedThreadFactory; -import org.apache.solr.prometheus.PrometheusExporterTestBase; -import org.apache.solr.prometheus.collector.MetricSamples; -import org.apache.solr.prometheus.exporter.MetricsConfiguration; -import org.apache.solr.prometheus.exporter.PrometheusExporterSettings; -import org.apache.solr.prometheus.exporter.SolrClientFactory; -import org.apache.solr.prometheus.exporter.SolrScrapeConfiguration; -import org.apache.solr.prometheus.utils.Helpers; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -@ThreadLeakLingering(linger = 10) -public class SolrCloudScraperTest extends PrometheusExporterTestBase { - - private MetricsConfiguration configuration; - private SolrCloudScraper solrCloudScraper; - private ExecutorService executor; - - private SolrCloudScraper createSolrCloudScraper() { - PrometheusExporterSettings settings = PrometheusExporterSettings.builder().build(); - SolrScrapeConfiguration scrapeConfiguration = - SolrScrapeConfiguration.standalone(cluster.getZkServer().getZkAddress()); - SolrClientFactory factory = new SolrClientFactory(settings, scrapeConfiguration); - var solrClient = factory.createCloudSolrClient(cluster.getZkServer().getZkAddress()); - return new SolrCloudScraper(solrClient, executor, factory, "test"); - } - - private ClusterState getClusterState() { - return cluster.getSolrClient().getClusterState(); - } - - private DocCollection getCollectionState() { - return getClusterState().getCollection(PrometheusExporterTestBase.COLLECTION); - } - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - executor = - ExecutorUtil.newMDCAwareFixedThreadPool( - 25, new SolrNamedThreadFactory("solr-cloud-scraper-tests")); - configuration = - Helpers.loadConfiguration("conf/prometheus-solr-exporter-scraper-test-config.xml"); - solrCloudScraper = createSolrCloudScraper(); - } - - @Override - @After - public void tearDown() throws Exception { - super.tearDown(); - IOUtils.closeQuietly(solrCloudScraper); - ExecutorUtil.shutdownNowAndAwaitTermination(executor); - } - - @Test - public void pingCollections() throws Exception { - Map collectionMetrics = - solrCloudScraper.pingAllCollections(configuration.getPingConfiguration().get(0)); - - assertEquals(1, collectionMetrics.size()); - assertTrue(collectionMetrics.containsKey(PrometheusExporterTestBase.COLLECTION)); - - List collectionSamples = - collectionMetrics.get(PrometheusExporterTestBase.COLLECTION).asList(); - assertEquals(1, collectionSamples.size()); - Collector.MetricFamilySamples collection1Metrics = collectionSamples.get(0); - assertEquals("solr_ping", collection1Metrics.name); - assertEquals(1, collection1Metrics.samples.size()); - - assertEquals(1.0, collection1Metrics.samples.get(0).value, 0.001); - assertEquals(List.of("zk_host", "cluster_id"), collection1Metrics.samples.get(0).labelNames); - assertEquals( - List.of(cluster.getZkServer().getZkAddress(), "test"), - collection1Metrics.samples.get(0).labelValues); - } - - @Test - public void pingCores() throws Exception { - Map allCoreMetrics = - solrCloudScraper.pingAllCores(configuration.getPingConfiguration().get(0)); - - final List collectionStates = getClusterState().collectionStream().toList(); - - long coreCount = - collectionStates.stream().mapToInt(docColl -> docColl.getReplicas().size()).sum(); - - assertEquals(coreCount, allCoreMetrics.size()); - - for (DocCollection docColl : collectionStates) { - String coreName = docColl.getReplicas().get(0).getCoreName(); - assertTrue(allCoreMetrics.containsKey(coreName)); - List coreMetrics = allCoreMetrics.get(coreName).asList(); - assertEquals(1, coreMetrics.size()); - assertEquals("solr_ping", coreMetrics.get(0).name); - assertEquals(1, coreMetrics.get(0).samples.size()); - assertEquals(1.0, coreMetrics.get(0).samples.get(0).value, 0.001); - } - } - - @Test - public void queryCollections() throws Exception { - List collection1Metrics = - solrCloudScraper.collections(configuration.getCollectionsConfiguration().get(0)).asList(); - - assertEquals(2, collection1Metrics.size()); - Collector.MetricFamilySamples liveNodeSamples = collection1Metrics.get(0); - assertEquals("solr_collections_live_nodes", liveNodeSamples.name); - assertEquals( - "See following URL: https://solr.apache.org/guide/solr/latest/deployment-guide/cluster-node-management.html#clusterstatus", - liveNodeSamples.help); - assertEquals(1, liveNodeSamples.samples.size()); - - assertEquals( - getClusterState().getLiveNodes().size(), liveNodeSamples.samples.get(0).value, 0.001); - - Collector.MetricFamilySamples shardLeaderSamples = collection1Metrics.get(1); - - DocCollection collection = getCollectionState(); - List allReplicas = collection.getReplicas(); - assertEquals(allReplicas.size(), shardLeaderSamples.samples.size()); - - Collection slices = getCollectionState().getSlices(); - - Set leaderCoreNames = - slices.stream() - .map(slice -> collection.getLeader(slice.getName()).getCoreName()) - .collect(Collectors.toSet()); - - for (Collector.MetricFamilySamples.Sample sample : shardLeaderSamples.samples) { - assertEquals("solr_collections_shard_leader", sample.name); - assertEquals( - Arrays.asList("collection", "shard", "replica", "core", "type", "zk_host", "cluster_id"), - sample.labelNames); - assertEquals( - leaderCoreNames.contains(sample.labelValues.get(3)) ? 1.0 : 0.0, sample.value, 0.001); - } - } - - @Test - public void search() throws Exception { - List samples = - solrCloudScraper.search(configuration.getSearchConfiguration().get(0)).asList(); - - assertEquals(1, samples.size()); - - Collector.MetricFamilySamples sampleFamily = samples.get(0); - assertEquals("solr_facets_category", sampleFamily.name); - assertEquals(FACET_VALUES.size(), sampleFamily.samples.size()); - - for (Collector.MetricFamilySamples.Sample sample : sampleFamily.samples) { - assertEquals(FACET_VALUES.get(sample.labelValues.get(0)), sample.value, 0.001); - } - } -} diff --git a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperBasicAuthTest.java b/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperBasicAuthTest.java deleted file mode 100644 index 8197bb7d9c7..00000000000 --- a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperBasicAuthTest.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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.solr.prometheus.scraper; - -import io.prometheus.client.Collector; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.concurrent.ExecutorService; -import org.apache.lucene.tests.util.LuceneTestCase; -import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.client.solrj.impl.Http2SolrClient; -import org.apache.solr.common.util.ExecutorUtil; -import org.apache.solr.common.util.IOUtils; -import org.apache.solr.common.util.SolrNamedThreadFactory; -import org.apache.solr.prometheus.PrometheusExporterTestBase; -import org.apache.solr.prometheus.exporter.MetricsConfiguration; -import org.apache.solr.prometheus.exporter.PrometheusExporterSettings; -import org.apache.solr.prometheus.exporter.SolrClientFactory; -import org.apache.solr.prometheus.exporter.SolrScrapeConfiguration; -import org.apache.solr.prometheus.utils.Helpers; -import org.apache.solr.util.SolrJettyTestRule; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; - -// Prometheus Exporter will be deprecated -@LuceneTestCase.AwaitsFix(bugUrl = "https://issues.apache.org/jira/browse/SOLR-17458") -public class SolrStandaloneScraperBasicAuthTest extends SolrTestCaseJ4 { - - @ClassRule public static final SolrJettyTestRule solrRule = new SolrJettyTestRule(); - - private static Http2SolrClient solrClient; - private static MetricsConfiguration configuration; - private static SolrStandaloneScraper solrScraper; - private static ExecutorService executor; - - private static String user = "solr"; - private static String pass = "SolrRocks"; - private static String securityJson = - "{\n" - + "\"authentication\":{ \n" - + " \"blockUnknown\": true, \n" - + " \"class\":\"solr.BasicAuthPlugin\",\n" - + " \"credentials\":{\"solr\":\"IV0EHq1OnNrj6gvRCwvFwTrZ1+z1oBbnQdiVC3otuq0= Ndd7LKvVBAaZIF0QAVi1ekCfAJXr1GGfLtRUXhgrF8c=\"}, \n" - + " \"realm\":\"My Solr users\", \n" - + " \"forwardCredentials\": false \n" - + "},\n" - + "\"authorization\":{\n" - + " \"class\":\"solr.RuleBasedAuthorizationPlugin\",\n" - + " \"permissions\":[{\"name\":\"security-edit\",\n" - + " \"role\":\"admin\"}],\n" - + " \"user-role\":{\"solr\":\"admin\"}\n" - + "}}"; - - @BeforeClass - public static void setupSolrHome() throws Exception { - Path solrHome = LuceneTestCase.createTempDir(); - Files.write(solrHome.resolve("security.json"), securityJson.getBytes(StandardCharsets.UTF_8)); - solrRule.startSolr(solrHome); - - Path configSet = LuceneTestCase.createTempDir(); - SolrStandaloneScraperTest.createConf(configSet); - solrRule - .newCollection() - .withConfigSet(configSet.toString()) - .withBasicAuthCredentials(user, pass) - .create(); - - configuration = - Helpers.loadConfiguration("conf/prometheus-solr-exporter-scraper-test-config.xml"); - - PrometheusExporterSettings settings = PrometheusExporterSettings.builder().build(); - SolrScrapeConfiguration scrapeConfiguration = - SolrScrapeConfiguration.standalone(solrRule.getBaseUrl()) - .withBasicAuthCredentials(user, pass); - solrClient = - new SolrClientFactory(settings, scrapeConfiguration) - .createStandaloneSolrClient(solrRule.getBaseUrl()); - executor = - ExecutorUtil.newMDCAwareFixedThreadPool( - 25, new SolrNamedThreadFactory("solr-cloud-scraper-tests")); - solrScraper = new SolrStandaloneScraper(solrClient, executor, "test"); - - Helpers.indexAllDocs(solrClient); - } - - @AfterClass - public static void cleanup() throws Exception { - // scraper also closes the client - IOUtils.closeQuietly(solrScraper); - ExecutorUtil.shutdownNowAndAwaitTermination(executor); - } - - @Test - public void search() throws Exception { - List samples = - solrScraper.search(configuration.getSearchConfiguration().get(0)).asList(); - - assertEquals(1, samples.size()); - - Collector.MetricFamilySamples sampleFamily = samples.get(0); - assertEquals("solr_facets_category", sampleFamily.name); - assertEquals(PrometheusExporterTestBase.FACET_VALUES.size(), sampleFamily.samples.size()); - - for (Collector.MetricFamilySamples.Sample sample : sampleFamily.samples) { - assertEquals( - PrometheusExporterTestBase.FACET_VALUES.get(sample.labelValues.get(0)), - sample.value, - 0.001); - } - } -} diff --git a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperTest.java b/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperTest.java deleted file mode 100644 index d7271c5c7c4..00000000000 --- a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperTest.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * 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.solr.prometheus.scraper; - -import io.prometheus.client.Collector; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutorService; -import org.apache.lucene.tests.util.LuceneTestCase; -import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.client.solrj.impl.Http2SolrClient; -import org.apache.solr.common.util.ExecutorUtil; -import org.apache.solr.common.util.IOUtils; -import org.apache.solr.common.util.SolrNamedThreadFactory; -import org.apache.solr.prometheus.PrometheusExporterTestBase; -import org.apache.solr.prometheus.collector.MetricSamples; -import org.apache.solr.prometheus.exporter.MetricsConfiguration; -import org.apache.solr.prometheus.exporter.PrometheusExporterSettings; -import org.apache.solr.prometheus.exporter.SolrClientFactory; -import org.apache.solr.prometheus.exporter.SolrScrapeConfiguration; -import org.apache.solr.prometheus.utils.Helpers; -import org.apache.solr.util.SolrJettyTestRule; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; - -// NOCOMMIT: This test is broken from OTEL migration and the /admin/plugins endpoint. Placing -// BadApple test but this must be fixed before this feature gets merged to a release branch -@LuceneTestCase.AwaitsFix(bugUrl = "https://issues.apache.org/jira/browse/SOLR-17458") -public class SolrStandaloneScraperTest extends SolrTestCaseJ4 { - - @ClassRule public static final SolrJettyTestRule solrRule = new SolrJettyTestRule(); - - private static MetricsConfiguration configuration; - private static SolrStandaloneScraper solrScraper; - private static ExecutorService executor; - private static Http2SolrClient solrClient; - - @BeforeClass - public static void setupBeforeClass() throws Exception { - solrRule.startSolr(LuceneTestCase.createTempDir()); - - Path configSet = LuceneTestCase.createTempDir(); - createConf(configSet); - solrRule.newCollection().withConfigSet(configSet.toString()).create(); - - PrometheusExporterSettings settings = PrometheusExporterSettings.builder().build(); - SolrScrapeConfiguration scrapeConfiguration = - SolrScrapeConfiguration.standalone(solrRule.getBaseUrl()); - solrClient = - new SolrClientFactory(settings, scrapeConfiguration) - .createStandaloneSolrClient(solrRule.getBaseUrl()); - executor = - ExecutorUtil.newMDCAwareFixedThreadPool( - 25, new SolrNamedThreadFactory("solr-cloud-scraper-tests")); - configuration = - Helpers.loadConfiguration("conf/prometheus-solr-exporter-scraper-test-config.xml"); - solrScraper = new SolrStandaloneScraper(solrClient, executor, "test"); - - Helpers.indexAllDocs(solrClient); - } - - public static void createConf(Path configSet) throws IOException { - Path subHome = configSet.resolve("conf"); - Files.createDirectories(subHome); - - Path top = SolrTestCaseJ4.TEST_PATH().resolve("collection1").resolve("conf"); - Files.copy(top.resolve("managed-schema.xml"), subHome.resolve("schema.xml")); - Files.copy(top.resolve("solrconfig.xml"), subHome.resolve("solrconfig.xml")); - - Files.copy(top.resolve("stopwords.txt"), subHome.resolve("stopwords.txt")); - Files.copy(top.resolve("synonyms.txt"), subHome.resolve("synonyms.txt")); - } - - @AfterClass - public static void cleanup() throws Exception { - // scraper also closes the client - IOUtils.closeQuietly(solrScraper); - ExecutorUtil.shutdownNowAndAwaitTermination(executor); - } - - @Test - public void pingCollections() throws IOException { - Map collectionMetrics = - solrScraper.pingAllCollections(configuration.getPingConfiguration().get(0)); - - assertTrue(collectionMetrics.isEmpty()); - } - - @Test - public void pingCores() throws Exception { - Map allCoreMetrics = - solrScraper.pingAllCores(configuration.getPingConfiguration().get(0)); - - assertEquals(1, allCoreMetrics.size()); - - List allSamples = allCoreMetrics.get("collection1").asList(); - Collector.MetricFamilySamples samples = allSamples.get(0); - - assertEquals("solr_ping", samples.name); - assertEquals(1, samples.samples.size()); - assertEquals(1.0, samples.samples.get(0).value, 0.001); - assertEquals(List.of("base_url", "cluster_id"), samples.samples.get(0).labelNames); - assertEquals(List.of(solrRule.getBaseUrl(), "test"), samples.samples.get(0).labelValues); - } - - @Test - public void queryCollections() throws Exception { - List collection1Metrics = - solrScraper.collections(configuration.getCollectionsConfiguration().get(0)).asList(); - - assertTrue(collection1Metrics.isEmpty()); - } - - @Test - public void metricsForHost() throws Exception { - Map metricsByHost = - solrScraper.metricsForAllHosts(configuration.getMetricsConfiguration().get(0)); - - assertEquals(1, metricsByHost.size()); - - List replicaSamples = - metricsByHost.get(solrRule.getBaseUrl()).asList(); - - assertEquals(1, replicaSamples.size()); - - assertEquals("solr_metrics_jvm_buffers", replicaSamples.get(0).name); - - assertEquals("cluster_id", replicaSamples.get(0).samples.get(0).labelNames.get(2)); - assertEquals("test", replicaSamples.get(0).samples.get(0).labelValues.get(2)); - } - - @Test - public void search() throws Exception { - List samples = - solrScraper.search(configuration.getSearchConfiguration().get(0)).asList(); - - assertEquals(1, samples.size()); - - Collector.MetricFamilySamples sampleFamily = samples.get(0); - assertEquals("solr_facets_category", sampleFamily.name); - assertEquals(PrometheusExporterTestBase.FACET_VALUES.size(), sampleFamily.samples.size()); - - for (Collector.MetricFamilySamples.Sample sample : sampleFamily.samples) { - assertEquals( - PrometheusExporterTestBase.FACET_VALUES.get(sample.labelValues.get(0)), - sample.value, - 0.001); - } - } -} diff --git a/solr/server/build.gradle b/solr/server/build.gradle index 8a0823f81d2..5c4025543a8 100644 --- a/solr/server/build.gradle +++ b/solr/server/build.gradle @@ -74,25 +74,6 @@ dependencies { libExt libs.apache.log4j.slf4j2impl libExt libs.apache.log4j.web - libExt(libs.dropwizard.metrics.core, { - exclude group: "com.rabbitmq", module: "amqp-client" - - }) - libExt(libs.dropwizard.metrics.graphite, { - exclude group: "com.rabbitmq", module: "amqp-client" - }) - def excludeTransitiveJetty = { - exclude group: "org.eclipse.jetty", module: "*" - exclude group: "org.eclipse.jetty.http2", module: "*" - exclude group: "org.eclipse.jetty.toolchain", module: "*" - exclude group: "org.eclipse.jetty.ee10", module: "*" - exclude group: "jakarta.servlet", module: "jakarta.servlet-api" - } - libExt(libs.dropwizard.metrics.jetty12, excludeTransitiveJetty) - libExt(libs.dropwizard.metrics.jetty12.ee10, excludeTransitiveJetty) - libExt libs.dropwizard.metrics.jvm - libExt libs.dropwizard.metrics.jmx - webapp project(path: ":solr:webapp", configuration: "war") startJar(variantOf(libs.eclipse.jetty.start) { classifier 'shaded' }, { diff --git a/solr/server/etc/jetty.xml b/solr/server/etc/jetty.xml index 374cf4924fe..2f20e329c93 100644 --- a/solr/server/etc/jetty.xml +++ b/solr/server/etc/jetty.xml @@ -29,16 +29,6 @@ - - - - - solr.jetty - - - - - @@ -178,14 +168,6 @@ - - - - - - - - @@ -221,9 +203,9 @@ - + - - + - + diff --git a/solr/server/gradle.lockfile b/solr/server/gradle.lockfile index 98f5c97cb24..025d73ef716 100644 --- a/solr/server/gradle.lockfile +++ b/solr/server/gradle.lockfile @@ -32,13 +32,7 @@ com.tdunning:t-digest:3.3=jarValidation,runtimeClasspath,solrCore commons-cli:commons-cli:1.10.0=jarValidation,runtimeClasspath,solrCore commons-codec:commons-codec:1.19.0=jarValidation,runtimeClasspath,solrCore commons-io:commons-io:2.17.0=jarValidation,runtimeClasspath,solrCore -io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,libExt,runtimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,libExt,runtimeClasspath,solrCore -io.dropwizard.metrics:metrics-graphite:4.2.26=jarValidation,libExt,runtimeClasspath,solrCore -io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,libExt,runtimeClasspath -io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,libExt,runtimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=jarValidation,libExt,runtimeClasspath,solrCore -io.dropwizard.metrics:metrics-jvm:4.2.26=jarValidation,libExt,runtimeClasspath,solrCore +io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,runtimeClasspath,solrCore io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.2.6.Final=jarValidation,runtimeClasspath,solrCore diff --git a/solr/solr-ref-guide/gradle.lockfile b/solr/solr-ref-guide/gradle.lockfile index 51e81c33171..b49a5fc4c2f 100644 --- a/solr/solr-ref-guide/gradle.lockfile +++ b/solr/solr-ref-guide/gradle.lockfile @@ -33,12 +33,9 @@ commons-cli:commons-cli:1.10.0=testRuntimeClasspath commons-codec:commons-codec:1.19.0=testRuntimeClasspath commons-io:commons-io:2.17.0=testCompileClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-annotation:4.2.26=testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=testRuntimeClasspath io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=testRuntimeClasspath io.dropwizard.metrics:metrics-jetty12:4.2.26=testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.2.6.Final=testCompileClasspath,testRuntimeClasspath diff --git a/solr/solrj-streaming/gradle.lockfile b/solr/solrj-streaming/gradle.lockfile index 11b6f28057c..11a549fedc0 100644 --- a/solr/solrj-streaming/gradle.lockfile +++ b/solr/solrj-streaming/gradle.lockfile @@ -34,12 +34,9 @@ commons-cli:commons-cli:1.10.0=jarValidation,testRuntimeClasspath commons-codec:commons-codec:1.19.0=jarValidation,permitTestUsedUndeclared,runtimeClasspath,testRuntimeClasspath commons-io:commons-io:2.17.0=jarValidation,permitTestUnusedDeclared,testCompileClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,testRuntimeClasspath io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=jarValidation,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=jarValidation,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.1.119.Final=permitTestUnusedDeclared diff --git a/solr/solrj-zookeeper/gradle.lockfile b/solr/solrj-zookeeper/gradle.lockfile index c5b981bba2e..c3c153da1f5 100644 --- a/solr/solrj-zookeeper/gradle.lockfile +++ b/solr/solrj-zookeeper/gradle.lockfile @@ -39,12 +39,9 @@ commons-cli:commons-cli:1.10.0=jarValidation,testRuntimeClasspath commons-codec:commons-codec:1.19.0=jarValidation,permitTestUsedUndeclared,runtimeClasspath,testRuntimeClasspath commons-io:commons-io:2.17.0=apiHelper,compileClasspath,jarValidation,permitTestUsedUndeclared,runtimeClasspath,testCompileClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,testRuntimeClasspath io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=jarValidation,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=jarValidation,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.1.119.Final=apiHelper diff --git a/solr/solrj/build.gradle b/solr/solrj/build.gradle index 6b753ff8e3a..9965c607d27 100644 --- a/solr/solrj/build.gradle +++ b/solr/solrj/build.gradle @@ -93,7 +93,6 @@ dependencies { exclude group: "org.apache.logging.log4j", module: "log4j-api" }) testImplementation libs.apache.commons.lang3 - testImplementation libs.dropwizard.metrics.core testImplementation libs.fasterxml.jackson.core.core } diff --git a/solr/solrj/gradle.lockfile b/solr/solrj/gradle.lockfile index 942b6868569..35d8bc7125a 100644 --- a/solr/solrj/gradle.lockfile +++ b/solr/solrj/gradle.lockfile @@ -34,12 +34,9 @@ commons-cli:commons-cli:1.10.0=jarValidation,testRuntimeClasspath commons-codec:commons-codec:1.19.0=compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath commons-io:commons-io:2.17.0=jarValidation,permitTestUnusedDeclared,testCompileClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-annotation:4.2.26=jarValidation,testRuntimeClasspath -io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=jarValidation,testRuntimeClasspath +io.dropwizard.metrics:metrics-core:4.2.26=jarValidation,testRuntimeClasspath io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=jarValidation,testRuntimeClasspath io.dropwizard.metrics:metrics-jetty12:4.2.26=jarValidation,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=jarValidation,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=jarValidation,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.1.119.Final=permitTestUnusedDeclared diff --git a/solr/test-framework/build.gradle b/solr/test-framework/build.gradle index d5ed939e79c..6c6f54685bd 100644 --- a/solr/test-framework/build.gradle +++ b/solr/test-framework/build.gradle @@ -91,4 +91,9 @@ dependencies { implementation libs.carrotsearch.randomizedtesting.runner implementation libs.junit.junit implementation libs.hamcrest.hamcrest + + implementation(libs.prometheus.metrics.expositionformats, { + exclude group: "io.prometheus", module: "prometheus-metrics-shaded-protobuf" + exclude group: "io.prometheus", module: "prometheus-metrics-config" + }) } diff --git a/solr/test-framework/gradle.lockfile b/solr/test-framework/gradle.lockfile index 9fbdc8045c3..cb9410dd9c6 100644 --- a/solr/test-framework/gradle.lockfile +++ b/solr/test-framework/gradle.lockfile @@ -36,11 +36,8 @@ commons-codec:commons-codec:1.19.0=apiHelper,compileClasspath,jarValidation,runt commons-io:commons-io:2.17.0=apiHelper,compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-annotation:4.2.26=compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-core:4.2.26=apiHelper,compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-graphite:4.2.26=apiHelper,jarValidation,runtimeClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath io.dropwizard.metrics:metrics-jetty12:4.2.26=compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-jmx:4.2.26=apiHelper,jarValidation,runtimeClasspath,testRuntimeClasspath -io.dropwizard.metrics:metrics-jvm:4.2.26=apiHelper,jarValidation,runtimeClasspath,testRuntimeClasspath io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.2.6.Final=apiHelper,compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath @@ -76,7 +73,7 @@ io.opentelemetry:opentelemetry-sdk:1.53.0=apiHelper,jarValidation,runtimeClasspa io.prometheus:prometheus-metrics-config:1.3.6=jarValidation,runtimeClasspath,testRuntimeClasspath io.prometheus:prometheus-metrics-exporter-common:1.3.6=jarValidation,runtimeClasspath,testRuntimeClasspath io.prometheus:prometheus-metrics-exporter-httpserver:1.3.6=jarValidation,runtimeClasspath,testRuntimeClasspath -io.prometheus:prometheus-metrics-exposition-formats:1.1.0=apiHelper +io.prometheus:prometheus-metrics-exposition-formats:1.1.0=apiHelper,compileClasspath,testCompileClasspath io.prometheus:prometheus-metrics-exposition-formats:1.3.6=jarValidation,runtimeClasspath,testRuntimeClasspath io.prometheus:prometheus-metrics-exposition-textformats:1.3.6=jarValidation,runtimeClasspath,testRuntimeClasspath io.prometheus:prometheus-metrics-model:1.1.0=apiHelper,compileClasspath,testCompileClasspath diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudAuthTestCase.java b/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudAuthTestCase.java index 7fbf26ab5cf..014e936289e 100644 --- a/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudAuthTestCase.java +++ b/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudAuthTestCase.java @@ -19,11 +19,6 @@ import static java.nio.charset.StandardCharsets.UTF_8; -import com.codahale.metrics.Counter; -import com.codahale.metrics.Meter; -import com.codahale.metrics.Metric; -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.Timer; import io.opentelemetry.exporter.prometheus.PrometheusMetricReader; import io.prometheus.metrics.model.snapshots.CounterSnapshot; import io.prometheus.metrics.model.snapshots.DataPointSnapshot; @@ -168,35 +163,6 @@ protected void assertAuthMetricsMinimums( errors); } - /** - * Common test method to be able to check security from any authentication plugin - * - * @param cluster the MiniSolrCloudCluster to fetch metrics from - * @param prefix the metrics key prefix, currently "SECURITY./authentication." for basic auth and - * "SECURITY./authentication/pki." for PKI - * @param keys what keys to examine - */ - Map countSecurityMetrics( - MiniSolrCloudCluster cluster, String prefix, List keys) { - List> metrics = new ArrayList<>(); - cluster - .getJettySolrRunners() - .forEach( - r -> { - MetricRegistry registry = - r.getCoreContainer().getMetricManager().registry("solr.node"); - assertNotNull(registry); - metrics.add(registry.getMetrics()); - }); - - Map counts = new HashMap<>(); - keys.forEach( - k -> { - counts.put(k, sumCount(prefix, k, metrics)); - }); - return counts; - } - /** Common test method to be able to check auth metrics from any authentication plugin */ void assertAuthMetricsMinimumsPrometheus( String handler, @@ -337,22 +303,6 @@ private static Map getMetricValues( return metrics; } - // Have to sum the metrics from all three shards/nodes - private long sumCount(String prefix, String key, List> metrics) { - assertTrue( - "Metric " + prefix + key + " does not exist", metrics.get(0).containsKey(prefix + key)); - if (AUTH_METRICS_METER_KEYS.contains(key)) - return metrics.stream().mapToLong(l -> ((Meter) l.get(prefix + key)).getCount()).sum(); - else if (AUTH_METRICS_TIMER_KEYS.contains(key)) - return (long) - ((long) 1000 - * metrics.stream() - .mapToDouble(l -> ((Timer) l.get(prefix + key)).getMeanRate()) - .average() - .orElse(0.0d)); - else return metrics.stream().mapToLong(l -> ((Counter) l.get(prefix + key)).getCount()).sum(); - } - public static void verifySecurityStatus( HttpClient cl, String url, String objPath, Object expected, int count) throws Exception { verifySecurityStatus(cl, url, objPath, expected, count, (String) null); diff --git a/solr/test-framework/src/java/org/apache/solr/core/MockQuerySenderListenerReqHandler.java b/solr/test-framework/src/java/org/apache/solr/core/MockQuerySenderListenerReqHandler.java index 7a2812e4862..ef549684da8 100644 --- a/solr/test-framework/src/java/org/apache/solr/core/MockQuerySenderListenerReqHandler.java +++ b/solr/test-framework/src/java/org/apache/solr/core/MockQuerySenderListenerReqHandler.java @@ -39,9 +39,8 @@ public void init(NamedList args) { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { - super.initializeMetrics(parentContext, attributes, scope); + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { + super.initializeMetrics(parentContext, attributes); solrMetricsContext.observableLongGauge( "mock_request", "mock", diff --git a/solr/test-framework/src/java/org/apache/solr/embedded/JettySolrRunner.java b/solr/test-framework/src/java/org/apache/solr/embedded/JettySolrRunner.java index 99fe2540846..78dcdcd24cf 100644 --- a/solr/test-framework/src/java/org/apache/solr/embedded/JettySolrRunner.java +++ b/solr/test-framework/src/java/org/apache/solr/embedded/JettySolrRunner.java @@ -16,9 +16,7 @@ */ package org.apache.solr.embedded; -import com.codahale.metrics.ConsoleReporter; -import com.codahale.metrics.MetricFilter; -import com.codahale.metrics.MetricRegistry; +import io.prometheus.metrics.expositionformats.PrometheusTextFormatWriter; import jakarta.servlet.DispatcherType; import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; @@ -40,7 +38,6 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -688,21 +685,14 @@ public void outputMetrics(Path outputDirectory, String fileName) throws IOExcept Set registryNames = metricsManager.registryNames(); for (String registryName : registryNames) { - MetricRegistry metricsRegisty = metricsManager.registry(registryName); - try (PrintStream ps = - outputDirectory == null - ? new PrintStream(OutputStream.nullOutputStream(), false, StandardCharsets.UTF_8) - : new PrintStream( - outputDirectory.resolve(registryName + "_" + fileName).toString(), - StandardCharsets.UTF_8)) { - ConsoleReporter reporter = - ConsoleReporter.forRegistry(metricsRegisty) - .convertRatesTo(TimeUnit.SECONDS) - .convertDurationsTo(TimeUnit.MILLISECONDS) - .filter(MetricFilter.ALL) - .outputTo(ps) - .build(); - reporter.report(); + var prometheusReader = metricsManager.getPrometheusMetricReader(registryName); + if (prometheusReader != null) { + try (OutputStream os = + outputDirectory == null + ? OutputStream.nullOutputStream() + : Files.newOutputStream(outputDirectory.resolve(registryName + "_" + fileName))) { + new PrometheusTextFormatWriter(false).write(os, prometheusReader.collect()); + } } } diff --git a/solr/test-framework/src/java/org/apache/solr/util/SolrMetricTestUtils.java b/solr/test-framework/src/java/org/apache/solr/util/SolrMetricTestUtils.java index 6bd14012567..548195acc59 100644 --- a/solr/test-framework/src/java/org/apache/solr/util/SolrMetricTestUtils.java +++ b/solr/test-framework/src/java/org/apache/solr/util/SolrMetricTestUtils.java @@ -16,7 +16,6 @@ */ package org.apache.solr.util; -import com.codahale.metrics.Counter; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.exporter.prometheus.PrometheusMetricReader; @@ -27,7 +26,6 @@ import io.prometheus.metrics.model.snapshots.Labels; import io.prometheus.metrics.model.snapshots.MetricSnapshot; import io.prometheus.metrics.model.snapshots.MetricSnapshots; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -61,32 +59,7 @@ public static String getRandomScope(Random random, boolean shouldDefineScope) { } public static SolrInfoBean.Category getRandomCategory(Random random) { - return getRandomCategory(random, random.nextBoolean()); - } - - public static SolrInfoBean.Category getRandomCategory( - Random random, boolean shouldDefineCategory) { - return shouldDefineCategory - ? CATEGORIES[TestUtil.nextInt(random, 0, CATEGORIES.length - 1)] - : null; - } - - public static Map getRandomMetrics(Random random) { - return getRandomMetrics(random, random.nextBoolean()); - } - - public static Map getRandomMetrics(Random random, boolean shouldDefineMetrics) { - return shouldDefineMetrics ? getRandomMetricsWithReplacements(random, new HashMap<>()) : null; - } - - /** - * Generate random OpenTelemetry metric names for testing Prometheus metrics. Returns a map of - * metric names to their expected increment values. - */ - public static Map getRandomPrometheusMetrics(Random random) { - return random.nextBoolean() - ? getRandomPrometheusMetricsWithReplacements(random, new HashMap<>()) - : null; + return CATEGORIES[TestUtil.nextInt(random, 0, CATEGORIES.length - 1)]; } public static Map getRandomPrometheusMetricsWithReplacements( @@ -112,68 +85,6 @@ public static Map getRandomPrometheusMetricsWithReplacements( public static final String SUFFIX = "_testing"; - // NOCOMMIT: This will get replaced by getRandomPrometheusMetricsWithReplacements - public static Map getRandomMetricsWithReplacements( - Random random, Map existing) { - HashMap metrics = new HashMap<>(); - ArrayList existingKeys = new ArrayList<>(existing.keySet()); - - int numMetrics = TestUtil.nextInt(random, 1, MAX_ITERATIONS); - for (int i = 0; i < numMetrics; ++i) { - boolean shouldReplaceMetric = !existing.isEmpty() && random.nextBoolean(); - String name = - shouldReplaceMetric - ? existingKeys.get(TestUtil.nextInt(random, 0, existingKeys.size() - 1)) - : TestUtil.randomSimpleString(random, 5, 10) - + SUFFIX; // must be simple string for JMX publishing - - Counter counter = new Counter(); - counter.inc(random.nextLong()); - metrics.put(name, counter); - } - - return metrics; - } - - public static SolrMetricProducer getProducerOf( - SolrInfoBean.Category category, String scope, Map metrics) { - return new SolrMetricProducer() { - SolrMetricsContext solrMetricsContext; - - @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { - this.solrMetricsContext = parentContext.getChildContext(this); - if (category == null) { - throw new IllegalArgumentException("null category"); - } - if (metrics == null || metrics.isEmpty()) { - return; - } - for (Map.Entry entry : metrics.entrySet()) { - solrMetricsContext.counter(entry.getKey(), category.toString(), scope); - } - } - - @Override - public SolrMetricsContext getSolrMetricsContext() { - return solrMetricsContext; - } - - @Override - public String toString() { - return "SolrMetricProducer.of{" - + "\ncategory=" - + category - + "\nscope=" - + scope - + "\nmetrics=" - + metrics - + "\n}"; - } - }; - } - public static DataPointSnapshot getDataPointSnapshot( PrometheusMetricReader reader, String metricName, Labels labels) { MetricSnapshots metricSnapshots = reader.collect(); @@ -366,9 +277,8 @@ public TestSolrMetricProducer(String coreName, Map metrics) { } @Override - public void initializeMetrics( - SolrMetricsContext parentContext, Attributes attributes, String scope) { - this.solrMetricsContext = parentContext.getChildContext(this); + public void initializeMetrics(SolrMetricsContext parentContext, Attributes attributes) { + this.solrMetricsContext = parentContext; for (Map.Entry entry : metrics.entrySet()) { String metricName = entry.getKey(); Long incrementValue = entry.getValue(); diff --git a/solr/webapp/gradle.lockfile b/solr/webapp/gradle.lockfile index 2358a1e548d..07e90198105 100644 --- a/solr/webapp/gradle.lockfile +++ b/solr/webapp/gradle.lockfile @@ -32,13 +32,7 @@ com.tdunning:t-digest:3.3=permitUnusedDeclared,solrCore commons-cli:commons-cli:1.10.0=permitUnusedDeclared,solrCore commons-codec:commons-codec:1.19.0=permitUnusedDeclared,solrCore commons-io:commons-io:2.17.0=permitUnusedDeclared,solrCore -io.dropwizard.metrics:metrics-annotation:4.2.26=serverLib -io.dropwizard.metrics:metrics-core:4.2.26=permitUnusedDeclared,serverLib,solrCore -io.dropwizard.metrics:metrics-graphite:4.2.26=permitUnusedDeclared,serverLib,solrCore -io.dropwizard.metrics:metrics-jetty12-ee10:4.2.26=serverLib -io.dropwizard.metrics:metrics-jetty12:4.2.26=serverLib -io.dropwizard.metrics:metrics-jmx:4.2.26=permitUnusedDeclared,serverLib,solrCore -io.dropwizard.metrics:metrics-jvm:4.2.26=permitUnusedDeclared,serverLib,solrCore +io.dropwizard.metrics:metrics-core:4.2.26=permitUnusedDeclared,solrCore io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor io.netty:netty-buffer:4.2.6.Final=permitUnusedDeclared,solrCore