001package com.nimbusds.common.config; 002 003 004import com.nimbusds.common.monitor.WildCardMetricFilter; 005import com.thetransactioncompany.util.PropertyFilter; 006import com.thetransactioncompany.util.PropertyParseException; 007import com.thetransactioncompany.util.PropertyRetriever; 008import net.jcip.annotations.Immutable; 009import org.apache.logging.log4j.LogManager; 010import org.apache.logging.log4j.Logger; 011 012import java.util.Collections; 013import java.util.LinkedList; 014import java.util.List; 015import java.util.Properties; 016import java.util.concurrent.TimeUnit; 017 018 019/** 020 * DropWizard metrics configuration. System property override is enabled. 021 * 022 * <p>The configuration is stored as public fields which become immutable 023 * (final) after their initialisation. 024 * 025 * <p>Property keys: monitor.* 026 * 027 * <p>Example properties: 028 * 029 * <pre> 030 * monitor.entryCountCacheTimeout=1800 031 * monitor.enableJMX=true 032 * monitor.graphite.enable=true 033 * monitor.graphite.host=carbon.server.com 034 * monitor.graphite.port=2003 035 * monitor.graphite.reportInterval=60 036 * monitor.graphite.batchSize=100 037 * monitor.graphite.prefix= 038 * monitor.graphite.ratesTimeUnit=SECONDS 039 * monitor.graphite.durationsTimeUnit=MILLISECONDS 040 * monitor.graphite.filter.1=authzStore.ldapConnector.* 041 * monitor.graphite.filter.2=tokenEndpoint.code.* 042 * monitor.graphite.filter.3=tokenEndpoint.refreshToken.* 043 * </pre> 044 */ 045@Immutable 046public final class MonitorConfiguration implements LoggableConfiguration { 047 048 049 /** 050 * The prefix for the property names. 051 */ 052 public static final String PREFIX = "monitor."; 053 054 055 /** 056 * The default entry count cache timeout (30 minutes). 057 */ 058 public static final long DEFAULT_ENTRY_COUNT_CACHE_TIMEOUT = 60 * 30; 059 060 061 /** 062 * Timeout for caching entry count results, in seconds. Zero means no 063 * caching, negative disabled readings. 064 */ 065 public final long entryCountCacheTimeout; 066 067 068 /** 069 * Enables / disables JMX reporting. 070 */ 071 public final boolean enableJMX; 072 073 074 /** 075 * Graphite reporting configuration. 076 */ 077 public static final class Graphite implements LoggableConfiguration { 078 079 080 /** 081 * Enables / disables reporting. 082 */ 083 public final boolean enable; 084 085 086 /** 087 * The name / IP address of the Carbon server host. 088 */ 089 public final String host; 090 091 092 /** 093 * The port of the Carbon server. 094 */ 095 public final int port; 096 097 098 /** 099 * The report interval, in seconds. 100 */ 101 public final int reportInterval; 102 103 104 /** 105 * Controls batching (pickling) of metrics to the Carbon 106 * server, zero if disabled. 107 */ 108 public final int batchSize; 109 110 111 /** 112 * Prefix for the metrics that are sent to the Carbon server. 113 * May be used to send a password or other credential to the 114 * server. 115 */ 116 public final String prefix; 117 118 119 /** 120 * The rates time unit. 121 */ 122 public final TimeUnit ratesTimeUnit; 123 124 125 /** 126 * The durations time unit. 127 */ 128 public final TimeUnit durationsTimeUnit; 129 130 131 /** 132 * The metrics filter (white list with wild card support). 133 */ 134 public final WildCardMetricFilter filter; 135 136 137 /** 138 * Creates a new Graphite reporting configuration. 139 * 140 * @param props The properties. Must not be {@code null}. 141 * 142 * @throws PropertyParseException On a missing or invalid 143 * property. 144 */ 145 public Graphite(final Properties props) 146 throws PropertyParseException { 147 148 var pr = new PropertyRetriever(props, true); 149 150 enable = pr.getOptBoolean(PREFIX + "graphite.enable", false); 151 152 if (! enable) { 153 host = null; 154 port = 0; 155 reportInterval = 0; 156 batchSize = 0; 157 prefix = null; 158 ratesTimeUnit = null; 159 durationsTimeUnit = null; 160 filter = null; 161 return; 162 } 163 164 host = pr.getString(PREFIX + "graphite.host"); 165 port = pr.getInt(PREFIX + "graphite.port"); 166 reportInterval = pr.getInt(PREFIX + "graphite.reportInterval"); 167 batchSize = pr.getInt(PREFIX + "graphite.batchSize"); 168 prefix = pr.getOptString(PREFIX + "graphite.prefix", null); 169 ratesTimeUnit = pr.getEnum(PREFIX + "graphite.ratesTimeUnit", TimeUnit.class); 170 durationsTimeUnit = pr.getEnum(PREFIX + "graphite.durationsTimeUnit", TimeUnit.class); 171 172 List<String> filterWhiteList = new LinkedList<>(); 173 174 for (String key: props.stringPropertyNames()) { 175 176 if (key.startsWith(PREFIX + "graphite.filter")) { 177 178 String filterEntry = props.getProperty(key); 179 180 if (filterEntry == null || filterEntry.trim().isEmpty()) { 181 continue; // skip 182 } 183 184 filterWhiteList.add(filterEntry.trim()); 185 } 186 } 187 188 filter = new WildCardMetricFilter(Collections.unmodifiableList(filterWhiteList)); 189 } 190 191 192 @Override 193 public void log() { 194 195 Logger log = LogManager.getLogger(LOG_CATEGORY); 196 197 log.info("[CM7002] Graphite reporting enabled: {}", enable); 198 199 if (! enable) { 200 return; 201 } 202 203 log.info("[CM7003] Graphite reporting host: {}", host); 204 log.info("[CM7004] Graphite reporting port: {}", port); 205 log.info("[CM7005] Graphite reporting interval: {}", reportInterval); 206 log.info("[CM7006] Graphite reporting batch size: {}", batchSize + (batchSize < 1 ? " disabled" : "")); 207 log.info("[CM7007] Graphite reporting prefix: {}", prefix); 208 log.info("[CM7008] Graphite reporting rates time unit: {}", ratesTimeUnit); 209 log.info("[CM7009] Graphite reporting durations time unit: {}", durationsTimeUnit); 210 211 final String filterSetting; 212 213 if (filter.matchesAny()) { 214 filterSetting = "ANY"; 215 } else if (filter.matchesNone()) { 216 filterSetting = "NONE"; 217 } else { 218 filterSetting = filter.getWhiteList().toString(); 219 } 220 221 log.info("[CM7010] Graphite reporting filter: {}", filterSetting); 222 } 223 } 224 225 226 /** 227 * The Graphite reporting configuration. 228 */ 229 public final Graphite graphite; 230 231 232 /** 233 * Creates a new monitoring configuration from the specified 234 * properties. 235 * 236 * @param props The properties. Must not be {@code null}. 237 * 238 * @throws ConfigurationException On a missing or invalid property. 239 */ 240 public MonitorConfiguration(final Properties props) 241 throws ConfigurationException { 242 243 var pr = new PropertyRetriever(props, true); 244 245 try { 246 entryCountCacheTimeout = pr.getOptLong(PREFIX + "entryCountCacheTimeout", DEFAULT_ENTRY_COUNT_CACHE_TIMEOUT); 247 enableJMX = pr.getOptBoolean(PREFIX + "enableJMX", false); 248 graphite = new Graphite(props); 249 } catch (PropertyParseException e) { 250 throw new ConfigurationException(e.getMessage() + ": Property: " + e.getPropertyKey(), e); 251 } 252 } 253 254 255 /** 256 * Logs the configuration details at INFO level. 257 */ 258 @Override 259 public void log() { 260 261 Logger log = LogManager.getLogger(LOG_CATEGORY); 262 log.info("[CM7000] Overriding system properties: {}", PropertyFilter.filterWithPrefix(PREFIX, System.getProperties()).stringPropertyNames()); 263 log.info("[CM7020] Entry count cache timeout: {}s", entryCountCacheTimeout); 264 log.info("[CM7001] JMX reporting enabled: {}", enableJMX); 265 graphite.log(); 266 } 267}