Package org.elasticsearch.flume

Source Code of org.elasticsearch.flume.ElasticSearchSink

package org.elasticsearch.flume;

import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.node.NodeBuilder.nodeBuilder;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import com.cloudera.flume.conf.SinkFactory.SinkBuilder;
import com.cloudera.flume.core.Event;
import com.cloudera.flume.core.EventSink;
import com.cloudera.flume.reporter.ReportEvent;
import com.cloudera.util.Pair;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.node.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ElasticSearchSink extends EventSink.Base {

    private static final Logger LOG = LoggerFactory.getLogger(ElasticSearchSink.class);
    private static final String DEFAULT_INDEX_NAME = "flume";
    private static final String DEFAULT_LOG_TYPE = "log";
    private static final int DEFAULT_ELASTICSEARCH_PORT = 9300;

    private Node node;
    private Client client;
    private String indexName = DEFAULT_INDEX_NAME;
    private String indexPattern = null;
    private String indexType = DEFAULT_LOG_TYPE;

    private Charset charset = Charset.defaultCharset();

    private String[] hostNames = new String[0];
    private String clusterName = ClusterName.DEFAULT.value();

    // Enabled only for testing
    private boolean localOnly = false;

    private AtomicLong eventErrorCount = new AtomicLong(0L);
    private static final String NO_OF_FAILED_EVENTS = "NO_OF_FAILED_EVENTS";

    @Override
    public void append(Event e) throws IOException {
        try {
            XContentBuilder builder = jsonBuilder()
                    .startObject()
                    .field("timestamp", new Date(e.getTimestamp()))
                    .field("host", e.getHost())
                    .field("priority", e.getPriority().name());

            addBody(builder, e.getBody());

            addAttrs(builder, e.getAttrs());

            index(e, builder);
        } catch (Exception ex) {
            LOG.error("Error Processing event: {}", e.toString(), ex);
            eventErrorCount.incrementAndGet();
        }
    }

    @Override
    public synchronized ReportEvent getMetrics() {
        ReportEvent event = new ReportEvent("ElasticSearchSink");
        event.setLongMetric(NO_OF_FAILED_EVENTS, eventErrorCount.longValue());
        return event;
    }

    private void addBody(XContentBuilder builder, byte[] data) throws IOException {
        XContentType contentType = XContentFactory.xContentType(data);

        if (contentType == null) {
            builder.startObject("message");
            addSimpleField(builder, "text", data);
            builder.endObject();
        } else {
            addComplexField(builder, "message", contentType, data);
        }
    }

    private void addAttrs(XContentBuilder builder, Map<String, byte[]> attrs) throws IOException {
        builder.startObject("fields");
        for (Map.Entry<String, byte[]> entry : attrs.entrySet()) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("field: {}, data: {}", entry.getKey(), new String(entry.getValue()));
            }
            addField(builder, entry.getKey(), entry.getValue());
        }
        builder.endObject();
    }

    private void addField(XContentBuilder builder, String fieldName, byte[] data) throws IOException {
        XContentType contentType = XContentFactory.xContentType(data);
        if (contentType == null) {
            addSimpleField(builder, fieldName, data);
        } else {
            addComplexField(builder, fieldName, contentType, data);
        }
    }

    private void addSimpleField(XContentBuilder builder, String fieldName, byte[] data) throws IOException {
        builder.field(fieldName, new String(data, charset));
    }

    private void addComplexField(XContentBuilder builder, String fieldName, XContentType contentType, byte[] data)
            throws IOException {
        XContentParser parser = null;
        try {
            parser = XContentFactory.xContent(contentType).createParser(data);
            parser.nextToken();
            builder.field(fieldName).copyCurrentStructure(parser);
        } finally {
            if (parser != null) {
                parser.close();
            }
        }
    }

    private void index(Event e, XContentBuilder builder) {
        String iName = indexName;
        if (indexPattern != null) {
            iName = e.escapeString(indexPattern);
        }
        client.prepareIndex(iName, indexType, null)
                .setSource(builder)
                .execute()
                .actionGet();

        if (!iName.equals(indexName)) {
            client.admin().indices().prepareAliases().addAlias(iName, indexName).execute().actionGet();
        }
    }

    @Override
    public void close() throws IOException, InterruptedException {
        super.close();

        if (client != null) {
            client.close();
        }
        if (node != null) {
            node.close();
        }
    }

    @Override
    public void open() throws IOException, InterruptedException {
        super.open();

        if (hostNames.length == 0) {
            LOG.info("Using ES AutoDiscovery mode");
            node = nodeBuilder().client(true).clusterName(clusterName).local(localOnly).node();
            client = node.client();
        } else {
            LOG.info("Using provided ES hostnames: {} ", Arrays.toString(hostNames));

            Settings settings = ImmutableSettings.settingsBuilder()
                    .put("cluster.name", clusterName)
                    .build();

            TransportClient transportClient = new TransportClient(settings);
            for (String esHostName : hostNames) {
                LOG.info("Adding TransportClient: {}", esHostName);
                transportClient = transportClient.addTransportAddress(new InetSocketTransportAddress(esHostName,
                        DEFAULT_ELASTICSEARCH_PORT));
            }
            client = transportClient;
        }

    }

    /**
     * This is a special function used by the SourceFactory to pull in this class as a plugin sink.
     */
    public static List<Pair<String, SinkBuilder>> getSinkBuilders() {
        List<Pair<String, SinkBuilder>> builders =
                new ArrayList<Pair<String, SinkBuilder>>();

        builders.add(new Pair<String, SinkBuilder>("elasticSearchSink", new ElasticSearchSinkBuilder()));
        return builders;
    }

    public String getClusterName() {
        return clusterName;
    }

    public void setClusterName(String clusterName) {
        this.clusterName = clusterName;
    }

    public String getIndexName() {
        return indexName;
    }

    public void setIndexName(String indexName) {
        this.indexName = indexName;
    }

    public String getIndexPattern() {
        return indexPattern;
    }

    public void setIndexPattern(String indexPattern) {
        this.indexPattern = indexPattern;
    }

    public String getIndexType() {
        return indexType;
    }

    public void setIndexType(String indexType) {
        this.indexType = indexType;
    }

    public void setHostNames(String[] hostNames) {
        this.hostNames = hostNames;
    }

    public String[] getHostNames() {
        return hostNames;
    }

    void setLocalOnly(boolean localOnly) {
        this.localOnly = localOnly;
    }

    boolean isLocalOnly() {
        return localOnly;
    }
}
TOP

Related Classes of org.elasticsearch.flume.ElasticSearchSink

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.