All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xins.server.FunctionStatistics Maven / Gradle / Ivy

The newest version!
/*
 * $Id: FunctionStatistics.java,v 1.30 2012/03/15 21:07:39 agoubard Exp $
 *
 * See the COPYRIGHT file for redistribution and use restrictions.
 */
package org.xins.server;

import java.util.Map;
import java.util.TimeZone;
import java.util.TreeMap;

import org.apache.log4j.NDC;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import org.xins.common.text.DateConverter;
import org.xins.common.xml.ElementFormatter;

/**
 * Statistics of a function.
 *
 * 

The implementation of this class is thread-safe. * * @version $Revision: 1.30 $ $Date: 2012/03/15 21:07:39 $ * @author Ernst de Haan * @author Anthony Goubard * * @since XINS 1.0.0 */ class FunctionStatistics { /** * String to insert instead of a figure when the figure is unavailable. */ private static final String NOT_AVAILABLE = "N/A"; /** * The time zone used when generating dates for output. */ private static final TimeZone TIME_ZONE = TimeZone.getDefault(); /** * Constructs a new FunctionStatistics instance. */ FunctionStatistics() { _successful = new Statistic(); _unsuccessful = new Statistic(); _errorCodeStatistics = new TreeMap(); } /** * Statistics for the successful calls. Never null. */ private final Statistic _successful; /** * Statistic over the unsuccessful calls. Never null. */ private final Statistic _unsuccessful; /** * Statistics over the unsuccessful calls sorted by error code. * The key of the map is the error code and the Statistic object * corresponding to the error code. Never null. */ private final Map _errorCodeStatistics; /** * Callback method that may be called after a call to this function. This * method will store statistics-related information. * *

This method does not have to be called. If statistics * gathering is disabled, then this method should not be called. * * @param start * the start time, in milliseconds since the UNIX Epoch. * * @param errorCode * the error code returned by the function if a result is unsuccessful; * this value is null only when success * is true. */ final synchronized void recordCall(long start, String errorCode) { long duration = System.currentTimeMillis() - start; // Call succeeded if (errorCode == null) { _successful.recordCall(start, duration); // Call failed } else { _unsuccessful.recordCall(start, duration); Statistic errorCodeStat = _errorCodeStatistics.get(errorCode); if (errorCodeStat == null) { errorCodeStat = new Statistic(); } errorCodeStat.recordCall(start, duration); _errorCodeStatistics.put(errorCode, errorCodeStat); } } /** * Resets the statistics for this function. */ final synchronized void resetStatistics() { _successful.reset(); _unsuccessful.reset(); _errorCodeStatistics.clear(); } /** * Get the successful statistic as an {@link org.xins.common.xml.Element}. * * @return * the successful element, cannot be null */ public synchronized Element getSuccessfulElement() { return _successful.getElement(true, null); } /** * Get the unsuccessful statistics as an array of {@link org.xins.common.xml.Element}. * * @param detailed * If true, the unsuccessful results will be returned * per error code. Otherwise only one unsuccessful containing all * unsuccessful result will be returned. * * @return * the successful element, cannot be empty. */ public synchronized Element[] getUnsuccessfulElement(boolean detailed) { if (!detailed || _errorCodeStatistics.isEmpty()) { Element[] result = new Element[1]; result[0] = _unsuccessful.getElement(false, null); return result; } else { Element[] result = new Element[_errorCodeStatistics.size()]; int i = 0; for (String nextErrorCode : _errorCodeStatistics.keySet()) { Statistic nextStat = _errorCodeStatistics.get(nextErrorCode); result[i] = nextStat.getElement(false, nextErrorCode); i++; } return result; } } /** * Group of statistics data. * *

The implementation of this class is thread-safe. * * @author Anthony Goubard * * @since XINS 1.1.0 */ private static final class Statistic { /** * The number of successful calls executed up until now. Initially * 0L. */ private int _calls; /** * The start time of the most recent call. Initially 0L. */ private long _lastStart; /** * The duration of the most recent call. Initially 0L. */ private long _lastDuration; /** * The context identifier of the most recent call. Initially empty. */ private String _lastContextId; /** * The total duration of all calls up until now. Initially * 0L. */ private long _duration; /** * The minimum time a call took. Initially set to * {@link Long#MAX_VALUE}. */ private long _min = Long.MAX_VALUE; /** * The start time of the call that took the shortest. Initially * 0L. */ private long _minStart; /** * The context identifier of the call that took the shortest. Initially empty. */ private String _minContextId; /** * The duration of the call that took the longest. Initially * 0L. */ private long _max; /** * The start time of the call that took the longest. Initially * 0L. */ private long _maxStart; /** * The context identifier of the call that took the longest. Initially empty. */ private String _maxContextId; /** * Constructs a new Statistic object. */ private Statistic() { _min = Long.MAX_VALUE; } /** * Records a call. * * @param start * the start time, in milliseconds since the UNIX Epoch, not * null. * * @param duration * duration of the call, in milliseconds since the * UNIX Epoch. */ public synchronized void recordCall(long start, long duration) { _lastStart = start; _lastDuration = duration; _calls++; _duration += duration; _min = _min > duration ? duration : _min; _max = _max < duration ? duration : _max; _minStart = (_min == duration) ? start : _minStart; _maxStart = (_max == duration) ? start : _maxStart; _lastContextId = NDC.peek(); if (_min == duration) { _minContextId = _lastContextId; } if (_max == duration) { _maxContextId = _lastContextId; } } /** * Get this statistic as an {@link Element}. * * @param successful * true if the result is successful, false otherwise. * @param errorCode * the errorCode of the unsuccessful result, if you want it also * specified in the returned element. * * @return * the statistic, cannot be null */ public synchronized Element getElement(boolean successful, String errorCode) { String average; String min; String minStart; String max; String maxStart; String lastStart; String lastDuration; if (_calls == 0) { average = NOT_AVAILABLE; min = NOT_AVAILABLE; minStart = NOT_AVAILABLE; max = NOT_AVAILABLE; maxStart = NOT_AVAILABLE; lastStart = NOT_AVAILABLE; lastDuration = NOT_AVAILABLE; } else if (_duration == 0) { average = "0"; min = String.valueOf(_min); minStart = DateConverter.toDateString(TIME_ZONE, _minStart); max = String.valueOf(_max); maxStart = DateConverter.toDateString(TIME_ZONE, _maxStart); lastStart = DateConverter.toDateString(TIME_ZONE, _lastStart); lastDuration = String.valueOf(_lastDuration); } else { average = String.valueOf(_duration / _calls); min = String.valueOf(_min); minStart = DateConverter.toDateString(TIME_ZONE, _minStart); max = String.valueOf(_max); maxStart = DateConverter.toDateString(TIME_ZONE, _maxStart); lastStart = DateConverter.toDateString(TIME_ZONE, _lastStart); lastDuration = String.valueOf(_lastDuration); } Element element = ElementFormatter.createMainElement(successful ? "successful" : "unsuccessful"); Document doc = element.getOwnerDocument(); element.setAttribute("count", String.valueOf(_calls)); element.setAttribute("average", average); if (errorCode != null) { element.setAttribute("errorcode", errorCode); } Element minElem = doc.createElement("min"); minElem.setAttribute("start", minStart); minElem.setAttribute("duration", min); minElem.setAttribute("contextId", _minContextId); element.appendChild(minElem); Element maxElem = doc.createElement("max"); maxElem.setAttribute("start", maxStart); maxElem.setAttribute("duration", max); maxElem.setAttribute("contextId", _maxContextId); element.appendChild(maxElem); Element lastElem = doc.createElement("last"); lastElem.setAttribute("start", lastStart); lastElem.setAttribute("duration", lastDuration); lastElem.setAttribute("contextId", _lastContextId); element.appendChild(lastElem); return element; } /** * Resets this statistic. */ public synchronized void reset() { _calls = 0; _lastStart = 0L; _lastDuration = 0L; _duration = 0L; _min = Long.MAX_VALUE; _minStart = 0L; _max = 0L; _maxStart = 0L; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy