Archive for the ‘Systemmonitoring’ Category

h1

NetApp Monitoring in neuem Blog

31. Oktober 2009

Zu dem Thema Monitoring von NetApp Speichergeräten schreibe ich ab sofort in einem eigenen Blog weiter …

blog.netapp-monitoring.info

h1

Debugging Nagios Plugins

9. Juni 2009

Heute war Debugging-Tag für die NetApp-Plugins für Nagios. Am meisten Probleme bereitete mir mein Ehrgeiz sie im ePN (Embedded Perlinterpreter for Nagios) laufen zu lassen. Bei einer Kundeninstallation wurden die Performancedaten nicht mehr verarbeitet, wenn das Script im ePN läuft – ein Fehler den ich bisher nicht nachvollziehen konnte, ich tippe hier auf eine fehlenden Kennzeichnung  (#nagios: -epn) im performance-Parser. Aber wer weiss …

Der andere Fehler waren einige Scripts, die sich im Nagios mit „Service check did not exit properly“ meldeten, während sie auf der Commandline problemlos liefen. Zunächst einmal drehte ich das Debugging im Nagios auf, indem ich in der nagios.cfg diese Werte setzte:

debug_level=16
debug_verbosity=1
debug_file=/usr/local/nagios/var/nagios.debug

Somit bekam ich dan schon alle Infos frei Haus geliefert, um die Fehler einzugrenzen. Z.B.
Embedded Perl failed to compile /usr/local/nagios/libexec/check_netapp_hardware.pl, compile error **ePN failed to compile /usr/local/nagios/libexec/check_netapp_hardware.pl: „Variable „$object“ will not stay shared at (eval 3969) line 240,“ at /usr/local/nagios/bin/p1.pl line 248.
– skipping plugin

Bei der Nachsicht in dem Plugin entdeckte ich, dass in einer Subroutine auf die mit my im Hauptprogramm definierte Variable (eben jene $object) zugegriffen wurde, was nicht 100%-ig sauber ist. Nach einer Änderung auf local our $object; lief das Plugin durch, bis zum nächsten Fehler, der dann sinngemäß gleich zu beheben war.

Anschliessend bekam ich dann noch die Meldung Check of service ‚CPU-Utilization‘ on host ’simbig‘ could not be performed due to a fork() error: ‚Cannot allocate memory‘! bzw. etwas ähnliches mit „too many open files“ was sich aber durch einen Neustart von Nagios beheben ließ.

Interessant auch, dass es schon ein Reihe von Wrapper-Scripts für Plugins gibt; die Folgenden habe ich gefunden aber sie für diese Debugging-Session dann gar nicht benötigt:

http://www.nagios.org/faqs/viewfaq.php?faq_id=379

http://www.waggy.at/nagios/capture_plugin.htm

h1

Nagios: Monitoring the lag-time of SnapMirrors on NetAppFiler

5. Mai 2009

I just finished a new version of check_netapp_snapmirror. You can use it to monitor the lag-time of several or all snap mirrors on a netapp-filer.

Some examples:

$ check_netapp_snapmirror.pl -H toaster -u nagios%pass
Checks the lag-time of all snampmirror-sources on toaster with the default-thresholds.

$ check_netapp_snapmirror.pl -H netapp11 -u nagios%pass -X netapp11:vol4
Checks the lag-time of all snapmirror-sources on netapp11 with the exception of vol4 using the default-thresholds.

$ check_netapp_snapmirror.pl -H netapp11 -u nagios%pass -X netapp11:vol2 -X netapp11:vol4 -w 120 -c 240
Checks the lag-time of all snapmirror-sources on netapp11 with the exception of vol2 and vol4 – thresholds are set to 120 and 240 sec.

$ check_netapp_snapmirror.pl -H toaster -u nagios%pass -l vo1 -e pair_state –ok_pairstate=snapmirrored –ok_pairstate=uninitialized –w_pairstate=source
Checks vol1, ok if state is either snapmirrored or uninitialized, warning if source.

$ check_netapp_snapmirror.pl -H toaster -u nagios%pass -e last_transfer_duration -w 360 -c 1800
Checks the last-transfer-duration of all snampmirror-sources on toaster. Warning if more than 5 minutes (360s) and critical if more than 1 hour (1800s).
http://ingo.lantschner.name/NetappNagiosPlugins.html

h1

Nagios-Plugins für NetApp: Usage und Beispiele online

20. Februar 2009

Ich habe heute die Seite mit den Nagios-Plugins für NetApp-Filer wesentlich erweitert und übsichtlicher gestaltet. Die Daten dazu werden per Perlscript drirekt aus dem git gezogen und sind somit leicht und präzise aktulell zu halten.

Um die Beispiele und Usage unabhängig vom Browser und der Fenstergröße auf einen Blick erfassbar zu machen, war es wichtig, dass keine unerwünschten Zeilenumbrüche gemacht werden. Dabei hat sich das via regex eingesetzte <nobr>-Attribut als sehr hilfreich erwiesen. Die subroutine lautet:

sub nobr {
    # hält die Bereiche der Parameter (-H host, --help, ...) zusammen
    s/\[?\-+\w+[\ = \]]\S*/<nobr>$&<\/nobr>/g;
}

Link http://ingo.lantschner.name/NetappNagiosPlugins.html

h1

Nagios-Plugins für NetApp verfügbar

13. Februar 2009

Seit heute kann man sich über die von mir erstelle Suite an Nagios-Plugins für NetApp Speichergeräte (Filer) auf meiner Homepage informieren.

Diese Plugins wurden auf Basis der NetApp-API (Manage ONTAP SDK) erstellt, holen ihre Daten über HTTP und sind daher auch mit zukünftigen Versionen von DATA ONTAP kompatibel.

Für weitere Informationen

http://ingo.lantschner.name/NetappNagiosPlugins.html

h1

Mehrsprachige Perlscripte

30. Juni 2008

Ein Perlscript, wie z.B. ein Plugin für Nagios zu schreiben, das in mehreren Sprachen seine Meldungen ausgibt, ist an sich einfach. Nur die Doku dazu ist eher mager und zu allererst steht man vor dem Problem, welches Modul man denn dafür am besten nehmen soll. Ich entschied mich dann für Locale::TextDomain – eine high-level Schnittstelle zu anderen Modulen.

Folgend ein kleines Beispiel:

#!/usr/bin/perl -w
use strict;
use warnings;
use lib "/opt/local/lib/perl5/site_perl/5.8.8";  # plattformspezifische Zeile
use Locale::TextDomain "en"; #  "./LocaleXData";
## einfaches Beispiel
my $translated = __"Hallo Welt!";
print "$translated\n";
## Anhängen eines Zeilenumbruchs (der zu übersetzende String muss in Klammern!)
print __("Mir geht's gut.") . "\n";
# Schön ist, dass man auch Umlaute verwenden kann -
# bei der Erstellung der po-Datei mit xgettext
# --out-format=UTF-8 angeben!
print __("Täglicher Unsinn mit scharfem ß.") . "\n";
## Variablen können auch übersetzt werden
my $msg = "Hallo Welt!";
print __$msg;
print "\n";
my $world = "Welt!";
print __"Hallo $world";
print "\n";

Dieses Script gibt folgende Ausgabe aus, wenn man ein paar Vorbereitungen getroffen hat:

$ export LANG=de_AT
$ ./world2.pl
Hallo Welt!
Mir geht's gut.
Täglicher Unsinn mit scharfem ß.
Hallo Welt!
Hallo Welt!

So und nun schalten wir auf English um:

$ export LANG=en_US
$ ./world2.pl
Hello World!
Mir geht's gut.
Daily nonsens with non-ASCII
Hello World!
Hello World!

Es wurden also die Texte „Hallo Welt!“ und „Täglicher Unsinn …“ übersetzt – letzterer etwas eigenwillig. Für „Mir geht’s gut.“ gabe s keine vor bereitet Übersetzung – daher wurde der deutsche Originaltext ausgegeben.

Die nötigen Vorarbeiten für dieses kleine „Wunder“ waren der Reihe nach:

  1. Installation von Locale::Textdomain mit cpan
  2. Anlegen eines Unterverzeichnisses LocaleData im Arbeitsverzeichnis des Scripts. Heisst das Verzeichnis anders, oder liegt es nicht in einem der @INC-Pfade muss es dediziert angegeben werden:
  3. use Locale::TextDomain "en",  "./mylocales";
  4. Export der zu übersetzenden Strings mit xgettext in ein po-File
  5. Übersetzeung dieser Strings (mit einem Editor) – der Text „Mir geht’s gut“ wurde dabei ausgelassen.
  6. Umwandlung des po in ein mo-File (binär) mittels msgfmt. Dieses ist exakt mit diesem Namen und Pfad LocaleData/<locale_name>/LC_MESSAGES/<localename>.mo abzulegen. Der locale-Name kommt also sowohl im Verzeichnis unterhalb von LocaleData als auch im Namen der Datei vor! Es kann allerdings auch en für en_US usw. verwendet werden.
  7. Im Script dann das Locale referenzieren. (Will man mehrere refrerenzieren, muss man das mit einer if-Abfrage machen.)

ABER: So ganz komplett ist die Sache nicht, denn vor allem die Mischung aus Fixtext und Variablen kann man man so nicht sauber übersetzen. Wie das nun geht sieht man am besten in diesem Beispiel:

#!/usr/bin/perl -w

use strict;
use warnings;

use lib "/opt/local/lib/perl5/site_perl/5.8.8";  # plattformspezifische Zeile
use Locale::TextDomain "en"; #  "./LocaleXData";

## einfaches Beispiel

my $translated = __"Hallo Welt!";
print "$translated\n";

## Anhängen eines Zeilenumbruchs (der zu übersetzende String muss in Klammern!)

print __("Mir geht's gut.") . "\n";

# Schön ist, dass man auch Umlaute verwenden kann - 
# bei der Erstellung der po-Datei mit xgettext 
# --out-format=UTF-8 angeben!
print __("Täglicher Unsinn mit scharfem ß.") . "\n";

## Variablen können auch übersetzt werden

my $msg = "Hallo Welt!";
print __$msg;
print "\n";

# Schwieriger wird es bei Variablen, die gemeinsam mit Fixtext ausgegeben
# werden sollen. Das folgende Beispiel funktioniert mehr oder weniger zufällig,
# und nur hier, da "Hallo Welt!" oben schon übersetzt wurde. Aber xgettext 
# würde sich dagegen sträuben ("world2.pl:37: ungültige Interpolation einer 
# Variablen bei »$«") 
my $world = "Welt!";
#print __"Hallo $world";  # muss für parsing mit xgettext auskomentiert werden
						  # danach könnte man es wieder aktivieren - Perl käme damit zurecht
						  # aber Lösung ist das natürlich keine ...
print "\n";

# Richtig ist die Mischung von Fixtext und Variablen so:
print __x ("Hallo {person}!\n",
	person => "Franz");

Dieses Script kann man nun so parsen:

$ xgettext world3.pl --from-code=UTF-8 --keyword=__ --keyword=__x

Und bekommt dann ein po-file, das man so übersetzt:

#: world3.pl:12
msgid "Hallo Welt!"
msgstr "Hello World!"

#: world3.pl:18
msgid "Mir geht's gut."
msgstr "I am fine."

#: world3.pl:23
msgid "Täglicher Unsinn mit scharfem ß."
msgstr "Daily nonsens with non-ASCII."

#: world3.pl:44
#, perl-brace-format
msgid "Hallo {person}!\n"
msgstr "Hello {person}!\n"

Und es dann ganz einfach in ein mo umwandelt und dieses wie oben schon beschrieben ablegt.

Und Die Ausgabe schaut dann so aus:

$ ./world3.pl 
Hallo Welt!
Mir geht's gut.
Täglicher Unsinn mit scharfem ß.
Hallo Welt!

Hallo Franz!

$ export LANG=en_US

$ ./world3.pl 
Hello World!
I am fine.
Daily nonsens with non-ASCII.
Hello World!

Hello Franz!
h1

SEO-Monitoring 3: Daten auswerten

27. Februar 2008

Wie in „SEO-Monitoring 2: Daten holen“ beschrieben, erhalten wir mit dem Skript get_google.pl jeden Tag ein neues Verzeichnis, in dem die Suchergebnisse als HTML-Files angelegt sind. Ein Vorteil des modularen Ansatzes (One task one tool) ist, dass es keineswegs nötig ist diese Verzeichnisstruktur mit dem Skript aufzubauen und zu befüllen. Genausogut kann man das manuell mit dem Browser machen, und die Seiten mit „Speichern als …“ als HTML-File ablegen. Das Skript get_google.pl macht ja nichts anderes, als einen „geskripteten“ Browser zur Verfügung zu stellen.

Results von get_google.pl (kleiner Ausschnitt)

In dem Bild oben sehen wir einen Ausschnitt aus dem Ergebnis von get_google.pl bei der Suche nach irgendwas in 1030 Wien um 9h05. Somit sind die Suchergebnisse für einen bestimmten Zeitpunkt und Begriff einmal vollständig archiviert, nur die Übersicht hat man so natürlich nicht … Daher ein weiteres Skript, das diese Verzeichnisse und alle Dateien systematisch durchsucht und daraus ein CSV-File (Kommaseperierte Datei) generiert. Dieses CSV-Ausgabefile soll z.B. aussehen wie folgt:

"Zeit[Epochenekunden]","Datum","Uhrzeit","Suchbegriff(e)","tad-position","ad-position","s-position","Anz. der Vorkommen in den S.E.",
"1204013102","2008-02-26","09h05","foo","0","1","11","2",
"1204013102","2008-02-26","09h05","bar","0","1","3","4",
"1204013102","2008-02-26","09h05","foo+bar","0","0","1","2",

So was sehen wir da oben nun: Zu dem Suchbegriff „foo“ wurde am 26. Februar um 9h05 eine bestimmte URL in den Google-Ergebnissen an der 11 Position angezeigt. In den Anzeigen (AdWords) war diese URL im rechten Block an 1. Stelle und im oberen Block gar nicht gelistet. In den ersten 100 Ergebnissen (ohne AdWords-Bereich), war diese URL 2 mal gelistet. Das alles entnehmen wir der ersten Zeile nach den Spaltenüberschriften (zweite Zeile im o.g. Ausschnitt).

Das bei Eingabe des Suchwortes „bar“ wird diese URL in den AdWords-Anzeigen oben nicht, auf der rechten Seite an erster Position und in den Suchergebnissen an 3. Stelle gelistet. Insgesamt ist diese URL 4 mal in den ersten 100 Ergebnissen zu finden. Das entnehmen wir der zweiten Zeile nach den Spaltenüberschriften (dritte Zeile im Beispiel oben).

Und nun die letzte Zeile: Hier wurde nach „foo bar“ gesucht. Die URL taucht in den Anzeigen gar nicht auf, dafür in den Suchergebnissen an erster Stelle und das zwei mal.

Dieses Beispiel ist übrigens fiktiv! Wenn jetzt wer verwundert innehält und frägt, was daran jetzt übersichtlich sein soll, sag ich – nur Geduld, denn eine CSV-Datei ist eine hervorragende Kandidatin für den Import in die unterschiedlichsten Anwendungen zur weiteren Verarbeitung.

Und damit zu dem Skript. Dieses benötig klarerweise einige Angaben: Nach welchen URLs in den Suchergebnissen gesucht werden soll; wo diese Suchergebnisse zu finden sind und wohin das CSV-File zu schreiben ist. Das meiste davon habe ich in dem Beispielskript fest kodiert – lediglich welches Unterverzeichnis in den Ergbnissen durchsucht werden soll wird beim Aufruf mitgegeben.

Damit das Skript ordentlich arbeiten kann, müssen beim Ablegen der Suchergebnisse als HTML-Files einige Konventionen eingehalten werden:

  • Das Basisverzeichnis für alle nun folgenden Verzeichnisse ist mit der Variable $basedir anzugeben. Es empfielt sich hier einen absoluten Pfad wie „/Users/Ingo/…./SEO-Monitor“ einzusetzen, wenn man das ganze mit einem Scheduler starten will.
  • In dem über die Variable $htmldir definierten Verzeichnis wird je befragtem Server ein eigenes Verzsichnis angelegt, z.B. http://www.google.ch. Je Tag ist ein eigenes Unterverzeichnis anzulegen im Format yyy-mm-dd.
  • Je Abfrage sind alle Ergebnisseiten zu benamsen wie folgt: Epochensekunden_Uhrzeit_Suchbegriffe_SSeite.html. Also z.B. sind die Ergebnisse 11-20 (zweite Seite) einer Suche nach „foo bar“ am 27 Februar 2008 um 15h55 auf google.at in dieser Datei abzulegen: /Users/Ingo/…/SEO-Monitor/google-results/www.google.at/2008-02-27/1204124118_15h55_foo+bar_S2.html

Aus dieser Datei bzw. ihrem Namen werden nun einige Informationen extrahiert: Die Zeit beispielsweise und die Seitennummer aber auch der Suchbegriff und der befragte Google-Server. Sehr wichtig ist die Kombination aus Zeit (Epochensekunden) und Suchbegriffen – diese definieren gemeinsam den Filegroupindex, legen also fest, welche Dateien zu einem bestimmten Suchbegriff und Zeitpunkt angelegt wurden. Alle Ergebnisse einer Filegroup werden dann in einer Zeile der ausgegeben CSV zusammengefasst!

Beispiel: Diese Dateien gehören zu ein und der selben Filegroup die den Namen „1204124118_foo+bar“ trägt:

1204124118_15h55_foo+bar_S1.html
1204124118_15h55_foo+bar_S2.html
….
1204124118_15h55_foo+bar_S100.html

Je wie oft nun die gesuchten URLs in den Suchergebnissen vorkommen, findet sich dann in einer Zeile des ausgegeben CSV-Files.

Das Skript durchsucht in seinem Hauptteil nun Token für Token jeder Datei. zunächst wird der Suchbegriff extrahiert. (Dieser ist zwar auch im Dateinamen zu finden, aber wir nehmen lieber den aus der Datei). Dann wird gesucht:

  • Auf Seite 1:
  • Anzeigen rechts, hier gibt es das Tag „<a id=an1, …“ – das ist praktisch, denn die Nummer gibt die Position wieder. Ablegen in einen Hash (%ad_pos) mit dem Filegroupindex als Schlüssel.
  • Anzeigen oben, hier gibt es das Tag „<a id=pa1, …“ – siehe oben. Ablegen in einen Hash (%tad_pos) mit dem Filegroupindex als Schlüssel.
  • Auch wenn es unwahrscheinlich ist, dass die selbe URL in den Anzeigen auf Seite 1 mehrfach vorkommt, so wird doch vom Skript sichergestellt, dass die jeweils beste Position erhalten bleibt.
  • Auf Seite 1 und allen folgenden Seiten
    • Die Tags der Suchergebnisse; wenn href und class=l, dann in diesem Tag nach den URLs suchen; das jeweils beste Position wird in einen Hash (%s_pos) mit dem Filegroupindex als Schlüssel abgelegt.

    Es werden also Anzeigen auf den Seiten 2-100 ignoriert – das entspricht aber dem normalen Userverhalten – wer schaut schon auf Seite 2 auf eine Anzeige?!

Sonst ist noch anzumerken, dass natürlich mehrere URLs gesucht werden können, z.B. apartments-wien.at und apartments-vienna.at – die jeweils beste Position wird in der Ausgabe angezeigt. Das ist sinnvoll, da so manche Organisation ja den selben Webauftritt unter verschiedenen URLs anbietet.

Am Ende des Skriptes wird dann ermittelt, welche Dateigruppen es gab – diese landen in einem Array namens @uFGIs (uniq FileGroupIndices). Dessen Elemente werden dann der Reihe nach in die Hashes %ad_pos usw. eingesetzt und so das CSV-File geschrieben.

That’s it. Zur Auswertung dieses CSVs dann wann anders.

P.S. Ja der Quellcode, den veröffentliche ich demnächst hier:

http://ingo.lantschner.name/Nagios.html