/** * 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.flume.sink; import com.google.common.base.Preconditions; import org.apache.flume.Channel; import org.apache.flume.Context; import org.apache.flume.CounterGroup; import org.apache.flume.Event; import org.apache.flume.EventDeliveryException; import org.apache.flume.Sink; import org.apache.flume.Transaction; import org.apache.flume.conf.Configurable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * <p> * A {@link Sink} implementation that simply discards all events it receives. A * <tt>/dev/null</tt> for Flume. * </p> * <p> * <b>Configuration options</b> * </p> * <p> * <i>This sink has no configuration parameters.</i> * </p> * <p> * <b>Metrics</b> * </p> * <p> * TODO * </p> */ public class NullSink extends AbstractSink implements Configurable { private static final Logger logger = LoggerFactory.getLogger(NullSink.class); private static final int DFLT_BATCH_SIZE = 100; private static final int DFLT_LOG_EVERY_N_EVENTS = 10000; private CounterGroup counterGroup; private int batchSize = DFLT_BATCH_SIZE; private int logEveryNEvents = DFLT_LOG_EVERY_N_EVENTS; public NullSink() { counterGroup = new CounterGroup(); } @Override public void configure(Context context) { batchSize = context.getInteger("batchSize", DFLT_BATCH_SIZE); logger.debug(this.getName() + " " + "batch size set to " + String.valueOf(batchSize)); Preconditions.checkArgument(batchSize > 0, "Batch size must be > 0"); logEveryNEvents = context.getInteger("logEveryNEvents", DFLT_LOG_EVERY_N_EVENTS); logger.debug(this.getName() + " " + "log event N events set to " + logEveryNEvents); Preconditions.checkArgument(logEveryNEvents > 0, "logEveryNEvents must be > 0"); } @Override public Status process() throws EventDeliveryException { Status status = Status.READY; Channel channel = getChannel(); Transaction transaction = channel.getTransaction(); Event event = null; long eventCounter = counterGroup.get("events.success"); try { transaction.begin(); int i = 0; for (i = 0; i < batchSize; i++) { event = channel.take(); if (++eventCounter % logEveryNEvents == 0) { logger.info("Null sink {} successful processed {} events.", getName(), eventCounter); } if(event == null) { status = Status.BACKOFF; break; } } transaction.commit(); counterGroup.addAndGet("events.success", (long) Math.min(batchSize, i)); counterGroup.incrementAndGet("transaction.success"); } catch (Exception ex) { transaction.rollback(); counterGroup.incrementAndGet("transaction.failed"); logger.error("Failed to deliver event. Exception follows.", ex); throw new EventDeliveryException("Failed to deliver event: " + event, ex); } finally { transaction.close(); } return status; } @Override public void start() { logger.info("Starting {}...", this); counterGroup.setName(this.getName()); super.start(); logger.info("Null sink {} started.", getName()); } @Override public void stop() { logger.info("Null sink {} stopping...", getName()); super.stop(); logger.info("Null sink {} stopped. Event metrics: {}", getName(), counterGroup); } @Override public String toString() { return "NullSink " + getName() + " { batchSize: " + batchSize + " }"; } }