001/*
002 * (C) Copyright 2006-2018 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     dmetzler
018 */
019package org.nuxeo.datadog.reporter;
020
021import java.util.EnumSet;
022import java.util.concurrent.TimeUnit;
023
024import org.apache.commons.lang3.StringUtils;
025import org.apache.commons.logging.Log;
026import org.apache.commons.logging.LogFactory;
027import org.coursera.metrics.datadog.DatadogReporter;
028import org.coursera.metrics.datadog.DatadogReporter.Expansion;
029import org.coursera.metrics.datadog.DefaultMetricNameFormatter;
030import org.coursera.metrics.datadog.transport.HttpTransport;
031import org.nuxeo.runtime.metrics.MetricsService;
032import org.nuxeo.runtime.model.ComponentContext;
033import org.nuxeo.runtime.model.ComponentInstance;
034import org.nuxeo.runtime.model.DefaultComponent;
035
036import com.codahale.metrics.MetricFilter;
037import com.codahale.metrics.MetricRegistry;
038import com.codahale.metrics.SharedMetricRegistries;
039
040public class DatadogReporterServiceImpl extends DefaultComponent implements DatadogReporterService {
041
042    private static final DefaultStringMatchingStrategy DEFAULT_STRING_MATCHING_STRATEGY = new DefaultStringMatchingStrategy();
043
044    private static final RegexStringMatchingStrategy REGEX_STRING_MATCHING_STRATEGY = new RegexStringMatchingStrategy();
045
046    private static final SubstringMatchingStrategy SUBSTRING_MATCHING_STRATEGY = new SubstringMatchingStrategy();
047
048    protected final MetricRegistry metrics = SharedMetricRegistries.getOrCreate(MetricsService.class.getName());
049
050    private DatadogReporter reporter;
051
052    private DatadogReporterConfDescriptor conf;
053
054    private static final Log log = LogFactory.getLog(DatadogReporterService.class);
055
056    @Override
057    public void start(ComponentContext context) {
058        if (reporter != null) {
059            startReporter();
060        }
061    }
062
063    @Override
064    public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
065        if ("configuration".equals(extensionPoint)) {
066            setConfiguration((DatadogReporterConfDescriptor) contribution);
067        }
068    }
069
070    private void setConfiguration(DatadogReporterConfDescriptor conf) {
071        if (StringUtils.isBlank(conf.getApiKey())) {
072            log.error("Datadog reporter service is not well configured : apiKey is empty. Your metrics won't be sent.");
073        } else {
074            this.conf = conf;
075            buildReporter();
076        }
077    }
078
079    private void buildReporter() {
080        HttpTransport httpTransport = new HttpTransport.Builder().withApiKey(conf.getApiKey()).build();
081        reporter = DatadogReporter.forRegistry(metrics)//
082                                  .withHost(conf.getHost())//
083                                  .withTags(conf.getTags())
084                                  .withTransport(httpTransport)//
085                                  .withExpansions(getExpansions())//
086                                  .filter(getFilter())
087                                  .withMetricNameFormatter(new DefaultMetricNameFormatter())//
088                                  .build();
089
090    }
091
092    private EnumSet<Expansion> getExpansions() {
093        return conf.filter.getExpansions();
094    }
095
096    public MetricFilter getFilter() {
097        final StringMatchingStrategy stringMatchingStrategy = conf.filter.getUseRegexFilters()
098                ? REGEX_STRING_MATCHING_STRATEGY
099                : (conf.filter.getUseSubstringMatching() ? SUBSTRING_MATCHING_STRATEGY
100                        : DEFAULT_STRING_MATCHING_STRATEGY);
101
102        return (name, metric) -> {
103            // Include the metric if its name is not excluded and its name is included
104            // Where, by default, with no includes setting, all names are included.
105            return !stringMatchingStrategy.containsMatch(conf.filter.getExcludes(), name)
106                    && (conf.filter.getIncludes().isEmpty()
107                            || stringMatchingStrategy.containsMatch(conf.filter.getIncludes(), name));
108        };
109    }
110
111    @Override
112    public void startReporter() {
113        if (reporter != null) {
114            log.info("Starting Datadog reporter");
115            reporter.start(conf.getPollInterval(), TimeUnit.SECONDS);
116        }
117    }
118
119    @Override
120    public void stopReporter() {
121        log.info("Stopping Datadog reporter");
122        reporter.stop();
123    }
124
125    DatadogReporter getReporter() {
126        return reporter;
127    }
128
129    DatadogReporterConfDescriptor getConfig() {
130        return conf;
131    }
132
133}