content: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF 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 org.apache.hadoop.chukwa.datacollection.adaptor;
  
  import java.io.IOException;
  import java.net.*;
  import java.nio.charset.Charset;
  import java.util.Arrays;
  import java.util.HashMap;
  
  import org.apache.hadoop.chukwa.*;
  import org.apache.hadoop.chukwa.conf.ChukwaConfiguration;
  import org.apache.log4j.Logger;
  
  /**
   * SyslogAdaptor reads UDP syslog message from a port and convert the message to Chukwa
   * Chunk for transport from Chukwa Agent to Chukwa Collector.  Usage:
   * 
   * add SyslogAdaptor [DataType] [Port] [SequenceNumber]
   * 
   * Syslog protocol facility name is mapped to Chukwa Data Type 
   * by SyslogAdaptor, hence each UDP port can support up to 24 data streams.
   * 
   * Data Type mapping can be overwritten in Chukwa Agent Configuration file, i.e.:
   * 
   * &lt;property&gt;
   *   &lt;name&gt;syslog.adaptor.port.9095.facility.LOCAL1&lt;/name&gt;
   *   &lt;value&gt;HADOOP&lt;/value&gt;
   * &lt;/property&gt;
   * 
   * When demux takes place, data received on port 9095 with facility name LOCAL0 will
   * be processed by demux parser for data type "HADOOP".
   */
  public class SyslogAdaptor extends UDPAdaptor {
  
    private final static Logger log = Logger.getLogger(SyslogAdaptor.class);
    public enum FacilityType { KERN, USER, MAIL, DAEMON, AUTH, SYSLOG, LPR, NEWS, UUCP, CRON, AUTHPRIV, FTP, NTP, AUDIT, ALERT, CLOCK, LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7 }
    public HashMap<Integer, String> facilityMap;
    DatagramSocket ds;
    volatile boolean running = true;
    volatile long bytesReceived = 0;
    
    public SyslogAdaptor() {
      facilityMap = new HashMap<Integer, String>(FacilityType.values().length);
    }
    
    public void send(byte[] buf, DatagramPacket dp) throws InterruptedException, IOException {
      StringBuilder source = new StringBuilder();
      source.append(dp.getAddress());
      String dataType = type;
      byte[] trimmedBuf =  Arrays.copyOf(buf, dp.getLength());
      String rawPRI = new String(trimmedBuf, 1, 4, Charset.forName("UTF-8"));
      int i = rawPRI.indexOf(">");
      if (i <= 3 && i > -1) {
        String priorityStr = rawPRI.substring(0,i);
        int priority = 0;
        int facility = 0;
        try {
          priority = Integer.parseInt(priorityStr);
          facility = (priority >> 3) << 3;
          facility = facility / 8;
          dataType = facilityMap.get(facility); 
        } catch (NumberFormatException nfe) {
          log.warn("Unsupported format detected by SyslogAdaptor:"+Arrays.toString(trimmedBuf));
        }
      }
  
      bytesReceived += trimmedBuf.length;
      Chunk c = new ChunkImpl(dataType, source.toString(), bytesReceived, trimmedBuf, SyslogAdaptor.this);
      dest.add(c);
    }
    
    @Override
    public String parseArgs(String s) {
      portno = Integer.parseInt(s);
      ChukwaConfiguration cc = new ChukwaConfiguration();
      for(FacilityType e : FacilityType.values()) {
        StringBuilder buffer = new StringBuilder();
        buffer.append("syslog.adaptor.port.");
        buffer.append(portno);
        buffer.append(".facility.");
        buffer.append(e.name());
        String dataType = cc.get(buffer.toString(), e.name());
        facilityMap.put(e.ordinal(), dataType);
      }
      return s;
    }
  
  }
  