1313import org .apache .logging .log4j .Logger ;
1414import org .apache .lucene .store .AlreadyClosedException ;
1515import org .elasticsearch .cluster .routing .ShardRouting ;
16+ import org .elasticsearch .cluster .service .ClusterService ;
1617import org .elasticsearch .common .component .AbstractLifecycleComponent ;
1718import org .elasticsearch .common .util .SingleObjectCache ;
19+ import org .elasticsearch .core .FixForMultiProject ;
1820import org .elasticsearch .core .TimeValue ;
1921import org .elasticsearch .index .IndexMode ;
2022import org .elasticsearch .index .IndexService ;
2123import org .elasticsearch .index .shard .DocsStats ;
2224import org .elasticsearch .index .shard .IllegalIndexShardStateException ;
2325import org .elasticsearch .index .shard .IndexShard ;
2426import org .elasticsearch .indices .IndicesService ;
27+ import org .elasticsearch .indices .SystemIndices ;
2528import org .elasticsearch .telemetry .metric .LongWithAttributes ;
2629import org .elasticsearch .telemetry .metric .MeterRegistry ;
2730
3336import java .util .concurrent .atomic .AtomicLong ;
3437import java .util .function .Supplier ;
3538
39+ import static org .elasticsearch .cluster .metadata .MetadataCreateIndexService .getTotalUserIndices ;
40+
3641/**
3742 * {@link IndicesMetrics} monitors index statistics on an Elasticsearch node and exposes them as metrics
3843 * through the provided {@link MeterRegistry}. It tracks the current total number of indices, document count, and
3944 * store size (in bytes) for each index mode.
4045 */
4146public class IndicesMetrics extends AbstractLifecycleComponent {
47+ public static final String USER_INDEX_TOTAL_METRIC_NAME = "es.indices.users.total" ;
4248 private final Logger logger = LogManager .getLogger (IndicesMetrics .class );
4349 private final MeterRegistry registry ;
4450 private final List <AutoCloseable > metrics = new ArrayList <>();
4551 private final IndicesStatsCache stateCache ;
52+ private final ClusterService clusterService ;
53+ private final SystemIndices systemIndices ;
4654
47- public IndicesMetrics (MeterRegistry meterRegistry , IndicesService indicesService , TimeValue metricsInterval ) {
55+ public IndicesMetrics (
56+ MeterRegistry meterRegistry ,
57+ IndicesService indicesService ,
58+ TimeValue metricsInterval ,
59+ ClusterService clusterService ,
60+ SystemIndices systemIndices
61+ ) {
4862 this .registry = meterRegistry ;
4963 // Use half of the update interval to ensure that results aren't cached across updates,
5064 // while preventing the cache from expiring when reading different gauges within the same update.
5165 var cacheExpiry = new TimeValue (metricsInterval .getMillis () / 2 );
5266 this .stateCache = new IndicesStatsCache (indicesService , cacheExpiry );
67+ this .clusterService = clusterService ;
68+ this .systemIndices = systemIndices ;
5369 }
5470
55- private static List <AutoCloseable > registerAsyncMetrics (MeterRegistry registry , IndicesStatsCache cache ) {
56- final int TOTAL_METRICS = 52 ;
71+ @ FixForMultiProject (description = "When multi-project arrives we should add project ID to the USER_INDEX_TOTAL_METRIC_NAME." )
72+ private static List <AutoCloseable > registerAsyncMetrics (
73+ MeterRegistry registry ,
74+ IndicesStatsCache cache ,
75+ ClusterService clusterService ,
76+ SystemIndices systemIndices
77+ ) {
78+ final int TOTAL_METRICS = 53 ;
5779 List <AutoCloseable > metrics = new ArrayList <>(TOTAL_METRICS );
5880 for (IndexMode indexMode : IndexMode .values ()) {
5981 String name = indexMode .getName ();
@@ -165,6 +187,14 @@ private static List<AutoCloseable> registerAsyncMetrics(MeterRegistry registry,
165187 )
166188 );
167189 }
190+ metrics .add (registry .registerLongGauge (USER_INDEX_TOTAL_METRIC_NAME , "Total number of user indices" , "index" , () -> {
191+ if (clusterService .state ().clusterRecovered () == false || clusterService .state ().nodes ().isLocalNodeElectedMaster () == false ) {
192+ return null ;
193+ }
194+ return new LongWithAttributes (
195+ getTotalUserIndices (systemIndices , clusterService .state ().getMetadata ().projects ().values ().iterator ().next ())
196+ );
197+ }));
168198 assert metrics .size () == TOTAL_METRICS : "total number of metrics has changed" ;
169199 return metrics ;
170200 }
@@ -180,7 +210,7 @@ static Supplier<LongWithAttributes> diffGauge(Supplier<Long> currentValue) {
180210
181211 @ Override
182212 protected void doStart () {
183- metrics .addAll (registerAsyncMetrics (registry , stateCache ));
213+ metrics .addAll (registerAsyncMetrics (registry , stateCache , clusterService , systemIndices ));
184214 }
185215
186216 @ Override
0 commit comments