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}