Java tutorial
/* * Copyright 2013-2015 Rackspace * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.rackspacecloud.blueflood.tracker; import com.rackspacecloud.blueflood.http.HttpRequestWithDecodedQueryParams; import com.rackspacecloud.blueflood.io.Constants; import com.rackspacecloud.blueflood.types.Metric; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpResponseStatus; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.management.MBeanServer; import javax.management.ObjectName; import java.lang.management.ManagementFactory; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Tracker implements TrackerMBean { public static final String trackerName = String.format("com.rackspacecloud.blueflood.tracker:type=%s", Tracker.class.getSimpleName()); private static final Logger log = LoggerFactory.getLogger(Tracker.class); private static final String EMPTY_STRING = ""; private final Pattern patternGetTid = Pattern.compile("/v\\d+\\.\\d+/([^/]+)/.*"); private DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // Tracker is a singleton private static final Tracker instance = new Tracker(); private boolean isRegistered = false; private Set tenantIds = new HashSet(); private boolean isTrackingDelayedMetrics = false; private Set<String> metricNames = new HashSet<String>(); // private constructor for singleton private Tracker() { // set dateFormatter to GMT since collectionTime for metrics should always be GMT/UTC dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT")); } public static Tracker getInstance() { return instance; } public synchronized void register() { if (isRegistered) return; try { ObjectName objectName = new ObjectName(trackerName); // register TrackerMBean only if not already registered MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); if (!mBeanServer.isRegistered(objectName)) { ManagementFactory.getPlatformMBeanServer().registerMBean(instance, objectName); } isRegistered = true; log.info("MBean registered as " + trackerName); } catch (Exception exc) { log.error("Unable to register MBean " + trackerName, exc); } } public void addTenant(String tenantId) { tenantIds.add(tenantId); log.info("[TRACKER] tenantId " + tenantId + " added."); } public void removeTenant(String tenantId) { tenantIds.remove(tenantId); log.info("[TRACKER] tenantId " + tenantId + " removed."); } public void removeAllTenants() { tenantIds.clear(); log.info("[TRACKER] all tenants removed."); } public Set getTenants() { return tenantIds; } public void addMetricName(String metricName) { metricNames.add(metricName); log.info("[TRACKER] Metric name " + metricName + " added."); } public void removeMetricName(String metricName) { metricNames.remove(metricName); log.info("[TRACKER] Metric name " + metricName + " removed."); } public void removeAllMetricNames() { metricNames.clear(); log.info("[TRACKER] All metric names removed."); } public Set<String> getMetricNames() { return metricNames; } public void setIsTrackingDelayedMetrics() { isTrackingDelayedMetrics = true; log.info("[TRACKER] Tracking delayed metrics started"); } public void resetIsTrackingDelayedMetrics() { isTrackingDelayedMetrics = false; log.info("[TRACKER] Tracking delayed metrics stopped"); } public boolean getIsTrackingDelayedMetrics() { return isTrackingDelayedMetrics; } public boolean isTracking(String tenantId) { return tenantIds.contains(tenantId); } public boolean doesMessageContainMetricNames(String logmessage) { boolean toLog = false; if (metricNames.size() == 0) { toLog = true; } else { for (String name : metricNames) { if (logmessage.contains(name)) { toLog = true; break; } } } return toLog; } public void track(HttpRequest request) { // check if tenantId is being tracked by JMX TenantTrackerMBean and log the request if it is if (request == null) return; String tenantId = findTid(request.getUri()); if (isTracking(tenantId)) { // get headers String headers = EMPTY_STRING; for (String headerName : request.headers().names()) { headers += "\n" + headerName + "\t" + request.headers().get(headerName); } // get parameters String queryParams = getQueryParameters(request); // get request content String requestContent = EMPTY_STRING; if (request instanceof FullHttpRequest) { FullHttpRequest fullReq = (FullHttpRequest) request; requestContent = fullReq.content().toString(Constants.DEFAULT_CHARSET); if ((requestContent != null) && (!requestContent.isEmpty())) { requestContent = "\nREQUEST_CONTENT:\n" + requestContent; } } // log request String logMessage = "[TRACKER] " + request.getMethod() + " request for tenantId " + tenantId + ": " + request.getUri() + queryParams + "\n" + "HEADERS: " + headers + requestContent; if (doesMessageContainMetricNames(logMessage)) { log.info(logMessage); } } } public void trackResponse(HttpRequest request, FullHttpResponse response) { // check if tenantId is being tracked by JMX TenantTrackerMBean and log the response if it is // HttpRequest is needed for original request uri and tenantId if (request == null) return; if (response == null) return; String tenantId = findTid(request.getUri()); if (isTracking(tenantId)) { HttpResponseStatus status = response.getStatus(); String messageBody = response.content().toString(Constants.DEFAULT_CHARSET); // get parameters String queryParams = getQueryParameters(request); // get headers String headers = ""; for (String headerName : response.headers().names()) { headers += "\n" + headerName + "\t" + response.headers().get(headerName); } // get response content String responseContent = ""; if ((messageBody != null) && (!messageBody.isEmpty())) { responseContent = "\nRESPONSE_CONTENT:\n" + messageBody; } String logMessage = "[TRACKER] " + "Response for tenantId " + tenantId + " " + request.getMethod() + " request " + request.getUri() + queryParams + "\nRESPONSE_STATUS: " + status.code() + "\nRESPONSE HEADERS: " + headers + responseContent; log.info(logMessage); } } /** * This method is used to log delayed metrics, if tracking delayed metrics * is turned on for this Blueflood service. * @param tenantid * @param delayedMetrics */ public void trackDelayedMetricsTenant(String tenantid, final List<Metric> delayedMetrics) { if (isTrackingDelayedMetrics) { String logMessage = String.format("[TRACKER][DELAYED METRIC] Tenant sending delayed metrics %s", tenantid); log.info(logMessage); // log individual delayed metrics locator and collectionTime double delayedMinutes; long nowMillis = System.currentTimeMillis(); for (Metric metric : delayedMetrics) { delayedMinutes = (double) (nowMillis - metric.getCollectionTime()) / 1000 / 60; logMessage = String.format( "[TRACKER][DELAYED METRIC] %s has collectionTime %s which is delayed by %.2f minutes", metric.getLocator().toString(), dateFormatter.format(new Date(metric.getCollectionTime())), delayedMinutes); log.info(logMessage); } } } /** * This method logs the delayed aggregated metrics for a particular tenant, * if tracking delayed metric is turned on for this Blueflood service. * Aggregated metrics have one single timestamp for the group of metrics that * are sent in one request. * * @param tenantId the tenantId who's the sender of the metrics * @param collectionTimeMs the collection timestamp (ms) in request payload * @param delayTimeMs the delayed time (ms) * @param delayedMetricNames the list of delayed metrics in request payload */ public void trackDelayedAggregatedMetricsTenant(String tenantId, long collectionTimeMs, long delayTimeMs, List<String> delayedMetricNames) { if (isTrackingDelayedMetrics) { String logMessage = String.format("[TRACKER][DELAYED METRIC] Tenant sending delayed metrics %s", tenantId); log.info(logMessage); // log individual delayed metrics locator and collectionTime double delayMin = delayTimeMs / 1000 / 60; logMessage = String.format( "[TRACKER][DELAYED METRIC] %s have collectionTime %s which is delayed by %.2f minutes", StringUtils.join(delayedMetricNames, ","), dateFormatter.format(new Date(collectionTimeMs)), delayMin); log.info(logMessage); } } String getQueryParameters(HttpRequest httpRequest) { String params = ""; Map<String, List<String>> parameters = ((HttpRequestWithDecodedQueryParams) httpRequest).getQueryParams(); for (Map.Entry<String, List<String>> param : parameters.entrySet()) { String paramName = param.getKey(); List<String> paramValues = param.getValue(); for (String paramValue : paramValues) { if (!params.equals("")) { params += "&"; } params += paramName + "=" + paramValue; } } if (!params.equals("")) params = "?" + params; return params; } String findTid(String uri) { Matcher m = patternGetTid.matcher(uri); if (m.matches()) return m.group(1); else return null; } }