Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 2013 Stackify
   *
   * Licensed 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 com.stackify.error.log4j12;
 
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
 
 
Log4j 1.2 logger appender for sending exceptions to Stackify.

Example appender configuration (*.properties file):

 log4j.appender.STACKIFY_ERROR=com.stackify.error.log4j12.StackifyErrorAppender
 log4j.appender.STACKIFY_ERROR.apiKey=YOUR_API_KEY
 log4j.appender.STACKIFY_ERROR.application=YOUR_APPLICATION_NAME
 log4j.appender.STACKIFY_ERROR.environment=YOUR_ENVIRONMENT
 
 

Example appender configuration (*.xml file):

 <appender name="STACKIFY_ERROR" class="com.stackify.error.log4j12.StackifyErrorAppender">
     <param name="apiKey" value="YOUR_API_KEY"/>
     <param name="application" value="YOUR_APPLICATION_NAME"/>
     <param name="environment" value="YOUR_ENVIRONMENT"/>
 </appender>
 
 

Be sure to shutdown Log4j to flush this appender of any errors and shutdown the background thread:

 LogManager.shutdown();
 

Author(s):
Eric Martin
 
 public class StackifyErrorAppender extends NonReentrantAppender {

Logger for the appender
 
 	private static final Logger LOGGER = Logger.getLogger(StackifyErrorAppender.class);

Maximum size of the error queue
 
 	private static final int MAX_QUEUE_SIZE = 1000;

Client side error governor to suppress duplicate errors
 
 	private ErrorGovernor errorGovernor = new ErrorGovernor();

The class responsible for sending the errors to Stackify
 
 	private AsyncErrorSender asyncErrorSender = null;

Background service for sending errors to Stackify
The API Client
	private ApiClient apiClient = null;

The environment detailassertNull
API URL (Appender configuration parameter)
	private String apiUrl = "https://api.stackify.com/Error/V1";

API Key (Appender configuration parameter)
	private String apiKey = null;

Application name (Appender configuration parameter)
	private String application = null;

Environment (Appender configuration parameter)
	private String environment = null;

JSON Converter (Appender configuration parameter)
	private String converter = "com.stackify.api.json.jackson.StackifyErrorJacksonConverter";

Returns:
the apiUrl
	public String getApiUrl() {
		return ;
	}

Parameters:
apiUrl the apiUrl to set
	public void setApiUrl(String apiUrl) {
		this. = apiUrl;
	}

Returns:
the apiKey
	public String getApiKey() {
		return ;
	}

Parameters:
apiKey the apiKey to set
	public void setApiKey(String apiKey) {
		this. = apiKey;
	}

Returns:
the application
	public String getApplication() {
		return ;
	}

Parameters:
application the application to set
	public void setApplication(String application) {
		this. = application;
	}

Returns:
the environment
	public String getEnvironment() {
		return ;
	}

Parameters:
environment the environment to set
	public void setEnvironment(String environment) {
		this. = environment;
	}

Returns:
the converter
	public String getConverter() {
		return ;
	}

Parameters:
converter the converter to set
	public void setConverter(String converter) {
		this. = converter;
	}

Returns:
the apiClient
	public ApiClient getApiClient() {
		return ;
	}

Returns:
the environmentDetail
	}

Returns:
True of Stackify_AsyncErrorSenderService is running
		if ( != null) {
		}
		return false;
	}

	public void activateOptions() {
		// check the api key
		if (( == null) || (.isEmpty())) {
			.error("API Key not set for the Stackify Error Appender");
			return;
		}
		// build the static API client record
		this. = ApiClients.getApiClient(StackifyErrorAppender.class"/stackify-error-log4j12.properties");
		// build the static environment details record
		// load the JSON converter
		// construct the error sender
		try {
			Class<?> converterClass = Class.forName();
			StackifyErrorConverter converterInstance = (StackifyErrorConverterconverterClass.newInstance();
			StackifyErrorSender errorSender = new StackifyErrorSender(converterInstance);
catch (ClassNotFoundException e) {
			throw new RuntimeException(e);
catch (InstantiationException e) {
			throw new RuntimeException(e);
catch (IllegalAccessException e) {
			throw new RuntimeException(e);
		}
		// startup the background service to asynchronously post errors to Stackify
		try {
catch (Throwable t) {
				.info("Exception starting the Stackify_AsyncErrorSenderService"t);	
			}
		}
	}

	protected void subAppend(final LoggingEvent event) {
		// Make sure we have a properly configured sender
		if ( == null) {
			return;
		}
		// Get the exception from the event
		// If it was a FATAL or ERROR without an exception, create a placeholder for the stack trace
		Throwable exception = getThrowable(event);
		if (exception == null) {
			if ((event.getLevel() == .) || (event.getLevel() == .)) {
				exception = new Throwable();
else {
				return;				
			}
		}
		try {
			// Build the tags for the error event
			List<Stringtags = new ArrayList<String>();
			tags.add("log4j12");
			tags.add(event.getLevel().toString().toLowerCase());
			tags.add(event.getLoggerName());
			// Build the StackifyError POJO from the LoggingEvent
			StackifyError.Builder errorBuilder = StackifyError.newBuilder();
			errorBuilder.apiClient();
			errorBuilder.occurredEpochMillis(new Date(event.getTimeStamp()));
			errorBuilder.error(Throwables.toErrorItem(getLogMessage(event), exception));
			errorBuilder.tags(tags);
			Map<StringStringcustomProperties = getCustomProperties(event);
			if (!customProperties.isEmpty()) {
				errorBuilder.customProperties(customProperties);
			}
			StackifyError error = errorBuilder.build();
			// Send the error to Stackify
			}
catch (Throwable t) {
				.info("Exception queueing error to Stackify_AsyncErrorSenderService"t);	
			}
		}
	}

	public void close() {
		if ( != null) {
			try {
catch (Throwable t) {
					.info("Exception stopping the Stackify_AsyncErrorSenderService"t);	
				}
			}
		}
	}

	public boolean requiresLayout() {
		return false;
	}

Returns the exception tied to this log event

Parameters:
event The log event
Returns:
The Throwable or null
	private Throwable getThrowable(final LoggingEvent event) {
		if (throwableInfo != null) {
			Throwable t = throwableInfo.getThrowable();
			if (t != null) {
				return t;
			}
		}
		Object message = event.getMessage();
		if (message != null) {
			if (message instanceof Throwable) {
				return (Throwablemessage;
			}
		}
		return null;
	}

Gets custom properties from the events MDC and MDC

Parameters:
event The logging event
Returns:
Map assembled from the event's MDC and NDC
	private Map<StringStringgetCustomProperties(final LoggingEvent event) {
		Map<StringStringcustomProperties = new HashMap<StringString>();
		// unload the MDC
		Map mdc = event.getProperties();
		if (mdc != null) {
		    Iterator mdcIterator = mdc.entrySet().iterator();
		    
		    while (mdcIterator.hasNext()) {
		        Map.Entry entryPair = (Map.EntrymdcIterator.next();
		        
		        Object key = entryPair.getKey();
		        Object value = entryPair.getValue();
		        
		        customProperties.put(key.toString(), value != null ? value.toString() : null);
		    }
		}
		// unload the NDC
		String ndc = event.getNDC();
		if (ndc != null) {
			if (!ndc.isEmpty()) {
				customProperties.put("NDC"ndc);
			}
		}
		// return the custom properties
		return customProperties;		
	}

Returns the log message

Parameters:
event The log event
Returns:
The log message or null
	private String getLogMessage(final LoggingEvent event) {
		Object message = event.getMessage();
		if (message != null) {
			if (message instanceof String) {
				return (Stringmessage;
			}
		}
		return null;
	}
New to GrepCode? Check out our FAQ X