001 /*
002 * GangliaContext.java
003 *
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020
021 package org.apache.hadoop.metrics.ganglia;
022
023 import java.io.IOException;
024 import java.net.DatagramPacket;
025 import java.net.SocketAddress;
026 import java.net.UnknownHostException;
027
028 import org.apache.commons.logging.Log;
029 import org.apache.commons.logging.LogFactory;
030 import org.apache.hadoop.conf.Configuration;
031 import org.apache.hadoop.metrics.ContextFactory;
032 import org.apache.hadoop.net.DNS;
033
034 /**
035 * Context for sending metrics to Ganglia version 3.1.x.
036 *
037 * 3.1.1 has a slightly different wire portal compared to 3.0.x.
038 */
039 public class GangliaContext31 extends GangliaContext {
040
041 String hostName = "UNKNOWN.example.com";
042
043 private static final Log LOG =
044 LogFactory.getLog("org.apache.hadoop.util.GangliaContext31");
045
046 public void init(String contextName, ContextFactory factory) {
047 super.init(contextName, factory);
048
049 LOG.debug("Initializing the GangliaContext31 for Ganglia 3.1 metrics.");
050
051 // Take the hostname from the DNS class.
052
053 Configuration conf = new Configuration();
054
055 if (conf.get("slave.host.name") != null) {
056 hostName = conf.get("slave.host.name");
057 } else {
058 try {
059 hostName = DNS.getDefaultHost(
060 conf.get("dfs.datanode.dns.interface","default"),
061 conf.get("dfs.datanode.dns.nameserver","default"));
062 } catch (UnknownHostException uhe) {
063 LOG.error(uhe);
064 hostName = "UNKNOWN.example.com";
065 }
066 }
067 }
068
069 protected void emitMetric(String name, String type, String value)
070 throws IOException
071 {
072 if (name == null) {
073 LOG.warn("Metric was emitted with no name.");
074 return;
075 } else if (value == null) {
076 LOG.warn("Metric name " + name +" was emitted with a null value.");
077 return;
078 } else if (type == null) {
079 LOG.warn("Metric name " + name + ", value " + value + " has no type.");
080 return;
081 }
082
083 LOG.debug("Emitting metric " + name + ", type " + type + ", value " +
084 value + " from hostname" + hostName);
085
086 String units = getUnits(name);
087 if (units == null) {
088 LOG.warn("Metric name " + name + ", value " + value
089 + " had 'null' units");
090 units = "";
091 }
092 int slope = getSlope(name);
093 int tmax = getTmax(name);
094 int dmax = getDmax(name);
095 offset = 0;
096 String groupName = name.substring(0,name.lastIndexOf("."));
097
098 // The following XDR recipe was done through a careful reading of
099 // gm_protocol.x in Ganglia 3.1 and carefully examining the output of
100 // the gmetric utility with strace.
101
102 // First we send out a metadata message
103 xdr_int(128); // metric_id = metadata_msg
104 xdr_string(hostName); // hostname
105 xdr_string(name); // metric name
106 xdr_int(0); // spoof = False
107 xdr_string(type); // metric type
108 xdr_string(name); // metric name
109 xdr_string(units); // units
110 xdr_int(slope); // slope
111 xdr_int(tmax); // tmax, the maximum time between metrics
112 xdr_int(dmax); // dmax, the maximum data value
113
114 xdr_int(1); /*Num of the entries in extra_value field for
115 Ganglia 3.1.x*/
116 xdr_string("GROUP"); /*Group attribute*/
117 xdr_string(groupName); /*Group value*/
118
119 for (SocketAddress socketAddress : metricsServers) {
120 DatagramPacket packet =
121 new DatagramPacket(buffer, offset, socketAddress);
122 datagramSocket.send(packet);
123 }
124
125 // Now we send out a message with the actual value.
126 // Technically, we only need to send out the metadata message once for
127 // each metric, but I don't want to have to record which metrics we did and
128 // did not send.
129 offset = 0;
130 xdr_int(133); // we are sending a string value
131 xdr_string(hostName); // hostName
132 xdr_string(name); // metric name
133 xdr_int(0); // spoof = False
134 xdr_string("%s"); // format field
135 xdr_string(value); // metric value
136
137 for (SocketAddress socketAddress : metricsServers) {
138 DatagramPacket packet =
139 new DatagramPacket(buffer, offset, socketAddress);
140 datagramSocket.send(packet);
141 }
142 }
143
144 }