001/* 002 * (C) Copyright 2020 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 * bdelbosc 018 */ 019package org.nuxeo.runtime.metrics.reporter; 020 021import static org.apache.commons.lang3.StringUtils.isBlank; 022 023import java.util.Arrays; 024import java.util.EnumSet; 025import java.util.List; 026import java.util.Map; 027import java.util.Set; 028import java.util.concurrent.TimeUnit; 029import java.util.stream.Collectors; 030 031import org.apache.logging.log4j.LogManager; 032import org.apache.logging.log4j.Logger; 033import org.coursera.metrics.datadog.DefaultMetricNameFormatter; 034import org.coursera.metrics.datadog.transport.HttpTransport; 035import org.coursera.metrics.datadog.transport.Transport; 036import org.coursera.metrics.datadog.transport.UdpTransport; 037import org.nuxeo.runtime.metrics.AbstractMetricsReporter; 038import org.nuxeo.runtime.metrics.reporter.patch.NuxeoDatadogReporter; 039 040import io.dropwizard.metrics5.MetricAttribute; 041import io.dropwizard.metrics5.MetricFilter; 042import io.dropwizard.metrics5.MetricRegistry; 043 044/** 045 * Reports metrics to Datadog. 046 * 047 * @since 11.1 048 */ 049public class DatadogReporter extends AbstractMetricsReporter { 050 051 private static final Logger log = LogManager.getLogger(DatadogReporter.class); 052 053 protected NuxeoDatadogReporter reporter; 054 055 protected String hostname; 056 057 protected List<String> tags; 058 059 @Override 060 public void init(long pollInterval, Map<String, String> options) { 061 super.init(pollInterval, options); 062 hostname = getHostname(); 063 tags = getTags(); 064 } 065 066 private String getHostname() { 067 String value = options.get("hostname"); 068 if (!isBlank(value)) { 069 return value; 070 } 071 value = getHostnameFromNuxeoUrl(); 072 if (!isBlank(value)) { 073 return value; 074 } 075 return getCurrentHostname(); 076 } 077 078 @Override 079 public void start(MetricRegistry registry, MetricFilter filter, Set<MetricAttribute> deniedExpansions) { 080 Transport transport; 081 if (getOptionAsBoolean("udp", false)) { 082 String host = requireOption("host", "when using UDP"); 083 int port = getOptionAsInt("port", 8125); 084 log.warn("Connecting using UDP {}:{} reporting every {}s from {}", host, port, pollInterval, hostname); 085 transport = new UdpTransport.Builder().withStatsdHost(host).withPort(port).withRetryingLookup(true).build(); 086 } else { 087 String apiKey = requireOption("apiKey", "when using HTTP"); 088 transport = new HttpTransport.Builder().withApiKey(apiKey).build(); 089 log.warn("Connecting using HTTP transport using apiKey reporting every {}s from {}", pollInterval, 090 hostname); 091 } 092 reporter = NuxeoDatadogReporter.forRegistry(registry) 093 .withHost(hostname) 094 .withTags(tags) 095 .withTransport(transport) 096 .withExpansions(getExpansions(deniedExpansions)) 097 .filter(filter) 098 .withMetricNameFormatter(new DefaultMetricNameFormatter()) 099 .build(); 100 reporter.start(getPollInterval(), TimeUnit.SECONDS); 101 } 102 103 protected List<String> getTags() { 104 String value = getOption("tags", "nuxeo"); 105 return Arrays.asList(value.split(",")); 106 } 107 108 protected EnumSet<NuxeoDatadogReporter.Expansion> getExpansions(Set<MetricAttribute> deniedExpansions) { 109 if (deniedExpansions.isEmpty()) { 110 return NuxeoDatadogReporter.Expansion.ALL; 111 } else { 112 return NuxeoDatadogReporter.Expansion.ALL.stream().filter(e -> { 113 switch (e) { 114 case MAX: 115 return !deniedExpansions.contains(MetricAttribute.MAX); 116 case MIN: 117 return !deniedExpansions.contains(MetricAttribute.MIN); 118 case MEAN: 119 return !deniedExpansions.contains(MetricAttribute.MEAN); 120 case MEDIAN: 121 return !deniedExpansions.contains(MetricAttribute.P50); 122 case P75: 123 return !deniedExpansions.contains(MetricAttribute.P75); 124 case P95: 125 return !deniedExpansions.contains(MetricAttribute.P95); 126 case P98: 127 return !deniedExpansions.contains(MetricAttribute.P98); 128 case P99: 129 return !deniedExpansions.contains(MetricAttribute.P99); 130 case P999: 131 return !deniedExpansions.contains(MetricAttribute.P999); 132 case COUNT: 133 return !deniedExpansions.contains(MetricAttribute.COUNT); 134 case STD_DEV: 135 return !deniedExpansions.contains(MetricAttribute.STDDEV); 136 case RATE_MEAN: 137 return !deniedExpansions.contains(MetricAttribute.MEAN_RATE); 138 case RATE_1_MINUTE: 139 return !deniedExpansions.contains(MetricAttribute.M1_RATE); 140 case RATE_5_MINUTE: 141 return !deniedExpansions.contains(MetricAttribute.M5_RATE); 142 case RATE_15_MINUTE: 143 return !deniedExpansions.contains(MetricAttribute.M15_RATE); 144 default: 145 return false; 146 } 147 }).collect(Collectors.toCollection(() -> EnumSet.noneOf(NuxeoDatadogReporter.Expansion.class))); 148 } 149 } 150 151 @Override 152 public void stop() { 153 log.debug("Stop reporting"); 154 reporter.stop(); 155 } 156 157}