Bei meiner Arbeit haben wir einen lang laufenden Dienst, der den Akka-Spray-Stack verwendet. Kürzlich stürzte er ab und wir wollten sein Logfile überprüfen, um einen Hinweis auf die Ursache zu finden. Aber dort war nichts zu finden, was uns weiterhelfen konnte.
Schließlich fanden wir die Ursache, es war ein OutOfMemoryError, der in einem der Akteure ausgelöst wurde, und da dieser nirgendwo abgefangen wurde (und das sollte er auch nicht), beendete er das gesamte Akteurssystem.
Es hätte uns einige Zeit erspart, wenn dieser Fehler irgendwo protokolliert worden wäre, und darum geht es in diesem Blog.
System.err
Jede Ausnahme oder jeder Fehler wird automatisch in System.err geschrieben. System.err schreibt in den Standard-Outputstream des Prozesses, der normalerweise die Konsole ist. Ich möchte dies für unseren Server ändern und leite System.err beim Start des Servers in einen eigenen, benutzerdefinierten Ausgabestrom namens LoggingOutputStream um, etwa so:
[code language="scala"]
import org.apache.log4j.{Level, Logger}
System.setErr(new PrintStream(new LoggingOutputStream(Logger.getRootLogger, Level.ERROR), true))
[/code]
Der LoggingOutputStream schreibt alles, was normalerweise in System.err landen würde, stattdessen in den RootLogger von log4j, und zwar mit dem Log-Level ERROR.
Jetzt fehlt nur noch die Implementierung unseres LoggingOutputStream:
[code language="scala"]
import java.io.{IOException, OutputStream}
import org.apache.log4j.{Priorität, Kategorie}
class LoggingOutputStream(category: Category, priority: Priority) extends OutputStream {
private val LINE_SEPARATOR = System.getProperty("line.separator")
private var geschlossen = false
private var buffer = new Array[Byte](2048)
private var count = 0
override def close() {
flush()
geschlossen = true
}
@throws(classOf[IOException])
override def write(b: Int) {
if (geschlossen) {
throw new IOException("Der Stream wurde geschlossen!")
}
wenn (b == 0) {
return
}
if (count == buffer.length) {
// Der Puffer ist voll; vergrößern Sie ihn
val newBuffer = new Array[Byte](2 * buffer.length)
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length)
Puffer = newBuffer
}
buffer(count) = b.toByte
Anzahl += 1
}
override def flush() {
wenn (Anzahl == 0) {
return
}
// Geben Sie keine Leerzeilen aus; beim Spülen aus PrintStream werden diese ausgegeben.
if (!isBlankLine) category.log(priority, new String(buffer.slice(0, count)))
zurücksetzen()
}
private def isBlankLine = (count == LINE_SEPARATOR.length) &&
((buffer(0).toChar == LINE_SEPARATOR.charAt(0) && count == 1)
|| (buffer(1).toChar == LINE_SEPARATOR.charAt(1)) && count == 2)
private def reset() {
Anzahl = 0
}
}
[/code]
Natürlich ist diese Lösung nicht spezifisch für Akka, sie funktioniert in jeder Scala-Anwendung.
Verfasst von
Cristiana
Some bio goes here
Unsere Ideen
Weitere Blogs
Contact
Let’s discuss how we can support your journey.



