Package com.cloudera.flume.reporter

Source Code of com.cloudera.flume.reporter.ReportEvent$LegacyReport

/**
* Licensed to Cloudera, Inc. under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  Cloudera, Inc. licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cloudera.flume.reporter;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Map.Entry;

import org.apache.commons.lang.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cloudera.flume.core.Attributes;
import com.cloudera.flume.core.EventImpl;
import com.cloudera.flume.core.Attributes.Type;
import com.google.common.base.Preconditions;

/**
* Reports are just events that have some helpers for quickly outputting data in
* human readable or machine parseable formats.
*
* For now, we use a convention where a attribute starting with "rpt." is a a
* reported field. Later we may include a avro schema or something to include
* type information as well.
*/
public class ReportEvent extends EventImpl {
  static final Logger LOG = LoggerFactory.getLogger(ReportEvent.class);

  final public static String R_NAME = "name";
  final public static String A_COUNT = "count";

  final Map<String, Long> longMetrics = new HashMap<String, Long>();
  final Map<String, Double> doubleMetrics = new HashMap<String, Double>();
  final Map<String, String> stringMetrics = new HashMap<String, String>();

  /**
   * Set a long-valued metric to supplied value. NOT THREAD SAFE.
   *
   * @param name
   *          metric name, null not allowed, if the report previously contained
   *          a mapping for the name the old value is replaced with the new.
   * @param value
   *          metric value to associate with name
   * @throws IllegalArgumentException
   *           if illegal arguments provided
   */
  public void setLongMetric(String name, long value) {
    Preconditions.checkArgument(name != null);
    longMetrics.put(name, value);
  }

  /**
   * Set a double-valued metric to supplied value. NOT THREAD SAFE.
   *
   * @param name
   *          metric name, null not allowed, if the report previously contained
   *          a mapping for the name the old value is replaced with the new.
   * @param value
   *          metric value to associate with name
   * @throws IllegalArgumentException
   *           if illegal arguments provided
   */
  public void setDoubleMetric(String name, double value) {
    Preconditions.checkArgument(name != null);
    doubleMetrics.put(name, value);
  }

  /**
   * Set a string-valued metric to supplied value. NOT THREAD SAFE.
   *
   * @param name
   *          metric name, null not allowed, if the report previously contained
   *          a mapping for the name the old value is replaced with the new.
   * @param value
   *          metric value to associate with name. Null values will be ignored
   *          (not included in the report).
   * @throws IllegalArgumentException
   *           if illegal arguments provided
   */
  public void setStringMetric(String name, String value) {
    Preconditions.checkArgument(name != null);
    if (value != null) {
      stringMetrics.put(name, value);
    } else if (LOG.isDebugEnabled()) {
      // TODO we should look for this during testing and address
      LOG.debug("Ignoring null string metric " + name);
    }
  }

  /**
   * Returns the value of a long-valued metric. NOT THREAD SAFE.
   *
   * @param name
   *          metric name, null not allowed
   * @throws IllegalArgumentException
   *           if illegal arguments provided
   */
  public Long getLongMetric(String name) {
    Preconditions.checkArgument(name != null);
    return longMetrics.get(name);
  }

  /**
   * Returns the value of a double-valued metric. NOT THREAD SAFE.
   *
   * @param name
   *          metric name, null not allowed
   * @throws IllegalArgumentException
   *           if illegal arguments provided
   */
  public Double getDoubleMetric(String name) {
    Preconditions.checkArgument(name != null);
    return doubleMetrics.get(name);
  }

  /**
   * Returns the value of a string-valued metric. NOT THREAD SAFE.
   *
   * @param name
   *          metric name, null not allowed
   * @throws IllegalArgumentException
   *           if illegal arguments provided
   */
  public String getStringMetric(String name) {
    Preconditions.checkArgument(name != null);
    return stringMetrics.get(name);
  }

  /**
   * Returns an unmodifiable map of all double metrics
   */
  public Map<String, Double> getAllDoubleMetrics() {
    return Collections.unmodifiableMap(doubleMetrics);
  }

  /**
   * Returns an unmodifiable map of all string metrics
   */
  public Map<String, String> getAllStringMetrics() {
    return Collections.unmodifiableMap(stringMetrics);
  }

  /**
   * Returns an unmodifiable map of all long metrics
   */
  public Map<String, Long> getAllLongMetrics() {
    return Collections.unmodifiableMap(longMetrics);
  }

  /**
   * Returns the total number of metrics. NOT THREAD SAFE.
   */
  public long getNumMetrics() {
    return this.doubleMetrics.size() + this.longMetrics.size()
        + this.stringMetrics.size();
  }

  /**
   * Constructs a copy of event e
   */
  public ReportEvent(ReportEvent e) {
    super(new byte[0]);
    Preconditions.checkNotNull(e);
    this.merge(e);
  }

  public ReportEvent(String src) {
    super(new byte[0]); // empty body
    this.setStringMetric(R_NAME, src);
  }

  /**
   * Construct a ReportEvent given various metrics.
   */
  public ReportEvent(Map<String, Long> longMetrics,
      Map<String, String> stringMetrics, Map<String, Double> doubleMetrics) {
    super(new byte[0]);
    this.longMetrics.putAll(longMetrics);
    this.stringMetrics.putAll(stringMetrics);
    this.doubleMetrics.putAll(doubleMetrics);
  }

  /**
   * Serialises event as JSON string
   */
  public void toJson(Writer o) throws IOException {
    PrintWriter pw = new PrintWriter(o);
    pw.print("{");

    // an inconsistency: Some of the "attributes" are not in the attribute hash
    // table -- time, priority, host, body.
    pw.print("\"host\" : \"" + StringEscapeUtils.escapeJava(getHost()) + "\"");

    // get the attributes and output them
    for (String attr : getAttrs().keySet()) {
      String v = Attributes.toStringStrict(this, attr);
      Type t = Attributes.getType(attr);

      pw.print(", \"" + StringEscapeUtils.escapeJava(attr) + "\" : ");
      if (t != null && t == Type.STRING) {
        pw.print("\"" + StringEscapeUtils.escapeJava(v) + "\"");
      } else {
        pw.print(StringEscapeUtils.escapeJava(v));
      }
    }

    for (Entry<String, String> entry : getAllStringMetrics().entrySet()) {
      pw.print(", \"" + StringEscapeUtils.escapeJava(entry.getKey()) + "\" : ");
      pw.print("\"" + StringEscapeUtils.escapeJava(entry.getValue()) + "\"");
    }

    for (Entry<String, Double> entry : getAllDoubleMetrics().entrySet()) {
      pw.print(", \"" + StringEscapeUtils.escapeJava(entry.getKey()) + "\" : ");
      pw.print(entry.getValue());
    }

    for (Entry<String, Long> entry : getAllLongMetrics().entrySet()) {
      pw.print(", \"" + StringEscapeUtils.escapeJava(entry.getKey()) + "\" : ");
      pw.print(entry.getValue());
    }

    pw.println("}");
  }

  /**
   * Defaults to printing data out as a bunch of html table cells.
   */
  public void toHtml(Writer o) throws IOException {
    PrintWriter pw = new PrintWriter(o);
    pw.print("<table>");

    pw.print("<tr>");
    pw.print("<th>host</th>");
    pw.print("<td>");
    pw.print(getHost());
    pw.println("</td>");
    pw.print("</tr>");

    // get the attributes, filter, sort and output them
    SortedMap<String, String> reportAttrs = new TreeMap<String, String>();

    for (String attr : getAttrs().keySet()) {
      reportAttrs.put(attr, Attributes.toString(this, attr));
    }

    for (Entry<String, Long> e : getAllLongMetrics().entrySet()) {
      reportAttrs.put(e.getKey(), e.getValue().toString());
    }

    for (Entry<String, Double> e : getAllDoubleMetrics().entrySet()) {
      reportAttrs.put(e.getKey(), e.getValue().toString());
    }

    for (Entry<String, String> e : getAllStringMetrics().entrySet()) {
      reportAttrs.put(e.getKey(), e.getValue());
    }

    for (Entry<String, String> a : reportAttrs.entrySet()) {
      pw.println("<tr><th>" + a.getKey() + "</th>");
      pw.print("<td>");
      pw.print("<div class=\"" + a.getKey() + "\">");
      pw.print(a.getValue());
      pw.print("</div>");
      pw.println("</td>");
      pw.println("</tr>");
    }

    pw.print("</table>");
  }

  /**
   * Returns event in string form: host [ priority date ] {attr1:val1}
   * {attr2:val2} {metric1:val1} {metric2:val2} body
   */
  public String toString() {
    StringBuilder metrics = new StringBuilder();

    // Iterate over strings, doubles and longs building a { key : value } string
    SortedMap<String, String> sortedStrings = new TreeMap<String, String>(this
        .getAllStringMetrics());
    for (Entry<String, String> e : sortedStrings.entrySet()) {
      metrics.append("{ " + e.getKey() + " : ");

      String o = e.getValue();
      metrics.append(o + " } ");
    }

    SortedMap<String, Double> sortedDoubles = new TreeMap<String, Double>(this
        .getAllDoubleMetrics());
    for (Entry<String, Double> e : sortedDoubles.entrySet()) {
      metrics.append("{ " + e.getKey() + " : ");

      String o = e.getValue().toString();
      metrics.append(o + " } ");
    }

    SortedMap<String, Long> sortedLongs = new TreeMap<String, Long>(this
        .getAllLongMetrics());
    for (Entry<String, Long> e : sortedLongs.entrySet()) {
      metrics.append("{ " + e.getKey() + " : ");

      String o = e.getValue().toString();
      metrics.append(o + " } ");
    }

    // This implementation taken from EventImpl
    String mbody = StringEscapeUtils.escapeJava(new String(getBody()));
    StringBuilder attrs = new StringBuilder();
    SortedMap<String, byte[]> sorted = new TreeMap<String, byte[]>(this.fields);
    for (Entry<String, byte[]> e : sorted.entrySet()) {
      attrs.append("{ " + e.getKey() + " : ");

      String o = Attributes.toString(this, e.getKey());
      attrs.append(o + " } ");
    }

    return getHost() + " [" + getPriority().toString() + " "
        + new Date(getTimestamp()) + "] " + attrs.toString()
        + metrics.toString() + mbody;

  }

  /**
   * Serialises event as text to supplied writer.
   */
  public void toText(Writer o) throws IOException {
    o.write(StringEscapeUtils.escapeJava(this.toString()));
  }

  /**
   * Legacy report takes a arbitrary string and turns in into a report.
   */
  static class LegacyReport extends ReportEvent {
    static final String ATTR_LEGACY = "report.legacy.html";
    static {
      Attributes.register(ATTR_LEGACY, Type.STRING);
    }

    LegacyReport(String s, byte[] data) {
      super(s);
      set(ATTR_LEGACY, data);
    }

    public void toHtml(Writer w) {
      PrintWriter pw = new PrintWriter(w);
      byte[] data = get(ATTR_LEGACY);
      pw.print(new String(data));
    }
  }

  /**
   * This is a temporary method present while I convert old reports into new
   * ones.
   */
  public static ReportEvent createLegacyHtmlReport(String name, String data) {
    return new LegacyReport(name, data.getBytes());
  }

  /**
   * Does the work for the merge methods by iterating over the set of metrics in
   * e and copying them to this event with a prefix.
   */
  protected void mergeWithPrefix(String prefix, ReportEvent e) {
    for (Entry<String, Double> entry : e.getAllDoubleMetrics().entrySet()) {
      String newKey = prefix + entry.getKey();
      if (getDoubleMetric(newKey) == null) {
        setDoubleMetric(newKey, entry.getValue());
      }
    }

    for (Entry<String, String> entry : e.getAllStringMetrics().entrySet()) {
      String newKey = prefix + entry.getKey();
      if (getStringMetric(newKey) == null) {
        setStringMetric(newKey, entry.getValue());
      }
    }

    for (Entry<String, Long> entry : e.getAllLongMetrics().entrySet()) {
      String newKey = prefix + entry.getKey();
      if (getLongMetric(newKey) == null) {
        setLongMetric(newKey, entry.getValue());
      }
    }
  }

  /**
   * This method merges in values from other events that are not present in the
   * current event.
   */
  public void merge(ReportEvent e) {
    super.merge(e);
    mergeWithPrefix("", e);
  }

  /**
   * This method "hierarchically" merges the attributes of another event
   * prefixing each attribute with the specified prefix.
   *
   * So if our current event has attributes (a,b,c), and the one being merged in
   * has attributes (d,e,f), and we have prefix be x, the result event will have
   * attributes (a,b,c, x.d, x.e, x.f)
   *
   * This can be recursive, so if if d was actually an event with (h,i,j) and
   * prefix in that call is y, we could end up with (a,b,c,x.d,x.e, x.f, x.y.h,
   * x.y.i, x.y.j)
   */
  public void hierarchicalMerge(String prefix, ReportEvent e) {
    // Copy the attributes
    super.hierarchicalMerge(prefix, e);
    // Copy the metrics
    mergeWithPrefix(prefix + ".", e);
  }

  /**
   * Return escaped String serialisation of this event
   */
  public String toText() {
    return StringEscapeUtils.escapeJava(this.toString());
  }

  /**
   * Return event as JSON string
   */
  public String toJson() {
    StringWriter sw = new StringWriter();
    try {
      toJson(sw);
    } catch (IOException e) {
      LOG.error("String writer should never throw IOException", e);
      return null;
    }
    return sw.getBuffer().toString();
  }

  /**
   * Returns event as HTML string
   */
  public String toHtml() {
    StringWriter sw = new StringWriter();
    try {
      toHtml(sw);
    } catch (IOException e) {
      LOG.error("String writer should never throw IOException", e);
      return null;
    }
    return sw.getBuffer().toString();
  }
}
TOP

Related Classes of com.cloudera.flume.reporter.ReportEvent$LegacyReport

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.