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