/******************************************************************************* * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved. * 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 *******************************************************************************/ package org.ebayopensource.turmeric.runtime.common.impl.internal.monitoring; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Formatter; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.logging.Level; import org.ebayopensource.turmeric.runtime.common.impl.utils.LogManager; import org.ebayopensource.turmeric.runtime.common.monitoring.ErrorStatusOptions; import org.ebayopensource.turmeric.runtime.common.monitoring.MetricCategory; import org.ebayopensource.turmeric.runtime.common.monitoring.MetricClassifier; import org.ebayopensource.turmeric.runtime.common.monitoring.MetricId; import org.ebayopensource.turmeric.runtime.common.monitoring.MetricThreshold; import org.ebayopensource.turmeric.runtime.common.monitoring.MetricsCollector; import org.ebayopensource.turmeric.runtime.common.monitoring.MetricsStorageProvider; import org.ebayopensource.turmeric.runtime.common.monitoring.value.LongSumMetricValue; import org.ebayopensource.turmeric.runtime.common.monitoring.value.MetricComponentType; import org.ebayopensource.turmeric.runtime.common.monitoring.value.MetricComponentValue; import org.ebayopensource.turmeric.runtime.common.monitoring.value.MetricValue; import org.ebayopensource.turmeric.runtime.common.monitoring.value.MetricValueAggregator; import com.ebay.kernel.component.IComponentStatusXml; import com.ebay.kernel.component.Registration; import com.ebay.kernel.util.StringUtils; import com.ebay.kernel.util.xml.IXmlStreamWriter; /** * @author ichernyshev */ public abstract class BaseMonitoringComponentStatus implements IComponentStatusXml { private static final String NULL_PLACEHOLDER = "NULL_PLACEHOLDER_" + System.currentTimeMillis(); private static final String SERVICE_STATUS_IMPAIRED = "IMPAIRED"; private static final String SERVICE_STATUS_NORMAL = "NORMAL"; private static final String SERVICE_STATUS_UNDEFINED = "UNDEFINED"; private final String m_name; private final String m_prefix; private final boolean m_isClient; private DiffSnapshotView m_diffSnapshotView; public BaseMonitoringComponentStatus(String name, boolean isClient, String prefix) { m_name = name; m_isClient = isClient; m_prefix = prefix; } public final String getName() { return m_name; } public final String getAlias() { return null; } public final String getStatus() { return "created"; } public final List getProperties() { return Collections.EMPTY_LIST; } public final void renderXml(IXmlStreamWriter xmlWriter, Map<String, String> props) { setupDiffSnapshotView(); xmlWriter.writeStartElement(m_prefix + "ServiceMonitoring_Root"); try { Collection<MetricValueAggregator> values; String mode = props.get("mode"); if (mode != null) { xmlWriter.writeAttribute("mode", mode); } if (mode != null && mode.equalsIgnoreCase("diff")) { if (m_diffSnapshotView != null) { long interval = m_diffSnapshotView.getLastInterval(); if (interval != -1) { xmlWriter.writeAttribute("interval", Long .toString(interval)); values = m_diffSnapshotView.getDiffAggregator(); if (values == null) { xmlWriter.writeAttribute("diff_error", "No diff data returned, internal error"); values = new ArrayList<MetricValueAggregator>(); } } else { xmlWriter.writeAttribute("diff_error", "No diff data available yet"); values = new ArrayList<MetricValueAggregator>(); } } else { xmlWriter.writeAttribute("diff_error", "Diff provider is not configured"); values = new ArrayList<MetricValueAggregator>(); } } else { MetricsCollector metricsCollector; if (m_isClient) { metricsCollector = MetricsCollector.getClientInstance(); } else { metricsCollector = MetricsCollector.getServerInstance(); } //parameters for resetting the metric of specific service String actionStr = props.get("action"); if (actionStr != null && actionStr.equals("reset")) { String targetStr = props.get("target"); if (targetStr != null) { MonitoringSystem.persistMetricsSnapSnapshot(targetStr, !m_isClient); metricsCollector.reset(targetStr); } } values = metricsCollector.getAllMetricValues(); } SortedMap<String, Collection<MetricValueAggregator>> metrics = buildMetricsMapForAdminNames(values); MetricCategory categoryFilter = null; String categoryStr = props.get("category"); if (categoryStr != null && !categoryStr.equalsIgnoreCase("all")) { categoryFilter = MetricCategory.fromString(categoryStr); xmlWriter.writeAttribute("category", categoryStr); } String detailStr = props.get("detail"); if (detailStr != null) { xmlWriter.writeAttribute("single-service", detailStr); for (Map.Entry<String, Collection<MetricValueAggregator>> e : metrics .entrySet()) { if (!e.getKey().equals(detailStr)) { continue; } String adminName = e.getKey(); Collection<MetricValueAggregator> values2 = e.getValue(); renderServiceMetrics(adminName, values2, true, categoryFilter, xmlWriter, props); } return; } String fullViewStr = props.get("fullview"); boolean isFullView = Boolean.parseBoolean(fullViewStr); Set<String> filter = null; String filterStr = props.get("filter"); if (filterStr != null) { List<String> names = StringUtils.splitStr(filterStr, ',', true); if (!names.isEmpty()) { filter = new HashSet<String>(names); if (fullViewStr == null) { isFullView = true; } } } for (Map.Entry<String, Collection<MetricValueAggregator>> e : metrics .entrySet()) { if (filter != null && !matchFilter(e.getKey(), filter)) { continue; } String adminName = e.getKey(); Collection<MetricValueAggregator> values2 = e.getValue(); renderServiceMetrics(adminName, values2, isFullView, categoryFilter, xmlWriter, props); } } finally { xmlWriter.writeEndElement(); } } private boolean matchFilter(String adminName, Set<String> filter) { if (filter.contains(adminName)) { return true; } return false; } private SortedMap<String, Collection<MetricValueAggregator>> buildMetricsMapForAdminNames( Collection<MetricValueAggregator> values) { SortedMap<String, Collection<MetricValueAggregator>> result = new TreeMap<String, Collection<MetricValueAggregator>>(); for (MetricValueAggregator value : values) { String adminName = value.getMetricId().getAdminName(); Collection<MetricValueAggregator> sublist = result.get(adminName); if (sublist == null) { sublist = new ArrayList<MetricValueAggregator>(); result.put(adminName, sublist); } sublist.add(value); } return result; } private SortedMap<String, Collection<MetricValueAggregator>> buildMetricsMapForOperations( Collection<MetricValueAggregator> values, boolean includeOperations) { SortedMap<String, Collection<MetricValueAggregator>> result = new TreeMap<String, Collection<MetricValueAggregator>>(); for (MetricValueAggregator value : values) { String opName = value.getMetricId().getOperationName(); if (!includeOperations && opName != null) { continue; } if (opName == null) { opName = NULL_PLACEHOLDER; } Collection<MetricValueAggregator> sublist = result.get(opName); if (sublist == null) { sublist = new ArrayList<MetricValueAggregator>(); result.put(opName, sublist); } sublist.add(value); } return result; } private void renderServiceMetrics(String adminName, Collection<MetricValueAggregator> values, boolean isFullView, MetricCategory categoryFilter, IXmlStreamWriter xmlWriter, Map<String, String> props) { xmlWriter.writeStartElement(m_prefix + "ServiceMonitoring"); try { xmlWriter.writeAttribute("name", adminName); SortedMap<String, Collection<MetricValueAggregator>> metricsMap = buildMetricsMapForOperations( values, isFullView); Collection<MetricValueAggregator> serviceLevelMetrics = metricsMap .get(NULL_PLACEHOLDER); if (serviceLevelMetrics != null) { renderServiceTotals(serviceLevelMetrics, xmlWriter, "ServiceMetrics", null, adminName, categoryFilter); } if (isFullView) { for (Map.Entry<String, Collection<MetricValueAggregator>> e : metricsMap .entrySet()) { String opName = e.getKey(); if (opName == NULL_PLACEHOLDER) { continue; } Collection<MetricValueAggregator> value2 = e.getValue(); renderServiceTotals(value2, xmlWriter, "OperationMetrics", opName, null, categoryFilter); } renderClassifiedMetrics(values, xmlWriter, categoryFilter); } } finally { xmlWriter.writeEndElement(); } } private void renderServiceTotals(Collection<MetricValueAggregator> values, IXmlStreamWriter xmlWriter, String elementName, String name, String adminName, MetricCategory categoryFilter) { xmlWriter.writeStartElement(elementName); try { if (name != null) { xmlWriter.writeAttribute("name", name); } MetricValueAggregator[] values2 = values .toArray(new MetricValueAggregator[values.size()]); Arrays.sort(values2, new MetricValueAggregatorComparatorByMetricName()); String metricName = null; String threshold = null; if (adminName != null) { MetricsConfigManager configManager; if (m_isClient) { configManager = MetricsConfigManager.getClientInstance(); } else { configManager = MetricsConfigManager.getServerInstance(); } ErrorStatusOptions errorStatusOption = configManager .getErrorStatusOption(adminName); if(errorStatusOption != null) { metricName = errorStatusOption.getMetric(); threshold = errorStatusOption.getThreshold(); } } MetricThreshold metricThreshold = null; MetricValue totalMetricValue = null; if (m_diffSnapshotView != null) { if(adminName != null) { totalMetricValue = m_diffSnapshotView .getTotalMetricValue(adminName); } if(totalMetricValue == null ) { if(metricName != null && adminName != null) { totalMetricValue = (new LongSumMetricValue(new MetricId(metricName, adminName, null)).fromString("0")); } } if (totalMetricValue instanceof MetricThreshold) { MetricThreshold mtTotal = (MetricThreshold) totalMetricValue; metricThreshold = (MetricThreshold) mtTotal .fromString(threshold); } } // LongSumMetricValue lsmv = (LongSumMetricValue)(new // LongSumMetricValue(id).fromString(threshold)); for (int i = 0; i < values2.length; i++) { MetricValueAggregator value = values2[i]; MetricId id = value.getMetricId(); if (categoryFilter != null && value.getCategory() != categoryFilter) { continue; } // calculate cummulative value for all classifiers MetricValue totalValue = value.getTotalValue(); if (totalValue == null) { // no data //continue; if(id == null) { continue; } if (id.getMetricName().equals(metricName)) { LongSumMetricValue lsmv = (LongSumMetricValue)(new LongSumMetricValue(id).fromString("0")); totalValue = lsmv; } else { continue; } } String status = SERVICE_STATUS_UNDEFINED; boolean renderStatus = false; if(adminName != null) { if (id.getMetricName().equals(metricName)) { renderStatus = true; try { if (metricThreshold != null) { int result = metricThreshold .compare(totalMetricValue); if (result == -1) { status = SERVICE_STATUS_IMPAIRED; } else { status = SERVICE_STATUS_NORMAL; } } } catch (ClassCastException ce) { //no op } } } xmlWriter.writeStartElement("metric"); try { xmlWriter.writeAttribute("name", id.getMetricName()); renderMetricValue(id, totalValue, xmlWriter); if (renderStatus) { renderMetricErrorStatus(status, id.getMetricName(), totalMetricValue, xmlWriter); } } finally { xmlWriter.writeEndElement(); } } } finally { xmlWriter.writeEndElement(); } } private void renderClassifiedMetrics( Collection<MetricValueAggregator> values, IXmlStreamWriter xmlWriter, MetricCategory categoryFilter) { xmlWriter.writeStartElement("AllMetrics"); try { MetricValueAggregator[] values2 = values .toArray(new MetricValueAggregator[values.size()]); Arrays.sort(values2, new MetricValueAggregatorComparatorByOpMetricName()); for (int i = 0; i < values2.length; i++) { MetricValueAggregator aggrValue = values2[i]; MetricId id = aggrValue.getMetricId(); if (categoryFilter != null && aggrValue.getCategory() != categoryFilter) { continue; } Collection<MetricClassifier> classifiers = aggrValue .getClassifiers(); if (classifiers == null || classifiers.isEmpty()) { continue; } for (MetricClassifier classifier : classifiers) { MetricValue value = aggrValue.getValue(classifier); if (value == null) { continue; } xmlWriter.writeStartElement("metric"); try { xmlWriter.writeAttribute("name", id.getMetricName()); String opName = id.getOperationName(); if (opName != null) { xmlWriter.writeAttribute("opname", opName); } xmlWriter.writeAttribute("usecase", classifier .getUseCase()); xmlWriter.writeAttribute("sourcedc", classifier .getSourceDC()); xmlWriter.writeAttribute("targetdc", classifier .getTargetDC()); renderMetricValue(id, value, xmlWriter); } finally { xmlWriter.writeEndElement(); } } } } finally { xmlWriter.writeEndElement(); } } private void renderMetricValue(MetricId id, MetricValue value, IXmlStreamWriter xmlWriter) { MetricComponentValue[] components = value.getValues(); List<MetricComponentType> types = value.getAllComponentsTypes(); for (int i = 0; i < components.length; i++) { MetricComponentValue component = components[i]; MetricComponentType type = types.get(i); Object valueObj = component.getValue(); String valueStr = getValueStr(id, valueObj, type); xmlWriter.writeStartElement("component"); try { xmlWriter.writeAttribute("name", component.getName()); xmlWriter.writeCData(valueStr); } finally { xmlWriter.writeEndElement(); } } } private void renderMetricErrorStatus(String status, String metricName, MetricValue mv, IXmlStreamWriter xmlWriter) { xmlWriter.writeStartElement("component"); try { xmlWriter.writeAttribute("name", "serviceStatus"); xmlWriter.writeCData(status); } finally { xmlWriter.writeEndElement(); } xmlWriter.writeStartElement("component"); try { xmlWriter.writeAttribute("name", "metricName"); xmlWriter.writeCData(metricName); } finally { xmlWriter.writeEndElement(); } xmlWriter.writeStartElement("component"); try { xmlWriter.writeAttribute("name", "currentvalue"); if (mv != null) { MetricComponentValue[] values = mv.getValues(); if (values[0] != null) { xmlWriter.writeCData(values[0].getValue().toString()); } } else { xmlWriter.writeCData("0"); } } finally { xmlWriter.writeEndElement(); } } private String getValueStr(MetricId id, Object value, MetricComponentType type) { Class clazz = type.getType(); if (clazz.equals(Double.class) || clazz.equals(Float.class)) { StringBuilder sb = new StringBuilder(); Formatter formatter = new Formatter(sb, Locale.US); formatter.format("%1$10.1f", value); return sb.toString(); } return String.valueOf(value); } private void setupDiffSnapshotView() { if (m_diffSnapshotView != null) { return; } try { MonitoringDesc monitoringDesc; if (m_isClient) { monitoringDesc = MonitoringSystem.getClientMonitoringDesc(); } else { monitoringDesc = MonitoringSystem.getServerMonitoringDesc(); } if (monitoringDesc != null) { Collection<StorageProviderDesc> descs = monitoringDesc .getAllProviderDescs(); for (StorageProviderDesc desc : descs) { MetricsStorageProvider provider = desc.getProvider(); if (provider instanceof DiffSnapshotView) { m_diffSnapshotView = (DiffSnapshotView) desc .getProvider(); break; } } } // TODO: allow diff interval changes in config bean // m_diffSnapshotView.setRefreshInterval(m_diffInterval); } catch (Throwable e) { LogManager.getInstance(this.getClass()).log( Level.SEVERE, "Exception looking up diff storage provider: " + e.toString(), e); } } static String getRelativeMetricName(MetricId id) { StringBuilder sb = new StringBuilder(); String opName = id.getOperationName(); if (opName != null) { sb.append(opName); sb.append('.'); } else { sb.append("All."); } sb.append(id.getMetricName()); return sb.toString(); } protected static final void initializeCompStatus( BaseMonitoringComponentStatus comp) { URL xslTemplate = BaseMonitoringComponentStatus.class .getResource("ServiceMonitoringCompStatus.xsl"); if (xslTemplate == null) { throw new RuntimeException( "Unable to find XSL template ServiceMonitoringCompStatus.xsl" + " for ServiceMonitoring component status " + comp.getClass().getName()); } Registration.registerComponent(comp, xslTemplate); } static class MetricValueAggregatorComparatorByMetricName implements Comparator<MetricValueAggregator> { public int compare(MetricValueAggregator obj1, MetricValueAggregator obj2) { String name1 = obj1.getMetricId().getMetricName(); String name2 = obj2.getMetricId().getMetricName(); return name1.compareTo(name2); } } static class MetricValueAggregatorComparatorByOpMetricName implements Comparator<MetricValueAggregator> { public int compare(MetricValueAggregator obj1, MetricValueAggregator obj2) { String name1 = getRelativeMetricName(obj1.getMetricId()); String name2 = getRelativeMetricName(obj2.getMetricId()); return name1.compareTo(name2); } } }