/******************************************************************************* * 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.monitoring.storage; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.OutputStream; import java.io.PrintStream; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Collection; import java.util.Date; import java.util.Formatter; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.ebayopensource.turmeric.runtime.common.exceptions.ErrorDataFactory; import org.ebayopensource.turmeric.runtime.common.exceptions.ServiceException; import org.ebayopensource.turmeric.runtime.common.monitoring.MetricClassifier; import org.ebayopensource.turmeric.runtime.common.monitoring.MetricId; import org.ebayopensource.turmeric.runtime.common.monitoring.MetricsStorageProvider; 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 org.ebayopensource.turmeric.runtime.errorlibrary.ErrorConstants; /** * This class provides a default metrics snapshot logger to log aggregated * metrics to a log file. Each metric value in a snapshot is logged as one line * in the file with the metric name, service admin name, operation name, usecase * name, client data center, server data center, and the metric value. These * fields are delimited. The name of the log file and the delimiter can be * customized using <storage-option> when configuring storage provider. For * example, * * <storage-provider name="DiffBasedFileLogger"> * <class-name>org.ebayopensource.turmeric.runtime.common.impl.monitoring.storage.DSnapshotFileLogger</class-name> * <storage-options> <option name="filename">MyMetrics.log</option> <option * name="delimiter">;</option> </storage-options> </storage-provider> * * By default the file name is SOAMetrics.log and the delimiter is ','. * * @author wdeng */ public class SnapshotFileLogger extends SnapshotLogger implements MetricsStorageProvider { private static final Logger LOG = Logger.getLogger(SnapshotFileLogger.class.getName()); public final static String PROP_FILENAME = "filename"; public final static String PROP_DELIMITER = "delimiter"; private final static String DEFAULT_LOG_FILE = "SOAMetrics.log"; private final static String DEFAULT_DELIMITER = ","; private String m_delimiter = DEFAULT_DELIMITER; private File m_logFile; private Formatter m_formatter; private PrintStream m_printStream; private Map<String, String> s_filenames = new HashMap<String, String>(); public SnapshotFileLogger() { File logDir = new File(System.getProperty("org.ebayopensource.turmeric.log.dir", ".")); m_logFile = new File(logDir, DEFAULT_LOG_FILE); } @Override public void init(Map<String, String> options, String name, String collectionLocation, Integer snapshotInterval) { super.init(options, name, collectionLocation, snapshotInterval); if (null == options || options.size() < 1) { return; } String filename = options.get(PROP_FILENAME); if (null != filename && filename.length() > 0) { m_logFile = new File(filename); if(!m_logFile.isAbsolute() && !filename.contains(File.separator)) { File logDir = new File(System.getProperty("org.ebayopensource.turmeric.log.dir", ".")); m_logFile = new File(logDir, filename); } } String delimiter = options.get(PROP_DELIMITER); if (null != delimiter && delimiter.length() > 0) { m_delimiter = delimiter; } writeHeader(name, collectionLocation); } @Override protected void epilog(long snapshotTime, Collection<MetricValueAggregator> snapshot) throws ServiceException { m_printStream.close(); } @Override protected void prelude(long snapshotTime, Collection<MetricValueAggregator> snapshot) throws ServiceException { try { OutputStream os = new FileOutputStream(m_logFile, true); m_printStream = new PrintStream(os); m_formatter = new Formatter(m_printStream, Locale.US); } catch (FileNotFoundException e) { throw new ServiceException( ErrorDataFactory.createErrorData(ErrorConstants.SVC_METRICS_CANNOT_WRITE_FILE, ErrorConstants.ERRORDOMAIN, new Object[] { m_logFile.getAbsolutePath() }), e); } } @Override protected void saveMetricValue(long timeSnapshot, MetricId id, MetricClassifier key, MetricValue value) { saveMetricValue(timeSnapshot, id, key, value, m_formatter, m_delimiter); } protected static void saveMetricValue(long timeSnapshot, MetricId id, MetricClassifier key, MetricValue value, Formatter formatter, String delimiter) { formatter.format( "%8$tD %8$tT%1$s%2$s%1$s%3$s%1$s%4$s%1$s%5$s%1$s%6$s%1$s%7$s", delimiter, id.getAdminName(), getOperationName(id), id .getMetricName(), key.getUseCase(), key.getSourceDC(), key.getTargetDC(), new Date(timeSnapshot)); List<MetricComponentType> componentTypes = value .getAllComponentsTypes(); MetricComponentValue[] values = value.getValues(); int remaining = values.length; for (MetricComponentType type : componentTypes) { if (remaining == 0) { break; } formatter.format(delimiter); for (int i = 0; i < values.length; i++) { MetricComponentValue v = values[i]; if (type.getName().equals(v.getName())) { formatComponentValue(v, formatter); remaining--; break; } } } formatter.format("\n"); } private static String getOperationName(MetricId id) { String operationName = id.getOperationName(); if (operationName == null) { String metricName = id.getMetricName(); if (metricName != null && metricName.toUpperCase().contains(".TOTAL")) { operationName = "ALL"; } else { operationName = "N/A"; } } return operationName; } private void writeHeader(String provider, String collectionLocation) { synchronized(s_filenames) { String lookup = s_filenames.get(provider); if (lookup == null) { if (!m_logFile.exists()) { try { OutputStream os = new FileOutputStream(m_logFile, true); PrintStream ps = new PrintStream(os); ps.printf("Provider Type=%s, Collection Location=%s, IP=%s, TID=%s\n", provider, collectionLocation, getIP(), getID()); s_filenames.put(provider, provider); ps.close(); } catch (FileNotFoundException e) { LOG.log(Level.WARNING, "Unable to write header", e); } } } } } private String getIP() { String result = ""; try { InetAddress addr = InetAddress.getLocalHost(); byte[] ipAddr = addr.getAddress(); for (int i = 0; i < ipAddr.length; i++) { if (i > 0) { result += "."; } result += ipAddr[i] & 0xFF; } } catch (UnknownHostException e) { LOG.log(Level.WARNING, "Unknown host for local host?", e); } return result; } private String getID() { return String.valueOf(Thread.currentThread().getId()); } }