PHP: Logging von SQL Queries / PDO Prepared Statements

Geschrieben von everflux am Januar 17th, 2015

Das Debugging von (legacy) PHP Anwendungen kann ganz schoen nervig sein. Da hilft auch der ganze Werkzeugkasten nicht, den man aus anderen Umgebungen gewohnt ist.

Percona Toolkit pt-query-digest auf tcpdump hat mal direkt Probleme bei der Auswertung.

Instrumentierung / AOP von PHP „Anwendungen“ – eher mau. Das einzige was einigermaßen tut, ist ‚runkit‘. Jedoch kann das nicht alles, was man gerne möchte. Insbesondere kann man sich damit nicht an die Konstruktoren von PHP internen Klassen (PDO) anhängen. Damit war der Plan vollständig ohne PHP Code Änderungen auszukommen erst mal dahin.

Aber erst mal die guten Nachrichten: Verwendet man runkit, kann man von mysql_query bzw. mysqli_query schonmal alles mitlesen.

PHP runkit ist schnell aus dem git repo (PECL ist veraltet) installiert:

cd /tmp
git clone git://github.com/zenovich/runkit.git
cd runkit
pecl install package.xml
echo 'extension=runkit.so' >> /etc/php5/fpm/conf.d/20-runkit.ini
echo 'runkit.internal_override = true' >> /etc/php5/fpm/conf.d/20-runkit.ini
echo 'opcache.enable = 0' >> /etc/php5/fpm/conf.d/20-runkit.ini
php5-fpm restart

Danach hängt man ein bisschen Magie in den PHP code und alle mysqli_query Aufrufe werden abgefangen:


if (function_exists("runkit_function_redefine"))
{

  //clean up from cached versions
  if (function_exists('__mysqli_query'))
  {
    runkit_function_remove('__mysqli_query');
  }

  $myqsliDelegate = 'file_put_contents("/tmp/queries.txt", $sql. ";\n", FILE_APPEND); return __mysqli_query($db, $sql);';

  runkit_function_rename('mysqli_query', '__mysqli_query');
  runkit_function_add('mysqli_query', '$db, $sql', $myqsliDelegate);
}

Jetzt kommt noch PDO, auch hier hätte man ja gerne die Prepared-Statements. Hier ist die Besonderheit dass erst die Datenbank die prepared sql statements mit Parametern belebt.
Dazu kann man sich dieser Klasse bedienen: https://github.com/noahheck/E_PDOStatement – die Interpolierung wird dann simuliert.
In meinen Fällen reichte das voll und ganz.
So sieht dann der runkit code für das Logging der PDO Statements mit der Hilfsklasse E_PDOStatement aus, die mir im Property fullQuery die interpolierte Query bereitstellt:



   $pdoDelegate = '$res = $this->__execute(); $query = $this->fullQuery; file_put_contents("/tmp/queries.txt", $query. "; --\n", FILE_APPEND); return $res;';
   runkit_method_rename("E_PDOStatement", "execute", '__execute');
   runkit_method_add("E_PDOStatement", "execute", '',  $pdoDelegate);


Leider muss jetzt noch an den Stellen, an denen das PDO instantiiert wird das E_PDOStatement konfiguriert werden. Normalerweise ist die Anzahl aber überschaubar. Damit nur auf Entwicklerrechnern das Logging aktiviert wird, habe ich noch einen environemnt Check dazu gepackt:


  if ((getenv("environment") === "LOCAL"))
  {
     require_once("lib/E_PDOStatement.php");
     $con->setAttribute(PDO::ATTR_STATEMENT_CLASS, array("E_PDOStatement", array($con)));
  }

Ingress: Axa Shield

Geschrieben von everflux am Januar 10th, 2015

Bei dem augmented Reality Game „Ingress“ von Google gibt es jetzt „Axa Shields“. Es handelt sich dabei um Werbung für die Versicherung „Axa“, deren Logo auch auf dem Schutzschild zu erkennen ist. Im Gegensatz zu der eher lieblosen und nervigen Vodafone-alle-Shops-sind-hässliche-Portale Werbung finde ich das einen gelungenen Schachzug: Es passt dass man als Versicherung ja eben „Schutz“ als Produkt hat. Dazu empfinde ich das Branding angenehm und nicht aufdringlich.

Man kann dass Shield vor allem bei Axa Agentur-Portalen hacken, jedoch auch einfach so, wie hier bei mir:

ingress-axa-shield

Auf der Meta-Ebene finde ich das ganze aber noch viel interessanter: Im Umfeld der Versicherer war schon lange abzusehen dass Änderungen im Auftreten, Umgang mit Kunden und aktuellen technischen Entwicklungen überfällig sind. In letzter Zeit – aber das kann natürlich selektive Wahrnehmung sein – mehren sich für mich die Zeichen für Evolution oder sogar Revolution:

  • Google arbeitet an KFZ Versicherungen: http://blogs.wsj.com/digits/2015/01/08/google-wants-to-sell-you-auto-insurance/
  • Die ING tritt auf der Devoxx auf – in einer Keynote – und stellt dort vor, wie ihr Technologie-Stack und Vorgehen im Wandel ist, gleichzeitig engagiert die ING sich stark in der Angular JavaScript Community und dem Framework mit OpenSource Entwicklungen wie spectINGular
  • Auch die LVM Versicherung mit Stammsitz Münster soll hier nicht fehlen: Seit bereits zwei Jahren sponsort sie die lokale Java Usergroup und stellt Raum und Catering

Eher ideenlos finde ich dagegen die Ideen einiger Versicherer Daten auszuwerten und günstigere KFZ Versicherungen anzubieten, wenn man sich permanent überwachen lässt und im Sinne der Versicherung Wohlverhalten an den Tag legt.

Aldi/Medion Lifetab S8312 lädt nicht / bootet nicht

Geschrieben von everflux am Januar 10th, 2015

Aldi hat ein Android Tablet (Medion Lifetab S8312) für 180 Euro im Angebot gehabt – incl. UMTS und sogar einem Monat mit 1.5GB Volumen direkt dabei. Da ich einen Ersatz für mein Nexus 7 gesucht habe, war das Lifetab S8312 eine gute Wahl: Gutes Display, richtige Größe, UMTS (wenn auch kein LTE) und ein passabler Prozessor. Als Betriebssystem kommt Android 4.4 Kitkat zum Einsatz, ob es jemals ein Lollipop Android 5.0 oder gar ein Cyanogen für das Lifetab S8312 geben wird, steht leider in den Sternen.

Nun zu dem Problem mit dem Lifetab: Als der Akkustand mit 15 Prozent angegeben wurde, hat sich das Tablet ausgeschaltet. Und war tot. Das Lifetab ließ sich nicht mehr starten. Also war die Vermutung dass das Device geladen werden muss – doch auch nach dem Anschluss an das Original Ladegerät von Aldi/Medion passierte nicht. Das S8312 zeigte keine Akku Ladung an, auch bootete es nicht automatisch und das Lifetab ließ sich auch nicht einschalten.

Da es keinen Reset Knopf gibt, habe ich den Standard-Android Trick versucht: Einschalter lange halten. Auch dann ließ sich das Aldi Tablet nicht starten. Manchmal hilft es bei gehaltenem Powerknopf das USB Ladekabel einzustecken. Auch nichts.

Was schließlich geholfen hat: Mit dem original Ladegerät nicht in der Steckdose das USB Ladekabel einstecken und den Einschalter eine Minute festhalten. Dann das Ladegerät in die Steckdose stecken. Dann erst den Einschalter loslassen. Kurz danach erscheint der Akku Ladeindikator.

lifetab-ladebildschirm

Analyse des Twitter Login Problems 2014-12

Geschrieben von everflux am Dezember 29th, 2014

Es fing damit an, dass Twitter mich ausgeloggt hat. Und ich mich nicht wieder einloggen konnte. Die native App faselte was von ‚retry later‘ oder falschem Passwort, die Webseite erzählte etwas von einem bekannten technischen Problem. Jedoch war auf status.twitter.com nichts zu sehen. Da ich davor einige Experimente mit Spring Integration und Twitter gemacht hatte und dabei auch mehrfach rate-limit Fehlermeldungen erzeugt hatte (versehentlich, wirklich!), machte ich mir Sorgen dass ich jetzt Twitter kaputt gemacht haben könnte.

Oder zumindest Twitter ernsthaft auf mich sauer sein könnte. Hilft alles nichts, muss man mal tiefer einsteigen.

Schaut man sich die Fehlermeldung an, sieht es aus, als wenn die OAuth Tokens, die Twitter zur Authentifizierung einsetzt und auch selbst ausstellt, von Twitter nicht verifiziert werden können. Die Signatur sei falsch. NSA Gedanken! Da ist bestimmt ein Schlapphut Schuld!

…. oder etwas ganz banales? Die Uhrzeit des Servers sieht komisch aus. Exakt ein Jahr in der Zukunft.

twitter-doy

So ganz habe ich zwar keine Idee wie so was mit der Hardware Uhr passieren könnte – aber ich habe eine Hypothese, was ein Programmierer tun könnte um den Fehler auszulösen.

Der Fehler trat ab ca. 0 Uhr UTC am 29.12. auf – zumindest hab ich ihn da bemerkt.

Es ist Montag der 29. 12. im Jahr 2014. Morgen ist Dienstag, 30., auch 2014. Mittwoch ist Silver, 31. – noch 2014. Das sind drei Tage. Die nächsten Tage sind alle schon in 2015.

Wenn sich jemand bei einem Date-Format einen super schwer zu findenden Bug einbauen möchte, dann verwendet er „YYYY“ statt „yyyy“ für die Jahreszahl. Das ist nämlich dann das „Week-Year“ und nicht das kalendarische Datum. Das ist dann das Jahr zu dem die Kalenderwoche gehört. Und es ist bereits KW 1 von 2015….

Das klingt abwegig? Habe ich schon zig mal in Code-Reviews gesehen. Die Wahrscheinlichkeit dass man dafür Sensibilität entwickelt hat, ohne dass man davon mal gebissen wurde halte ich für recht gering.

Inzwischen hat Twitter dazu ein Statement veröffentlicht

Between 4:00 and 9:25 PST today some users were unable to sign in to twitter.
This issue was due to a bug in our front end code, which has been patched.
We apologize for any inconvenience caused by this.

Da scheine ich gar nicht schlecht gelegen zu haben mit dem Bug – es war zumindest nicht die Hardware-Uhr und 04:00 PST ist 00:00 UTC 🙂

Zu solchen Verwirrungen traegt es u.U. bei, dass in Ruby „Y“ genau das richtige ist und in Java „y“ – aber „Y“ auch erstmal funktioniert und keine augenscheinlichen Probleme verursacht.

Referenzen:

Gourmondo: TECHNICAL_PRBLEM fail

Geschrieben von everflux am November 9th, 2014

Diese Sache mit lokalisierten Texten ist aber auch wirklich blöde…

gourmondo-fail

Bundesamt für Steuern: Zope fail

Geschrieben von everflux am September 26th, 2014

Dank dem total unkomplizierten Steuerrecht muss man beim VAT reversed Verfahren zur Abrechnung von IT Dienstleistungen im EU Binnenland immer sicherstellen, dass die VAT Nummer auch korrekt ist – und zum Rechnungsempfänger gehört.
Die Anwendung des Bundesamts für Steuern fühlt sich etwas rustikal an, tut aber meistens. Meistens.
bundesamt-fuer-steuern-fail

Gelöschte Datei retten solange sie offen ist

Geschrieben von everflux am Juli 13th, 2014

Durch eine unglueckliche Konstellation kam es dazu, dass mir von laufenden, produktiven, KVM Maschinen die Images abhanden kamen. Kurzum: Gelöscht. Aber da die Maschinen noch liefen eine gute Gelegenheit sich an der Rettung zu versuchen, und nicht über ein Backup zu arbeiten.
Dadurch, dass die Datei Images noch in Benutzung waren, war ein File-Handle mit dem jeweiligen Prozess verknüpft. Dieser kann nach Belieben noch mit der Datei arbeiten, auch das Dateisystem betrachtet die zu der Datei gehörenden Datenblöcke nicht als frei und bewahrt sie somit vor Verlust. Solange der Prozess läuft aber nur.

Zur Illustration verwenden wir einmal folgende Kommandos:

wget --limit-rate=1000 http://releases.ubuntu.com/14.04/ubuntu-14.04-desktop-amd64.iso

Der Download ist extra langsam gedreht, so dass genug Zeit ist zum experimentieren.
Nun loeschen wir die Datei – das wget laeuft weiter.

rm ubuntu-14.04-desktop-amd64.iso

Suchen wir nun nach Prozessen, die auf gelöschte Dateien zugreifen und filtern nach Dateien mit dem Wort „ubuntu“:

lsof | grep deleted | grep ubuntu
wget 10694 tkruse 4w REG 252,1 195943 1573596 /home/tkruse/ubuntu-14.04-desktop-amd64.iso (deleted)

Der einfachste Weg den Inhalt zu retten wäre nun, einfach die Datei(inhalte) zu kopieren. Dazu suchen wir das Filehandle des Prozesses „10694“ (dem wget aus dem lsof)


ls -l /proc/10694/fd             
total 0
lrwx------ 1 tkruse tkruse 64 Jul 12 13:02 0 -> /dev/pts/7
lrwx------ 1 tkruse tkruse 64 Jul 12 13:02 1 -> /dev/pts/7
lrwx------ 1 tkruse tkruse 64 Jul 12 13:02 2 -> /dev/pts/7
lrwx------ 1 tkruse tkruse 64 Jul 12 13:02 3 -> socket:[797560]
l-wx------ 1 tkruse tkruse 64 Jul 12 13:02 4 -> /home/tkruse/ubuntu-14.04-desktop-amd64.iso.1 (deleted)

Das Datei handle können wir als Quelle nehmen, und den Inhalt nun kopieren:

cp /proc/10694/fd/4 /home/tkruse/rescue

Da die Maschinen noch laufen, wäre es eigentlich schön nicht einen Zustand zu kopieren, sondern die Datei auf ’nicht gelöscht‘ setzen zu können. Das ging mal mit ln -L, wurde jedoch aus Sicherheitsgründen aus dem Kernel entfernt.

Dazu kann man nur noch direkt ins Dateisystem eingreifen. Nichts für Angsthasen – und ein fsck sollte danach besser stattfinden.
Mittels debugfs kann man einen neuen Link auf die inode der Datei anlegen. Darüber kann danach wieder ein Zugriff erfolgen. Jedoch wird dabei der Link-Count nicht erhöht, so dass die Datei nicht wirklich wieder hergestellt ist.
Die inode ist die Zahl aus dem lsof vor dem Dateipfad, in diesem Fall „1573596“. Legen wir also eine neue Datei an, die diese inode nutzt:

sudo debugfs -w /dev/mapper/ubuntu--gnome--vg-root -R "link <1573596> rescue"

Anschließend kann man den Prozess, der die Datei bisher noch offen und damit am Leben gehalten hat, beenden und die Datei (auf ein anderes Dateisystem) kopieren.

cp rescue ....

Ist man damit fertig, kann man den Link wieder aufheben.

sudo debugfs -w /dev/mapper/ubuntu--gnome--vg-root -R "unlink rescue"

Durch durch das debugfs ist es im Prinzip auch möglich den Linkcount zu reparieren, das war mir jedoch etwas zu warm. Auch bin ich nicht sicher, wie es sich mit dem „gelöscht“ Flag tatsächlich verhält, so dass ich die Daten dann auf ein anderes Dateisystem kopiert habe (um versehentliches überschreiben zu verhindern), das betroffene Dateisystem ausgehängt und per fsck geprüft habe.
Soweit ich das beurteilen kann: Die Datei wurde perfekt gerettet und alles läuft mit minimaler Downtime weiter.

Abmessungen Magnum Sekt Flasche

Geschrieben von everflux am Juli 4th, 2014

Das war schwer – um den passenden Kühler zu kaufen, brauchte ich die Abmessungen einer Sektflasche in der Größe „Magnum“. Alle Größen für Champagner Flaschen waren jedoch ausschließlich in Litern zu finden, nicht in Zentimetern oder Millimetern. Da hilft alles nichts, man kauft sich eine Referenzflasche.

Hier nun die ungefähren Abmessungen eines Moët & Chandon Magnum (1.5l) im metrischen Maßsystem: 115mm x 420mm

If you think this message is wrong….

Geschrieben von everflux am Mai 30th, 2014

access-denied

Diagnose mit sysdig

Geschrieben von everflux am Mai 17th, 2014

Wäre es nicht fantastisch, wenn es ein Tool gäbe, dass wie tcpdump auf System-Ebene arbeitet? Vielleicht noch gemischt mit lsof. Und strace. Und das ganze vielleicht auch so dass man im Nachhinein filtern kann!

Das gibt es. Es nennt sich „sysdig“ und ist OpenSource: http://www.sysdig.org/ bzw. https://github.com/draios/sysdig/

Die Installation auf einem Ubuntu 14.04 sollte eigentlich so funktionieren:

curl -s https://s3.amazonaws.com/download.draios.com/stable/install-sysdig | sudo bash

Das hat leider nicht ganz geklappt:

curl -s https://s3.amazonaws.com/download.draios.com/stable/install-sysdig | sudo bash
[sudo] password for tkruse:
* Detecting operating system
* Installing Draios public key
OK
* Installing Draios repository
* Installing kernel headers
E: Package 'linux-headers-3.11.0-12-generic' has no installation candidate
Unable to find kernel development files for the current kernel version 3.11.0-12-generic
This usually means that your system is not up-to-date or you installed a custom kernel version.
The installation will continue but you'll need to install these yourself in order to use sysdig.
Please write to the mailing list at https://groups.google.com/forum/#!forum/sysdig
if you need further assistance.
* Installing Sysdig
Selecting previously unselected package sysdig.
(Reading database ... 207643 files and directories currently installed.)
Preparing to unpack .../sysdig_0.1.82_amd64.deb ...
Unpacking sysdig (0.1.82) ...
Processing triggers for man-db (2.6.7.1-1) ...
Setting up sysdig (0.1.82) ...
Loading new sysdig-0.1.82 DKMS files...
First Installation: checking all kernels...
Building only for 3.11.0-12-generic
Module build for the currently running kernel was skipped since the
kernel source for this kernel does not seem to be installed.

Offenbar war mein Kernel nicht beim Update auf Ubuntu 14.04 mitgezogen worden:

uname -a
Linux charix 3.11.0-12-generic #19-Ubuntu SMP Wed Oct 9 16:20:46 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

Dafuer gab es keine Kernel-Header mehr, so dass die sysdig Module nicht kompiliert und installiert werden konnten.
Das ist schnell zu beheben, neuer Kernel und neue Header:

sudo apt-get install linux-image-3.13.0-24-generic
sudo dpkg-reconfigure sysdig
Removing old sysdig-0.1.82 DKMS files...

-------- Uninstall Beginning --------
Module: sysdig
Version: 0.1.82
Kernel: 3.13.0-24-generic (x86_64)
-------------------------------------

Status: Before uninstall, this module version was ACTIVE on this kernel.

sysdig-probe.ko:
- Uninstallation
- Deleting from: /lib/modules/3.13.0-24-generic/updates/dkms/
- Original module
- No original module was found for this module on this kernel.
- Use the dkms install command to reinstall any previous module version.

depmod....

DKMS: uninstall completed.

------------------------------
Deleting module version: 0.1.82
completely from the DKMS tree.
------------------------------
Done.
Loading new sysdig-0.1.82 DKMS files...
Building for 3.11.0-12-generic and 3.13.0-24-generic
Module build for the currently running kernel was skipped since the
kernel source for this kernel does not seem to be installed.
Building initial module for 3.13.0-24-generic
Done.

sysdig-probe:
Running module version sanity check.
- Original module
- No original module exists within this kernel
- Installation
- Installing to /lib/modules/3.13.0-24-generic/updates/dkms/

depmod....

DKMS: install completed.

Danach kann dann sysdig auch schon benutzt werden.
Hier ein Beispiel: „Zeige alle Prozesse, die auf Dateien in /etc zugreifen“

sudo sysdig evt.type=open and fd.name contains /etc

Die Ausgabe sieht z.B. dann so aus:

208208 13:10:12.791863631 0 DNS (4278) < open fd=73(/etc/hosts) name=/etc/hosts flags=1(O_RDONLY) mode=0 
208307 13:10:12.792037164 3 DNS (4283) < open fd=74(/etc/hosts) name=/etc/hosts flags=1(O_RDONLY) mode=0 
444807 13:10:27.793785895 0 DNS (5019) < open fd=72(/etc/hosts) name=/etc/hosts flags=1(O_RDONLY) mode=0 
470806 13:10:32.317263671 1 gnome-settings- (3411) < open fd=19(/etc/fstab) name=/etc/fstab flags=1(O_RDONLY) mode=0 
546476 13:10:42.794281200 2 DNS (4278) < open fd=72(/etc/hosts) name=/etc/hosts flags=1(O_RDONLY) mode=0 

Auch kann man mal eben schnell schauen wer am meisten Netzwerkbandbreite braucht:

sudo sysdig -c topprocs_net

Beispielausgabe:

Bytes     Process   
------------------------------
23.82KB   Socket
546B      dnsmasq
239B      pidgin
215B      DNS

(Socket ist hier der Firefox, der eine Webseite lädt.)

Das ist extrem praktische für diverse Diagnosen. Ein interessantes Beispiel für den Einsatz liefert der Blog-Post der Entwickler, die dabei im Nachhinein analysieren, was bei einem Einbruch in einen Honeypot-Server passierte: http://draios.com/fishing-for-hackers/

Viele weitere Beispiele (IO, CPU, Security…) finden sich auf dieser Seite: https://github.com/draios/sysdig/wiki/Sysdig%20Examples


http://everflux.de/
Copyright © 2007, 2008 everflux. Alle Rechte vorbehalten. All rights reserved.