Accesslogs in die Datenbank

Gibheer
21
June
2011
16
30

Da ich mal unsere access-logs der letzten paar Tage auswerten wollte, brauchte ich eine Moeglichkeit die Daten in eine Datenbank zu packen. Dummerweise sind die Log-Dateien der Webserver nicht Datenbankgerecht und keiner hat ein Interface um Datensaetze gleich in eine Datenbank zu schreiben.
Deswegen hab ich mir eine Methode ueberlegt, mit der ich die Daten in die Datenbank bekomme, ohne dass es viel Aufwand bedarf.

Voraussetzungen

Da das hier eine Art kleines Tutorial wird hier eine Liste der Programme die ich benutzt habe:

  • lighttpd
  • PostgreSQL
  • simples Shell (sh FreeBSD Version)
  • cron
  • logrotate (newsyslog in FreeBSD)

Logformat setzen

Als erstes brauche ich ein Logformat, welches sich auch gut verarbeiten laesst. Im Default sind alle Felder durch Whitespaces getrennt und es gibt Felder, welche nicht immer gefuellt sind, was sich nur sehr schwer parsen laesst.
Deswegen hatte ich mir ueberlegt, das Logformat in Richtung CSV-Datei auszurichten. Im lighttpd muss dazu das Module mod_accesslog eingebunden werden.
Danach steht die Option accesslog.format:http://redmine.lighttpd.net/wiki/1/Docs:ModAccesslog zur Verfuegung. Diese habe ich bei uns auf folgenden Wert gesetzt

# log format for csv
# %h host ip
# %t timestamp of the end of the request
# %m request method
# %s status code
# %b bytes sent
# %U request URL
# %f real filename
# %q query string
# %T time used in secounds
accesslog.format = "%h|%t|%m|%s|%b|%U|%f|%q|%T|%{User-Agent}i|%{Referer}i"

Das Zeichen | ist dabei mein CSV-Trennzeichen, damit ich die Werte auseinander halten kann.

Datenbankschema

Das Datenbankschema entspricht dem Schema der CSV-Datei.

CREATE TABLE logs (
    ip text,
    datum text,
    method text,
    code integer,
    bytes integer,
    req_file text,
    full_path text,
    query_string text,
    time_taken integer,
    user_agent text,
    referer text
);

optionaler User

Wenn man auf Nummer sicher gehen will, kann man noch einen zusaetzlichen User anlegen, welcher nur Insertrechte auf diese Tabelle hat. Damit kann man ausschliessen, dass irgendwas doofes passiert, wie zum Beispiel ein Drop Table oder aehnliches.
Das geht dann mit folgendem Befehl:

create role wwwimport login password 'changeme!';

Logrotate

Lighttpd schreibt per default nach /var/log/lighttpd/access.log bis kein Speicher mehr da ist. Wenn man allerdings die Datei allerdings verschiebt und eine neue hinstellt ohne den Server neu zu starten, so loggt dieser in die verschobene Datei. Wird sie geloescht, dann loggt der Server garnicht mehr.
Da das fuer die Logverarbeitung ungeschickt ist, musste da irgendwie ein logrotate rein. Unter FreeBSD geht das mit /etc/newsyslog.conf wo ich den Eintrag

/var/log/lighttpd/access.log www:www 664 7 * @T00 Z /var/run/lighttpd.pid

gesetzt habe. Das erstellt Archive im Format access.log.<counter>.gz. Allerdings wird dabei auch am Anfang der neuen und am Ende der alten Datei eine Zeile eingesetzt, dass ein rotate stattgefunden hat.

das Script als cron

Um die Daten in die Datenbank zu bekommen habe ich den Befehl COPY genommen, da er schneller als 9000 einzelne Selects arbeitet.
Zusaetzlich hat der Timestamp den kleinen Makel, dass er von [ und ] umgeben ist, wodurch sich das Feld nicht einfach als Timestamp speichern laesst.
Die Timestamps lassen sich allerdings recht einfach mit folgendem Befehl bereinigen

sed -e "s/[][]//g"

Das Problem mit der zusaetzlichen Zeile loesen wir mit einem grep.

grep -v "logfile turned over"

geloest. Das gibt nur noch die Zeilen aus, welche nicht den String enthalten.

Insgesamt kommt dabei bei mir folgendes kleines Script raus.

#!/usr/bin/env ksh

LOG_PATH="/var/log/lighttpd"
LOG_FILE="access.log"
TABLE="logs"
DATABASE="test"
DBUSER="wwwimport"
DBPASS="changeme!"

WORKDIR="/tmp/logimport"

# create a workdir
if [ -d $WORKDIR ]; then
  echo 'Job is running!'
  exit 1
else
  mkdir -m 700 $WORKDIR
fi

files=$(ls $LOG_PATH/$LOG_FILE*gz)
workfile="${WORKDIR}/dump.sql"

echo "COPY ${TABLE} FROM STDIN WITH DELIMITER '|';" >> $workfile

for file in $files; do
  gzcat $file | sed -e "s/[][]//g" | grep -v "logfile turned over" >> $workfile
  rm $file
done

PGPASSWORD="$DBPASS" psql -U $DBUSER -f $workfile $DATABASE

# delete the workdir
rm $workfile
rmdir $WORKDIR
exit 0

Das habe ich dann noch irgendwo gespeichert und im cron mit

0 23 * * * sh logimport.sh

eingetragen. Jetzt importiert es munter meine Logs und ich kann anfangen R zu lernen.

Schwarze Seelen brauchen bunte Socken - Teil 3

Stormwind
03
June
2011
16
42

Hallo Ihr,

letztes Wochenende war es mal wieder so weit. In Leipzig war wieder Wollefest. Diesmal das 4. und das dritte bei dem ich dabei war.
Ich muss gestehen, dass ich im Moment nicht so sehr auf schon “strickfertige” Wolle stehe. Deswegen habe ich mir überwiegend Kammzüge gekauft.
Die zwei Wollknäule von Schoppel (Farbe “Kleiner Fuchs”) habe ich für eine Ergänzung meines eigentlich schon fertigen Rocks gekauft. Aber leider ist er etwas kurz geraten, so dass er nicht wirklich zum Rock – eher zum Nierenwärmer – taugt. Aber dieser Markel muss natürlich behoben werden. Auch wenn das noch viel Arbeit bedeuten wird.
Nur dem schönen Dankeschönstrang von der Zauberwiese konnte ich dann doch nicht widerstehen und musste ihn unbedingt mitnehmen. Ausserdem noch ein Paar Ohrringe… man erinnere sich an die Gießkannen von letztem Jahr. Diesmal nur ein klein wenig unauffälliger, mit verschiedenen Aufschriften “Leben” und “Tod”.
Die Verkäuferin hat mir erzählt, dass die die Worte aus einem alten Buch, in dem sich ein Pärchen immerzu Liebesbriefe geschrieben hat und leider doch nicht zusammen finden konnte. Wer weiß?
Die sind auf jeden Fall einen Hinkucker wert.

Eigentlich wollte ich meine Kniestrümpfe an dem Samstag weiterstricken, aber daraus wurde nichts. Ich hatte nämlich mein Little Gem mit nach Leipzig genommen… und da ich es schon mal dabei hatte, sollte ich es auch mit aufs Wollefest nehmen und unbedingt ein bissel was Spinnen. Zum Opfer fiel mir ein Kammzug aus der Krabbelkiste von Dibadu, den ich an diesem Tag zur Hälfte versponnen habe (Die Spule kann man auch auf dem Foto sehen).
Ich hatte mich extra in die hinterste Ecke verkrochen, aber trotzdem hab ich das Gefühl, dass ich die meist fotographierte Person auf dem Wollefest war. So viele kamen dann doch vorbei, fanden mein Spinnrad total süß und wollten wissen, was das für eins ist. Dabei war ich bei weitem nicht die einzige Spinnerin auf dem Fest.
Auf dem gepflasterten Platz neben dem Stand des Strickcafes hatte sich nämlich Lady Ramone niedergelassen und ihren Spinnkurs gegeben. Es sollten möglichst kunstvolle Garne hergestellt werden.
Ich hätte am liebsten auch mitgewerkelt, aber ich hab diesen Kurs schon für das Wollfest in Nierstein gebucht auf dem ich kommendes Wochenende bin.
Ich bin schon gespannt, was mich da erwartet.

Bis denne…
… ich werde natürlich berichten

Technik hinter dem neuen Blog

Gibheer
18
May
2011
12
25

Whaerend der alte Blog noch auf eine Datenbank zurueck gegriffen hat, ist der neue Blog komplett statisch. Alle Blogeintraege werden in Form von Textdateien geschrieben und anschliessend zu html konvertiert.

Als Generator benutzen wir jekyll, was auch bei github zum Einsatz kommt. Es laesst sich einfach erweitern und mit verschiedenen Markupsprachen kombinieren. Die einzelnen Eintraege bekommen einen Markupunabhaengigen Header verpasst in dem Daten gespeichert werden, wie zum Beispiel Keywords, das Erscheinungsdatum, der Autor und was man noch so moechte.

Da mir html schreiben auf dauer zu nervig war, habe ich mich umgeschaut, welche anderen Sorten von Markup es denn gibt und bin auf Textile, Markdown, Haml und noch ein paar andere gestossen. Da ich Textile schon durch redmine kannte und die syntax mir einfacher als die von Markdown vorkam, habe ich mich fuer Textile entschieden. Haml wollte ich fuer die Layouts benutzen, allerdings waere es einiges an Aufwand gewesen Jekyll dies beizubringen. Also sind zumindest die Layouts in einfachem HTML geschrieben.

Da ich ab und zu auch mal Syntax-Highlighting benoetige, stand natuerlich noch die Frage im Raum, mit welcher Engine sich dieses Problem loesen laesst. Jekyll hat dafuer bereits eine Schnittstelle eingebaut, welches auf die Pythonlib Pygments zugreift. Es erschien mir allerdings etwas abwegig beim kompillieren zwei verschiedene Scriptsprachen laufen zu lassen. Da die einzig andere Loesung unter Ruby coderay heisst, habe ich dieses eingebaut und mit Textile verkuppelt.

Da wir das Design ein bischen aufpeppen wollten und damit auch etwas CSS3 einzustreuen, stand natuerlich die Frage im Raum: “Wollen wir die ganzen besonderheiten selber bauen?” Natuerlich nicht! Deswegen habe ich zuerst Sass und spaeter noch Compass hinzugenommen.
Sass ist eine Sprache, mit der sich leicht CSS schreiben laesst. Es bietet Unterstuetzung fuer Variablen, Funktionen und Mixins. Mit letzterem lassen sich Attributsbloecke bilden und dann mit einer Zeile an der jeweiligen Stelle importieren.
Compass bietet dazu weitere Funktionen, um zum Beispiel Farben zu bearbeiten, Farbverlaeufe zu erstellen oder das komplette Layout zurueck zusetzen.
Wenn man sein Design dann fertig hat, kann man Sass dann anweisen die CSS-Datei
so zu formatieren, dass einiges an Speicher gespart werden kann.

Da der Blog nun allerdings komplett statisch ist, haben wir ein Javascript von Disqus mit eingebaut, welches eine Diskusionsplatform bereitstellt. Ob sich das allerdings lohnt, muss sich erst noch zeigen.

Den Blog insgesamt werde ich vielleicht bald auf github hochladen, aber mal schauen. Auf jeden Fall werde ich noch ein paar weitere Eintraege machen, in denen ich weitere Teile vorstellen werde.

viel Spass

jede Menge Umzuege

Gibheer
27
April
2011
16
23

Endlich haben wir auch den letzten Umzug hinter uns. Stormwind und ich haben in den letzten 2 Monaten einen Umzugsmarathon hingelegt. Zu aller erst haben wir angefangen den Blog von serendipity auf jekyll und damit von dynamisch generierten Seiten auf statische Seiten umzustellen.
Dann haben wir auch noch den Wohnort gewechselt und hocken nun in Karlsruhe in einer wunderschoenen Wohnung direkt am Berg. Hier auch noch mal ein dickes danke an die Helfer. Es sieht sogar schon etwas wohnlich aus ;)
Und zu guter letzt habe ich auch noch den Hoster von hetzner zu ovh gewechselt. Wahrscheinlich haben das viele noch garnicht mitbekommen, aber der wechsel fand innerhalb von einem Tag statt, inklusive der Domainumstellung verlief sehr glatt.
Bisher gab es nur kleinere Probleme mit IPv6, welche aber anscheind geloest sind.

Wir werden wahrscheinlich noch weitere Sachen in den Blog einbauen, wie zum Beispiel eine Blaetterfunktion oder eine Liste aller Keywords, die wir in den Eintraegen haben. Aber das kommt spaeter noch.

DTrace fuer den Linuxlator in FreeBSD

Gibheer
27
April
2011
15
34

DTrace ist eine sehr nette Sache, wenn man wissen will, was auf seinem System alles los ist. Warum zum Beispiel ein Programm X eigentlich tut, dass auf einmal alles so traege ist. DTrace stammt von Sun Solaris und hat auch den Einzug in FreeBSD gefunden.
FreeBSD hat die Moeglichkeit durch eine Linux ABI Programme auszufuehren, die eben diese brauchen. Bisher war es aber nicht moeglich mittels DTrace in diese Funktionen schauen zu koennen.
Alexander Leidinger hat allerdings seinen Patch von 2008 fuer -current aktualisiert, so dass man damit die Moeglichkeit hat, auch mit DTrace in die Linux Schnittstelle schauen zu koennen.
Er hat dazu auch eine Zusammenfassung geschrieben, in der er den Status des Patches beschreibt.
Ob und wann dieser Patch allerdings so weit ist, dass man ihn in FreeBSD-current findet, schreibt er leider selbst nicht.

daily zfs snapshots

Gibheer
26
April
2011
13
00

In (Open)Solaris gab es eine Funktion mit dem Namen TimeMachine. Das sind einzelne Scripte, welche in regelmaessigen Abstaenden laufen und Snapshots der Dateisysteme erstellen.
Da es diese Funktion unter FreeBSD so noch nicht gibt, hatte ich mir gedacht, so ein Script selbst zu bauen. Wie ich dann feststellen durfte, gibt es bereits eine handvoll Scripte, die genaue diese Aufgabe auf verschiedene Art und Weise vollbringen.

Da ich aber ohnehin Uebung in Shellscripten brauchte, habe ich es einfach mal weiter geschrieben und dabei herausgekommen ist ein Script, welches taegliche, woechentliche, monatliche und jaehrliche Snapshots erstellen kann. Die Konfiguration wird nicht in ein Config file geschrieben sondern in Form von Properties direkt auf die ZFS-Partition geschrieben.
Einzig in der /etc/periodic.conf muss ein Eintrag snapshot_zfs_enable="YES" hinterlegt werden.

Das Script koennt ihr euch hier runterladen. Dieses koennt ihr nach /usr/local/etc/periodic/daily/900.snapshot_zfs oder nach /etc/periodic/daily/900.snapshot_zfs entpacken. Wenn in der /etc/periodic.conf der Eintrag fuer snapshots drin ist, dann laeuft das Script von nun an jeden Tag.

Jetzt koennen wir fuer eine ZFS Partition mal das Snapshot einschalten:

# zfs set org.snap:auto-snapshot=on tank/storage
# zfs get org.snap:auto-snapshot
NAME               PROPERTY               VALUE   SOURCE
tank/storage       org.snap:auto-snapshot on      local
tank/storage/foo   org.snap:auto-snapshot on      inherited from tank/storage

Mit diesen Einstellungen jeden Tag ein Snapshot erstellt, wobei 10 taegliche, 3 woechentliche und 3 monatliche Snapshots aufgehoben werden. Zusaetzlich gibt es noch die Option fuer jaehrliche Snapshots. Die Zahl der aufzuhebenden Snapshots laesst sich mit den Properties org.snap:keep-daily, org.snap:keep-weekly, org.snap:keep-monthly und org.snap:keep-yearly festlegen.

Dokumentation in Textile schreiben

Gibheer
20
January
2011
17
00

Da ich mal Dokumentation schreiben musste, OpenOffice aber schon beim ersten Tastenschlag keine Lust mehr hatte, ich mich bei HTML staendig verschrieben habe, bin ich einfach auf Textile umgestiegen und hab erfolgreich Dokumetation schreiben koennen.

Textile ist ein einfaches Wikiaehnliches Markup. Zusammen mit Ruby ist daraus ein kleines Script geschrieben, welches mir mein textile File in ein HTML-Grundgeruest stopft, den Code etwas aufhuebscht und dann einfach schnell arbeitet.

Als Bibliotheken kamen dabei RedCloth, RedclothCoderay und CodeRay zum Einsatz.

Damit das Script funktioniert muessen die Gems CodeRay, RedCloth und RedclothCoderay installiert sein.
Als naechstes muss im Verzeichniss des Scriptes eine index_template.html angelegt werden. Darin kann {{content}} als Platzhalter fuer den Content des textile-Files benutzt werden. In die index.textile kommt dann das Markup rein. Mit {{toc}} kann in diesem File eine Inhaltsangabe aus den h[1-3]. erstellt werden.

Speichert einfach das folgende Script in einer Datei und ruft es mit ruby auf und schon bekommt ihr euer textile umgewandelt.

# To change this template, choose Tools | Templates
# and open the template in the editor.

require 'rubygems'
require 'redcloth'
require 'coderay'
require 'redclothcoderay'

RedclothCoderay.coderay_options :css => :class
search_headlines = /h([1-3])\.\s(.*)/

def build_menu array, depth
  result = ""
  if array.length > 0 then
    array.each do |el|
      result << '*' * (depth + 1) + ' "' + el[:bez]+"\":\##{el[:bez].gsub(/\s/,'_')}\n"
      if el[:toc].length > 0 then
        result << build_menu(el[:toc], depth + 1)
      end
    end
  end
  result
end

File.open 'index.html', 'w' do |file|
  index = File.read('index_template.html')
  code = File.read('documentation.textile')
  toc = []
  code.gsub! search_headlines do |sub|
    match = sub.scan(search_headlines)[0]
    if match[0] == 1.to_s then
      toc << {:bez => match[1], :toc => []}
    elsif match[0] == 2.to_s then
      toc.last[:toc] << {:bez => match[1], :toc => []}
    elsif match[0] == 3.to_s then
      toc.last[:toc].last[:toc] << {:bez => match[1], :toc => []}
    end
    'h'+match[0]+'(#'+match[1].gsub(/\s/,'_')+'). '+match[1]
  end
  code = code.gsub(//, build_menu(toc, 0)+"\n")
  file.write(index.gsub //, RedCloth.new(code).to_html)
end
puts 'ready'

Shells in anderen Sprachen

Gibheer
11
January
2011
07
54

Ich hatte mir schon länger überlegt, warum es eigentlich keine Shells in anderen Scriptsprachen ausser shell gibt. Python, Ruby und Perl bringen eigene Shells mit, in denen man Code ausführen und testen kann. Diese Shells sind allerdings nicht mit den Funktionen einer zsh oder bash ausgestattet und es fehlt der einfache Zugriff auf Programme wie rsync und co.

Heute morgen habe ich allerdings die Rush gefunden, eine Shell, welche in Ruby geschrieben wurde und auch mit Rubysyntax bedient wird.
Die “Navigation” sieht zwar recht gewöhnungsbedürftig aus und es gibt noch keine direkte Möglichkeit um zum Beispiel git aufzurufen, aber ich denke mal, dass das durchaus eine interessante Shell wird.

ZFS Versionen

Gibheer
05
January
2011
13
37

Da es anscheinend keine aktuelle Liste der ZPOOL Versionen gibt mit den Informationen, wann welche Funktion hinzugekommen ist, hinterlege ich dir erstmal hier.

Die Liste stammt aus einem Solaris 11 Express. Solaris 11 benutzt im Moment ZPOOL 31, FreeBSD 8.1 Version 15, wobei 9.0 wahrscheinlich Version 28 enthalten wird.

VER DESCRIPTION
--- --------------------------------------------------------
1 Initial ZFS version
2 Ditto blocks (replicated metadata)
3 Hot spares and double parity RAID-Z
4 zpool history
5 Compression using the gzip algorithm
6 bootfs pool property
7 Separate intent log devices
8 Delegated administration
9 refquota and refreservation properties
10 Cache devices
11 Improved scrub performance
12 Snapshot properties
13 snapused property
14 passthrough-x aclinherit
15 user/group space accounting
16 stmf property support
17 Triple-parity RAID-Z
18 Snapshot user holds
19 Log device removal
20 Compression using zle (zero-length encoding)
21 Deduplication
22 Received properties
23 Slim ZIL
24 System attributes
25 Improved scrub stats
26 Improved snapshot deletion performance
27 Improved snapshot creation performance
28 Multiple vdev replacements
29 RAID-Z/mirror hybrid allocator
30 Encryption
31 Improved ‘zfs list’ performance

Spielwahn mit Wasser

Gibheer
24
December
2010
16
50

Da heute wieder so viel schoener Schnee gefallen ist, hab ich einfach angefangen und einen Schneemann gebaut. Er kommt in etwa auf 2,30m und ist damit der groesste, den ich bisher gebaut habe.

Viel Spass mit dem vielen Schnee ;)