1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * See LICENSE.txt included in this distribution for the specific 9 * language governing permissions and limitations under the License. 10 * 11 * When distributing Covered Code, include this CDDL HEADER in each 12 * file and include the License file at LICENSE.txt. 13 * If applicable, add the following below this CDDL HEADER, with the 14 * fields enclosed by brackets "[]" replaced with your own identifying 15 * information: Portions Copyright [yyyy] [name of copyright owner] 16 * 17 * CDDL HEADER END 18 */ 19 20 /* 21 * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. 22 */ 23 package org.opengrok.indexer; 24 25 import io.micrometer.core.instrument.Clock; 26 import io.micrometer.core.instrument.MeterRegistry; 27 import io.micrometer.core.instrument.Tag; 28 import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics; 29 import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics; 30 import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics; 31 import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics; 32 import io.micrometer.core.instrument.binder.system.ProcessorMetrics; 33 import io.micrometer.prometheus.PrometheusConfig; 34 import io.micrometer.prometheus.PrometheusMeterRegistry; 35 import io.micrometer.statsd.StatsdConfig; 36 import io.micrometer.statsd.StatsdMeterRegistry; 37 import io.micrometer.statsd.StatsdFlavor; 38 import org.opengrok.indexer.configuration.RuntimeEnvironment; 39 import org.opengrok.indexer.index.Indexer; 40 import org.opengrok.indexer.logger.LoggerFactory; 41 42 import java.util.Collections; 43 import java.util.List; 44 import java.util.logging.Level; 45 import java.util.logging.Logger; 46 import java.util.stream.Collectors; 47 48 /** 49 * Encapsulates logic of meter registry setup and handling. 50 * Generally, the web application publishes metrics to Prometheus and the Indexer to StatsD. 51 */ 52 public final class Metrics { 53 54 private static final Logger LOGGER = LoggerFactory.getLogger(Metrics.class); 55 56 private static final StatsdConfig statsdConfig = new StatsdConfig() { 57 @Override 58 public String get(String k) { 59 return null; 60 } 61 62 @Override 63 public StatsdFlavor flavor() { 64 return RuntimeEnvironment.getInstance().getStatsdConfig().getFlavor(); 65 } 66 67 @Override 68 public int port() { 69 return RuntimeEnvironment.getInstance().getStatsdConfig().getPort(); 70 } 71 72 @Override 73 public String host() { 74 return RuntimeEnvironment.getInstance().getStatsdConfig().getHost(); 75 } 76 77 @Override 78 public boolean buffered() { 79 return true; 80 } 81 }; 82 83 private static PrometheusMeterRegistry prometheusRegistry; 84 private static StatsdMeterRegistry statsdRegistry; 85 86 static { 87 MeterRegistry registry = null; 88 89 if (RuntimeEnvironment.getInstance().getStatsdConfig().isEnabled()) { LOGGER.log(Level.INFO, "configuring StatsdRegistry")90 LOGGER.log(Level.INFO, "configuring StatsdRegistry"); 91 statsdRegistry = new StatsdMeterRegistry(statsdConfig, Clock.SYSTEM); 92 registry = statsdRegistry; 93 } else if (!RuntimeEnvironment.getInstance().isIndexer()) { LOGGER.log(Level.INFO, "configuring PrometheusRegistry")94 LOGGER.log(Level.INFO, "configuring PrometheusRegistry"); 95 prometheusRegistry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT); 96 registry = prometheusRegistry; 97 } 98 99 if (registry != null) { 100 new ClassLoaderMetrics().bindTo(registry); 101 new JvmMemoryMetrics().bindTo(registry); 102 new JvmGcMetrics().bindTo(registry); 103 new ProcessorMetrics().bindTo(registry); 104 new JvmThreadMetrics().bindTo(registry); 105 } 106 } 107 Metrics()108 private Metrics() { 109 } 110 updateSubFiles(List<String> subFiles)111 public static void updateSubFiles(List<String> subFiles) { 112 // Add tag for per-project reindex. 113 if (statsdRegistry != null && !subFiles.isEmpty()) { 114 String projects = subFiles.stream(). 115 map(s -> s.startsWith(Indexer.PATH_SEPARATOR_STRING) ? s.substring(1) : s). 116 collect(Collectors.joining(",")); 117 Tag commonTag = Tag.of("projects", projects); 118 LOGGER.log(Level.FINE, "updating statsdRegistry with common tag: {}", commonTag); 119 statsdRegistry.config().commonTags(Collections.singleton(commonTag)); 120 } 121 } 122 getPrometheusRegistry()123 public static PrometheusMeterRegistry getPrometheusRegistry() { 124 return prometheusRegistry; 125 } 126 getStatsdRegistry()127 private static StatsdMeterRegistry getStatsdRegistry() { 128 return statsdRegistry; 129 } 130 131 /** 132 * Get registry based on running context. 133 * @return MeterRegistry instance 134 */ getRegistry()135 public static MeterRegistry getRegistry() { 136 if (RuntimeEnvironment.getInstance().isIndexer()) { 137 return getStatsdRegistry(); 138 } else { 139 return getPrometheusRegistry(); 140 } 141 } 142 } 143