Aplikacijų monitoringas: Splunk

Svarbiausia monitoringo paskirtis – laiku pastebėti problemas. Jau anksčiau rašiau apie būdą kaip saugoti klaidas. Visgi aptartas būdas turi keletą problemų.
Saugomas klaidas tarkime duomenų bazių lentelėje peržiūrime retai, taigi apie greitą reakciją ir kalbos negali būti. Klaidų pranešimai el. paštu gelbsti laikinai, galop el. paštas gali būti apkrautas daugybe pranešimų į kuriuos natūraliai jau pradedi nebereaguoti, arba gali būti taip, kad klaida kartojasi cikle, tuomet net dešimties minučių laikotarpio pakanka tam, kad paštas bus verčiamas laiškais net kelias dienas. Dar gali atsirasti klaidų senuose projektuose prie kurių jokių FTP prisijungimų jau nebėra ir pan.
Nutariau rasti centralizuotą sprendimą kuris padėtų surinkti visas klaidas į vieną vietą tolimesnei analizei. Pirmiausia ką radau tai servisas loggly tačiau nemokama paskyra turi apribojimų, greitis taip pat testavimo metu buvo neypatingas. Kitas niuansas yra tai, kad klaidos saugomos trečiųjų šalių serveriuose, o kaip žinia klaidos gali turėti pakankamai jautrios informacijos. Taigi antra idėja buvo pasirašyti kažką panašaus pačiam. Tačiau teko jos greitai atsisakyti, nes kažkokiam rimtesniam funkcionalumui suprojektuoti ir aprašyti reikia daugybės laiko. Po kelių bandymų ieškant analogų radau splunk.
Nemokama paskyra leidžia indeksuoti iki 500 MB per dieną, kas yra tikrai daug. Taip pat teks atsisakyti keleto funkcijų kurių tiesa pasakius jau kelis mėnesius naudodamas – nepasigedau. Detaliau galėsite pasinagrinėti čia. Tikslas yra vienas, sau ir kitiems kolegoms suteikti galimybę peržiūrėti ir analizuoti klaidas. Jei kam reikia daugiau – galite pasirinkti mokamą paskyrą, bet kainos ten tikrai nemažos.
Iš esmės šis produktas rinkti visą informaciją, log’us, klaidas ir t.t. bet kadangi aš splunk naudoju tik klaidoms rinkti, tai plačiau kitų funkcijų nenagrinėsiu.
Taigi, kaip surenkamos klaidos. Yra galimybė tiesiog skaityti kokį lokalų failą, klausytis TCP arba UDP porto arba galima pasirašyti savo skriptą kuris surenka norimą informaciją. Klausantis porto, galite nukreipti savo serverio syslog’ą į splunk, o tarkime PHP klaidas loginti su error-log funkcija. Aš truputį nusižiūrėjęs nuo loggly sumaniau klaidas perduoti per curl. Kodėl? O gi priežastis paprasta – dalis projektų talpinama ne mūsų serveriuose (užsakovų nuomojami shared hostingai ir pan), todėl apie kažkokius syslog galima paprasčiausia pamiršti. O curl veikia visur ir visada.
Tik yra vienas BET. Jei kilus kažkokioms problemoms nepavyksta perduoti klaidos pranešimo, tuomet lankytojas tai iš karto pajus. Žinoma yra curl timeout, tačiau jis nutrauks susijungimą ir niekas apie jokias problemas nebe sužinos. Čia į pagalbą pasitelkiau nodeJS. Man labai patinka galimybė gražinti HTTP susijungimui kažkokį response ir nutraukti susijungimą, o toliau ramiai dirbti numatytus darbus. Tarkime perdavimas į splunk trunka 10sek, tai PHP taip ir lauks tas 10 sek, o lankytojas matys kaip puslapis retai kraunasi. Su nodeJS kaip tarpininku PHP perduoda informaciją ir gavės response sau ramiai baigia darbą, o nodeJS dirba toliau.

var HOST = '192.168.xx.x';
var HOST2 = '192.168.xx.x';
var PORT = 9997;
 
exports.log = function (req, res) {
    res.end('{"status":"ok"}');
    var host = req.headers.host=='log.domain.ltd'?HOST2:HOST;
    var message = {
        host_from:req.headers.host,
        type:'log',
        message:req.body
    };
 
    var client = new net.Socket();
    client.setTimeout(1000, function () {
        client.destroy();
    });
    client.connect(PORT, host, function () {
        client.write(JSON.stringify(message));
    });
    client.on('data', function (data) {
        client.destroy();
    });
    client.on('close', function () {});
};

Čia ištrauka iš mano naudojamos nodeJS express aplikacijos kur tiesiog perduodu į splunk viską ką gaunu per POST, plius pagal tai į kurį domeną atėjo duomenys paskirstau į kelis skirtingus splunk serverius. Jei konkrečiai tai tiesiog atskyriau production error’us nuo development.
Na o PHP pusėje viskas atrodo taip:

        if (defined('LOG_SERVER')) {
            $array = array(
                'type'=>$error['type'],
                'error_type'=>$error['error_type'],
                'line'=>$error['line'],
                'file'=>$file,
                'path'=>$path,
                'host'=>$host,
                'message'=>$full_message,
                'request_uri'=>$request_uri,
                'trace'=>self::cleanTrace($error['trace']),
                'server_name'=>$server_name,
                'identifier'=>defined('IDENTIFIER')?IDENTIFIER:'unknown'
            );
 
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, LOG_SERVER);
            curl_setopt($ch, CURLOPT_HTTPHEADER, array('content-type:application/json'));
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch,CURLOPT_TIMEOUT,5);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS,  json_encode($array));
            curl_exec($ch);
            curl_close($ch);
        }

Labai nesigilinant – į masyvą surenkama informacija iš pagautų exceptionų ar klaidų ir išsiunčiama į nurodytą nodeJS aplikaciją.
Toliau einame prie paties splunk. Įdiegimas paprastas, tiesiog atsisiunčiame .deb ar kokį kitą jūsų distribucijai tinkamą instaliacijos failą ir įdiegiame. Jokių sudėtingų konfigūracijos klausimų nesulauksite, viskas labai paprasta. Su komanda /opt/splunk/bin/splunk start pasileidžiame serverį (šią komandą iškarto įsidedame į cronjob’ą priekyje prirašę @reboot), tuomet su naršykle jungiamės prie serverio IP nurodę portą 8000.
Pirmas darbas yra nusistatyti nemokamą licenciją, kad per daug neprisirištumėme prie mokamos paskyros privalumų :) . Taigi sukuriame pirmą input’ą „test“ ant tarkime porto TCP 3000 porto.

Tuomet pasirošome mini nodeJS programėlę:

var http = require('http')
    , net = require('net');
 
http.createServer(function (req, res) {
  res.end('OK');
  console.log('message accepted');
  var data = "";
  req.on('data',function(chunk) {
   data += chunk;
  });
  req.on('end',function() {
    var client = new net.Socket();
    client.setTimeout(1000, function () {
     client.destroy();
    });
    client.connect(3000, '127.0.0.1', function () {
     client.write(data);
    });
    client.on('data', function (data) {
     client.destroy();
    });
    client.on('close', function () {});
  });
}).listen(1337, '0.0.0.0');

Ją pasileidę kitoje konsolėje gali vykdyti komandas imituodami kokios nors aplikacijos darbą:

curl --data '{"type":"test","host":"domainA.ltd","message":{"error":"some error","file":"some file","line":"some line","trace":["step 1","step 2"]}}' -m 1 http://localhost:1337;
curl --data '{"type":"test","host":"domainB.ltd","message":{"error":"some error","file":"some file","line":"some line","trace":["step 1","step 2"]}}' -m 1 http://localhost:1337;

Jei curl užklausą paleistumėme tiesiai ant 3000-ojo port’o, pamatytumėme, kad curl turi laukti visą sekundę, nes splunk nieko negrąžina ir susijungimo nenutraukia, tad nodeJS puikiai sugeria tą laukimą. Taip pat kai splunk informaciją gauna maišytu formatu – neveikia syntax highlight ir kyla problemų su laukelių indeksavimu.
Taigi grįžtame prie web gui ir pasirenkame aplikaciją „search“ ir ten matysime visus sukurtus inputus. Spaudžiame ant savo sukurto vienintelio inputo ir matome savo žinutes kurias perdavėme per curl

Paspaudus ant kurios nors laukelio reikšmės ši automatiškai atsiranda paieškoje, kad padėtų atrinkti dominančius pranešimus. Pavyzdžiui jei norime matyti tik pranešimus iš domainB.ltd tai paieškos laukelyje reikia nurodyti source=“test“ | spath „host“ | search „host“=“domainB.ltd“. Paieška yra labai galinga, taip pat kažką berašant splunk nuolat sufleruoja kokios yra galimybės, turėdami laiko galėsite pasinagrinėti giliau. Didelis privalumas yra tai, kad paiešką galima išsaugoti. Taip pat naudinga smulkmena yra tai, kad visi parametrai yra matomi url’e tad patogu atfiltravus tam tikrus pranešimus numesti nuorodą kolegai, kuris gali problemas ištaisyti. Kaip bebūtų keista ši smulkmena dažnai pamirštama daugybės programuotojų :)
Šiame trumpame straipsnyje turbūt neapžvelgiau net pusės visų splunk galimybių (gali būti, kad pusės ir nežinau), tačiau dabar žinosite, kad toks dalykas yra ir galėsite išsibandyti savo aplinkoje. Svarbiausias darbas padarytas – visos klaidos surenkamos į vieną vietą ir laisvai minutei atsiradus galime analizuoti.

Žygimantas

Lead developer at Soundest. Zend Certified Engineer.

More Posts - Website

Žymos: , ,

4 komentarai

  1. Darxx

    Visai teisingai. Tik manau būtų neblogai AngularJs dar panaudoti su NodeJs ir toliau plėtoti GUI.

    • NodeJS šiuo atveju veikia tik kaip proxy ir nieko daugiau. Rašyti savo GUI buvau užsidegęs, bet pamačius kiek yra darbo kad padaryti bent mažą dalį iš esamų įrankių – atsisakiau.

      • Darxx

        Pamėgink AngularJS. Asmeniškai GUI pusėje man labai sumažino darbo. jQuery gerai tačiau per daug aprašyti reikia palyginus su AngularJs. Ir aplikacijai augant su jquery kodas tampa netestuojamas. Tačiau abi bibliotekos lieka labai vertos dėmesio.

Parašykite komentarą

El. pašto adresas nebus skelbiamas. Būtini laukeliai pažymėti *

Galite naudoti šias HTML žymas ir atributus: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>