/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.util.monitor; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; import org.slf4j.Logger; /** * Collects statistics on the number of bytes written and emits info to a log. * This is for testing/development and not intended for use in production code. */ public class ReportingOutputStream extends FilterOutputStream { /** * The frequency of logging. */ private static final long TIME_TO_REPORT = 1000000000; // 1s /** * The logger. */ private final Logger _logger; /** * The name of the stream. */ private final String _streamName; /** * The next time (system nano time) that reporting will occur. */ private long _nextReportTime; /** * The call stack. */ private int _callStack; /** * The write time (system nano time). */ private long _writeTime; /** * The bytes written. */ private long _writeBytes; /** * The number of write operations. */ private long _writeOperations; /** * Creates an instance. * * @param logger the device to report to, not null * @param streamName the name to include in the log output, should not be null * @param underlying the underlying stream, not null */ public ReportingOutputStream(final Logger logger, final String streamName, final OutputStream underlying) { super(underlying); _logger = logger; _streamName = streamName; _nextReportTime = System.nanoTime() + TIME_TO_REPORT; } //------------------------------------------------------------------------- @Override public void write(final int b) throws IOException { beginWrite(); try { out.write(b); _writeBytes++; } finally { endWrite(); } } @Override public void write(final byte[] b, final int off, final int len) throws IOException { beginWrite(); try { out.write(b, off, len); _writeBytes += len; } finally { endWrite(); } } @Override public void flush() throws IOException { beginWrite(); try { super.flush(); } finally { endWrite(); } } //------------------------------------------------------------------------- /** * Called when beginning to write. */ private void beginWrite() { if (_callStack++ == 0) { _writeOperations++; _writeTime -= System.nanoTime(); } } /** * Called when ending to write. */ private void endWrite() { if (--_callStack == 0) { long time = System.nanoTime(); _writeTime += time; if (time >= _nextReportTime) { _nextReportTime = time + TIME_TO_REPORT; _logger.info("Stream {} wrote {}Kb in {}ms from {} operations ({}M)", new Object[] {_streamName, (double) _writeBytes / 1024d, (double) _writeTime / 1000000d, _writeOperations, (double) _writeBytes * 8192d / (double) _writeTime}); // scale down influence of older data _writeOperations >>= 1; _writeBytes >>= 1; _writeTime >>= 1; } } } }