package org.dcache.cells;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import diskCacheV111.vehicles.Message;
import dmg.cells.nucleus.CellCommandListener;
import dmg.cells.nucleus.CellEndpoint;
import dmg.cells.nucleus.CellMessage;
import dmg.cells.nucleus.CellMessageAnswerable;
import dmg.cells.nucleus.CellMessageSender;
import dmg.cells.nucleus.SerializationException;
import dmg.util.command.Command;
import org.dcache.commons.stats.RequestCounters;
import org.dcache.commons.stats.RequestExecutionTimeGauges;
public class MessageProcessingMonitor
implements CellCommandListener, CellMessageSender
{
/**
* Request counters used to count message processing.
*/
private final RequestCounters<Class<? extends Serializable>> _counters;
/**
* Request gauges used to measure message processing.
*/
private final RequestExecutionTimeGauges<Class<? extends Serializable>> _gauges;
private CellEndpoint _endpoint;
/**
* If true then message processing will be monitored and
* administrative commands to query the monitoring results are
* activated.
*/
private boolean _enabled;
public MessageProcessingMonitor()
{
_counters = new RequestCounters<>("Messages");
_gauges = new RequestExecutionTimeGauges<>("Messages");
_enabled = false;
}
@Override
public void setCellEndpoint(CellEndpoint endpoint)
{
_endpoint = endpoint;
}
public void setEnabled(boolean enabled)
{
_enabled = enabled;
}
public boolean isEnabled()
{
return _enabled;
}
public CellEndpoint getReplyCellEndpoint(CellMessage envelope)
{
if (_enabled) {
Class<? extends Serializable> type = envelope.getMessageObject().getClass();
return new MonitoringReplyCellEndpoint(type);
} else {
return _endpoint;
}
}
@Command(name = "monitoring enable", hint = "gather message handling statistics",
description="Gather some basic statistics on whether sent messages " +
"were successful and how long they took to process.")
public class MonitoringEnableCommand implements Callable<String>
{
@Override
public String call()
{
_enabled = true;
return "";
}
}
@Command(name = "monitoring disable", hint = "disable message monitoring",
description = "Stops gathering of message handling statistics.")
public class MonitoringDisableCommand implements Callable<String>
{
@Override
public String call()
{
_enabled = false;
return "";
}
}
@Command(name = "monitoring info", hint = "display message monitoring information",
description = "Provides information about message processing.")
public class MonitoringInfoCommand implements Callable<String>
{
@Override
public String call()
{
return _counters.toString() + "\n\n" + _gauges.toString();
}
}
public class MonitoringReplyCellEndpoint implements CellEndpoint
{
private final Class<? extends Serializable> _type;
private final long _startTime;
public MonitoringReplyCellEndpoint(Class<? extends Serializable> type)
{
_startTime = System.currentTimeMillis();
_type = type;
_counters.incrementRequests(_type);
}
@Override
public void sendMessage(CellMessage envelope, SendFlag... flags)
throws SerializationException
{
boolean success = false;
try {
_endpoint.sendMessage(envelope, flags);
success = true;
} finally {
_gauges.update(_type, System.currentTimeMillis() - _startTime);
Object o = envelope.getMessageObject();
if (!success || o instanceof Exception ||
(o instanceof Message) && ((Message) o).getReturnCode() != 0) {
_counters.incrementFailed(_type);
}
}
}
@Override
public void sendMessage(CellMessage envelope, CellMessageAnswerable callback,
Executor executor, long timeout, SendFlag... flags)
{
throw new UnsupportedOperationException("Cannot use callback for reply");
}
@Override
public Map<String,Object> getDomainContext()
{
return _endpoint.getDomainContext();
}
}
}