Skip to content

Instantly share code, notes, and snippets.

@alno
Created May 11, 2014 15:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alno/fd2eadfd776bad03ee3d to your computer and use it in GitHub Desktop.
Save alno/fd2eadfd776bad03ee3d to your computer and use it in GitHub Desktop.
package utils
import ch.qos.logback.core.AppenderBase
import ch.qos.logback.classic.spi.ILoggingEvent
import ch.qos.logback.classic.spi.IThrowableProxy
import com.ning.http.client._
import scala.beans.BeanProperty
import scala.collection.convert.WrapAsScala._
import java.net.InetAddress
class HoneybadgerAppender extends AppenderBase[ILoggingEvent] {
import HoneybadgerAppender._
@BeanProperty
var apiKey: String = null
private var enabledEnvironments = Seq("production", "staging")
private var enabled = enabledEnvironments contains environment
def getEnabledEnvironments: String =
enabledEnvironments.mkString(",")
def setEnabledEnvironments(envs: String) {
enabledEnvironments = envs split "," map { _.trim }
enabled = enabledEnvironments contains environment
}
private lazy val httpClientConfig = new AsyncHttpClientConfigBean
private lazy val httpClient = new AsyncHttpClient(httpClientConfig)
def append(event: ILoggingEvent) =
if (enabled)
httpClient.preparePost("https://api.honeybadger.io/v1/notices")
.addHeader("X-API-Key", apiKey)
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
.setBody(encode(event))
.execute(new AsyncCompletionHandler[Unit] {
override def onCompleted(res: Response) = {
println(res.getStatusCode() + ": " + res.getResponseBody())
}
override def onThrowable(err: Throwable) {
err.printStackTrace()
}
})
def encode(event: ILoggingEvent): String =
Json.writeValueAsString(notice(event))
def notice(e: ILoggingEvent): Notice =
Notice(notifier, error(e, e.getThrowableProxy), request, server)
val notifier =
Notifier("Scala notifier", "0.0.1", "scala")
val environment =
System.getenv.getOrElse("APP_ENV", "development")
val server =
Server(environment, InetAddress.getLocalHost.getHostName)
val request =
Request(null, null, null, Map.empty, Map.empty, null, null)
def error(e: ILoggingEvent, t: IThrowableProxy) =
Error(t.getClassName, e.getMessage + ": " + t.getMessage, t.getStackTraceElementProxyArray.map { e => backtraceElement(e.getStackTraceElement) })
def backtraceElement(e: StackTraceElement) =
BacktraceElement(e.getLineNumber.toString, e.getFileName, e.getMethodName)
}
object HoneybadgerAppender {
case class Notice(notifier: Notifier, error: Error, request: Request, server: Server)
case class Request(url: String, component: String, action: String, params: Map[String, String], session: Map[String, String], cgi_data: Map[String, String], context: Map[String, String])
case class Notifier(name: String, version: String, language: String)
case class Server(environment_name: String, hostname: String)
case class Error(`class`: String, message: String, backtrace: Seq[BacktraceElement])
case class BacktraceElement(number: String, file: String, method: String)
}
<configuration>
<appender name="HONEYBADGER" class="utils.HoneybadgerAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<apiKey>111111111111</apiKey>
<enabledEnvironments>production,staging</enabledEnvironments>
</appender>
<root level="INFO">
<appender-ref ref="HONEYBADGER" />
</root>
</configuration>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment