Package ch.ethz.inf.vs.californium.proxy

Source Code of ch.ethz.inf.vs.californium.proxy.StatsResource$StatHelper

package ch.ethz.inf.vs.californium.proxy;

/*******************************************************************************
* Copyright (c) 2012, Institute for Pervasive Computing, ETH Zurich.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Californium (Cf) CoAP framework.
******************************************************************************/


import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import ch.ethz.inf.vs.californium.coap.CoAP.ResponseCode;
import ch.ethz.inf.vs.californium.coap.MediaTypeRegistry;
import ch.ethz.inf.vs.californium.coap.Request;
import ch.ethz.inf.vs.californium.coap.Response;
import ch.ethz.inf.vs.californium.server.resources.CoapExchange;
import ch.ethz.inf.vs.californium.server.resources.ResourceBase;

import com.google.common.cache.CacheStats;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;

/**
* Resource that encapsulate the proxy statistics.
*
* @author Francesco Corazza
*
*/
public class StatsResource extends ResourceBase {
 
  private final Table<String, String, StatHelper> statsTable = HashBasedTable.create();

  private static String CACHE_LOG_NAME = "_cache_log.log";

  /**
   * Instantiates a new stats resource.
   *
   * @param cacheResource
   */
  public StatsResource(CacheResource cacheResource) {
    super("stats");
    getAttributes().setTitle("Keeps track of the requests served by the proxy.");

    // add the sub-resource to show stats
    add(new CacheStatResource("cache", cacheResource));
    add(new ProxyStatResource("proxy"));
  }

  public void updateStatistics(Request request, boolean cachedResponse) {
    URI proxyUri = null;
    try {
      proxyUri = new URI(request.getOptions().getProxyURI());
    } catch (URISyntaxException e) {
      LOGGER.warning(String.format("Proxy-uri malformed: %s",
          request.getOptions().getProxyURI()));
    }

    if (proxyUri == null) {
      // throw new IllegalArgumentException("proxyUri == null");
      return;
    }

    // manage the address requester
    String addressString = proxyUri.getHost();
    if (addressString != null) {
      // manage the resource requested
      String resourceString = proxyUri.getPath();
      if (resourceString != null) {
        // check if there is already an entry for the row/column
        // association
        StatHelper statHelper = statsTable.get(addressString, resourceString);
        if (statHelper == null) {
          // create a new stat if it not present
          statHelper = new StatHelper();

          // add the new element to the table
          statsTable.put(addressString, resourceString, statHelper);
        }

        // increment the count of the requests
        statHelper.increment(cachedResponse);
      }
    }
  }

  /**
   * Builds a pretty print from the statistics gathered.
   *
   * @return the statistics string
   */
  private String getStatString() {
    StringBuilder builder = new StringBuilder();

    builder.append(String.format("Served %d addresses and %d resources\n", statsTable.rowKeySet().size(), statsTable.cellSet().size()));
    builder.append("_\n");
    // iterate over every row (addresses)
    for (String address : statsTable.rowKeySet()) {
      builder.append(String.format("|- %s\n", address));
      builder.append("|\t _\n");
      // iterate over every column for a specific address
      for (String resource : statsTable.row(address).keySet()) {
        builder.append(String.format("|\t |- %s: \n", resource));

        // get the statistics
        StatHelper statHelper = statsTable.get(address, resource);
        builder.append(String.format("|\t |------ total requests: %d\n", statHelper.getTotalCount()));
        builder.append(String.format("|\t |------ total cached replies: %d\n", statHelper.getCachedCount()));
        // builder.append(String.format("|\t |------ last period (%d sec) requests: %d\n",
        // PERIOD_SECONDS, statHelper.getLastPeriodCount()));
        // builder.append(String.format("|\t |------ last period (%d sec) avg delay (nanosec): %d\n",
        // PERIOD_SECONDS, statHelper.getLastPeriodAvgDelay()));
        builder.append("|\t |\n");
      }
      builder.append("|\t  ̄\n");
      builder.append("|\n");
    }
    builder.append(" ̄\n");

    return builder.length() == 0 ? "The proxy has not received any request, yet." : builder.toString();
  }

  private static final class CacheStatResource extends ResourceBase {
    private CacheStats relativeCacheStats;
    private final CacheResource cacheResource;

    private static final long DEFAULT_LOGGING_DELAY = 5;
    ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

    /**
     * Instantiates a new debug resource.
     *
     * @param resourceIdentifier
     *            the resource identifier
     * @param cacheResource
     */
    public CacheStatResource(String resourceIdentifier, CacheResource cacheResource) {
      super(resourceIdentifier);

      this.cacheResource = cacheResource;
      relativeCacheStats = cacheResource.getCacheStats();
    }

    /**
     * Method to get the stats about the cache.
     *
     * @return
     */
    public String getStats() {
      StringBuilder stringBuilder = new StringBuilder();
      CacheStats cacheStats = cacheResource.getCacheStats().minus(relativeCacheStats);

      stringBuilder.append(String.format("Total succesful loaded values: %d %n", cacheStats.loadSuccessCount()));
      stringBuilder.append(String.format("Total requests: %d %n", cacheStats.requestCount()));
      stringBuilder.append(String.format("Hits ratio: %d/%d - %.3f %n", cacheStats.hitCount(), cacheStats.missCount(), cacheStats.hitRate()));
      stringBuilder.append(String.format("Average time spent loading new values (nanoseconds): %.3f %n", cacheStats.averageLoadPenalty()));
      stringBuilder.append(String.format("Number of cache evictions: %d %n", cacheStats.evictionCount()));

      return stringBuilder.toString();
    }

    @Override
    public void handleDELETE(CoapExchange exchange) {
      // reset the cache
      relativeCacheStats = cacheResource.getCacheStats().minus(relativeCacheStats);
      exchange.respond(ResponseCode.DELETED);
    }

    @Override
    public void handleGET(CoapExchange exchange) {
      String payload = "Available commands:\n - GET: show statistics\n - POST write stats to file\n - DELETE: reset statistics\n\n";
      payload += getStats();
      Response response = new Response(ResponseCode.CONTENT);
      response.setPayload(payload);
      response.getOptions().setContentFormat(MediaTypeRegistry.TEXT_PLAIN);
      exchange.respond(response);
    }

    @Override
    public void handlePOST(CoapExchange exchange) {
      // TODO include stopping the writing => make something for the whole
      // proxy
      // executor.shutdown();
      // request.respond(CodeRegistry.RESP_DELETED, "Stopped",
      // MediaTypeRegistry.TEXT_PLAIN);

      // starting to log the stats on a new file

      // create the new file
      String logName = System.nanoTime() + CACHE_LOG_NAME;
      final File cacheLog = new File(logName);
      try {
        cacheLog.createNewFile();

        // write the header
        com.google.common.io.Files.write("hits%, avg. load, #evictions \n", cacheLog, Charset.defaultCharset());
      } catch (IOException e) {
      }

      executor.scheduleWithFixedDelay(new Runnable() {

        @Override
        public void run() {
          CacheStats cacheStats = cacheResource.getCacheStats().minus(relativeCacheStats);

          String csvStats = String.format("%.3f, %.3f, %d %n", cacheStats.hitRate(), cacheStats.averageLoadPenalty(), cacheStats.evictionCount());
          try {
            com.google.common.io.Files.append(csvStats, cacheLog, Charset.defaultCharset());
          } catch (IOException e) {
          }
        }
      }, 0, DEFAULT_LOGGING_DELAY, TimeUnit.SECONDS);

      Response response = new Response(ResponseCode.CREATED);
      response.setPayload("Creted log: " + logName);
      response.getOptions().setContentFormat(MediaTypeRegistry.TEXT_PLAIN);
      exchange.respond(response);
    }
  }

  private final class ProxyStatResource extends ResourceBase {

    public ProxyStatResource(String resourceIdentifier) {
      super(resourceIdentifier);
    }

    /*
     * (non-Javadoc)
     * @see
     * ch.ethz.inf.vs.californium.endpoint.resources.LocalResource#performDELETE
     * (ch.ethz.inf.vs.californium.coap.DELETERequest)
     */
    @Override
    public void handleDELETE(CoapExchange exchange) {
      // reset all the statistics
      statsTable.clear();
      exchange.respond(ResponseCode.DELETED);
    }

    /*
     * (non-Javadoc)
     * @see
     * ch.ethz.inf.vs.californium.endpoint.resources.LocalResource#performGET
     * (ch.ethz.inf.vs.californium.coap.GETRequest)
     */
    @Override
    public void handleGET(CoapExchange exchange) {
      String payload = "Available commands:\n - GET: show statistics\n - POST write stats to file\n - DELETE: reset statistics\n\n";
      payload += getStatString();
      Response response = new Response(ResponseCode.CONTENT);
      response.setPayload(payload);
      response.getOptions().setContentFormat(MediaTypeRegistry.TEXT_PLAIN);
      exchange.respond(response);
    }

  }

  /**
   * The Class StatisticsHelper.
   *
   * @author Francesco Corazza
   */
  private static class StatHelper {
    private int totalCount = 0;
    private int cachedCount = 0;

    public int getCachedCount() {
      return cachedCount;
    }
   
    /**
     * @return the totalCount
     */
    public int getTotalCount() {
      return totalCount;
    }

    public void increment(boolean cachedResponse) {
      // add the total request counter
      totalCount++;
      if (cachedResponse) {
        cachedCount++;
      }

      // add the new request's timestamp to the list
      // long currentTimestamp = System.nanoTime();
      // lastPeriodTimestamps.add(currentTimestamp);

      // clean the list by the old entries
      // cleanTimestamps(currentTimestamp);
    }
  }
}
TOP

Related Classes of ch.ethz.inf.vs.californium.proxy.StatsResource$StatHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.