You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by bo...@apache.org on 2015/04/20 00:11:56 UTC

[2/4] incubator-ranger git commit: RANGER-397 - Implement reliable streaming audits to configurable destinations

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/eb1e9b5c/agents-audit/src/main/java/org/apache/ranger/audit/provider/BaseAuditProvider.java
----------------------------------------------------------------------
diff --git a/agents-audit/src/main/java/org/apache/ranger/audit/provider/BaseAuditProvider.java b/agents-audit/src/main/java/org/apache/ranger/audit/provider/BaseAuditProvider.java
index a068b8f..576176c 100644
--- a/agents-audit/src/main/java/org/apache/ranger/audit/provider/BaseAuditProvider.java
+++ b/agents-audit/src/main/java/org/apache/ranger/audit/provider/BaseAuditProvider.java
@@ -17,71 +17,296 @@
  * under the License.
  */
 package org.apache.ranger.audit.provider;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.ranger.audit.model.AuditEventBase;
+import org.apache.ranger.audit.model.AuthzAuditEvent;
+
+import com.google.gson.GsonBuilder;
+
 import java.util.concurrent.atomic.AtomicLong;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 import java.util.Properties;
 
 public abstract class BaseAuditProvider implements AuditProvider {
 	private static final Log LOG = LogFactory.getLog(BaseAuditProvider.class);
 
 	private static final String AUDIT_LOG_FAILURE_REPORT_MIN_INTERVAL_PROP = "xasecure.audit.log.failure.report.min.interval.ms";
-	public static final int AUDIT_ASYNC_MAX_QUEUE_SIZE_DEFAULT     = 10 * 1024;
-	public static final int AUDIT_ASYNC_MAX_FLUSH_INTERVAL_DEFAULT =  5 * 1000;
+	public static final int AUDIT_MAX_QUEUE_SIZE_DEFAULT = 1024 * 1024;
+	public static final int AUDIT_BATCH_INTERVAL_DEFAULT_MS = 1000;
+	public static final int AUDIT_BATCH_SIZE_DEFAULT = 1000;
+
+	private AtomicLong lifeTimeInLogCount = new AtomicLong(0);
 
-	private int   mLogFailureReportMinIntervalInMs = 60 * 1000;
+	private int mLogFailureReportMinIntervalInMs = 60 * 1000;
 
-	private AtomicLong mFailedLogLastReportTime       = new AtomicLong(0);
+	private AtomicLong mFailedLogLastReportTime = new AtomicLong(0);
 	private AtomicLong mFailedLogCountSinceLastReport = new AtomicLong(0);
-	private AtomicLong mFailedLogCountLifeTime        = new AtomicLong(0);
-	private int maxQueueSize     =  AUDIT_ASYNC_MAX_QUEUE_SIZE_DEFAULT;
-	private int maxFlushInterval = AUDIT_ASYNC_MAX_FLUSH_INTERVAL_DEFAULT;
+	private AtomicLong mFailedLogCountLifeTime = new AtomicLong(0);
+
+	public static final String PROP_NAME = "name";
+	public static final String PROP_CLASS_NAME = "classname";
+	public static final String PROP_QUEUE = "queue";
+
+	public static final String PROP_BATCH_SIZE = "batch.size";
+	public static final String PROP_QUEUE_SIZE = "queue.size";
+	public static final String PROP_BATCH_INTERVAL = "batch.interval.ms";
+
+	public static final String PROP_FILE_SPOOL_ENABLE = "filespool.enable";
+	public static final String PROP_FILE_SPOOL_WAIT_FOR_FULL_DRAIN = "filespool.drain.full.wait.ms";
+	public static final String PROP_FILE_SPOOL_QUEUE_THRESHOLD = "filespool.drain.threshold.percent";
+
+	public static final String PROP_DEFAULT_PREFIX = "xasecure.audit.provider";
+
+	private boolean isDrain = false;
+	private String providerName = null;
+
+	private int maxQueueSize = AUDIT_MAX_QUEUE_SIZE_DEFAULT;
+	private int maxBatchInterval = AUDIT_BATCH_INTERVAL_DEFAULT_MS;
+	private int maxBatchSize = AUDIT_BATCH_SIZE_DEFAULT;
+
+	protected int failedRetryTimes = 3;
+	protected int failedRetrySleep = 3 * 1000;
+
+	protected AuditProvider consumer = null;
+	protected AuditFileSpool fileSpooler = null;
+
+	protected boolean fileSpoolerEnabled = false;
+	protected int fileSpoolMaxWaitTime = 5 * 60 * 1000; // Default 5 minutes
+	protected int fileSpoolDrainThresholdPercent = 80;
+
+	int errorLogIntervalMS = 30 * 1000; // Every 30 seconds
+	long lastErrorLogMS = 0;
 
 	protected Properties props = null;
 
 	public BaseAuditProvider() {
 	}
-	
+
+	public BaseAuditProvider(AuditProvider consumer) {
+		this.consumer = consumer;
+	}
+
 	@Override
 	public void init(Properties props) {
+		init(props, null);
+	}
+
+	@Override
+	public void init(Properties props, String basePropertyName) {
 		LOG.info("BaseAuditProvider.init()");
 		this.props = props;
-		
-		mLogFailureReportMinIntervalInMs = getIntProperty(props, AUDIT_LOG_FAILURE_REPORT_MIN_INTERVAL_PROP, 60 * 1000);
+		String propPrefix = PROP_DEFAULT_PREFIX;
+		if (basePropertyName != null) {
+			propPrefix = basePropertyName;
+		}
+		LOG.info("propPrefix=" + propPrefix);
+		// Get final token
+		List<String> tokens = MiscUtil.toArray(propPrefix, ".");
+		String finalToken = tokens.get(tokens.size() - 1);
+
+		String name = MiscUtil.getStringProperty(props, basePropertyName + "."
+				+ PROP_NAME);
+		if (name != null && !name.isEmpty()) {
+			providerName = name;
+		}
+		if (providerName == null) {
+			providerName = finalToken;
+			LOG.info("Using providerName from property prefix. providerName="
+					+ providerName);
+		}
+		LOG.info("providerName=" + providerName);
+
+		setMaxBatchSize(MiscUtil.getIntProperty(props, propPrefix + "."
+				+ PROP_BATCH_SIZE, getMaxBatchSize()));
+		setMaxQueueSize(MiscUtil.getIntProperty(props, propPrefix + "."
+				+ PROP_QUEUE_SIZE, getMaxQueueSize()));
+		setMaxBatchInterval(MiscUtil.getIntProperty(props, propPrefix + "."
+				+ PROP_BATCH_INTERVAL, getMaxBatchInterval()));
+
+		fileSpoolerEnabled = MiscUtil.getBooleanProperty(props, propPrefix
+				+ "." + PROP_FILE_SPOOL_ENABLE, false);
+		String logFolderProp = MiscUtil.getStringProperty(props, propPrefix
+				+ "." + AuditFileSpool.PROP_FILE_SPOOL_LOCAL_DIR);
+		if (fileSpoolerEnabled || logFolderProp != null) {
+			LOG.info("File spool is enabled for " + getName()
+					+ ", logFolderProp=" + logFolderProp + ", " + propPrefix
+					+ "." + AuditFileSpool.PROP_FILE_SPOOL_LOCAL_DIR + "="
+					+ fileSpoolerEnabled);
+			fileSpoolerEnabled = true;
+			fileSpoolMaxWaitTime = MiscUtil.getIntProperty(props, propPrefix
+					+ "." + PROP_FILE_SPOOL_WAIT_FOR_FULL_DRAIN,
+					fileSpoolMaxWaitTime);
+			fileSpoolDrainThresholdPercent = MiscUtil.getIntProperty(props,
+					propPrefix + "." + PROP_FILE_SPOOL_QUEUE_THRESHOLD,
+					fileSpoolDrainThresholdPercent);
+			fileSpooler = new AuditFileSpool(this, consumer);
+			fileSpooler.init(props, basePropertyName);
+		} else {
+			LOG.info("File spool is disabled for " + getName());
+		}
+
+		try {
+			new GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z").create();
+		} catch (Throwable excp) {
+			LOG.warn(
+					"Log4jAuditProvider.init(): failed to create GsonBuilder object. events will be formated using toString(), instead of Json",
+					excp);
+		}
 
+		mLogFailureReportMinIntervalInMs = MiscUtil.getIntProperty(props,
+				AUDIT_LOG_FAILURE_REPORT_MIN_INTERVAL_PROP, 60 * 1000);
+
+	}
+
+	public AuditProvider getConsumer() {
+		return consumer;
+	}
+
+	public void setConsumer(AuditProvider consumer) {
+		this.consumer = consumer;
 	}
 
 	public void logFailedEvent(AuditEventBase event) {
 		logFailedEvent(event, null);
- 	}
+	}
 
 	public void logFailedEvent(AuditEventBase event, Throwable excp) {
 		long now = System.currentTimeMillis();
-		
-		long timeSinceLastReport  = now - mFailedLogLastReportTime.get();
-		long countSinceLastReport = mFailedLogCountSinceLastReport.incrementAndGet();
-		long countLifeTime        = mFailedLogCountLifeTime.incrementAndGet();
 
-		if(timeSinceLastReport >= mLogFailureReportMinIntervalInMs) {
+		long timeSinceLastReport = now - mFailedLogLastReportTime.get();
+		long countSinceLastReport = mFailedLogCountSinceLastReport
+				.incrementAndGet();
+		long countLifeTime = mFailedLogCountLifeTime.incrementAndGet();
+
+		if (timeSinceLastReport >= mLogFailureReportMinIntervalInMs) {
 			mFailedLogLastReportTime.set(now);
 			mFailedLogCountSinceLastReport.set(0);
 
-			if(excp != null) {
-				LOG.warn("failed to log audit event: " + MiscUtil.stringify(event), excp);
+			if (excp != null) {
+				LOG.warn(
+						"failed to log audit event: "
+								+ MiscUtil.stringify(event), excp);
 			} else {
-				LOG.warn("failed to log audit event: " + MiscUtil.stringify(event));
+				LOG.warn("failed to log audit event: "
+						+ MiscUtil.stringify(event));
+			}
+
+			if (countLifeTime > 1) { // no stats to print for the 1st failure
+				LOG.warn("Log failure count: " + countSinceLastReport
+						+ " in past "
+						+ formatIntervalForLog(timeSinceLastReport) + "; "
+						+ countLifeTime + " during process lifetime");
+			}
+		}
+	}
+
+	public void logFailedEvent(Collection<AuditEventBase> events, Throwable excp) {
+		for (AuditEventBase event : events) {
+			logFailedEvent(event, excp);
+		}
+	}
+
+	public void logFailedEventJSON(String event, Throwable excp) {
+		long now = System.currentTimeMillis();
+
+		long timeSinceLastReport = now - mFailedLogLastReportTime.get();
+		long countSinceLastReport = mFailedLogCountSinceLastReport
+				.incrementAndGet();
+		long countLifeTime = mFailedLogCountLifeTime.incrementAndGet();
+
+		if (timeSinceLastReport >= mLogFailureReportMinIntervalInMs) {
+			mFailedLogLastReportTime.set(now);
+			mFailedLogCountSinceLastReport.set(0);
+
+			if (excp != null) {
+				LOG.warn("failed to log audit event: " + event, excp);
+			} else {
+				LOG.warn("failed to log audit event: " + event);
+			}
+
+			if (countLifeTime > 1) { // no stats to print for the 1st failure
+				LOG.warn("Log failure count: " + countSinceLastReport
+						+ " in past "
+						+ formatIntervalForLog(timeSinceLastReport) + "; "
+						+ countLifeTime + " during process lifetime");
 			}
+		}
+	}
 
-			if(countLifeTime > 1) { // no stats to print for the 1st failure
-				LOG.warn("Log failure count: " + countSinceLastReport + " in past " + formatIntervalForLog(timeSinceLastReport) + "; " + countLifeTime + " during process lifetime");
+	public void logFailedEventJSON(Collection<String> events, Throwable excp) {
+		for (String event : events) {
+			logFailedEventJSON(event, excp);
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.apache.ranger.audit.provider.AuditProvider#log(org.apache.ranger.
+	 * audit.model.AuditEventBase)
+	 */
+	@Override
+	public boolean log(AuditEventBase event) {
+		List<AuditEventBase> eventList = new ArrayList<AuditEventBase>();
+		eventList.add(event);
+		return log(eventList);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.apache.ranger.audit.provider.AuditProvider#logJSON(java.lang.String)
+	 */
+	@Override
+	public boolean logJSON(String event) {
+		AuditEventBase eventObj = MiscUtil.fromJson(event,
+				AuthzAuditEvent.class);
+		return log(eventObj);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.apache.ranger.audit.provider.AuditProvider#logJSON(java.util.Collection
+	 * )
+	 */
+	@Override
+	public boolean logJSON(Collection<String> events) {
+		boolean ret = true;
+		for (String event : events) {
+			ret = logJSON(event);
+			if (!ret) {
+				break;
 			}
 		}
- 	}
+		return ret;
+	}
+
+	public void setName(String name) {
+		providerName = name;
+	}
+
+	@Override
+	public String getName() {
+		return providerName;
+	}
+
+	@Override
+	public boolean isDrain() {
+		return isDrain;
+	}
+
+	public void setDrain(boolean isDrain) {
+		this.isDrain = isDrain;
+	}
 
-	
 	public int getMaxQueueSize() {
 		return maxQueueSize;
 	}
@@ -90,84 +315,95 @@ public abstract class BaseAuditProvider implements AuditProvider {
 		this.maxQueueSize = maxQueueSize;
 	}
 
-	public int getMaxFlushInterval() {
-		return maxFlushInterval;
+	@Override
+	public int getMaxBatchInterval() {
+		return maxBatchInterval;
 	}
 
-	public void setMaxFlushInterval(int maxFlushInterval) {
-		this.maxFlushInterval = maxFlushInterval;
+	public void setMaxBatchInterval(int maxBatchInterval) {
+		this.maxBatchInterval = maxBatchInterval;
 	}
 
-	public static Map<String, String> getPropertiesWithPrefix(Properties props, String prefix) {
-		Map<String, String> prefixedProperties = new HashMap<String, String>();
-
-		if(props != null && prefix != null) {
-			for(String key : props.stringPropertyNames()) {
-				if(key == null) {
-					continue;
-				}
-
-				String val = props.getProperty(key);
+	@Override
+	public int getMaxBatchSize() {
+		return maxBatchSize;
+	}
 
-				if(key.startsWith(prefix)) {
-					key = key.substring(prefix.length());
+	public void setMaxBatchSize(int maxBatchSize) {
+		this.maxBatchSize = maxBatchSize;
+	}
 
-					if(key == null) {
-						continue;
-					}
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.ranger.audit.provider.AuditProvider#waitToComplete()
+	 */
+	@Override
+	public void waitToComplete() {
+		if (consumer != null) {
+			consumer.waitToComplete(-1);
+		}
+	}
 
-					prefixedProperties.put(key, val);
-				}
-			}
+	@Override
+	public void waitToComplete(long timeout) {
+		if (consumer != null) {
+			consumer.waitToComplete(timeout);
 		}
+	}
 
-		return prefixedProperties;
+	@Override
+	public boolean isFlushPending() {
+		return false;
 	}
-	
-	public static boolean getBooleanProperty(Properties props, String propName, boolean defValue) {
-		boolean ret = defValue;
 
-		if(props != null && propName != null) {
-			String val = props.getProperty(propName);
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.ranger.audit.provider.AuditProvider#getLastFlushTime()
+	 */
+	@Override
+	public long getLastFlushTime() {
+		if (consumer != null) {
+			return consumer.getLastFlushTime();
+		}
+		return 0;
+	}
 
-			if(val != null) {
-				ret = Boolean.valueOf(val);
-			}
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.ranger.audit.provider.AuditProvider#flush()
+	 */
+	@Override
+	public void flush() {
+		if (consumer != null) {
+			consumer.flush();
 		}
+	}
 
-		return ret;
+	public AtomicLong getLifeTimeInLogCount() {
+		return lifeTimeInLogCount;
 	}
-	
-	public static int getIntProperty(Properties props, String propName, int defValue) {
-		int ret = defValue;
 
-		if(props != null && propName != null) {
-			String val = props.getProperty(propName);
+	public long addLifeTimeInLogCount(long count) {
+		return lifeTimeInLogCount.addAndGet(count);
+	}
 
-			if(val != null) {
-				try {
-					ret = Integer.parseInt(val);
-				} catch(NumberFormatException excp) {
-					ret = defValue;
-				}
-			}
+	public void logError(String msg) {
+		long currTimeMS = System.currentTimeMillis();
+		if (currTimeMS - lastErrorLogMS > errorLogIntervalMS) {
+			LOG.error(msg);
+			lastErrorLogMS = currTimeMS;
 		}
-
-		return ret;
 	}
-	
-	
-	public static String getStringProperty(Properties props, String propName) {
-		String ret = null;
 
-		if(props != null && propName != null) {
-			String val = props.getProperty(propName);
-			if ( val != null){
-				ret = val;
-			}
+	public void logError(String msg, Throwable ex) {
+		long currTimeMS = System.currentTimeMillis();
+		if (currTimeMS - lastErrorLogMS > errorLogIntervalMS) {
+			LOG.error(msg, ex);
+			lastErrorLogMS = currTimeMS;
 		}
-
-		return ret;
 	}
 
 	public String getTimeDiffStr(long time1, long time2) {

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/eb1e9b5c/agents-audit/src/main/java/org/apache/ranger/audit/provider/BufferedAuditProvider.java
----------------------------------------------------------------------
diff --git a/agents-audit/src/main/java/org/apache/ranger/audit/provider/BufferedAuditProvider.java b/agents-audit/src/main/java/org/apache/ranger/audit/provider/BufferedAuditProvider.java
index be32519..ec5e9a8 100644
--- a/agents-audit/src/main/java/org/apache/ranger/audit/provider/BufferedAuditProvider.java
+++ b/agents-audit/src/main/java/org/apache/ranger/audit/provider/BufferedAuditProvider.java
@@ -17,6 +17,7 @@
  */
 package org.apache.ranger.audit.provider;
 
+import java.util.Collection;
 import java.util.Properties;
 
 import org.apache.ranger.audit.model.AuditEventBase;
@@ -32,7 +33,7 @@ public abstract class BufferedAuditProvider extends BaseAuditProvider {
 	}
 
 	@Override
-	public void log(AuditEventBase event) {
+	public boolean log(AuditEventBase event) {
 		if(event instanceof AuthzAuditEvent) {
 			AuthzAuditEvent authzEvent = (AuthzAuditEvent)event;
 
@@ -52,6 +53,30 @@ public abstract class BufferedAuditProvider extends BaseAuditProvider {
 		if(! mBuffer.add(event)) {
 			logFailedEvent(event);
 		}
+		return true;
+	}
+
+	@Override
+	public boolean log(Collection<AuditEventBase> events) {
+		for (AuditEventBase event : events) {
+			log(event);
+		}
+		return true;
+	}
+
+	@Override
+	public boolean logJSON(String event) {
+		AuditEventBase eventObj = MiscUtil.fromJson(event,
+				AuthzAuditEvent.class);
+		return log(eventObj);
+	}
+
+	@Override
+	public boolean logJSON(Collection<String> events) {
+		for (String event : events) {
+			logJSON(event);
+		}
+		return false;
 	}
 
 	@Override
@@ -68,6 +93,11 @@ public abstract class BufferedAuditProvider extends BaseAuditProvider {
 	public void waitToComplete() {
 	}
 
+	
+	@Override
+	public void waitToComplete(long timeout) {
+	}
+
 	@Override
 	public boolean isFlushPending() {
 		return false;

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/eb1e9b5c/agents-audit/src/main/java/org/apache/ranger/audit/provider/DbAuditProvider.java
----------------------------------------------------------------------
diff --git a/agents-audit/src/main/java/org/apache/ranger/audit/provider/DbAuditProvider.java b/agents-audit/src/main/java/org/apache/ranger/audit/provider/DbAuditProvider.java
index 7414a7a..f4976fb 100644
--- a/agents-audit/src/main/java/org/apache/ranger/audit/provider/DbAuditProvider.java
+++ b/agents-audit/src/main/java/org/apache/ranger/audit/provider/DbAuditProvider.java
@@ -19,6 +19,7 @@
 package org.apache.ranger.audit.provider;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Map;
 import java.util.Properties;
 
@@ -31,6 +32,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.ranger.audit.dao.DaoManager;
 import org.apache.ranger.audit.model.AuditEventBase;
+import org.apache.ranger.audit.model.AuthzAuditEvent;
 import org.apache.ranger.authorization.hadoop.utils.RangerCredentialProvider;
 
 
@@ -38,7 +40,7 @@ import org.apache.ranger.authorization.hadoop.utils.RangerCredentialProvider;
  * NOTE:
  * - Instances of this class are not thread-safe.
  */
-public class DbAuditProvider extends BaseAuditProvider {
+public class DbAuditProvider extends AuditDestination {
 
 	private static final Log LOG = LogFactory.getLog(DbAuditProvider.class);
 
@@ -73,17 +75,17 @@ public class DbAuditProvider extends BaseAuditProvider {
 
 		super.init(props);
 
-		mDbProperties         = BaseAuditProvider.getPropertiesWithPrefix(props, AUDIT_JPA_CONFIG_PROP_PREFIX);
-		mCommitBatchSize      = BaseAuditProvider.getIntProperty(props, AUDIT_DB_BATCH_SIZE_PROP, 1000);
-		mDbRetryMinIntervalMs = BaseAuditProvider.getIntProperty(props, AUDIT_DB_RETRY_MIN_INTERVAL_PROP, 15 * 1000);
+		mDbProperties         = MiscUtil.getPropertiesWithPrefix(props, AUDIT_JPA_CONFIG_PROP_PREFIX);
+		mCommitBatchSize      = MiscUtil.getIntProperty(props, AUDIT_DB_BATCH_SIZE_PROP, 1000);
+		mDbRetryMinIntervalMs = MiscUtil.getIntProperty(props, AUDIT_DB_RETRY_MIN_INTERVAL_PROP, 15 * 1000);
 
-		boolean isAsync = BaseAuditProvider.getBooleanProperty(props, AUDIT_DB_IS_ASYNC_PROP, false);
+		boolean isAsync = MiscUtil.getBooleanProperty(props, AUDIT_DB_IS_ASYNC_PROP, false);
 
 		if(! isAsync) {
 			mCommitBatchSize = 1; // Batching not supported in sync mode
 		}
 
-		String jdbcPassword = getCredentialString(BaseAuditProvider.getStringProperty(props, AUDIT_DB_CREDENTIAL_PROVIDER_FILE), AUDIT_DB_CREDENTIAL_PROVIDER_ALIAS);
+		String jdbcPassword = getCredentialString(MiscUtil.getStringProperty(props, AUDIT_DB_CREDENTIAL_PROVIDER_FILE), AUDIT_DB_CREDENTIAL_PROVIDER_ALIAS);
 
 		if(jdbcPassword != null && !jdbcPassword.isEmpty()) {
 			mDbProperties.put(AUDIT_JPA_JDBC_PASSWORD, jdbcPassword);
@@ -91,7 +93,7 @@ public class DbAuditProvider extends BaseAuditProvider {
 	}
 
 	@Override
-	public void log(AuditEventBase event) {
+	public boolean log(AuditEventBase event) {
 		LOG.debug("DbAuditProvider.log()");
 
 		boolean isSuccess = false;
@@ -113,6 +115,30 @@ public class DbAuditProvider extends BaseAuditProvider {
 				logFailedEvent(event);
 			}
 		}
+		return isSuccess;
+	}
+
+	@Override
+	public boolean log(Collection<AuditEventBase> events) {
+		for (AuditEventBase event : events) {
+			log(event);
+		}
+		return true;
+	}
+
+	@Override
+	public boolean logJSON(String event) {
+		AuditEventBase eventObj = MiscUtil.fromJson(event,
+				AuthzAuditEvent.class);
+		return log(eventObj);
+	}
+
+	@Override
+	public boolean logJSON(Collection<String> events) {
+		for (String event : events) {
+			logJSON(event);
+		}
+		return false;
 	}
 
 	@Override
@@ -132,6 +158,13 @@ public class DbAuditProvider extends BaseAuditProvider {
 	@Override
     public void waitToComplete() {
 		LOG.info("DbAuditProvider.waitToComplete()");
+		waitToComplete(-1);
+	}
+
+	@Override
+	public void waitToComplete(long timeout) {
+		LOG.info("DbAuditProvider.waitToComplete():timeout=" + timeout);
+
 	}
 
 	@Override

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/eb1e9b5c/agents-audit/src/main/java/org/apache/ranger/audit/provider/DummyAuditProvider.java
----------------------------------------------------------------------
diff --git a/agents-audit/src/main/java/org/apache/ranger/audit/provider/DummyAuditProvider.java b/agents-audit/src/main/java/org/apache/ranger/audit/provider/DummyAuditProvider.java
index a6e3ef1..619a99d 100644
--- a/agents-audit/src/main/java/org/apache/ranger/audit/provider/DummyAuditProvider.java
+++ b/agents-audit/src/main/java/org/apache/ranger/audit/provider/DummyAuditProvider.java
@@ -17,9 +17,11 @@
  */
 package org.apache.ranger.audit.provider;
 
+import java.util.Collection;
 import java.util.Properties;
 
 import org.apache.ranger.audit.model.AuditEventBase;
+import org.apache.ranger.audit.model.AuthzAuditEvent;
 
 
 public class DummyAuditProvider implements AuditProvider {
@@ -29,8 +31,32 @@ public class DummyAuditProvider implements AuditProvider {
 	}
 
 	@Override
-	public void log(AuditEventBase event) {
+	public boolean log(AuditEventBase event) {
 		// intentionally left empty
+		return true;
+	}
+
+	@Override
+	public boolean log(Collection<AuditEventBase> events) {
+		for (AuditEventBase event : events) {
+			log(event);
+		}
+		return true;
+	}
+
+	@Override
+	public boolean logJSON(String event) {
+		AuditEventBase eventObj = MiscUtil.fromJson(event,
+				AuthzAuditEvent.class);
+		return log(eventObj);
+	}
+
+	@Override
+	public boolean logJSON(Collection<String> events) {
+		for (String event : events) {
+			logJSON(event);
+		}
+		return false;
 	}
 
 	@Override
@@ -48,6 +74,13 @@ public class DummyAuditProvider implements AuditProvider {
 		// intentionally left empty
 	}
 
+	
+	@Override
+	public int getMaxBatchSize() {
+		// TODO Auto-generated method stub
+		return 0;
+	}
+
 	@Override
 	public boolean isFlushPending() {
 		return false;
@@ -62,4 +95,45 @@ public class DummyAuditProvider implements AuditProvider {
 	public void flush() {
 		// intentionally left empty
 	}
+
+	/* (non-Javadoc)
+	 * @see org.apache.ranger.audit.provider.AuditProvider#init(java.util.Properties, java.lang.String)
+	 */
+	@Override
+	public void init(Properties prop, String basePropertyName) {
+		// intentionally left empty		
+	}
+
+	/* (non-Javadoc)
+	 * @see org.apache.ranger.audit.provider.AuditProvider#waitToComplete(long)
+	 */
+	@Override
+	public void waitToComplete(long timeout) {
+		// intentionally left empty		
+	}
+
+	/* (non-Javadoc)
+	 * @see org.apache.ranger.audit.provider.AuditProvider#getName()
+	 */
+	@Override
+	public String getName() {
+		return this.getClass().getName();
+	}
+
+	/* (non-Javadoc)
+	 * @see org.apache.ranger.audit.provider.AuditProvider#isDrain()
+	 */
+	@Override
+	public boolean isDrain() {
+		return false;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.apache.ranger.audit.provider.AuditProvider#getMaxBatchInterval()
+	 */
+	@Override
+	public int getMaxBatchInterval() {
+		// TODO Auto-generated method stub
+		return 0;
+	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/eb1e9b5c/agents-audit/src/main/java/org/apache/ranger/audit/provider/FileAuditDestination.java
----------------------------------------------------------------------
diff --git a/agents-audit/src/main/java/org/apache/ranger/audit/provider/FileAuditDestination.java b/agents-audit/src/main/java/org/apache/ranger/audit/provider/FileAuditDestination.java
new file mode 100644
index 0000000..62ecab1
--- /dev/null
+++ b/agents-audit/src/main/java/org/apache/ranger/audit/provider/FileAuditDestination.java
@@ -0,0 +1,230 @@
+/*
+ * 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.ranger.audit.provider;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.audit.model.AuditEventBase;
+
+/**
+ * This class write the logs to local file
+ */
+public class FileAuditDestination extends AuditDestination {
+	private static final Log logger = LogFactory
+			.getLog(FileAuditDestination.class);
+
+	public static final String PROP_FILE_LOCAL_DIR = "dir";
+	public static final String PROP_FILE_LOCAL_FILE_NAME_FORMAT = "filename.format";
+	public static final String PROP_FILE_FILE_ROLLOVER = "file.rollover.sec";
+
+	String baseFolder = null;
+	String fileFormat = null;
+	int fileRolloverSec = 24 * 60 * 60; // In seconds
+	private String logFileNameFormat;
+
+	boolean initDone = false;
+
+	private File logFolder;
+	PrintWriter logWriter = null;
+
+	private Date fileCreateTime = null;
+
+	private String currentFileName;
+
+	private boolean isStopped = false;
+
+	@Override
+	public void init(Properties prop, String propPrefix) {
+		super.init(prop, propPrefix);
+
+		// Initialize properties for this class
+		// Initial folder and file properties
+		String logFolderProp = MiscUtil.getStringProperty(props, propPrefix
+				+ "." + PROP_FILE_LOCAL_DIR);
+		logFileNameFormat = MiscUtil.getStringProperty(props, propPrefix + "."
+				+ PROP_FILE_LOCAL_FILE_NAME_FORMAT);
+		fileRolloverSec = MiscUtil.getIntProperty(props, propPrefix + "."
+				+ PROP_FILE_FILE_ROLLOVER, fileRolloverSec);
+
+		if (logFolderProp == null || logFolderProp.isEmpty()) {
+			logger.error("File destination folder is not configured. Please set "
+					+ propPrefix
+					+ "."
+					+ PROP_FILE_LOCAL_DIR
+					+ ". name="
+					+ getName());
+			return;
+		}
+		logFolder = new File(logFolderProp);
+		if (!logFolder.isDirectory()) {
+			logFolder.mkdirs();
+			if (!logFolder.isDirectory()) {
+				logger.error("FileDestination folder not found and can't be created. folder="
+						+ logFolder.getAbsolutePath() + ", name=" + getName());
+				return;
+			}
+		}
+		logger.info("logFolder=" + logFolder + ", name=" + getName());
+
+		if (logFileNameFormat == null || logFileNameFormat.isEmpty()) {
+			logFileNameFormat = "%app-type%_ranger_audit.log";
+		}
+
+		logger.info("logFileNameFormat=" + logFileNameFormat + ", destName="
+				+ getName());
+
+		initDone = true;
+	}
+
+	@Override
+	public boolean logJSON(Collection<String> events) {
+		try {
+			PrintWriter out = getLogFileStream();
+			for (String event : events) {
+				out.println(event);
+			}
+			out.flush();
+		} catch (Throwable t) {
+			logError("Error writing to log file.", t);
+			return false;
+		}
+		return true;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.apache.ranger.audit.provider.AuditProvider#log(java.util.Collection)
+	 */
+	@Override
+	synchronized public boolean log(Collection<AuditEventBase> events) {
+		if (isStopped) {
+			logError("log() called after stop was requested. name=" + getName());
+			return false;
+		}
+		List<String> jsonList = new ArrayList<String>();
+		for (AuditEventBase event : events) {
+			try {
+				jsonList.add(MiscUtil.stringify(event));
+			} catch (Throwable t) {
+				logger.error("Error converting to JSON. event=" + event);
+			}
+		}
+		return logJSON(jsonList);
+
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.ranger.audit.provider.AuditProvider#start()
+	 */
+	@Override
+	public void start() {
+		// Nothing to do here. We will open the file when the first log request
+		// comes
+	}
+
+	@Override
+	synchronized public void stop() {
+		if (logWriter != null) {
+			logWriter.flush();
+			logWriter.close();
+			logWriter = null;
+			isStopped = true;
+		}
+	}
+
+	// Helper methods in this class
+	synchronized private PrintWriter getLogFileStream() throws Exception {
+		closeFileIfNeeded();
+
+		// Either there are no open log file or the previous one has been rolled
+		// over
+		if (logWriter == null) {
+			Date currentTime = new Date();
+			// Create a new file
+			String fileName = MiscUtil.replaceTokens(logFileNameFormat,
+					currentTime.getTime());
+			File outLogFile = new File(logFolder, fileName);
+			if (outLogFile.exists()) {
+				// Let's try to get the next available file
+				int i = 0;
+				while (true) {
+					i++;
+					int lastDot = fileName.lastIndexOf('.');
+					String baseName = fileName.substring(0, lastDot);
+					String extension = fileName.substring(lastDot);
+					String newFileName = baseName + "." + i + extension;
+					File newLogFile = new File(logFolder, newFileName);
+					if (!newLogFile.exists()) {
+						// Move the file
+						if (!outLogFile.renameTo(newLogFile)) {
+							logger.error("Error renameing file. " + outLogFile
+									+ " to " + newLogFile);
+						}
+						break;
+					}
+				}
+			}
+			if (!outLogFile.exists()) {
+				logger.info("Creating new file. destName=" + getName()
+						+ ", fileName=" + fileName);
+				// Open the file
+				logWriter = new PrintWriter(new BufferedWriter(new FileWriter(
+						outLogFile)));
+			} else {
+				logWriter = new PrintWriter(new BufferedWriter(new FileWriter(
+						outLogFile, true)));
+			}
+			fileCreateTime = new Date();
+			currentFileName = outLogFile.getPath();
+		}
+		return logWriter;
+	}
+
+	private void closeFileIfNeeded() throws FileNotFoundException, IOException {
+		if (logWriter == null) {
+			return;
+		}
+		if (System.currentTimeMillis() - fileCreateTime.getTime() > fileRolloverSec * 1000) {
+			logger.info("Closing file. Rolling over. name=" + getName()
+					+ ", fileName=" + currentFileName);
+			logWriter.flush();
+			logWriter.close();
+			logWriter = null;
+			currentFileName = null;
+		}
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/eb1e9b5c/agents-audit/src/main/java/org/apache/ranger/audit/provider/HDFSAuditDestination.java
----------------------------------------------------------------------
diff --git a/agents-audit/src/main/java/org/apache/ranger/audit/provider/HDFSAuditDestination.java b/agents-audit/src/main/java/org/apache/ranger/audit/provider/HDFSAuditDestination.java
new file mode 100644
index 0000000..a36c40f
--- /dev/null
+++ b/agents-audit/src/main/java/org/apache/ranger/audit/provider/HDFSAuditDestination.java
@@ -0,0 +1,243 @@
+/*
+ * 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.ranger.audit.provider;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FSDataOutputStream;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.ranger.audit.model.AuditEventBase;
+
+/**
+ * This class write the logs to local file
+ */
+public class HDFSAuditDestination extends AuditDestination {
+	private static final Log logger = LogFactory
+			.getLog(HDFSAuditDestination.class);
+
+	public static final String PROP_HDFS_DIR = "dir";
+	public static final String PROP_HDFS_SUBDIR = "subdir";
+	public static final String PROP_HDFS_FILE_NAME_FORMAT = "filename.format";
+	public static final String PROP_HDFS_ROLLOVER = "file.rollover.sec";
+
+	String baseFolder = null;
+	String fileFormat = null;
+	int fileRolloverSec = 24 * 60 * 60; // In seconds
+	private String logFileNameFormat;
+
+	boolean initDone = false;
+
+	private String logFolder;
+	PrintWriter logWriter = null;
+
+	private Date fileCreateTime = null;
+
+	private String currentFileName;
+
+	private boolean isStopped = false;
+
+	@Override
+	public void init(Properties prop, String propPrefix) {
+		super.init(prop, propPrefix);
+
+		// Initialize properties for this class
+		// Initial folder and file properties
+		String logFolderProp = MiscUtil.getStringProperty(props, propPrefix
+				+ "." + PROP_HDFS_DIR);
+		String logSubFolder = MiscUtil.getStringProperty(props, propPrefix
+				+ "." + PROP_HDFS_SUBDIR);
+		if (logSubFolder == null || logSubFolder.isEmpty()) {
+			logSubFolder = "%app-type%/%time:yyyyMMdd%";
+		}
+
+		logFileNameFormat = MiscUtil.getStringProperty(props, propPrefix + "."
+				+ PROP_HDFS_FILE_NAME_FORMAT);
+		fileRolloverSec = MiscUtil.getIntProperty(props, propPrefix + "."
+				+ PROP_HDFS_ROLLOVER, fileRolloverSec);
+
+		if (logFileNameFormat == null || logFileNameFormat.isEmpty()) {
+			logFileNameFormat = "%app-type%_ranger_audit_%hostname%" + ".log";
+		}
+
+		if (logFolderProp == null || logFolderProp.isEmpty()) {
+			logger.fatal("File destination folder is not configured. Please set "
+					+ propPrefix + "." + PROP_HDFS_DIR + ". name=" + getName());
+			return;
+		}
+
+		logFolder = logFolderProp + "/" + logSubFolder;
+		logger.info("logFolder=" + logFolder + ", destName=" + getName());
+		logger.info("logFileNameFormat=" + logFileNameFormat + ", destName="
+				+ getName());
+
+		initDone = true;
+	}
+
+	@Override
+	public boolean logJSON(Collection<String> events) {
+		try {
+			PrintWriter out = getLogFileStream();
+			for (String event : events) {
+				out.println(event);
+			}
+			out.flush();
+		} catch (Throwable t) {
+			logError("Error writing to log file.", t);
+			return false;
+		}
+		return true;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.apache.ranger.audit.provider.AuditProvider#log(java.util.Collection)
+	 */
+	@Override
+	synchronized public boolean log(Collection<AuditEventBase> events) {
+		if (isStopped) {
+			logError("log() called after stop was requested. name=" + getName());
+			return false;
+		}
+		List<String> jsonList = new ArrayList<String>();
+		for (AuditEventBase event : events) {
+			try {
+				jsonList.add(MiscUtil.stringify(event));
+			} catch (Throwable t) {
+				logger.error("Error converting to JSON. event=" + event);
+			}
+		}
+		return logJSON(jsonList);
+
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.apache.ranger.audit.provider.AuditProvider#start()
+	 */
+	@Override
+	public void start() {
+		// Nothing to do here. We will open the file when the first log request
+		// comes
+	}
+
+	@Override
+	synchronized public void stop() {
+		try {
+			if (logWriter != null) {
+				logWriter.flush();
+				logWriter.close();
+				logWriter = null;
+				isStopped = true;
+			}
+		} catch (Throwable t) {
+			logger.error("Error closing HDFS file.", t);
+		}
+	}
+
+	// Helper methods in this class
+	synchronized private PrintWriter getLogFileStream() throws Throwable {
+		closeFileIfNeeded();
+
+		// Either there are no open log file or the previous one has been rolled
+		// over
+		if (logWriter == null) {
+			Date currentTime = new Date();
+			// Create a new file
+			String fileName = MiscUtil.replaceTokens(logFileNameFormat,
+					currentTime.getTime());
+			String parentFolder = MiscUtil.replaceTokens(logFolder,
+					currentTime.getTime());
+			Configuration conf = new Configuration();
+
+			String fullPath = parentFolder
+					+ org.apache.hadoop.fs.Path.SEPARATOR + fileName;
+			String defaultPath = fullPath;
+			URI uri = URI.create(fullPath);
+			FileSystem fileSystem = FileSystem.get(uri, conf);
+
+			Path hdfPath = new Path(fullPath);
+			logger.info("Checking whether log file exists. hdfPath=" + fullPath);
+			int i = 0;
+			while (fileSystem.exists(hdfPath)) {
+				i++;
+				int lastDot = defaultPath.lastIndexOf('.');
+				String baseName = defaultPath.substring(0, lastDot);
+				String extension = defaultPath.substring(lastDot);
+				fullPath = baseName + "." + i + extension;
+				hdfPath = new Path(fullPath);
+				logger.info("Checking whether log file exists. hdfPath=" + fullPath);
+			}
+			logger.info("Log file doesn't exists. Will create and use it. hdfPath=" + fullPath);
+			// Create parent folders
+			createParents(hdfPath, fileSystem);
+
+			// Create the file to write
+			logger.info("Creating new log file. hdfPath=" + fullPath);
+			FSDataOutputStream ostream = fileSystem.create(hdfPath);
+			logWriter = new PrintWriter(ostream);
+			fileCreateTime = new Date();
+			currentFileName = fullPath;
+		}
+		return logWriter;
+	}
+
+	private void createParents(Path pathLogfile, FileSystem fileSystem)
+			throws Throwable {
+		logger.info("Creating parent folder for " + pathLogfile);
+		Path parentPath = pathLogfile != null ? pathLogfile.getParent() : null;
+
+		if (parentPath != null && fileSystem != null
+				&& !fileSystem.exists(parentPath)) {
+			fileSystem.mkdirs(parentPath);
+		}
+	}
+
+	private void closeFileIfNeeded() throws FileNotFoundException, IOException {
+		if (logWriter == null) {
+			return;
+		}
+		// TODO: Close the file on absolute time. Currently it is implemented as
+		// relative time
+		if (System.currentTimeMillis() - fileCreateTime.getTime() > fileRolloverSec * 1000) {
+			logger.info("Closing file. Rolling over. name=" + getName()
+					+ ", fileName=" + currentFileName);
+			logWriter.flush();
+			logWriter.close();
+			logWriter = null;
+			currentFileName = null;
+		}
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/eb1e9b5c/agents-audit/src/main/java/org/apache/ranger/audit/provider/LocalFileLogBuffer.java
----------------------------------------------------------------------
diff --git a/agents-audit/src/main/java/org/apache/ranger/audit/provider/LocalFileLogBuffer.java b/agents-audit/src/main/java/org/apache/ranger/audit/provider/LocalFileLogBuffer.java
index cdc4d53..83eb324 100644
--- a/agents-audit/src/main/java/org/apache/ranger/audit/provider/LocalFileLogBuffer.java
+++ b/agents-audit/src/main/java/org/apache/ranger/audit/provider/LocalFileLogBuffer.java
@@ -502,13 +502,18 @@ class DestinationDispatcherThread<T> extends Thread {
 				break;
 			}
 
-			// loop until log is sent successfully
-			while(!mStopThread && !mDestination.sendStringified(log)) {
-				try {
-					Thread.sleep(destinationPollIntervalInMs);
-				} catch(InterruptedException excp) {
-					throw new RuntimeException("LocalFileLogBuffer.sendCurrentFile(" + mCurrentLogfile + "): failed while waiting for destination to be available", excp);
+			try {
+				// loop until log is sent successfully
+				while(!mStopThread && !mDestination.sendStringified(log)) {
+					try {
+						Thread.sleep(destinationPollIntervalInMs);
+					} catch(InterruptedException excp) {
+						throw new RuntimeException("LocalFileLogBuffer.sendCurrentFile(" + mCurrentLogfile + "): failed while waiting for destination to be available", excp);
+					}
 				}
+			} catch ( AuditMessageException msgError) {
+				mLogger.error("Error in log message:" + log);
+				//If there is error in log message, then it will be skipped
 			}
 		}
 

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/eb1e9b5c/agents-audit/src/main/java/org/apache/ranger/audit/provider/Log4jAuditProvider.java
----------------------------------------------------------------------
diff --git a/agents-audit/src/main/java/org/apache/ranger/audit/provider/Log4jAuditProvider.java b/agents-audit/src/main/java/org/apache/ranger/audit/provider/Log4jAuditProvider.java
index 0d0809a..a5a52a0 100644
--- a/agents-audit/src/main/java/org/apache/ranger/audit/provider/Log4jAuditProvider.java
+++ b/agents-audit/src/main/java/org/apache/ranger/audit/provider/Log4jAuditProvider.java
@@ -18,17 +18,18 @@
 
 package org.apache.ranger.audit.provider;
 
+import java.util.Collection;
 import java.util.Properties;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.ranger.audit.model.AuditEventBase;
+import org.apache.ranger.audit.model.AuthzAuditEvent;
 
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
+import com.sun.tools.hat.internal.util.Misc;
 
 
-public class Log4jAuditProvider extends BaseAuditProvider {
+public class Log4jAuditProvider extends AuditDestination {
 
 	private static final Log LOG      = LogFactory.getLog(Log4jAuditProvider.class);
 	private static final Log AUDITLOG = LogFactory.getLog("xaaudit." + Log4jAuditProvider.class.getName());
@@ -37,7 +38,6 @@ public class Log4jAuditProvider extends BaseAuditProvider {
 	public static final String AUDIT_LOG4J_MAX_QUEUE_SIZE_PROP     = "xasecure.audit.log4j.async.max.queue.size" ;
 	public static final String AUDIT_LOG4J_MAX_FLUSH_INTERVAL_PROP = "xasecure.audit.log4j.async.max.flush.interval.ms";
 
-	private Gson mGsonBuilder = null;
 
 	public Log4jAuditProvider() {
 		LOG.info("Log4jAuditProvider: creating..");
@@ -48,53 +48,54 @@ public class Log4jAuditProvider extends BaseAuditProvider {
 		LOG.info("Log4jAuditProvider.init()");
 
 		super.init(props);
-
-		try {
-			mGsonBuilder = new GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z").create();
-		} catch(Throwable excp) {
-			LOG.warn("Log4jAuditProvider.init(): failed to create GsonBuilder object. events will be formated using toString(), instead of Json", excp);
-		}
 	}
 
 	@Override
-	public void log(AuditEventBase event) {
+	public boolean log(AuditEventBase event) {
 		if(! AUDITLOG.isInfoEnabled())
-			return;
+			return true;
 		
 		if(event != null) {
-			String eventStr = mGsonBuilder != null ? mGsonBuilder.toJson(event) : event.toString();
-
+			String eventStr = MiscUtil.stringify(event);
 			AUDITLOG.info(eventStr);
 		}
+		return true;
 	}
 
 	@Override
-	public void start() {
-		// intentionally left empty
-	}
-
-	@Override
-	public void stop() {
-		// intentionally left empty
+	public boolean log(Collection<AuditEventBase> events) {
+		for (AuditEventBase event : events) {
+			log(event);
+		}
+		return true;
 	}
 
 	@Override
-    public void waitToComplete() {
-		// intentionally left empty
+	public boolean logJSON(String event) {
+		AuditEventBase eventObj = MiscUtil.fromJson(event,
+				AuthzAuditEvent.class);
+		return log(eventObj);
 	}
 
 	@Override
-	public boolean isFlushPending() {
+	public boolean logJSON(Collection<String> events) {
+		for (String event : events) {
+			logJSON(event);
+		}
 		return false;
 	}
-	
+
 	@Override
-	public long getLastFlushTime() {
-		return 0;
+	public void start() {
+		// intentionally left empty
 	}
 
 	@Override
-	public void flush() {
+	public void stop() {
 		// intentionally left empty
 	}
+
+	
+
+	
 }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/eb1e9b5c/agents-audit/src/main/java/org/apache/ranger/audit/provider/LogDestination.java
----------------------------------------------------------------------
diff --git a/agents-audit/src/main/java/org/apache/ranger/audit/provider/LogDestination.java b/agents-audit/src/main/java/org/apache/ranger/audit/provider/LogDestination.java
index 44e94ad..d6f87cf 100644
--- a/agents-audit/src/main/java/org/apache/ranger/audit/provider/LogDestination.java
+++ b/agents-audit/src/main/java/org/apache/ranger/audit/provider/LogDestination.java
@@ -18,6 +18,7 @@
  */
 package org.apache.ranger.audit.provider;
 
+import org.apache.ranger.audit.model.AuditEventBase;
 
 public interface LogDestination<T> {
 	public void start();
@@ -26,9 +27,20 @@ public interface LogDestination<T> {
 
 	boolean isAvailable();
 
-	public boolean send(T log);
+	public boolean send(AuditEventBase log) throws AuditMessageException;
 
-	public boolean sendStringified(String log);
+	public boolean send(AuditEventBase[] logs) throws AuditMessageException;
+
+	public boolean sendStringified(String log) throws AuditMessageException;
+
+	public boolean sendStringified(String[] logs) throws AuditMessageException;
 
 	public boolean flush();
+
+	/**
+	 * Name for the destination
+	 * 
+	 * @return
+	 */
+	public String getName();
 }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/eb1e9b5c/agents-audit/src/main/java/org/apache/ranger/audit/provider/MiscUtil.java
----------------------------------------------------------------------
diff --git a/agents-audit/src/main/java/org/apache/ranger/audit/provider/MiscUtil.java b/agents-audit/src/main/java/org/apache/ranger/audit/provider/MiscUtil.java
index 17230b2..487da5a 100644
--- a/agents-audit/src/main/java/org/apache/ranger/audit/provider/MiscUtil.java
+++ b/agents-audit/src/main/java/org/apache/ranger/audit/provider/MiscUtil.java
@@ -20,6 +20,12 @@ import java.io.File;
 import java.net.InetAddress;
 import java.rmi.dgc.VMID;
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
 import java.util.UUID;
 
 import org.apache.log4j.helpers.LogLog;
@@ -28,88 +34,96 @@ import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 
 public class MiscUtil {
-	public static final String TOKEN_START        = "%";
-	public static final String TOKEN_END          = "%";
-	public static final String TOKEN_HOSTNAME     = "hostname";
-	public static final String TOKEN_APP_TYPE     = "app-type";
+	public static final String TOKEN_START = "%";
+	public static final String TOKEN_END = "%";
+	public static final String TOKEN_HOSTNAME = "hostname";
+	public static final String TOKEN_APP_TYPE = "app-type";
 	public static final String TOKEN_JVM_INSTANCE = "jvm-instance";
-	public static final String TOKEN_TIME         = "time:";
-	public static final String TOKEN_PROPERTY     = "property:";
-	public static final String TOKEN_ENV          = "env:";
-	public static final String ESCAPE_STR           = "\\";
+	public static final String TOKEN_TIME = "time:";
+	public static final String TOKEN_PROPERTY = "property:";
+	public static final String TOKEN_ENV = "env:";
+	public static final String ESCAPE_STR = "\\";
 
 	static VMID sJvmID = new VMID();
 
 	public static String LINE_SEPARATOR = System.getProperty("line.separator");
 
-	private static Gson   sGsonBuilder = null;
+	private static Gson sGsonBuilder = null;
 	private static String sApplicationType = null;
 
 	static {
 		try {
-			sGsonBuilder = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss.SSS").create();
-		} catch(Throwable excp) {
-			LogLog.warn("failed to create GsonBuilder object. stringigy() will return obj.toString(), instead of Json", excp);
+			sGsonBuilder = new GsonBuilder().setDateFormat(
+					"yyyy-MM-dd HH:mm:ss.SSS").create();
+		} catch (Throwable excp) {
+			LogLog.warn(
+					"failed to create GsonBuilder object. stringigy() will return obj.toString(), instead of Json",
+					excp);
 		}
 	}
 
 	public static String replaceTokens(String str, long time) {
-		if(str == null) {
+		if (str == null) {
 			return str;
 		}
 
-		if(time <= 0) {
+		if (time <= 0) {
 			time = System.currentTimeMillis();
 		}
 
-        for(int startPos = 0; startPos < str.length(); ) {
-            int tagStartPos = str.indexOf(TOKEN_START, startPos);
-            
-            if(tagStartPos == -1) {
-            	break;
-            }
-
-            int tagEndPos = str.indexOf(TOKEN_END, tagStartPos + TOKEN_START.length());
-
-            if(tagEndPos == -1) {
-            	break;
-            }
-
-            String tag   = str.substring(tagStartPos, tagEndPos+TOKEN_END.length());
-            String token = tag.substring(TOKEN_START.length(), tag.lastIndexOf(TOKEN_END));
-            String val   = "";
-
-            if(token != null) {
-	            if(token.equals(TOKEN_HOSTNAME)) {
-	            	val = getHostname();
-	            } else if(token.equals(TOKEN_APP_TYPE)) {
-	            	val = getApplicationType();
-	            } else if(token.equals(TOKEN_JVM_INSTANCE)) {
-	            	val = getJvmInstanceId();
-	            } else if(token.startsWith(TOKEN_PROPERTY)) {
-	            	String propertyName = token.substring(TOKEN_PROPERTY.length());
-	
-	                val = getSystemProperty(propertyName);
-	            } else if(token.startsWith(TOKEN_ENV)) {
-	            	String envName = token.substring(TOKEN_ENV.length());
-	
-	                val = getEnv(envName);
-	            } else if(token.startsWith(TOKEN_TIME)) {
-	                String dtFormat = token.substring(TOKEN_TIME.length());
-	                
-	                val = getFormattedTime(time, dtFormat);
-	            }
-            }
-
-            if(val == null) {
-            	val = "";
-            }
-
-            str = str.substring(0, tagStartPos) + val + str.substring(tagEndPos + TOKEN_END.length());
-            startPos = tagStartPos + val.length();
-        }
-
-        return str;
+		for (int startPos = 0; startPos < str.length();) {
+			int tagStartPos = str.indexOf(TOKEN_START, startPos);
+
+			if (tagStartPos == -1) {
+				break;
+			}
+
+			int tagEndPos = str.indexOf(TOKEN_END,
+					tagStartPos + TOKEN_START.length());
+
+			if (tagEndPos == -1) {
+				break;
+			}
+
+			String tag = str.substring(tagStartPos,
+					tagEndPos + TOKEN_END.length());
+			String token = tag.substring(TOKEN_START.length(),
+					tag.lastIndexOf(TOKEN_END));
+			String val = "";
+
+			if (token != null) {
+				if (token.equals(TOKEN_HOSTNAME)) {
+					val = getHostname();
+				} else if (token.equals(TOKEN_APP_TYPE)) {
+					val = getApplicationType();
+				} else if (token.equals(TOKEN_JVM_INSTANCE)) {
+					val = getJvmInstanceId();
+				} else if (token.startsWith(TOKEN_PROPERTY)) {
+					String propertyName = token.substring(TOKEN_PROPERTY
+							.length());
+
+					val = getSystemProperty(propertyName);
+				} else if (token.startsWith(TOKEN_ENV)) {
+					String envName = token.substring(TOKEN_ENV.length());
+
+					val = getEnv(envName);
+				} else if (token.startsWith(TOKEN_TIME)) {
+					String dtFormat = token.substring(TOKEN_TIME.length());
+
+					val = getFormattedTime(time, dtFormat);
+				}
+			}
+
+			if (val == null) {
+				val = "";
+			}
+
+			str = str.substring(0, tagStartPos) + val
+					+ str.substring(tagEndPos + TOKEN_END.length());
+			startPos = tagStartPos + val.length();
+		}
+
+		return str;
 	}
 
 	public static String getHostname() {
@@ -142,7 +156,8 @@ public class MiscUtil {
 		String ret = null;
 
 		try {
-			ret = propertyName != null ? System.getProperty(propertyName) : null;
+			ret = propertyName != null ? System.getProperty(propertyName)
+					: null;
 		} catch (Exception excp) {
 			LogLog.warn("getSystemProperty(" + propertyName + ") failed", excp);
 		}
@@ -166,9 +181,9 @@ public class MiscUtil {
 		String ret = null;
 
 		try {
-            SimpleDateFormat sdf = new SimpleDateFormat(format);
+			SimpleDateFormat sdf = new SimpleDateFormat(format);
 
-            ret = sdf.format(time);
+			ret = sdf.format(time);
 		} catch (Exception excp) {
 			LogLog.warn("SimpleDateFormat.format() failed: " + format, excp);
 		}
@@ -177,15 +192,16 @@ public class MiscUtil {
 	}
 
 	public static void createParents(File file) {
-		if(file != null) {
+		if (file != null) {
 			String parentName = file.getParent();
 
 			if (parentName != null) {
 				File parentDir = new File(parentName);
 
-				if(!parentDir.exists()) {
-					if(! parentDir.mkdirs()) {
-						LogLog.warn("createParents(): failed to create " + parentDir.getAbsolutePath());
+				if (!parentDir.exists()) {
+					if (!parentDir.mkdirs()) {
+						LogLog.warn("createParents(): failed to create "
+								+ parentDir.getAbsolutePath());
 					}
 				}
 			}
@@ -195,14 +211,16 @@ public class MiscUtil {
 	public static long getNextRolloverTime(long lastRolloverTime, long interval) {
 		long now = System.currentTimeMillis() / 1000 * 1000; // round to second
 
-		if(lastRolloverTime <= 0) {
-			// should this be set to the next multiple-of-the-interval from start of the day?
+		if (lastRolloverTime <= 0) {
+			// should this be set to the next multiple-of-the-interval from
+			// start of the day?
 			return now + interval;
-		} else if(lastRolloverTime <= now) {
+		} else if (lastRolloverTime <= now) {
 			long nextRolloverTime = now + interval;
 
 			// keep it at 'interval' boundary
-			long trimInterval = (nextRolloverTime - lastRolloverTime) % interval;
+			long trimInterval = (nextRolloverTime - lastRolloverTime)
+					% interval;
 
 			return nextRolloverTime - trimInterval;
 		} else {
@@ -211,23 +229,24 @@ public class MiscUtil {
 	}
 
 	public static long getRolloverStartTime(long nextRolloverTime, long interval) {
-		return (nextRolloverTime <= interval) ? System.currentTimeMillis() : nextRolloverTime - interval;
+		return (nextRolloverTime <= interval) ? System.currentTimeMillis()
+				: nextRolloverTime - interval;
 	}
 
 	public static int parseInteger(String str, int defValue) {
 		int ret = defValue;
 
-		if(str != null) {
+		if (str != null) {
 			try {
 				ret = Integer.parseInt(str);
-			} catch(Exception excp) {
+			} catch (Exception excp) {
 				// ignore
 			}
 		}
 
 		return ret;
 	}
-	
+
 	public static String generateUniqueId() {
 		return UUID.randomUUID().toString();
 	}
@@ -235,10 +254,10 @@ public class MiscUtil {
 	public static <T> String stringify(T log) {
 		String ret = null;
 
-		if(log != null) {
-			if(log instanceof String) {
-				ret = (String)log;
-			} else if(MiscUtil.sGsonBuilder != null) {
+		if (log != null) {
+			if (log instanceof String) {
+				ret = (String) log;
+			} else if (MiscUtil.sGsonBuilder != null) {
 				ret = MiscUtil.sGsonBuilder.toJson(log);
 			} else {
 				ret = log.toString();
@@ -247,4 +266,114 @@ public class MiscUtil {
 
 		return ret;
 	}
+
+	static public <T> T fromJson(String jsonStr, Class<T> clazz) {
+		return sGsonBuilder.fromJson(jsonStr, clazz);
+	}
+
+	public static String getStringProperty(Properties props, String propName) {
+		String ret = null;
+
+		if (props != null && propName != null) {
+			String val = props.getProperty(propName);
+			if (val != null) {
+				ret = val;
+			}
+		}
+
+		return ret;
+	}
+
+	public static boolean getBooleanProperty(Properties props, String propName,
+			boolean defValue) {
+		boolean ret = defValue;
+
+		if (props != null && propName != null) {
+			String val = props.getProperty(propName);
+
+			if (val != null) {
+				ret = Boolean.valueOf(val);
+			}
+		}
+
+		return ret;
+	}
+
+	public static int getIntProperty(Properties props, String propName,
+			int defValue) {
+		int ret = defValue;
+
+		if (props != null && propName != null) {
+			String val = props.getProperty(propName);
+			if (val != null) {
+				try {
+					ret = Integer.parseInt(val);
+				} catch (NumberFormatException excp) {
+					ret = defValue;
+				}
+			}
+		}
+
+		return ret;
+	}
+
+	public static long getLongProperty(Properties props, String propName,
+			long defValue) {
+		long ret = defValue;
+
+		if (props != null && propName != null) {
+			String val = props.getProperty(propName);
+			if (val != null) {
+				try {
+					ret = Long.parseLong(val);
+				} catch (NumberFormatException excp) {
+					ret = defValue;
+				}
+			}
+		}
+
+		return ret;
+	}
+
+	public static Map<String, String> getPropertiesWithPrefix(Properties props,
+			String prefix) {
+		Map<String, String> prefixedProperties = new HashMap<String, String>();
+
+		if (props != null && prefix != null) {
+			for (String key : props.stringPropertyNames()) {
+				if (key == null) {
+					continue;
+				}
+
+				String val = props.getProperty(key);
+
+				if (key.startsWith(prefix)) {
+					key = key.substring(prefix.length());
+
+					if (key == null) {
+						continue;
+					}
+
+					prefixedProperties.put(key, val);
+				}
+			}
+		}
+
+		return prefixedProperties;
+	}
+
+	/**
+	 * @param destListStr
+	 * @param delim
+	 * @return
+	 */
+	public static List<String> toArray(String destListStr, String delim) {
+		List<String> list = new ArrayList<String>();
+		StringTokenizer tokenizer = new StringTokenizer(destListStr, delim);
+		while (tokenizer.hasMoreTokens()) {
+			list.add(tokenizer.nextToken());
+		}
+		return list;
+	}
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/eb1e9b5c/agents-audit/src/main/java/org/apache/ranger/audit/provider/MultiDestAuditProvider.java
----------------------------------------------------------------------
diff --git a/agents-audit/src/main/java/org/apache/ranger/audit/provider/MultiDestAuditProvider.java b/agents-audit/src/main/java/org/apache/ranger/audit/provider/MultiDestAuditProvider.java
index 1eec345..57ac0a0 100644
--- a/agents-audit/src/main/java/org/apache/ranger/audit/provider/MultiDestAuditProvider.java
+++ b/agents-audit/src/main/java/org/apache/ranger/audit/provider/MultiDestAuditProvider.java
@@ -18,6 +18,7 @@
 package org.apache.ranger.audit.provider;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Properties;
 
@@ -25,14 +26,13 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.ranger.audit.model.AuditEventBase;
 
-
 public class MultiDestAuditProvider extends BaseAuditProvider {
 
-	private static final Log LOG = LogFactory.getLog(MultiDestAuditProvider.class);
+	private static final Log LOG = LogFactory
+			.getLog(MultiDestAuditProvider.class);
 
 	protected List<AuditProvider> mProviders = new ArrayList<AuditProvider>();
 
-
 	public MultiDestAuditProvider() {
 		LOG.info("MultiDestAuditProvider: creating..");
 	}
@@ -47,109 +47,166 @@ public class MultiDestAuditProvider extends BaseAuditProvider {
 
 		super.init(props);
 
-		for(AuditProvider provider : mProviders) {
-    		try {
-                provider.init(props);
-    		} catch(Throwable excp) {
-    			LOG.info("MultiDestAuditProvider.init(): failed " + provider.getClass().getCanonicalName() + ")", excp);
-    		}
-        }
+		for (AuditProvider provider : mProviders) {
+			try {
+				provider.init(props);
+			} catch (Throwable excp) {
+				LOG.info("MultiDestAuditProvider.init(): failed "
+						+ provider.getClass().getCanonicalName() + ")", excp);
+			}
+		}
 	}
 
 	public void addAuditProvider(AuditProvider provider) {
-		if(provider != null) {
-			LOG.info("MultiDestAuditProvider.addAuditProvider(providerType=" + provider.getClass().getCanonicalName() + ")");
+		if (provider != null) {
+			LOG.info("MultiDestAuditProvider.addAuditProvider(providerType="
+					+ provider.getClass().getCanonicalName() + ")");
 
 			mProviders.add(provider);
 		}
 	}
 
 	public void addAuditProviders(List<AuditProvider> providers) {
-		if(providers != null) {
-			for(AuditProvider provider : providers) {
+		if (providers != null) {
+			for (AuditProvider provider : providers) {
 				addAuditProvider(provider);
 			}
 		}
 	}
 
 	@Override
-	public void log(AuditEventBase event) {
-        for(AuditProvider provider : mProviders) {
-    		try {
-                provider.log(event);
-    		} catch(Throwable excp) {
-    			logFailedEvent(event, excp);
-    		}
-        }
+	public boolean log(AuditEventBase event) {
+		for (AuditProvider provider : mProviders) {
+			try {
+				provider.log(event);
+			} catch (Throwable excp) {
+				logFailedEvent(event, excp);
+			}
+		}
+		return true;
+	}
+
+	@Override
+	public boolean log(Collection<AuditEventBase> events) {
+		for (AuditProvider provider : mProviders) {
+			try {
+				provider.log(events);
+			} catch (Throwable excp) {
+				logFailedEvent(events, excp);
+			}
+		}
+		return true;
+	}
+
+	@Override
+	public boolean logJSON(String event) {
+		for (AuditProvider provider : mProviders) {
+			try {
+				provider.logJSON(event);
+			} catch (Throwable excp) {
+				logFailedEventJSON(event, excp);
+			}
+		}
+		return true;
+	}
+
+	@Override
+	public boolean logJSON(Collection<String> events) {
+		for (AuditProvider provider : mProviders) {
+			try {
+				provider.logJSON(events);
+			} catch (Throwable excp) {
+				logFailedEventJSON(events, excp);
+			}
+		}
+		return true;
 	}
 
 	@Override
 	public void start() {
-		for(AuditProvider provider : mProviders) {
-    		try {
+		for (AuditProvider provider : mProviders) {
+			try {
 				provider.start();
-    		} catch(Throwable excp) {
-    			LOG.error("AsyncAuditProvider.start(): failed for provider { " + provider.getClass().getName() + " }", excp);
-    		}
+			} catch (Throwable excp) {
+				LOG.error("AsyncAuditProvider.start(): failed for provider { "
+						+ provider.getClass().getName() + " }", excp);
+			}
 		}
 	}
 
 	@Override
 	public void stop() {
-		for(AuditProvider provider : mProviders) {
+		for (AuditProvider provider : mProviders) {
 			try {
 				provider.stop();
-			} catch(Throwable excp) {
-    			LOG.error("AsyncAuditProvider.stop(): failed for provider { " + provider.getClass().getName() + " }", excp);
+			} catch (Throwable excp) {
+				LOG.error("AsyncAuditProvider.stop(): failed for provider { "
+						+ provider.getClass().getName() + " }", excp);
 			}
 		}
 	}
 
 	@Override
-    public void waitToComplete() {
-		for(AuditProvider provider : mProviders) {
+	public void waitToComplete() {
+		for (AuditProvider provider : mProviders) {
 			try {
 				provider.waitToComplete();
-			} catch(Throwable excp) {
-    			LOG.error("AsyncAuditProvider.waitToComplete(): failed for provider { " + provider.getClass().getName() + " }", excp);
+			} catch (Throwable excp) {
+				LOG.error(
+						"AsyncAuditProvider.waitToComplete(): failed for provider { "
+								+ provider.getClass().getName() + " }", excp);
+			}
+		}
+	}
+
+	@Override
+	public void waitToComplete(long timeout) {
+		for (AuditProvider provider : mProviders) {
+			try {
+				provider.waitToComplete(timeout);
+			} catch (Throwable excp) {
+				LOG.error(
+						"AsyncAuditProvider.waitToComplete(): failed for provider { "
+								+ provider.getClass().getName() + " }", excp);
 			}
 		}
 	}
-	
+
 	@Override
 	public boolean isFlushPending() {
-		for(AuditProvider provider : mProviders) {
-			if(provider.isFlushPending()) {
+		for (AuditProvider provider : mProviders) {
+			if (provider.isFlushPending()) {
 				return true;
 			}
 		}
-		
+
 		return false;
 	}
-	
+
 	@Override
 	public long getLastFlushTime() {
 		long lastFlushTime = 0;
-		for(AuditProvider provider : mProviders) {
+		for (AuditProvider provider : mProviders) {
 			long flushTime = provider.getLastFlushTime();
-			
-			if(flushTime != 0) {
-				if(lastFlushTime == 0 || lastFlushTime > flushTime) {
+
+			if (flushTime != 0) {
+				if (lastFlushTime == 0 || lastFlushTime > flushTime) {
 					lastFlushTime = flushTime;
 				}
 			}
 		}
-		
+
 		return lastFlushTime;
 	}
-	
+
 	@Override
 	public void flush() {
-		for(AuditProvider provider : mProviders) {
+		for (AuditProvider provider : mProviders) {
 			try {
 				provider.flush();
-			} catch(Throwable excp) {
-    			LOG.error("AsyncAuditProvider.flush(): failed for provider { " + provider.getClass().getName() + " }", excp);
+			} catch (Throwable excp) {
+				LOG.error("AsyncAuditProvider.flush(): failed for provider { "
+						+ provider.getClass().getName() + " }", excp);
 			}
 		}
 	}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/eb1e9b5c/agents-audit/src/main/java/org/apache/ranger/audit/provider/hdfs/HdfsAuditProvider.java
----------------------------------------------------------------------
diff --git a/agents-audit/src/main/java/org/apache/ranger/audit/provider/hdfs/HdfsAuditProvider.java b/agents-audit/src/main/java/org/apache/ranger/audit/provider/hdfs/HdfsAuditProvider.java
index 620951c..a18e3e9 100644
--- a/agents-audit/src/main/java/org/apache/ranger/audit/provider/hdfs/HdfsAuditProvider.java
+++ b/agents-audit/src/main/java/org/apache/ranger/audit/provider/hdfs/HdfsAuditProvider.java
@@ -22,7 +22,6 @@ import java.util.Properties;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.ranger.audit.model.AuditEventBase;
-import org.apache.ranger.audit.provider.BaseAuditProvider;
 import org.apache.ranger.audit.provider.BufferedAuditProvider;
 import org.apache.ranger.audit.provider.DebugTracer;
 import org.apache.ranger.audit.provider.LocalFileLogBuffer;
@@ -44,7 +43,7 @@ public class HdfsAuditProvider extends BufferedAuditProvider {
 
 		super.init(props);
 
-		Map<String, String> hdfsProps = BaseAuditProvider.getPropertiesWithPrefix(props, "xasecure.audit.hdfs.config.");
+		Map<String, String> hdfsProps = MiscUtil.getPropertiesWithPrefix(props, "xasecure.audit.hdfs.config.");
 
 		String encoding                                = hdfsProps.get("encoding");
 

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/eb1e9b5c/agents-audit/src/main/java/org/apache/ranger/audit/provider/hdfs/HdfsLogDestination.java
----------------------------------------------------------------------
diff --git a/agents-audit/src/main/java/org/apache/ranger/audit/provider/hdfs/HdfsLogDestination.java b/agents-audit/src/main/java/org/apache/ranger/audit/provider/hdfs/HdfsLogDestination.java
index 6b5cb4b..49f4e65 100644
--- a/agents-audit/src/main/java/org/apache/ranger/audit/provider/hdfs/HdfsLogDestination.java
+++ b/agents-audit/src/main/java/org/apache/ranger/audit/provider/hdfs/HdfsLogDestination.java
@@ -29,6 +29,7 @@ import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FSDataOutputStream;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
+import org.apache.ranger.audit.model.AuditEventBase;
 import org.apache.ranger.audit.provider.DebugTracer;
 import org.apache.ranger.audit.provider.LogDestination;
 import org.apache.ranger.audit.provider.MiscUtil;
@@ -36,6 +37,8 @@ import org.apache.ranger.audit.provider.MiscUtil;
 public class HdfsLogDestination<T> implements LogDestination<T> {
 	public final static String EXCP_MSG_FILESYSTEM_CLOSED = "Filesystem closed";
 
+	private String name = getClass().getName();
+	
 	private String  mDirectory                = null;
 	private String  mFile                     = null;
 	private int     mFlushIntervalSeconds     = 1 * 60;
@@ -57,6 +60,20 @@ public class HdfsLogDestination<T> implements LogDestination<T> {
 		mLogger = tracer;
 	}
 
+	
+	public void setName(String name) {
+		this.name = name;
+	}
+
+
+	/* (non-Javadoc)
+	 * @see org.apache.ranger.audit.provider.LogDestination#getName()
+	 */
+	@Override
+	public String getName() {
+		return name;
+	}
+	
 	public String getDirectory() {
 		return mDirectory;
 	}
@@ -133,11 +150,11 @@ public class HdfsLogDestination<T> implements LogDestination<T> {
 	}
 
 	@Override
-	public boolean send(T log) {
-		boolean ret = false;
+	public boolean send(AuditEventBase log) {
+		boolean ret = true;
 		
 		if(log != null) {
-			String msg = log.toString();
+			String msg = MiscUtil.stringify(log);
 
 			ret = sendStringified(msg);
 		}
@@ -145,6 +162,18 @@ public class HdfsLogDestination<T> implements LogDestination<T> {
 		return ret;
 	}
 
+	
+	@Override
+	public boolean send(AuditEventBase[] logs) {
+		for(int i = 0; i < logs.length; i++) {
+			boolean ret = send(logs[i]);
+			if(!ret) {
+				return ret;
+			}
+		}
+		return true;
+	}
+
 	@Override
 	public boolean sendStringified(String log) {
 		boolean ret = false;
@@ -169,6 +198,18 @@ public class HdfsLogDestination<T> implements LogDestination<T> {
 	}
 
 	@Override
+	public boolean sendStringified(String[] logs) {
+		for(int i = 0; i < logs.length; i++) {
+			boolean ret = sendStringified(logs[i]);
+			if(!ret) {
+				return ret;
+			}
+		}
+		return true;
+	}
+	
+	
+	@Override
 	public boolean flush() {
 		mLogger.debug("==> HdfsLogDestination.flush()");
 
@@ -448,4 +489,5 @@ public class HdfsLogDestination<T> implements LogDestination<T> {
 		
 		return sb.toString();
 	}
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/eb1e9b5c/agents-audit/src/main/java/org/apache/ranger/audit/provider/kafka/KafkaAuditProvider.java
----------------------------------------------------------------------
diff --git a/agents-audit/src/main/java/org/apache/ranger/audit/provider/kafka/KafkaAuditProvider.java b/agents-audit/src/main/java/org/apache/ranger/audit/provider/kafka/KafkaAuditProvider.java
index 0ec8790..5f39e69 100644
--- a/agents-audit/src/main/java/org/apache/ranger/audit/provider/kafka/KafkaAuditProvider.java
+++ b/agents-audit/src/main/java/org/apache/ranger/audit/provider/kafka/KafkaAuditProvider.java
@@ -16,6 +16,7 @@
  */
 package org.apache.ranger.audit.provider.kafka;
 
+import java.util.Collection;
 import java.util.Properties;
 
 import kafka.javaapi.producer.Producer;
@@ -46,12 +47,12 @@ public class KafkaAuditProvider extends BaseAuditProvider {
 		LOG.info("init() called");
 		super.init(props);
 
-		setMaxQueueSize(BaseAuditProvider.getIntProperty(props,
-				AUDIT_MAX_QUEUE_SIZE_PROP, AUDIT_ASYNC_MAX_QUEUE_SIZE_DEFAULT));
-		setMaxFlushInterval(BaseAuditProvider.getIntProperty(props,
+		setMaxQueueSize(MiscUtil.getIntProperty(props,
+				AUDIT_MAX_QUEUE_SIZE_PROP, AUDIT_MAX_QUEUE_SIZE_DEFAULT));
+		setMaxBatchInterval(MiscUtil.getIntProperty(props,
 				AUDIT_MAX_QUEUE_SIZE_PROP,
-				AUDIT_ASYNC_MAX_FLUSH_INTERVAL_DEFAULT));
-		topic = BaseAuditProvider.getStringProperty(props,
+				AUDIT_BATCH_INTERVAL_DEFAULT_MS));
+		topic = MiscUtil.getStringProperty(props,
 				AUDIT_KAFKA_TOPIC_NAME);
 		if (topic == null || topic.isEmpty()) {
 			topic = "ranger_audits";
@@ -59,7 +60,7 @@ public class KafkaAuditProvider extends BaseAuditProvider {
 
 		try {
 			if (!initDone) {
-				String brokerList = BaseAuditProvider.getStringProperty(props,
+				String brokerList = MiscUtil.getStringProperty(props,
 						AUDIT_KAFKA_BROKER_LIST);
 				if (brokerList == null || brokerList.isEmpty()) {
 					brokerList = "localhost:9092";
@@ -87,7 +88,7 @@ public class KafkaAuditProvider extends BaseAuditProvider {
 	}
 
 	@Override
-	public void log(AuditEventBase event) {
+	public boolean log(AuditEventBase event) {
 		if (event instanceof AuthzAuditEvent) {
 			AuthzAuditEvent authzEvent = (AuthzAuditEvent) event;
 
@@ -118,7 +119,32 @@ public class KafkaAuditProvider extends BaseAuditProvider {
 		} catch (Throwable t) {
 			LOG.error("Error sending message to Kafka topic. topic=" + topic
 					+ ", message=" + message, t);
+			return false;
 		}
+		return true;
+	}
+
+	@Override
+	public boolean log(Collection<AuditEventBase> events) {
+		for (AuditEventBase event : events) {
+			log(event);
+		}
+		return true;
+	}
+
+	@Override
+	public boolean logJSON(String event) {
+		AuditEventBase eventObj = MiscUtil.fromJson(event,
+				AuthzAuditEvent.class);
+		return log(eventObj);
+	}
+
+	@Override
+	public boolean logJSON(Collection<String> events) {
+		for (String event : events) {
+			logJSON(event);
+		}
+		return false;
 	}
 
 	@Override
@@ -143,8 +169,10 @@ public class KafkaAuditProvider extends BaseAuditProvider {
 	@Override
 	public void waitToComplete() {
 		LOG.info("waitToComplete() called");
-		// TODO Auto-generated method stub
-
+	}
+	
+	@Override
+	public void waitToComplete(long timeout) {
 	}
 
 	@Override

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/eb1e9b5c/agents-audit/src/main/java/org/apache/ranger/audit/provider/solr/SolrAuditProvider.java
----------------------------------------------------------------------
diff --git a/agents-audit/src/main/java/org/apache/ranger/audit/provider/solr/SolrAuditProvider.java b/agents-audit/src/main/java/org/apache/ranger/audit/provider/solr/SolrAuditProvider.java
index 1b463e6..9ee4ec0 100644
--- a/agents-audit/src/main/java/org/apache/ranger/audit/provider/solr/SolrAuditProvider.java
+++ b/agents-audit/src/main/java/org/apache/ranger/audit/provider/solr/SolrAuditProvider.java
@@ -19,6 +19,7 @@
 
 package org.apache.ranger.audit.provider.solr;
 
+import java.util.Collection;
 import java.util.Date;
 import java.util.Properties;
 
@@ -55,12 +56,12 @@ public class SolrAuditProvider extends BaseAuditProvider {
 		LOG.info("init() called");
 		super.init(props);
 
-		setMaxQueueSize(BaseAuditProvider.getIntProperty(props,
-				AUDIT_MAX_QUEUE_SIZE_PROP, AUDIT_ASYNC_MAX_QUEUE_SIZE_DEFAULT));
-		setMaxFlushInterval(BaseAuditProvider.getIntProperty(props,
+		setMaxQueueSize(MiscUtil.getIntProperty(props,
+				AUDIT_MAX_QUEUE_SIZE_PROP, AUDIT_MAX_QUEUE_SIZE_DEFAULT));
+		setMaxBatchInterval(MiscUtil.getIntProperty(props,
 				AUDIT_MAX_QUEUE_SIZE_PROP,
-				AUDIT_ASYNC_MAX_FLUSH_INTERVAL_DEFAULT));
-		retryWaitTime = BaseAuditProvider.getIntProperty(props,
+				AUDIT_BATCH_INTERVAL_DEFAULT_MS));
+		retryWaitTime = MiscUtil.getIntProperty(props,
 				AUDIT_RETRY_WAIT_PROP, retryWaitTime);
 	}
 
@@ -68,7 +69,7 @@ public class SolrAuditProvider extends BaseAuditProvider {
 		if (solrClient == null) {
 			synchronized (lock) {
 				if (solrClient == null) {
-					String solrURL = BaseAuditProvider.getStringProperty(props,
+					String solrURL = MiscUtil.getStringProperty(props,
 							"xasecure.audit.solr.solr_url");
 
 					if (lastConnectTime != null) {
@@ -118,11 +119,11 @@ public class SolrAuditProvider extends BaseAuditProvider {
 	 * audit.model.AuditEventBase)
 	 */
 	@Override
-	public void log(AuditEventBase event) {
+	public boolean log(AuditEventBase event) {
 		if (!(event instanceof AuthzAuditEvent)) {
 			LOG.error(event.getClass().getName()
 					+ " audit event class type is not supported");
-			return;
+			return false;
 		}
 		AuthzAuditEvent authzEvent = (AuthzAuditEvent) event;
 		// TODO: This should be done at a higher level
@@ -144,7 +145,7 @@ public class SolrAuditProvider extends BaseAuditProvider {
 				connect();
 				if (solrClient == null) {
 					// Solr is still not initialized. So need to throw error
-					return;
+					return false;
 				}
 			}
 
@@ -155,7 +156,7 @@ public class SolrAuditProvider extends BaseAuditProvider {
 						LOG.debug("Ignore sending audit. lastConnect=" + diff
 								+ " ms");
 					}
-					return;
+					return false;
 				}
 			}
 			// Convert AuditEventBase to Solr document
@@ -176,8 +177,32 @@ public class SolrAuditProvider extends BaseAuditProvider {
 
 		} catch (Throwable t) {
 			LOG.error("Error sending message to Solr", t);
+			return false;
 		}
+		return true;
+	}
+
+	@Override
+	public boolean log(Collection<AuditEventBase> events) {
+		for (AuditEventBase event : events) {
+			log(event);
+		}
+		return true;
+	}
+
+	@Override
+	public boolean logJSON(String event) {
+		AuditEventBase eventObj = MiscUtil.fromJson(event,
+				AuthzAuditEvent.class);
+		return log(eventObj);
+	}
 
+	@Override
+	public boolean logJSON(Collection<String> events) {
+		for (String event : events) {
+			logJSON(event);
+		}
+		return false;
 	}
 
 	/*
@@ -208,10 +233,15 @@ public class SolrAuditProvider extends BaseAuditProvider {
 	 */
 	@Override
 	public void waitToComplete() {
-		// TODO Auto-generated method stub
 
 	}
 
+	
+	@Override
+	public void waitToComplete(long timeout) {
+		
+	}
+
 	/*
 	 * (non-Javadoc)
 	 * 

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/eb1e9b5c/security-admin/.gitignore
----------------------------------------------------------------------
diff --git a/security-admin/.gitignore b/security-admin/.gitignore
index 4a3ed53..bf7dc37 100644
--- a/security-admin/.gitignore
+++ b/security-admin/.gitignore
@@ -3,3 +3,6 @@
 /bin/
 /target
 .settings/
+.pydevproject
+log4j.xml
+*.log

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/eb1e9b5c/security-admin/pom.xml
----------------------------------------------------------------------
diff --git a/security-admin/pom.xml b/security-admin/pom.xml
index 3220886..286740c 100644
--- a/security-admin/pom.xml
+++ b/security-admin/pom.xml
@@ -251,6 +251,8 @@
 		<dependency>
 		    <groupId>junit</groupId>
 		    <artifactId>junit</artifactId>
+		    <version>4.11</version>
+		    <scope>test</scope>
 		</dependency>
 		<dependency>
 			<groupId>org.mockito</groupId>
@@ -421,13 +423,15 @@
 					<additionalClasspathElement>${project.basedir}/src/main/webapp/META-INF</additionalClasspathElement>
 				</additionalClasspathElements>
 			</configuration>
+<!--
 			<dependencies>
 				<dependency>
 					<groupId>org.apache.maven.surefire</groupId>
 					<artifactId>surefire-junit47</artifactId>
-					<version>2.17</version>
+					<version>2.18</version>
 				</dependency>
 			</dependencies>
+-->
 		</plugin>
 
 	</plugins>