Log gyűjtés, egy kicsit másképp

Központosított logolás építése rsyslog és MongoDB segítségével

CC0 image by StockSnap

Ma a központosított logolásról lesz szó. No nem arról a szintről, amikor az alkalmazásod több tíz gigányi logot termel naponta és azt kellene valahova elpakolnod. Arra ott a méltán híres ELK stack. Nem, mi maradunk a hobbi szintnél, amikor van néhány géped, amik lehet, hogy egész életük során összesen nem látnak majd több tíz gigányi logot.

Elképzelhető, hogy nagyobb forgalom mellett is működhet egy ilyesmi felállás, de odáig nem jutott el ez a kis projekt, hogy méréseket is végezzek. Kicsit korábban sikerült már akadályokba ütközni, de erről majd később, kezdjük az elején.

A központosítás

Minden (jó linuxos) háztartásban megtalálható egy syslog. Most konkrétan az rsyslog változatával fogunk foglalkozni, de az elv valószínűleg a többivel is működhet. Először is szükségünk van egy központi szerverre, aminek küldhetjük az adatokat. Szerencsénkre az rsyslog-nak megmondhatjuk, hogy legyen olyan kedves és kívülről is fogadjon be logsorokat:

/etc/rsyslog.conf
module(load="imtcp")
input(type="imtcp" port="514")

Amit itt érdemes tudni, hogy ez egy plain text kommunikáció, így ha féltjük a logjainkat a gonosz kémektől, gondoskodnunk kell a biztonságukról. Az rsyslog tud TLS-en is kommunikálni, de felhúzhatunk egy SSH tunnel-t vagy VPN-t is a gépek között. A következő parancs segítségével kipróbálhatjuk, hogy minden jól működik-e:

$ logger -n <központi szerver> -P 514 -T "Test message"

Ezek után már csak a kliens gépeket kell beállítani, hogy továbbítsák a logjaikat a központba:

/etc/rsyslog.d/10-forward.conf
action(type="omfwd" Target="<központi szerver>" Port="514" Protocol="tcp")

És kész is vagyunk. Köszönöm a figyelmet, gyertek máskor is.

Az adatbázis

Na jó, nem ússzátok meg ennyivel. Az igaz, hogy egy központi gépen vannak a logjaink, de még mindig csak fájlokban. Mi lenne, ha mondjuk inkább MongoDB-be pakolnánk?

Nyilván nem sokkal lennénk előrébb, ha csak soronként bedobálnánk őket egy adatbázisba. Viszont ha valami egyszerűen feldolgozható formátumban érkeznének, mondjuk JSON-ként...

/etc/rsyslog.d/10-forward.conf
template(name="syslog-json" type="list") {
  constant(value="{")

  constant(value="\"timestamp\":\"")
  property(name="timereported" dateFormat="rfc3339" format="json")

  constant(value="\",\"host\":\"")
  property(name="hostname" format="json")

  constant(value="\",\"tag\":\"")
  property(name="programname" format="json")

  constant(value="\",\"facility\":\"")
  property(name="syslogfacility-text" format="json")

  constant(value="\",\"severity\":\"")
  property(name="syslogseverity-text" format="json")

  constant(value="\",\"message\":\"")
  property(name="msg" format="json")

  constant(value="\"}")
}

action(type="omfwd" template="syslog-json" Target="<központi szerver>" Port="514" Protocol="tcp")

Most már futhat valami service a központi gépen, ami figyeli a logfájlokba érkező új sorokat és betolja őket az adatbázisba. Vagy akár írhatunk egy egyszerű log fogadó szervert is, ami közvetlenül adatbázisba menti az érkező sorokat.

server.js
const net = require('net');
const readline = require('readline');
const MongoClient = require('mongodb').MongoClient;

(async () => {
  const host = '127.0.0.1';
  const port = 514;
  const connstring = 'mongodb://localhost:27017';

  const db = (await MongoClient.connect(connstring)).db('logging');

  net.createServer(socket => {
    const rl = readline.createInterface(socket, socket);
    rl.on('line', async data => {
      let jsonData = JSON.parse(data.toString().trim());
      jsonData.timestamp = new Date(jsonData.timestamp);

      await db.collection('syslog').insertOne(jsonData);
    });
  }).listen({ host, port, exclusive: true });
})();

A syslog protokol nem egy bonyolult jószág, a konkrét logsorokat küldi, így soronként egy-egy JSON-t kapunk, ami mehet is az adatbázisba. Vagy mentés előtt még végezhetünk rajta módosításokat, ha szükségesnek látjuk (például a dátumot string-ként tartalmazó mezőt Date objektummá alakíthatjuk).

Ezen a ponton megvan minden log a szervereinkről... amik syslog-ba érkeznek. Mi a helyzet a többivel? Ha az alkalmazás elég okos, akkor tud direktbe logolni a központi szerverre JSON formátumba. Vagy küldheti a logokat a lokális rsyslog-nak, ami majd továbbítja őket a központba.

/etc/rsyslog.d/10-forward.conf
template(name="json-msg" type="list") {
  property(name="msg")
}

if $syslogfacility-text == "local7" then {
  action(type="omfwd" template="json-msg" Target="<központi szerver>" Port="514" Protocol="tcp")
  stop
}

Itt a local7 facility-re érkező logoknál arra számítunk, hogy a log üzenet már egy valid JSON, így a többi részét figyelmen kívül hagyhatjuk és csak azt továbbítjuk.

Alább pedig az látható, hogy az nginx-et (1.11.8-as verziótól) hogyan tudjuk rábírni arra, hogy JSON formátumban küldje a logjait az rsyslog-nak. A local7 facility nála az alapbeállítás, úgyhogy azzal nem is kell törődnünk.

/etc/nginx/conf.d/10-logformat.conf
log_format json escape=json '{"timestamp": $msec, '
  '"network":{'
  '"client_ip": "$remote_addr", '
  '"bytes_write": $body_bytes_sent}, '
  '"http":{'
  '"ident": "$host", '
  '"response_time": $request_time, '
  '"status_code": $status, '
  '"request": "$request_uri", '
  '"verb": "$request_method", '
  '"referer": "$http_referer", '
  '"useragent": "$http_user_agent"}, '
  '"message": "$request"}';

access_log syslog:server=unix:/dev/log,nohostname json;

A megjelenítés

Itt kezdtek felmerülni a problémák. A MongoDB egyértelmű választásnak tűnt még azon a ponton, amikor JSON dokumentumokat kellett tárolni, de ha egy Kibana szerű felületet is szeretnénk hozzá, akkor már nem érződik annyira jó döntésnek.

Persze mindig ott a lehetőség, hogy megírunk magunknak egy hasonló felületet. Megfelelően kicsi scope mellett talán van is esély a befejezésre, de ez azért távol áll az ideális helyzettől. Némi keresés után a Redash-t sikerült még megtalálnom. Támogatja a MongoDB-t, tud grafikonokat generálni az adatokból és van lehetőség mentett lekérdezésekre is.

Query szerkesztő

Példa dashboard

Határozottan kényelmetlenebbnek érződik, mint a Kibana. Főleg a lekérdezések összerakása (ami egy hatalmas JSON), de a grafikonok se olyan kényelmesek/okosak. Annyi előnye azért még biztos van, hogy nem kell lefejleszteni.

Összességében egy remek hétvégi program volt kicsit közelebbről megismerkedni a syslog-gal és megpróbálni összerakni egy alternatív megoldást. Csak ajánlani tudom mindenkinek, mint tapasztalatszerzési lehetőséget. Viszont ha éles rendszerek központi logolásáról van szó, lehet, hogy jobban járunk a kitaposott ösvényekkel.

Hozzáfűznél valamit?

Dobj egy emailt a blog kukac deadlime pont hu címre.

Feliratkoznál?

Az RSS feed-et ajánljuk, ha kedveled a régi jó dolgokat.