syslog-ng über mysql

Lord_Icon

Member
Hi,

ich würde gern gewisse Logs zur weiteren (einfachen) Auswertung in eine DB bringen.

Diverse SSF-User verwiesen immer auf den syslog-daemon.
Hiermit habe ich aber Probleme, da er mir nichts loggt.

Datenbank einrichten:
* Tabelle: syslog angelegt
* Tabelle mit folgenden Spalten gefüllt
Code:
CREATE TABLE `logs` (
  `host` varchar(32) default NULL,
  `facility` varchar(10) default NULL,
  `priority` varchar(10) default NULL,
  `level` varchar(10) default NULL,
  `tag` varchar(10) default NULL,
  `datetime` datetime default NULL,
  `program` varchar(15) default NULL,
  `msg` text,
  `seq` bigint(20) unsigned NOT NULL auto_increment,
  PRIMARY KEY  (`seq`),
  KEY `host` (`host`),
  KEY `program` (`program`),
  KEY `datetime` (`datetime`),
  KEY `priority` (`priority`),
  KEY `facility` (`facility`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

syslog-ng eingerichtet:
vi /etc/syslog-ng/syslog-ng.conf

Als erste Zeile folgendes Eingetragen:
Code:
options {
        chain_hostnames(off);
        sync(0);
        stats(43200);
};

source src { unix-stream("/dev/log"); internal(); pipe("/proc/kmsg"); };

destination d_mysql {
          program("/usr/bin/mysql --user=[COLOR="Red"]root[/COLOR] --password=[COLOR="Red"]*******[/COLOR] syslog" template("INSERT INTO logs (host, facility, priority, level, tag, datetime, program, msg) VALUES ( '$HOST', '$FACILITY', '$PRIORITY', '$LEVEL', '$TAG', '$YEAR-$MONTH-$DAY $HOUR:$MIN:$SEC','$PROGRAM', '$MSG' );\n")
          template-escape(yes)); };

destination messages { file("/var/log/messages"); };

log {
        source(src);destination(messages); destination(d_mysql);
};

syslog-ng restart + mxsql zur Sicherheit auch.


Soo... nun sollte es ja schon mal "losloggen".
Tut es anscheind auch, da in der Datei: message nichts mehr geschrieben wird. Was ja auch korrekt ist, da dies nun in die DB geschrieben werden sollte.

Leider ist und bleibt diese leer.
Leider habe ich vom syslog-ng keine separate Log-Datei. (vermute mal, das diese in die message schreibt)


Hat einer eine Idee ?
Passwort + root als Mysql User sollten korrekt sein.
 
Tu dir einen Gefallen und mach es richtig:

Schwierig zu erkennen, wo ich was falsch gemacht habe... bei der fülle an Befehlen.

Ich habe es anhand deines Links + diverse anderen Seiten was anderes zusammengestellt.

Ziel ist es (wenn auch später) die Logs auf einen anderen Server zu übertragen.
Deshalb auch der Versand über tcp. Da aber vorerst auf "Spielwiese"... läuft es auf 127.0.0.1:3306 (Port 3306 per telnet ansprechbar).

/etc/syslog-ng # vi syslog-ng.conf (+added)
Code:
source net {
udp(ip("127.0.0.1") port(3306));
};
destination d_mysql{
pipe("/var/log/mysql.pipe"
template("INSERT INTO logs
(host, facility, priority, level, tag, datetime, program, msg)
VALUES ( '$HOST', '$FACILITY', '$PRIORITY', '$LEVEL', '$TAG',
'$YEAR-$MONTH-$DAY $HOUR:$MIN:$SEC','$PROGRAM', '$MSG' );\n")
template-escape(yes));
};
log {
source(net);
destination(d_mysql);
};

vi /etc/init.d/sqlsyslogd (neue Datei)
Code:
case "$1" in
start)
if [ -x /var/log/mysql.pipe ]; then
mkfifo /var/log/mysql.pipe
else
# if the service is already running, do not start another one
PIDS=`pidofproc mysql`
if [ "$PIDS" ]; then
printf "sqlsyslogd is already running.\n"
exit 1
fi
mysql -u root --password=123456 syslog < /var/log/mysql.pipe &
fi
;;
stop )
killproc mysql
;;
*)
printf "Usage: sqlsyslogd {start|stop}\n"
exit 1;
esac
exit 0;


Soo... für mich ist das erstmal das minium um Fehler gering zu halten.

syslog soll also die Logeinträge in /var/log/mysql.pipe schicken.
Ich erhoffe mir dadurch, das keine Logs anhanden kommen, wenn SQL mal lahmt oder komplett tot ist.

Das Bash Script ließt sich /var/log/mysql.pipe ein und schaufelt es dann in die DB.

Soweit die Theorie.

Code:
s -ef |grep sqlsyslogd
root     22059     1  0 16:33 pts/0    00:00:00 /bin/bash /etc/init.d/sqlsyslogd start
Script läuft schon mal = schön.

cat /var/log/mysql.pipe => gibt leider nichts aus :(

Da ich aber über den Ablauf von einer pipe Datei nicht wirklich was weiß, dachte ich mir, das ich mir mal TCPdump anschaue.

tcpdump | grep syslog
Gibt leider auch kein Output.
Somit schätze ich, das der syslog Daemon noch nichts schickt.

Warum weiß ich aber auch nicht. Die Logs protokollieren leider nichts.
 
Weil ich die Logs erstmal in eine mkfifo-Datei speichern möchte. (Auf dem Server direkt).

Von dort aus wird es dann in die DB geschoben.

mkfifo-Datein sollen ja den Vorteil haben, das mehrer Programme darauf gleichzeitig schreiben/lesen können/dürfen.

Da ich später im prod. Einsatz das ganze auf einen externen Log-Server schieben möchte, kann es durchaus vorkommen, das:
* evtl. das Netzwerk hängt = Logs im Nivada verschwunden
* externer Log-Server Down = Logs im Nivada verschwunden
* Externe MYSQL DB down = Logs im Nivada verschwunden

Wie sich das ganze dann im Dauerlauf verhält wird dann nur ein Test zeigen. Dafür müsste ich aber das ganze mal auf meiner Spielwiese zum rennen bekommen. Leider wird in der messages-Datei (wo bisher auch die syslog-Einträge gespeichert werden) nicht protokolliert. Nur der syslog reboot selbst. Aber keine Fehler.
Das macht das Suchen natürlich schwierig :(
 
Ich habe gerade gesehen, dass das disk-based buffering von syslog-ng OSE nicht unterstützt wird. Vergiss meinen letzten Beitrag.
 
Also ich komme der Lösung schon mal näher.

Ich bin jetzt soweit, das ich in eine Datei schreiben kann:
Code:
destination auth { file("/var/log/auth.test"

Da ich aber in eine pipe schrieben möchte:
Code:
destination auth { pipe("/var/log/auth.pipe"

Syslog möchte dies auch tun... darf aber nicht:
Oct 29 19:31:27 Spielwiese syslog-ng[19023]: Error opening file for writing; filename='/var/log/auth.pipe', error='Permission denied (13)'

Okay... aber welches Recht braucht denn die Datei?
chmod 777 bringt keine Lösung.

chown syslog:syslog auth.pipe => aber syslog habe ich als User/gruppe nicht.

Unter was läuft denn der syslog-daemon`?
Bzw. wenn eine Datei 777 hat... warum bekomme ich dennoch "Permission denied" ?
 
juhuu.... endlich. Es läuft.

Version 2.9.xx kann anscheind NICHT in SQL loggen.

Nachdem ich ein aufwendiges Update auf die aktuelle 3er Version gemacht habe, habe ich nun erste Loggs in der DB. Zwar immer noch nicht über die pipe Datei... aber das steht vorerst auf ein anderes Blatt.


Nach dem Update bekomme ich auf tty1 etliche Logmeldungen.
Code:
Welcome to openSUSE 11.1 - Kernel 2.6.27.12-2-xen (tty1).


Spielwiese login: SFW2-INext-ACC-TCP IN=eth0 OUT= MAC=00:16:3e:1a:10:01:00:12:1e:19:d0:bc:98:00 SRC=65.***.209.39 DST=80.130.**.*** LEN=48 TOS=0x00 PREC=0x00 TTL=119 ID=19510 DF PROTO=TCP SPT=63240 DPT=80
WINDOW=65535 RES=0x00 SYN URGP=0 OPT (020405B401010402)
SFW2-INext-ACC-TCP IN=eth0 OUT= MAC=00:16:3e:1a:45:01:40:12:1e:29:d0:bc:08:00 SRC=187.40.28.221 DST=80.130.**.*** LEN=48 TOS=0x00 PREC=0x00 TTL=119 ID=20379 DF PROTO=TCP SPT=61044 DPT=25 WINDOW=65535 RES=0x00 SYN URGP=0 OPT (020405AC01010402)

Sieht mir aus wie von der Firewall.
Allerdings habe ich eine Regel für diese... es sollte also garnicht zur Visuellen Ausgabe kommen.
Code:
filter f_iptables   { facility(kern) and match("IN=") and match("OUT="); };
#
# Firewall (iptables) messages in one file:
#
destination firewall { file("/var/log/firewall"); };
log { source(src); filter(f_iptables); destination(firewall); };

Nur wird diese Datei nicht angelegt. Anscheind greift diese Regel nicht mehr.
In der Changelog wird diesbezüglich aber auch nichts genannt.

Hast du hier noch eine Idee?
 
Syslog in MySQL mit logrotate

Hallo liebe Forengemeinde,

ich habe mal dieses Thema gewählt, da es thematisch zu dem vorherigen passt.
Ich habe derzeitig den Syslog am laufen der in eine MySQL Datenbank logt. Das klappt auch einwandfrei. Nun ist es aber so, dass ich sehr viele Logs mitschreiben muss. Nun quillt meine Tabelle in der Datenbank langsam über und die Zugriffszeiten sind sehr lang. Jetzt möchte ich, dass ich die Tabelle wöchtenlich wechsle.
Lässt sich dies mit logrotate umsetzen? Wenn ja, könnte mir dazu jemand einen Denkanstoss oder sogar ein Beispiel nennen?

MFG
 
hmmm... ich ahne was du vor hast. Aber das wird in die Hose gehen... selbst wenn du es hinbekommst, das er wöchentlich in eine andere DB switcht.

Aber um deine Bitte des Denkanstoßes zu entsprechen:
Logrote bringt dir hier überhaupt nichts. Logrote arbeitet mit Datein zusammen und nicht mit einer DB.
Dein Wunsch, das Logrote deine DB aufräumt wird also nicht klappen.

Eine Möglichkeit wäre es, wenn du die syslog-ng.cfg 4mal in einen Ordner kopierst und diese entsprechend für jede Woche konfigurierst. Also immer mit verschiedene Datenbanken.
Cron wird dir dann behilflich sein, diese 4 Datein einmal pro Woche in den syslog ordner zu kopieren. syslog-ng reststen und schon sollte er in eine andere DB loggen. Das wäre nach meiner bescheidenen Meinung nach die einfachste Lösung... wenn ich davon ausgehen kann, das du mit 1 Posting noch unter Anfänger zählst.

Wenn du Fortgeschrittender User bist, kannst du dir auch ein Script schrieben, der dir entweder Zeilexxx komplett neu schreibt... oder...oder..oder. Da gibt es viele professionelle Lösungen.

ABER: Dein Vorhaben ist sclicht weg dumm. Bei Logs geht es daum, das du diese längerfristig auswerten kannst/sollst. Du hast nach Umsetzung deines Vorhabens Zugriff auf max. 7 Tage Ereignisse.

Also... schreibe dir ein PHP Script, was dir deine DB aufräumt.
Hier hast du viele Möglichkeiten.

Z.B. erstmal zählen, wieviel Emails am 25.01 gesendet worden sind.... wieviel empfangen... etc.
Das wird dann in eine neue Tabelle geschrieben und die bereits eingelesenen Daten gelöscht.

Warum läuft denn deine DB voll?
SQL kann mehrere zich hundert tausende Einträge haben.. und dennoch zügig arbeiten.

Oder läßt du dir alle Logs ohne Zeilen(Seiten)-begrenzung anzeigen :eek:

Wenn du schön alle Dienste in einer Tabelle speicherst und dein Server sauber arbeitert, dann solltest du kaum logeinträge haben.
 
Hmm,

ich möchte das ganze nochmal ein bsichen detailierter ausführen. Derzeitig nutze ich Syslog-ng um von verschiedenen Remote Clients alle Meldungen auf den Server zu loggen. Diese lasse ich in eine MySQL Datenbank schreiben. Ich filtere die Meldungen und schreibe sie in unterschiedliche Tabellen innerhalb einer Datenbank. Nun habe ich genau ein Kriterium, welche pro Sekunde je nach Tageszeit, bis zu ca. 60 Einträge macht. Nun habe ich eine Tabelle mit 24.671.379 Einträgen und ist ca 4,6 GB gross. Diese Einträge werden von mir manuell nach einer gewissen Zeit gelöscht. Zugreifen tue ich über ein selbstgeschriebens Front-End um die Daten zu analysieren. Wenn ich nun über das Front End die Blätterfunktion nutze oder nicht mehr benötigte Datensätze löschen will, braucht die Datenbank dazu ewig. Die anderen Tabellen sind davon nicht betroffen. Ich denke das hängt wohl damit zusammen, dass MySQL dafür eine andere Datei nutzt. Kann ich aber nicht genau sagen, da ich nicht weiss wie MySQL die Daten ablegt. Ist mir aber auch nicht wirklich wichtig. Das Front-End würde ich dementsprechend anpassen, so dass ich die gewünschte Woche aufrufe, die Daten auswerte und dann lösche. Um nun aber die ewigen Zeiten zu verhindern, dachte ich halt ursprünglich daran, die MySQL Tabelle innerhalb der Datenbank zu wechseln, indem ich z.b. den ersten Teil der Datetime dafür nutze. Zur Not würde ich auch tägliche neue Tabellen in Kauf nehmen.

Trotzdem danke ich aber schon einmal für deine ausführliche Antwort.
 
25Millionen Einträge ?

Sind das alle Dienste in einer Tabelle (apache,SSHD,Messages) oder nur jeweils ein Dienst ?

Aber wie gesagt: SQL kommt mit etlichen Einträgen klar. Ob 25 Mille da noch mit reinzählt, müsste ein anderer Beantworten.

Da ich eine DB habe mit IP Adressen und diese auch mehrere Millionen Einträge hat, weiß ich, das SQL damit durchaus zurecht kommt. Wobei es aber keine 25Millionen sind.

Vermuten würde ich, das deine SELECT Abfrage nicht das wahre ist.
Beispiel:
SELECT * FROM `log-apache` WHERE `level` = 'error'

Später grenzt du das dann in dein Script auf z.B. 30 Seiten.

Besser wäre hier:
SELECT * FROM `log-apache` WHERE `level` = 'error' LIMIT 0,30 oder ähnliches.

Aber das is halt nur eine Vermutung. Müsste man sich mal eine select anweisung anschaun. ggf. hast du zich Bedingungen drin die SQL erstmal durchackern müsste.

Ideal wäre, wenn du eine Parse-Time setzten kannst. Dann siehst du, wie lange SQL für die Abfrage bebraucht hat
 
Code:
Zeige Datensätze 0 - 29 (30 insgesamt, die Abfrage dauerte 37.8424 sek)
SQL-Befehl: SELECT *
FROM `temper`
WHERE datetime < '2010-01-13 12:55:35'
AND datetime < '2010-01-14 12:55:35'
ORDER BY datetime ASC
LIMIT 30 , 30

In die Datenbank werden Temperaturdaten, Luftdruckwerte sowie Lichfaktoren eingetragen.
 
uff... okay. Das sieht soweit sauber aus.

Wobei ICH eher fan von Timestamp bin. Aber das sollte SQL keine größeren Probleme machen.

Tja... dann bleibt dir tatsächlich nichts anderes übrig als das mal ein bissel umzubauen. 40sek für eine 24h Abfrage...
Selbst wenn du jetzt noch SQL Tuning betreiben würdest, kommst du auf keinen akzeptablen Wert.

Fraglich wäre jetzt noch um SELECT * tatsächlich not tut ... aber das mußt du wissen.

Also wenn ich eine solche Parse Time hätte, dann würde ich mir ein Script bauen, was einmal im Monat anläuft und je jeweiligen Monat ein eine separate DB schiebt.

Fraglich ist auch, wieviel Spalten deinen DB-Struktur aufweist. Wenn du nicht alle Felder benötigst... dann ändere die SELECT klausel.

Desweiteren wäre es evtl. sogar ratsam, ein Script zu bauen, was nachts läuft und den letzten Tag zusammenfasst und diese Informationen kummuliert wegspeichert. Hat zur Folge, das du in der Gesamtübersicht normal arbeiten kannst... und wenn sich dann mal die Detailansicht interessiert... tja... dann hast du wieder die Wartezeit.

Auch fraglich, ob du wirklich jeden Tag die Detailansicht aufrufst.
Wenn du das jetzt mit ja beantwortest, dann würde ich dir wirklich mal n grundlegenen Umbau empfehlen.

Sysng loggt immer in Tabelle 1.

EIN Script läuft nun nachts und verschiebt alle Daten in Tabelle 2.
EIN weiteres Script läuft einmal Monatlich nachts und schiebt die letzten 30 Tage in Tabelle 3.

Tabelle 1 wäre dann die 24h "live" Ansicht.
Tabelle 2 dann die 30 Tage Ansicht.
Tabelle 3 wäre dann alles.

Nur so als grober Vorschlag. Wenn du täglich die Millionen Einträge hast = dann könnte Tabelle 2 evtl. schon eine gewisse Wartezeit produzieren.

Aber ich denke, das du mein Vorschlag bzw. das Prinzip verstanden hast.
Tabelle 3 kannst du ja dann (wenn Laufzeit noch akzeptabel) auf 1 Jahr begrenzen.



ODER:
Du kaufst dir ein High-End Server auf 4 x 60GB SSHD Platten (Raid10) und ein Corei7 Quad Core Prozzi.
Ich glaube dann hast du erstmal Ruhe... ggf. ein MYSQL Cluster Verband aufbauen. Läuft wie ein "geölter Blitz" :D
 
Ok. Also die Serverleistung haben wir meiner Meinugn nach eigentlich schon ausreichend gewählt. Ist nen Quad Core Opteron mit ausreichend Speicher und Kapazität. Der macht auch nix anderes, als die Daten zu loggen und das Front End zu bedienen.

Wie müsste so nen Script ungefähr aussehen? Ich hab mich damit noch überhaupt nicht beschäftigt. Ich kann wohl mit MySQL und PHP um usw. aber mit Scripts kenn ich mich gar nicht aus.

So wie ich das verstanden habe, (Korrekturen gerne gesehen, wenn das nicht richtig ist) mach ich das wohl über einen Cronjob.
Innerhalb des Crons lasse ich die Tabelle täglich kopieren. Ich glaub einfacher wäre auch sie einfach umzubenennen und dann die Standart Tabelle wieder neu erstellen, oder?

Wie kann ich denn wohl per Script den Namen der Tabelle festlegen? Z.b. Timestamp oder Datetime? Da gibt es ja sicherlich eine Variable für, oder?

Viele Fragen :)
 
Code:
Gelöschte Zeilen: 928235 (die Abfrage dauerte 283.3290 sek)
SQL-Befehl: DELETE FROM `temper` WHERE datetime < '2009-07-26 08:00:00'

Mal nochwas zu der Laufzeit :confused:
 
Wie müsste so nen Script ungefähr aussehen? Ich hab mich damit noch überhaupt nicht beschäftigt. Ich kann wohl mit MySQL und PHP um usw. aber mit Scripts kenn ich mich gar nicht aus.
Na so wirst du hier nicht weiterkommen.
Denke mal nicht, das dir hier jm. den ganzen Code vorkaut.
1: SELECT * ... WHERE 'tag' >= 00:00:00 AND 'tag' =< 23:59:59
Das sind die Daten, die du wegspeichern willst. Pack diese in ein array und lass dann eine Schleife drüberlaufen, die dir diese Daten als Update Anweisung zusammenbaut.

Die neue Update Anweisung schickst du nun in die neue Tabelle.

Im nächsten zuge extrahierst du aus dem Array alle ID's. Denn nun kannst du dir ein Delete Befehl zusammen bauen.

So wie ich das verstanden habe, (Korrekturen gerne gesehen, wenn das nicht richtig ist) mach ich das wohl über einen Cronjob.
Korrekt. Du schreibst dir erstmal das Script (normale PHP Datei) die dann zur gewissen Zeit von Cron ausgeführt wird.

Innerhalb des Crons lasse ich die Tabelle täglich kopieren. Ich glaub einfacher wäre auch sie einfach umzubenennen und dann die Standart Tabelle wieder neu erstellen, oder?
Also MIR fällt jetzt kein Befehl ein, der das gewähleisten würde.
Wobei das eh überflüssig ist, da du damit das ganze System zerstörst.
Angenommen es gibt ein Befehl dann wird auch dieser sicherlich eine gwisse Laufzeit haben. Im Anschluß erstellst du die neue Tabelle... aber was sind mit den neu reingekommenen Daten innerhalb der Laufzeit?
Ausserdem kannst du es schlecht skalieren. Wenn du innerhalb einer Sekunde soviele Datein reinbekommst = dann hast du schon mehr als nur 24h verschoben

Wie kann ich denn wohl per Script den Namen der Tabelle festlegen? Z.b. Timestamp oder Datetime? Da gibt es ja sicherlich eine Variable für, oder?
Viele Fragen :)
Wie gesagt = ICH bevorzugs das. Das Umstellen bringt dir nicht viel. da du dann auch das Programm erweitern mußt, das die Daten in die DB drückt. Vermutlich hast du hier aber keinen Zugriff.


Soo... mittlerweile wird es gewaltig Off-Topic.
Du brauchst PHP+MYSQL Programmierkenntnisse. Und in dieser Rubrik befinden wir uns beim besten Willen nicht.
 
Jut dann trotzdem schönen Dank. DIE Programmierkentnisse sind ja wenigstens vorhanden, somit sollte ich das wohl schaffen.
 
Back
Top