Package net.opentsdb.tsd

Source Code of net.opentsdb.tsd.StatsRpc$SerializerCollector

// This file is part of OpenTSDB.
// Copyright (C) 2013  The OpenTSDB Authors.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 2.1 of the License, or (at your
// option) any later version.  This program is distributed in the hope that it
// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
// General Public License for more details.  You should have received a copy
// of the GNU Lesser General Public License along with this program.  If not,
// see <http://www.gnu.org/licenses/>.
package net.opentsdb.tsd;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import net.opentsdb.core.IncomingDataPoint;
import net.opentsdb.core.TSDB;
import net.opentsdb.stats.StatsCollector;
import net.opentsdb.utils.JSON;

import org.jboss.netty.channel.Channel;
import org.jboss.netty.handler.codec.http.HttpMethod;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;

import com.stumbleupon.async.Deferred;

/**
* Handles fetching statistics from all over the code, collating them in a
* string buffer or list, and emitting them to the caller. Stats are collected
* lazily, i.e. only when this method is called.
* This class supports the 1.x style HTTP call as well as the 2.x style API
* calls.
* @since 2.0
*/
public final class StatsRpc implements TelnetRpc, HttpRpc {

  /**
   * Telnet RPC responder that returns the stats in ASCII style
   * @param tsdb The TSDB to use for fetching stats
   * @param chan The netty channel to respond on
   * @param cmd call parameters
   */
  public Deferred<Object> execute(final TSDB tsdb, final Channel chan,
      final String[] cmd) {
    final boolean canonical = tsdb.getConfig().getBoolean("tsd.stats.canonical");
    final StringBuilder buf = new StringBuilder(1024);
    final ASCIICollector collector = new ASCIICollector("tsd", buf, null);
    doCollectStats(tsdb, collector, canonical);
    chan.write(buf.toString());
    return Deferred.fromResult(null);
  }

  /**
   * HTTP resposne handler
   * @param tsdb The TSDB to which we belong
   * @param query The query to parse and respond to
   */
  public void execute(final TSDB tsdb, final HttpQuery query) {
    // only accept GET/POST
    if (query.method() != HttpMethod.GET && query.method() != HttpMethod.POST) {
      throw new BadRequestException(HttpResponseStatus.METHOD_NOT_ALLOWED,
          "Method not allowed", "The HTTP method [" + query.method().getName() +
          "] is not permitted for this endpoint");
    }
   
    final boolean canonical = tsdb.getConfig().getBoolean("tsd.stats.canonical");
   
    // if we don't have an API request we need to respond with the 1.x version
    if (query.apiVersion() < 1) {
      final boolean json = query.hasQueryStringParam("json");
      final StringBuilder buf = json ? null : new StringBuilder(2048);
      final ArrayList<String> stats = json ? new ArrayList<String>(64) : null;
      final ASCIICollector collector = new ASCIICollector("tsd", buf, stats);
      doCollectStats(tsdb, collector, canonical);
      if (json) {
        query.sendReply(JSON.serializeToBytes(stats));
      } else {
        query.sendReply(buf);
      }
      return;
    }
   
    // we have an API version, so go newschool
    final List<IncomingDataPoint> dps = new ArrayList<IncomingDataPoint>(64);
    final SerializerCollector collector = new SerializerCollector("tsd", dps,
        canonical);
    ConnectionManager.collectStats(collector);
    RpcHandler.collectStats(collector);
    tsdb.collectStats(collector);
    query.sendReply(query.serializer().formatStatsV1(dps));
  }
 
  /**
   * Helper to record the statistics for the current TSD
   * @param tsdb The TSDB to use for fetching stats
   * @param collector The collector class to call for emitting stats
   */
  private void doCollectStats(final TSDB tsdb, final StatsCollector collector,
      final boolean canonical) {
    collector.addHostTag(canonical);
    ConnectionManager.collectStats(collector);
    RpcHandler.collectStats(collector);
    tsdb.collectStats(collector);
  }
 
  /**
   * Implements the StatsCollector with ASCII style output. Builds a string
   * buffer response to send to the caller
   */
  final class ASCIICollector extends StatsCollector {

    final StringBuilder buf;
    final ArrayList<String> stats;
   
    /**
     * Default constructor
     * @param prefix The prefix to prepend to all statistics
     * @param buf The buffer to store responses in
     * @param stats An array of strings to write for the old style JSON output
     * May be null. If that's the case, we'll try to write to the {@code buf}
     */
    public ASCIICollector(final String prefix, final StringBuilder buf,
        final ArrayList<String> stats) {
      super(prefix);
      this.buf = buf;
      this.stats = stats;
    }
   
    /**
     * Called by the {@link #record} method after a source writes a statistic.
     */
    @Override
    public final void emit(final String line) {
      if (stats != null) {
        stats.add(line.substring(0, line.length() - 1))// strip the '\n'
      } else {
        buf.append(line);
      }
    }
  }
 
  /**
   * Implements the StatsCollector with a list of IncomingDataPoint objects that
   * can be passed on to a serializer for output.
   */
  final class SerializerCollector extends StatsCollector {
   
    final boolean canonical;
    final List<IncomingDataPoint> dps;
   
    /**
     * Default constructor
     * @param prefix The prefix to prepend to all statistics
     * @param dps The array to store objects in
     */
    public SerializerCollector(final String prefix,
        final List<IncomingDataPoint> dps, final boolean canonical) {
      super(prefix);
      this.dps = dps;
      this.canonical = canonical;
    }

    /**
     * Override that records the stat to an IncomingDataPoint object and puts it
     * in the list
     * @param name Metric name
     * @param value The value to store
     * @param xtratag An optional extra tag in the format "tagk=tagv". Can only
     * have one extra tag
     */
    @Override
    public void record(final String name, final long value,
        final String xtratag) {
     
      final IncomingDataPoint dp = new IncomingDataPoint();
      dp.setMetric(prefix + "." + name);
      dp.setTimestamp(System.currentTimeMillis() / 1000L);
      dp.setValue(Long.toString(value));
     
      String tagk = "";
      if (xtratag != null) {
        if (xtratag.indexOf('=') != xtratag.lastIndexOf('=')) {
          throw new IllegalArgumentException("invalid xtratag: " + xtratag
              + " (multiple '=' signs), name=" + name + ", value=" + value);
        } else if (xtratag.indexOf('=') < 0) {
          throw new IllegalArgumentException("invalid xtratag: " + xtratag
              + " (missing '=' signs), name=" + name + ", value=" + value);
        }
        final String[] pair = xtratag.split("=");
        tagk = pair[0];
        addExtraTag(tagk, pair[1]);
      }
     
      addHostTag(canonical);
    
      final HashMap<String, String> tags =
        new HashMap<String, String>(extratags);
      dp.setTags(tags);
      dps.add(dp);
     
      if (!tagk.isEmpty()) {
        clearExtraTag(tagk);
      }
    }
   
  }
}
TOP

Related Classes of net.opentsdb.tsd.StatsRpc$SerializerCollector

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.