com.stackify.error.logback.StackifyErrorAppender Maven / Gradle / Ivy
/*
* 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.logback;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.classic.spi.ThrowableProxy;
import ch.qos.logback.core.AppenderBase;
import com.stackify.api.ApiClient;
import com.stackify.api.EnvironmentDetail;
import com.stackify.api.StackifyError;
import com.stackify.api.common.ApiClients;
import com.stackify.api.common.EnvironmentDetails;
import com.stackify.api.common.http.StackifyErrorSender;
import com.stackify.api.common.lang.Throwables;
import com.stackify.api.json.StackifyErrorConverter;
/**
* Logback logger appender for sending exceptions to Stackify.
*
*
* Example:
*
* {@code
*
* YOUR_API_KEY
* YOUR_APPLICATION_NAME
* YOUR_ENVIRONMENT
*
* }
*
*
* @author Eric Martin
*/
public class StackifyErrorAppender extends AppenderBase {
/**
* The class responsible for sending the errors to Stackify
*/
private StackifyErrorSender errorSender;
/**
* The API Client
*/
private ApiClient apiClient = null;
/**
* The environment detail
*/
private EnvironmentDetail environmentDetail = null;
/**
* 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";
/**
* @return the apiUrl
*/
public String getApiUrl() {
return apiUrl;
}
/**
* @param apiUrl the apiUrl to set
*/
public void setApiUrl(String apiUrl) {
this.apiUrl = apiUrl;
}
/**
* @return the apiKey
*/
public String getApiKey() {
return apiKey;
}
/**
* @param apiKey the apiKey to set
*/
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
/**
* @return the application
*/
public String getApplication() {
return application;
}
/**
* @param application the application to set
*/
public void setApplication(String application) {
this.application = application;
}
/**
* @return the environment
*/
public String getEnvironment() {
return environment;
}
/**
* @param environment the environment to set
*/
public void setEnvironment(String environment) {
this.environment = environment;
}
/**
* @return the converter
*/
public String getConverter() {
return converter;
}
/**
* @param converter the converter to set
*/
public void setConverter(String converter) {
this.converter = converter;
}
/**
* @return the errorSender
*/
protected StackifyErrorSender getErrorSender() {
return errorSender;
}
/**
* @return the apiClient
*/
protected ApiClient getApiClient() {
return apiClient;
}
/**
* @return the environmentDetail
*/
protected EnvironmentDetail getEnvironmentDetail() {
return environmentDetail;
}
/**
* @see ch.qos.logback.core.AppenderBase#start()
*/
@Override
public void start() {
super.start();
// check the api key
if ((apiKey == null) || (apiKey.isEmpty())) {
addError("API Key not set for the Stackify Error Appender");
return;
}
// build the static API client record
this.apiClient = ApiClients.getApiClient(StackifyErrorAppender.class, "/stackify-error-logback.properties");
// build the static environment details record
this.environmentDetail = EnvironmentDetails.getEnvironmentDetail(application, environment);
// load the JSON converter
try {
Class> converterClass = Class.forName(converter);
StackifyErrorConverter converterInstance = (StackifyErrorConverter) converterClass.newInstance();
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);
}
}
/**
* @see ch.qos.logback.core.AppenderBase#append(java.lang.Object)
*/
@Override
protected void append(final ILoggingEvent event) {
// Make sure the API Key is set
if ((apiKey == null) || (apiKey.isEmpty())) {
return;
}
// Get the exception from the event
// If it was ERROR without an exception, create a placeholder for the stack trace
Throwable exception = getThrowable(event);
if (exception == null) {
if (event.getLevel() == Level.ERROR) {
exception = new Throwable();
} else {
return;
}
}
try {
// Build the tags for the error event
List tags = new ArrayList();
tags.add("logback");
tags.add(event.getLevel().toString().toLowerCase());
tags.add(event.getLoggerName());
// Build the StackifyError POJO from the LoggingEvent
StackifyError.Builder errorBuilder = StackifyError.newBuilder();
errorBuilder.apiClient(apiClient);
errorBuilder.environmentDetail(environmentDetail);
errorBuilder.occurredEpochMillis(new Date(event.getTimeStamp()));
errorBuilder.error(Throwables.toErrorItem(exception));
errorBuilder.tags(tags);
StackifyError error = errorBuilder.build();
// Send the error to Stackify
int rc = errorSender.send(apiUrl, apiKey, Collections.singletonList(error));
if (rc != HttpURLConnection.HTTP_OK) {
addInfo("Stackify Error Service returned HTTP " + Integer.toString(rc));
}
} catch (Throwable t) {
addInfo("Exception posting to Stackify Error Service", t);
}
}
/**
* Returns the exception tied to this log event
* @param event The log event
* @return The Throwable or null
*/
private Throwable getThrowable(final ILoggingEvent event) {
IThrowableProxy iThrowableProxy = event.getThrowableProxy();
if (iThrowableProxy != null) {
if (iThrowableProxy instanceof ThrowableProxy) {
ThrowableProxy throwableProxy = (ThrowableProxy) iThrowableProxy;
return throwableProxy.getThrowable();
}
}
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy