Ich möchte ein kleines, praktisches Ruby-Skript vorstellen, mit dessen Hilfe man einen kurzen Überblick über die zeitliche Verteilung von Exceptions in Errbit generieren kann.
Daten aus MongoDB extrahieren
Zunächst muss die Nomenklatur geklärt werden. :) Eine Exception wird in der
darunterliegenden MongoDB-Collection problems
gespeichert, zusätzliche
Informationen dazu in der Collection errs
und jedes Auftreten resultiert in
einem Eintrag in der Collection notices
.
Aus der Errbit-URL zu einem Problem (beispielsweise
https://errbit.example.com/apps/5122466fd9d1af0dab004ca6/problems/551cea21d9d1af2ab600013e
)
kann nun die problem_id
aus der URL entnommen werden (der Teil nach
problems/
). Um an die notices
zu gelangen, suchen wir zunächst nach der
err_id
auf der mongo
-Konsole:
var problemId = '551cea21d9d1af2ab600013e';
var errId = db.errs.findOne({problem_id: ObjectId(problemId)})['_id'];
Damit besorgen wir uns von allen zugehörigen notices
den Zeitstempel der
Erstellung. Wir möchten im Ergebnis daher pro Eintrag nur das
created_at
-Feld haben,
der Rest interessiert uns nicht.
var notices = db.notices.find({err_id: errId}, {"created_at": 1});
Um nun das Ganze tageweise zu gruppieren, kann man
db.collection.group()
verwenden. Dazu benötigen wir zwei Funktionen, eine stellt pro Dokument in der
Collection einen Schlüssel zum Gruppieren bereit, das ist in unserem Fall das
Datum:
var keyFunction = function(notice) {
var date = new Date(notice.created_at);
var dateKey = (date.getDate() + "." + (date.getMonth()+1) + "."
+ date.getFullYear() + '');
return {day: dateKey};
};
Die zweite Funktion ist denkbar einfach, sie summiert pro key einfach immer auf:
var reduceFunction = function(obj, result) {
result.count++;
};
Damit können wir nun gruppieren:
db.notices.group(
{
keyf: keyFunction,
cond: { err_id: errId },
initial: { count:0 },
reduce: reduceFunction
});
Ein beispielhafter Output sieht dann so aus:
[
{ "day" : "16.4.2015", "count" : 1 }
]
Abfrage per Ruby-Skript
Nachdem ich das Ganze gerne komfortabel aus meiner Unix-Shell abfragen möchte, habe ich dazu ein kleines Ruby-Skript geschrieben, um diesen Prozess zu beschleunigen. Ich verwende hierzu das net-ssh Gem, um mich auf dem Rechner mit der Errbit-Installation einzuloggen und den Port des MongoDB-Servers an meinen Client weiterzuleiten, da in meinem Fall ein direkter Zugriff auf MongoDB von außen nicht erlaubt ist. Der Zugriff auf die Datenbank erfolgt mittels mongo.
#!/usr/bin/env ruby
require 'mongo'
require 'net/ssh/gateway'
require 'date'
include Mongo
gateway = Net::SSH::Gateway.new('errbit.example.com', 'mein_user_name')
gateway.open '127.0.0.1', 27_017, 27_017
db = MongoClient.new('localhost', 27_017).db('errbit')
err_id = db.collection('errs')
.find_one(problem_id: BSON::ObjectId(ARGV.first))['_id']
reduce_function =<<-END
function(obj, result) { result.count++; }
END
key_function = <<-END
function(notice) {
var date = new Date(notice.created_at);
var dateKey = (date.getDate()+"."+(date.getMonth()+1)+"."+date.getFullYear()+'');
return { 'day':dateKey };
}
END
res = db.collection('notices').group(
keyf: key_function,
cond: { err_id: err_id },
initial: { count: 0 },
reduce: reduce_function
)
res.each do |item|
item['count'] = item['count'].to_i
item['day'] = Date.parse item['day']
end.sort! { |x, y| x['day'] <=> y['day'] }
res.each { |item| puts "#{item['day']}: #{item['count']}" }
Damit erhält man eine GnuPlot-kompatible Ausgabe, die man dann auch noch hübsch graphisch auftragen kann:
~ $ ./errbit_stat.rb 551cea21d9d1af2ab600013e
2015-04-02: 5
2015-04-08: 2
2015-04-09: 277
2015-04-10: 536
2015-04-11: 454
2015-04-12: 560
2015-04-13: 715
2015-04-14: 428
2015-04-15: 440
2015-04-16: 648
2015-04-17: 462
2015-04-18: 303
2015-04-19: 1250
2015-04-20: 1124
2015-04-21: 487
2015-04-22: 316
2015-04-23: 154
2015-04-24: 114
2015-04-25: 112
2015-04-26: 126
2015-04-27: 89
Plotten mit Gnuplot
Zunächst leiten wir die Ausgabe des Ruby-Skripts in eine Textdatei um, die wir anschließend als Datengrundlage für GnuPlot verwenden:
~ $ ./errbit_stat.rb 551cea21d9d1af2ab600013e > 551cea21d9d1af2ab600013e.dat
Ein einfaches GnuPlot-Skript, das auf die Ordinate das Datum und auf die Abszisse die Anzahl der Fehler aufträgt kann z.B. so aussehen:
set title 'Häufigkeit der Exception FooException'
set term png
set output 'foo_exception_plot.png'
set xdata time
set timefmt '%Y-%m-%d'
set xlabel 'Datum'
set ylabel 'Häufigkeit'
set autoscale y
plot '551cea21d9d1af2ab600013e.dat' using 1:2 with linespoints