.st0{fill:#FFFFFF;}

checkMK

Tutorial: Debuggen von CheckMK-Checks

 Juni 1, 2020

By  Simon Meggle

Das Debuggen von CheckMK-Checks hat mich schon viele graue Haare gekostet. Inzwischen habe ich mir für unterschiedliche Situationen Techniken angeeignet, die ich mit Dir teilen möchte. Damit wenigstens Deine Haare noch länger ihre Farbe behalten...

More...

Weil mir die Idee zu diesem Artikel kam, während ich den RobotMK-Check programmiere, taucht dieser auch in den meisten Codebeispielen auf. Natürlich sind die hier vorgestellten Techniken auf alle Checks anwendbar! Steigen wir also direkt ein.

TL;DR

Am Ende dieses Posts weißt Du

Zwei Wege, wie Du CheckMK-Checks nicht debuggen solltest

na(t)ive Ausführung des Checks

Diese blutige Nase holt sich sicher jeder mal, der CheckMK auf der Kommandozeile erkundet:

OMD[cmk]:~/share/check_mk/checks$ python multipath
Traceback (most recent call last):
File "multipath", line 375, in <module>
'group': "multipath",
NameError: name 'check_info' is not defined

Die native Ausführung des CHecks als Python-Script fährt direkt gegen die Wand.

Aber... Warum ist das eigentlich so?

Ein kleiner Exkurs.

(Wenn Du schon CheckMK-fit bist, lies weiter bei "Frickelei mit main()".

Wer Nagios kennt und sich das Check-Verzeichnis von CheckMK ansieht (~/share/check_mk/checks, bzw. das gleiche unterhalb von ~/local für selbstgeschriebene Checks), könnte auf die Idee kommen, dass hier die "Plugins" liegen - also eben jene Scripte, die Nagios periodisch ausführt, um irgend etwas zu prüfen und das Ergebnis darüber zu bekommen.

Nagios-Plugins sind immer für Datenerhebung und Auswertung verantwortlich; in ihnen entscheidet sich, ob das, was geprüft wurde, OK, WARNING oder CRITICAL ist. Betrachten wir ein Nagios-Plugin als eine kleine Blackbox: abhängig davon, was wir reingeben (Zielhost, Thresholds und weitere Parameter), liefert es ein entsprechendes Ergebniss. Input - Output.

Die Scripte, die wir in CheckMK unterhalb der checks-Verzeichnisse finden, heißen deswegen "Checks", weil sie nur für die Auswertung der Monitoring-Daten verantwortlich sind. Erhoben wurden die Daten bereits in den Agenten, die auf den Hosts installiert sind.

Was so ein Agent nach seinem Aufruf in CheckMK reinkippt, ist bei bloßer Betrachtung ein richtiges Durcheinander, nämlich ein ellenlanges Textsnippet mit je einem Abschnitt pro Check-Typ und dazwischen Daten. Kostprobe gefällig?

telnet foohost 6556
...
...
<<<tcp_conn_stats>>>
01 13
0A 27
06 3
<<<diskstat>>>
1590958578
8 0 sda 2356123 248021 142890654 598776 1728548 1419646 87541101 5413436 0 755282 6011728
8 1 sda1 226 167 5519 44 1 0 1 0 0 32 44
8 2 sda2 443 0 47564 189 28 0 4257 43 0 200 232
8 3 sda3 2355384 247854 142833291 598529 1652880 1419646 87536843 5334686 0 709185 5932716
253 0 dm-0 886774 0 35962342 183162 997154 0 22444569 6531899 0 366289 6715582
253 1 dm-1 853331 0 6830352 138971 1246280 0 9970240 13460441 0 67739 13611117
253 2 dm-2 865651 0 100037381 338000 829774 0 55122034 3627502 0 343929 3965586
[dmsetup_info]
<<<kernel>>>
1590958578
nr_free_pages 61219
nr_alloc_batch 3864

Und wer soll das jetzt verstehen?

Ganz einfach: das erledigen für uns die "Checks" auf dem CheckMK-Server. Jeder Check versteht genau den Kauderwelsch in "seinem" Abschnitt. Für einen Agenten-Output mit bspw. 18 Abschnitten sind also auch 18 verschiedene Checks zuständig.

Die Checks nun jeweils einzeln zu starten/zu parametrisieren, wäre natürlich die Performance-Hölle. CheckMK liest stattdessen bereits beim Start alle verfügbaren Checks in seinen Speicher. Genauer gesagt: es erweitert seinen eigenen Python-Code mit dem Code der Checks, indem es diesen jeweils als Modul einbindet. Wie viele das sind, variiert je nach CheckMK-Version - bei einer 1.6.9 sind es über 1.700 Checks:

OMD[cmk]:~/share/check_mk/checks$ cmk -L | wc -l
1774

Über den Abschnittsnamen im Agenten-Output kann CheckMK also ins richtige Check-Modul springen und diesem die Daten im Abschnitt zur Auswertung übergeben.

Allerdings sind die Agenten-Abschnitts-Daten nicht das einzige, was der Check bekommt. Ebenfalls zur Laufzeit muss der Check wissen, ob WATO-Regeln für diesen Host bzw. für diesen Service existieren. Die beeinflussen ggf. die Schwellwerte.

So viel also vorab zum Verständnis für Dich, warum Du CheckMK-Checks nicht direkt auf der Bash bzw. mit dem Python-Interpreter ausführen kannst: es fehlt der Kontext in Form von Agenten-Daten und ggf. WATO-Regeln (in Wirklichkeit ist es etwas komplexer, aber das soll für hier genügen).

Frickelei mit __main__()

Nun könnte man auf die Idee kommen, all das einfach zu faken, was CheckMK zur Laufzeit dem Check übergibt und dann händisch (!) die Funktionen für Inventory und Check aufzurufen. Praktisch an dieser Methode ist vielleicht noch, dass man relativ offen mit den Testdaten hantieren kann. Der folgende Codeblock wird Dir dennoch, solltest Du ihn vervollständigen und benutzen, körperliche Schmerzen bereiten. Lass es und lies ganz schnell weiter. 🙂

if __name__ == "__main__": 
global check_info
check_info = {}

check_info['robotmk'] = {
"parse_function": parse_robot,
"inventory_function": inventory_robot,
"check_function": check_robot,
"service_description": "Robot",
"group": "robotmk",
"has_perfdata": True
}

if __name__ == "__main__":
# eigene Variablen...
# Setzen globaler CMK-Variablen, Einlesen eigener Testdaten...
global inventory_robotmk_rules
inventory_robotmk_rules = ast.literal_eval(
open('test/fixtures/inventory_robotmk_rules/discovery_slvel_%d.py' % debugset['discovery_level']).read())
# Faken der Agenten-Daten
testdaten = 'test/fixtures/robot/%s/output.json' % debugset['suite']
mk_output = ast.literal_eval(open(datafile, 'r').read())
# PARSE
parsed = parse_robot(mk_output)
# INVENTORY
  inventory = inventory_robot(parsed)
# CHECK
state, msg, perfdata = check_robot("1S 3S 2S 3T", checkgroup_parameters, parsed)
print "ENDE---"

CheckMK-Check als Script debuggen

Pro

  • keine weiteren Tools notwendig  

Contra

  • Check arbeitet ohne MK-Kontext
  • Faken aller Laufzeitdaten, Gefahr von Falschannahmen
  • Eingriff in den Code

Tipp:

Einen CheckMK-Check mit main() zu einem Script zu vergewaltigen, ist Frickelei. Um es debuggen zu können, muss der CheckMK-Kontext (Agenten-Daten, Regelsätze) gefaked werden. 


Brot und Butter: debuggen mit "cmk" und "print"

Wir gehen jetzt eine Stufe nach oben auf der Debugging-Leiter.

Innerhalb der OMD-Instanz gibt es das CheckMK-Kommandozeilentool cmk (vollständige Doku: hier). Der Befehl erlaubt es unter anderem, Checks von Hand zu triggern. In diesem Fall geben wir CheckMK also den Befehl, doch bitte den Agenten-Output mit unserem Check zu prüfen. Na bitte, er wird nun also im CheckMK-Kontext ausgeführt :

OMD[cmk]:~$ cmk -nv --checks=robotmk robothost1
Check_MK version 1.6.0p9
+ FETCHING DATA
[agent] Execute data source
[piggyback] Execute data source
No piggyback files for 'robothost1'. Skip processing.
No piggyback files for '127.0.0.1'. Skip processing.
Robot 1S 3S 2S 3T OK - [S] '1S 3S 2S 3T': PASS (7.69s), OK:
OK - [agent] Version: 1.6.0p9, OS: linux, execution time 0.3 sec | execution_time=0.329 user_time=0.020 system_time=0.000 children_user_time=0.000 children_system_time=0.000 cmk_time_agent=0.317

Die Parameter im Einzelnen:

  • -n - Ohne diesen Schalter würde das Ergebnis dieses Check auch ins Monitoring-System durchschlagen. -n sorgt dafür, dass uns die Ausgabe nur angezeigt wird. Nutze diesen Schalter, wenn Du auf einem Produktiv-System debuggst.
  • --checks - Name des Checks, den wir debuggen möchten (Checkname: siehe cmk -L)
  • robothost1 - Name eines Hosts, der im Monitoring-System angelegt sein muss

Zum Test baue ich in meinen Check einen Fehler ein:

print "ups ein" fehler

Hier hilft mir die Ausgabe von cmk noch nicht weiter:

OMD[cmk]:~$ cmk -nv --checks=robotmk robothost1
Error in plugin file /omd/sites/cmk/local/share/check_mk/checks/robotmk: invalid syntax (<unknown>, line 27)
Check_MK version 1.6.0p9
Unknown plugin file robotmk
Unknown plugin file robotmk
+ FETCHING DATA
[agent] Execute data source
[piggyback] Execute data source
No piggyback files for 'robothost1'. Skip processing.
No piggyback files for '127.0.0.1'. Skip processing.
OK - [agent] Version: 1.6.0p9, OS: linux, execution time 0.3 sec | execution_time=0.319 user_time=0.010 system_time=0.010 children_user_time=0.000 children_system_time=0.000 cmk_time_agent=0.293

Wir brauchen noch den Schalter --debug - dann sehen wir auch, welche Python-Exception in unserem Check auftritt. Und schon sehen wir ihn samt Stacktrace:

OMD[cmk]:~$ cmk --debug -nv --checks=robotmk robothost1
Error in plugin file /omd/sites/cmk/local/share/check_mk/checks/robotmk: invalid syntax (<unknown>, line 27)
Traceback (most recent call last):
File "/omd/sites/cmk/bin/cmk", line 84, in <module>
config.load_all_checks(check_api.get_check_api_context)
File "/omd/sites/cmk/lib/python/cmk_base/config.py", line 1253, in load_all_checks
load_checks(get_check_api_context, filelist)
File "/omd/sites/cmk/lib/python/cmk_base/config.py", line 1311, in load_checks
load_check_includes(f, check_context)
File "/omd/sites/cmk/lib/python/cmk_base/config.py", line 1422, in load_check_includes
for include_file_name in cached_includes_of_plugin(check_file_path):
File "/omd/sites/cmk/lib/python/cmk_base/config.py", line 1451, in cached_includes_of_plugin
includes = includes_of_plugin(check_file_path)
File "/omd/sites/cmk/lib/python/cmk_base/config.py", line 1519, in includes_of_plugin
tree = ast.parse(open(check_file_path).read())
File "/omd/sites/cmk/lib/python2.7/ast.py", line 37, in parse
return compile(source, filename, mode, PyCF_ONLY_AST)
File "<unknown>", line 27
print "ups ein" fehler
^
SyntaxError: invalid syntax

Jetzt sind wir immerhin schon imstande, mit "print"-Statements z.B. den Inhalt von Variablen anzeigen zu lassen:

myvar = "easy"
print "----> Debugging ist %s" % myvar
OMD[cmk]:~$ cmk --debug -nv --checks=robotmk robothost1
----> Debugging ist easy
Check_MK version 1.6.0p9
+ FETCHING DATA
[agent] Execute data source
[piggyback] Execute data source
No piggyback files for 'robothost1'. Skip processing.
No piggyback files for '127.0.0.1'. Skip processing.
Robot 1S 3S 2S 3T OK - [S] '1S 3S 2S 3T': PASS (7.69s), OK:
OK - [agent] Version: 1.6.0p9, OS: linux, execution time 0.3 sec | execution_time=0.316 user_time=0.020 system_time=0.000 children_user_time=0.000 children_system_time=0.000 cmk_time_agent=0.296

Debuggen mit "cmk"

Pro

  • keine weiteren Tools notwendig  
  • Debugging im MK-Context  

Contra

  • Eingriff in den Code
  • "one-shot"-Debugging mit print ist nur bedingt nützlich und zeitaufwändig

Tipp:

Diesen Weg benutze ich besonders für erste "Smoke Tests", also wenn ich schnell sehen will, ob ein Check funktioniert oder nicht. Er ist eine echte Abkürzung im Gegensatz zum Testen über die Weboberfläche - mehr aber auch nicht. Mit "print" debugged man nicht. Enter Debugger.

Python-Debugger

Puristisch: CheckMK und der Python-Debugger "pdb"

Bevor wir hier einsteigen: Was zeichnet überhaupt einen "Debugger" aus? Debugger schimpft sich, was mir u.a. folgendes erlaubt:

  • den Code Zeile für Zeile ausführen
  • sämtliche Code-Bestandteile (Variablen, Funktionen, Klassen etc.) ansehen und verändern
  • den Code bis zu einem Haltepunkt (Breakpoint) laufen und dann stoppen zu lassen

Python bringt hierzu das Modul pdb mit:

python -m pdb mein_script.py

Und schon sind wir quasi mitten im laufenden Code und können uns alles in Ruhe ansehen.

Stop... den Check im Debugger auszuführen ist nicht die Lösung. Denn auch mit Debugger werden wir am fehlenden Kontext von CheckMK scheitern (siehe oben).

Dankenswerterweise ist das cmk-Kommando ebenfalls ein Python-Script, was es uns erlaubt, den kompletten Aufruf im Debugger zu starten. Alles was wir zuvor benötigen, ist der Pfad, an dem cmk abgelegt ist:

OMD[cmk]:~$ which cmk
~/bin/cmk
OMD[cmk]:~$ python -m pdb bin/cmk --debug -nv --checks=robotmk robothost1
[2] > /opt/omd/sites/cmk/bin/cmk(34)<module>()
-> import os
(Pdb++)

Der Debugger hält cmk nun an der ersten ausführbaren Zeile an und wartet darauf, dass wir mit

  • "n": nächste Zeile ausführen
  • "s": in Funktion hineinspringen 
  • "r": laufen lassen bis zum Aussprungpunkt der aktuellen Routine

durch den Code marschieren.

Noch sind wir aber nicht in unserem Code-Teil und wir kennen die exakte Stelle im Code von cmk nicht, an der die Funktionen in unserem Check ausgeführt werden (und die wollen wir auch nicht suchen).

Deshalb setzen wir im laufenden Debugger einfach einen Breakpoint mit "b" auf die erste ausführbare Zeile (27) unseres Codes. (Achtung, relative Pfade sind nicht erlaubt).

"r" lässt den Debugger dann so lange rennen, bis unser Haltepunkt erreicht ist. Jetzt sind wir mitten in unserem eigenen Code und können ihn schrittweise durchgehen oder auch mit veränderten Daten testen.

"q" beendet den Debugger. "h" bietet eine schnelle Übersicht über die wichtigsten Befehle; das Netz ist voll von Tutorials um den Debugging-Dinosaurier "pdb".

...
# Breakpoint setzen: stoppe in Zeile 27 unseres Checks
(Pdb++) b /omd/sites/cmk/local/share/check_mk/checks/robotmk:27 
(Pdb++) r
[6] > /omd/sites/cmk/local/share/check_mk/checks/robotmk(27)<module>()
-> myvar = "easy" # manuelles Editieren einer Variable
(Pdb++) n
[6] > /omd/sites/cmk/local/share/check_mk/checks/robotmk(28)<module>()
-> print "----> Debugging ist %s" % myvar
(Pdb++) myvar = "not so hard!"
(Pdb++) n
----> Debugging ist not so hard!

Alternativ zum Setzen des Breakpoints zur Laufzeit kann dieser auch im Code verankert werden; der Debugger hält dann automatisch an dieser Stelle an. Die Breakpoints lassen sich ein/auskommentieren und verschieben - das ist wesentlich einfacher, als bei jedem Start des Debuggers erst wieder die Haltepunkte zu setzen.

Achtung: man pfuscht aber im Code herum, und das auch noch zusätzlich im import-Header. Ich habe mir angewöhnt, solche temporären Änderungen immer noch mit einer weiteren Kommentarzeile zu flaggen, damit ich am Ende meiner Debugging-Session alle "Häufchen" entfernen kann: 

# DEBUG
import pdb
...
...
pdb.set_trace() # <--- Breakpoint

Komfortabel: CheckMK und der interaktive Python-Debugger "ipdb"

So etwas wie Komfort macht sich breit, wenn man statt pdb den ipdb einsetzt. Er gehört zur interaktiven (und sehr zu empfehlenden) IPython-Shell und lässt sich ganz einfach per pip install ipdb nachinstallieren.

ipdb ist genauso aufzurufen (-m ipdb) und glänzt u.a. durch

  • Tab-Completion von Variablen, Klassen und Funktionen
  • Embedded IPython-Shell: erlaubt es, während des Debuggens zum Ausprobieren in einen "Sandkasten" abzutauchen, ohne den Scope des Haupt-Scripts zu beeinflussen
  • Syntax-Highlighting
  • benutzerfreundlicher

Debuggen mit pdb/ipdb

Pro

  • keine weiteren Tools notwendig (pdb)  
  • Debugging im MK-Context    
  • Erleichterung: ipdb    

Contra

  • braucht etwas Übung 
  • Setzen von Breakpoints erfordert Eingriff in den Code 

Tipp:

Ipython und ipdb gehören für mich zum Handwerkszeug Nr. 1, wenn ich direkt auf der Kommandozeile unterwegs bin (z.B. beim Kunden). Hat man die Kürzel zur Ablaufsteuerung mal heraus, geht das Debuggen wirklich gut von der Hand. Und mit pdb/ipdb lässt sich so ziemlich jeder Python-Code gegen das Licht halten.


Überholspur: CheckMK Remote Debugging mit VS Code Studio

Ja... natürlich braucht man nicht unbedingt eine grafische Oberfläche für die Python-Entwicklung. tmuxvim & Co. bieten ja eine Fülle an Möglichkeiten, um sich auszutoben. Allerdings bleibt mein Lieblingseditor der VS Studio Code - insbesondere, weil er seit einiger Zeit das Arbeiten auf entfernten Maschinen beherrscht.

Das bedeutet: auf meinem Mac läuft VSC, das sich per SSH zu einem Remote-Host verbunden hat (in meinem Fall der ELABIT-Entwicklungsserver mit allen möglichen CMK-Versionen, Docker etc.) und mich nicht nur die Dateien dort bearbeiten, sondern auch debuggen lässt. Ich zeige Dir, wie man das einrichtet.

SSH-Connection

Wie schon erwähnt, benutzt Visual Studio Code SSH, um sich zum Server zu verbinden. Das ist meine SSH-Config in .ssh/config auf meinem Mac:

Host cmk_eldev
Hostname eldev
User cmk
IdentityFile ~/.ssh/id_rsa_eldev

Erklärung:

  • Host - Name der Verbindung (frei wählbar)
  • Hostname - auflösbarer Name oder IP-Adresse meines Entwicklungsservers "eldev"
  • User - Username für die Verbindung (CheckMK-Site-User)
  • IdentityFile - Pfad zum SSH-PrivateKey; der Public Key muss auf der OMD-Site hinterlegt sein in $OMD_ROOT/.ssh/authorized_keys

Mit dieser SSH-Config ist es mir - und auch VSC nun möglich, direkt auf eldev zu springen:

datil 01:11 $ ssh cmk_eldev
Last login: Sun May 31 20:59:59 2020 from datil.fritz.box
OMD[cmk]:~$

Code bereitstellen

In diesem Beispiel möchte ich den CheckMK-Check von RobotMK debuggen. Für mich hat sich bewährt, das Repository an einem separaten Ort zu clonen ($OMD_ROOT/robotmk) und den Check per Symlink in CheckMK zu bringen:

[cmk]:~/local/share/check_mk/checks$ ln -sf ~/robotmk/checks/robotmk robotmk
OMD[cmk]:~$ cd local/share/check_mk/checks/
OMD[cmk]:~/local/share/check_mk/checks$ ln -sf ~/robotmk/checks/robotmk robotmk

Das hat den Vorteil, dass ich die Datei nicht wieder zurück ins Repository kopieren muss, um committen zu können!

VSC-Plugin "Remote Development"

Ich öffne nun Visual Studio Code und installiere über die Plugin-Verwaltung das Plugin "Remote Development":

Nach der Installation zeigt die Toolbar links das Icon des "Remote Explorers" an:

Wenn ich daraufklicke, sehe ich sämtliche Verbindungen, die in meiner SSH-Config definiert sind - inklusive der zuletzt angelegten, die sich per Rechtsklick jetzt aktivieren lässt:

Bei der erstmaligen Verbindung kann es ca. 30 Sekunden dauern, bis VSC im Homedir des Remote-Users (cmk) das entsprechende Gegenstück (.vscode-server, NodeJS-basiert) installiert hat.

Dass der Remote-Server läuft und Dein VSC mit ihm verbunden ist, sieht man jetzt links unten in der Statusleiste:

Ab diesem Zeitpunkt kann es auch sein, dass bestimmte andere Plugins, die normalerweise links in der Toolbar zu sehen sind, verschwunden sind. Das ist normal. Das liegt daran, dass der "Server"-Teil von VSC jetzt auf dem Host eldev läuft. Der "Client"-Teil von VSC auf meinem Mac dient lediglich als Anzeige-Frontend.

Remote-VSC-Plugin "Python"

VSC auf eldev ist also nahezu jungfräulich - um Python debuggen zu können, muss ich zumindest wieder die Python-Erweiterung installieren. Die bringt auch gleich den Debugger mit, den wir jetzt gleich kennenlernen werden.

Arbeitsverzeichnis öffnen

Als nächstes binde ich das komplette Home-Dir der OMD-Site ein: dazu klicke ich auf "Open Folder" und wähle wie vorgeschlagen /omd/sites/cmk aus:

Debugging-Konfiguration "launch.json" anlegen

Jetzt, wo ich die Python-Erweiterung installiert habe, kann ich den Debugger öffnen:

Der allerdings möchte noch konfiguriert werden; dazu benutze ich den vorgeschlagenen Link "create a launch.json file" und wähle darauf folgend "Python File" als Konfigurations-Typ:

Mit der JSON-Datei "launch.json" teile ich Visual Studio Code genau mit, welche Datei ich mit welchem Interpreter und welchen Argumenten debuggen will. Ich kann beliebig viele solcher Debug-Konfigurationen anlegen. Die einfachste, nämlich das aktuell geöffnete File zu debuggen, ist bereits vorhanden.

Für unseren "Spezialfall" ~/bin/cmk mitsamt seinen Argumenten lege ich mir eine weitere Konfiguration namens cmk - robot an:

{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
},
// meine neue Check-Debug-Config
{
"name": "cmk - robot",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/bin/cmk",
"args": [
"-v",
"-n",
"--checks=robotmk",
"robothost1"
],
"console": "integratedTerminal",
"pythonPath": "${workspaceFolder}/bin/python"
}
]
}

Zur Erklärung:

  • type - dürfte klar sein
  • request - neben "launch" gibt es auch "test", um Unittests zu fahren
  • program - das zu startende Programm. Beachte die Variable für den Workspace-Folder
  • args - jedes Argument (siehe oben) ist ein eigenes Listenelement
  • console - wo soll die Ausgabe landen
  • pythonPath - ganz wichtig: welches Python soll benutzt werden? Natürlich das von OMD!

Debugger starten

Nun ist es an der Zeit, den Debugger laufen zu lassen. Ich setze vorher aber noch einen Haltepunkt in "robotmk", indem ich die Zeile anklicke und "F9" (Set Breakpoint) drücke. Der rote Punkt zeigt mir das an:

Der Debugger startet, indem ich die soeben erstellte Debugging-Config cmk - robot auswähle und den grünen Pfeil daneben anklicke (oder "F5" drücke):

Und wie erwartet stoppt der Debugger am Haltepunkt mitten in meinem Check, mit dem kompletten CheckMK-Kontext außenherum! 

Man hat ziemlich schnell den Dreh raus, wo Haltpunkte Sinn machen. Ist ein Haltepunkt erreicht, kann ich mit "F11" z.B. Funktionen, die zu CheckMK gehören, hinabsteigen und sehe genau, was sie dort ausführen. Besonders das finde ich wichtig, denn die (ansonsten hervorragende) Dokumentation von CheckMK ist bezüglich Entwicklung ein großer weißer Fleck. Die meisten Funktionen und Module sind im Code aber bereits dokumentiert. 

Der Variableninspektor links zeigt immer den aktuellen lokalen und globalen Variablen-Scope. Per Mouseover wird mir der Wert von Variablen an jeder Stelle im Code angezeigt.

Die Debug Console im unteren Bereich gibt mir darüber hinaus die Möglichkeit, im aktuellen Kontext eigene Python-Schnipsel zu testen. Es ist also nicht notwendig, zwischen SSH-Terminal und VSC hin- und her zu springen:

Remote-Debugging mit VS Code

Pro

  • Überblick über den kompletten lokalen und globalen Scope zur Laufzeit  
  • Debugging im MK-Context
  • Überwachung von Variablen möglich (watch)
  • pytest-Unterstützung
  • hervorragender Lerneffekt

Contra

  • Voraussetzung: Desktop zum Start der GUI 

Tipp:

Eigene Checks und Plugins lassen sich per Remote-Debugging in Visual Studio Code extrem komfortabel entwickeln und debuggen. VSC punktet bei mir besonders durch die offene Plugin-Schnittstelle (um z.B. auch Robot-Tests damit schreiben und debuggen zu können) und seine aufgeräumte Oberfläche

Dank Pytest-Unterstützung lassen sich Tests selektiv starten und debuggen. 

Wer mit VSC nicht warm wird: PyCharm verfügt ebenfalls über das Remote-Debugging-Feature; ich persönlich finde das aber lange nicht so gut umgesetzt wie in VSC. 

Und zuletzt soll nicht unterschätzt werden, welche Aha-Effekte ein gut gemachtes Debugging-Cockpit hervorruft. Gerade fremden Code während der Ausführung im Kontext mit Livedaten zu sehen, ist extrem wertvoll. 

Zusammenfassung

Selbstverständlich ist man mit dieser Methode nicht auf CheckMK-Checks beschränkt. Um z.B. ein Plugin zu debuggen, muss lediglich eine SSH-Verbindung hergestellt werden, mit der es möglich ist, das Plugin in /usr/lib/check_mk_agent/plugins/ zu editieren.

Welche der hier vorgestellten Debugging-Techniken für Dich passt, hängt davon ab, welchen Code Du zu debuggen hast und in welcher Umgebung Du Dich befindest.

Kleinere Fixes lassen sich locker noch mit ipdb (oder sofern gar nichts nachinstalliert werden darf, pdb) erschlagen. Für die Entwicklung eigener Checks und Plugins ist der Python-Debugger in VSC aber ein unschlagbar gutes Werkzeug. Dazu brauchst Du eine Desktop-Oberfläche (Win/Linux/Mac), in der Visual Studio Code gestartet wird.

Bonus

Falls Du CheckMK-Checks mit PyTest entwickelst: das Python-Plugin in VSC bietet den besonderen Leckerbissen, auf die gleiche wie die hier vorgestellte Art und Weise PyTest-Tests zu debuggen. Bei RobotMK hilft mir das, bereits während der Entwicklung zu sehen, wo ich mir evtl. gerade ins Knie schieße, wenn Tests auf rot gehen 🙂

Simon Meggle


Selbständiger und unabhängiger Spezialist für die Themen IT-Monitoring (CheckMK), End2End-Testing/Testautomatisierung (RobotFramework) und Datacenter-Automatision/Ansible. Maintainer des RobotMK-Projekts (robotmk.org).

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}
>