Po zhvillojmë ndërfaqen më të përshtatshme në botë* për shikimin e log-eve

Po zhvillojmë ndërfaqen më të përshtatshme në botë* për shikimin e log-eve Nëse ndonjëherë keni përdorur ndërfaqe uebi për të parë log-ët, me siguri keni vënë re se, në të shumtën e rasteve, këto ndërfaqe janë të ngarkuara dhe ( shpesh) nuk janë shumë të rehatshme dhe reaguese. Disa mund të zakonshme, disa janë krejtësisht të tmerrshme, por, siç mendoj unë, arsyeja e gjitha problemeve është se i qasemi gabimisht detyrës së shikimit të log-ëve: mundohemi të krijojmë një ndërfaqe uebi aty ku funksionon më mirë CLI (ndërfaqja e komandave). Personalish, më pëlqen të punoj me tail, grep, awk dhe të tjerë, dhe prandaj për mua mezi pres të kisha një ndërfaqe të ngjashme me tail dhe grep, e cila e njëjta kohë mund të përdoret për të lexuar log-ët që vijnë nga shumë serverë. Pra, natyrisht, t'i lexosh ato nga ClickHouse!

*sipas mendimit personal të përdoruesit të Habra youROCK

Përshëndetni logscli

Nuk kam gjetur një emër për ndërfaqen time, dhe, për të qenë të sinqertë, ajo ekziston më shumë si një prototip, por nëse dëshironi të shihni menjëherë burimet, mirëseerdhet: https://github.com/YuriyNasretdinov/logscli (350 rreshta kod të përzgjedhur në Go).

Mundësitë

Kisha që kisha për të bërë një ndërfaqe që do të dukej e njohur për ata që janë mësuar me tail/grep, do të thotë se mbështet këto gjëra:

  1. Shikimi i të gjitha logeve, pa filtrimin.
  2. Lëni rreshtat që përmbajnë një nën-string të caktuar (flamuri -F u grep).
  3. Lëni rreshtat që përshtaten me një shprehje të rregullt (flamuri -E u grep).
  4. Për default, shikimi bëhet në rendin e kronologjisë së kundërt, pasi zakonisht janë loget më të freskëta ato që janë më interesante.
  5. Trego kontekstin përreth çdo rrjeshti (parametrat -A, -B dhe -C u grep, që printojnë N rreshta para, pas, dhe përreth çdo rreshti të përputhjes përkatësisht).
  6. Shikimi i logeve të ardhura në kohë reale, me filtrimin dhe pa të (në thelb tail -f | grep).
  7. Ndërfaqja duhet të jetë e kompatibilitetshme me më pak, head, tail dhe të tjera — për default, rezultatet duhet të kthehen pa kufizime në numrin e tyre; rreshtat printohen në mënyrë të vazhdueshme derisa përdoruesi të jetë i interesuar për t'i marrë; sinjali SIGPIPE duhet të ndërpresë heshtur transmetimin e logeve, ashtu siç bëjnë tail, grep dhe utilitetet e tjera UNIX.

Realizimi

Do të supozoj se ju tashmë diçka siç u keni dërguar loget në ClickHouse. Nëse jo, atëherë rekomandoj të provoni lsd dhe kittenhouse, si dhe këtë artikull për dërgimin e logëve.

Së pari, duhet të përcaktojmë skemën e bazës. Duke qenë se logët zakonisht dëshirojmë t'i marrim të renditura sipas kohës, është logjike t'i ruajmë ashtu. Nëse ka shumë kategori logësh dhe ato janë të njëjta, mund ta bëjmë kategorinë e logëve kolona e parë e çelësit primar - kjo do të lejojë të kemi një tabelë në vend të disa, që do të jetë një përmirësim i madh kur futim në ClickHouse (në serverat me disqe të ngurtë rekomandohet të futen të dhënat jo më shpesh se ~1 herë në sekondë për të gjithë serverin).

Pra, na nevojitet një skemë tabelash e tillë:

CREATE TABLE logs(
    category LowCardinality(String), -- kategoria e logëve (opcional)
    time DateTime, -- koha e ngjarjes
    millis UInt16, -- milisekondat (mund të jenë gjithashtu mikroskonda, etj.): rekomandohet të ruhen, nëse ka shumë ngjarje, për të lehtësuar ndarjen e ngjarjeve nga njëra-tjetra
    ..., -- fusha tuaja, për shembull emri i serverit, niveli i logaritjes, etj.
    message String -- teksti i mesazhit
) ENGINE=MergeTree()
ORDER BY (category, time, millis)

Fatkeqësisht, nuk arrita të gjej burime të hapura me logje realiste që mund të merrja dhe shkarkoja menjëherë, prandaj përdora si shembull në vend të kësaj komente për produkte nga Amazon deri në vitin 2015. Sigurisht, struktura e tyre nuk është krejtësisht e njëjtë me atë të logjeve tekstuale, por për ilustrim kjo nuk është thelbësore.

udhëzimi për ngarkimin e komenteve Amazon në ClickHouse

Të krijojmë një tabelë:

CREATE TABLE amazon(
   review_date Date,
   time DateTime DEFAULT toDateTime(toUInt32(review_date) * 86400 + rand() % 86400),
   millis UInt16 DEFAULT rand() % 1000,
   marketplace LowCardinality(String),
   customer_id Int64,
   review_id String,
   product_id LowCardinality(String),
   product_parent Int64,
   product_title String,
   product_category LowCardinality(String),
   star_rating UInt8,
   helpful_votes UInt32,
   total_votes UInt32,
   vine FixedString(1),
   verified_purchase FixedString(1),
   review_headline String,
   review_body String
)
ENGINE=MergeTree()
ORDER BY (time, millis)
SETTINGS index_granularity=8192

Në datasetin e Amazonit ka vetëm datën e rishikimit, por nuk ka kohën e saktë, prandaj do të mbushim këto të dhëna me rastësi.

Nuk është e nevojshme të shkarkoni të gjitha skedarët tsv dhe mund të kufizoheni në të parët ~10-20, për të marrë një grup të dhënash mjaft të madh që nuk do t'i përshtatet 16 GB RAM. Për ngarkimin e skedarëve TSV kam përdorur komandën e mëposhtme:

për i në *.tsv; bëj
    echo $i;
    tail -n +2 $i | pv |
    clickhouse-client --input_format_allow_errors_ratio 0.5 --query='INSERT INTO amazon(marketplace,customer_id,review_id,product_id,product_parent,product_title,product_category,star_rating,helpful_votes,total_votes,vine,verified_purchase,review_headline,review_body,review_date) FORMAT TabSeparated'
done

Në një Disk të Qëndrueshëm Standard (i cili është HDD) në Google Cloud me një madhësi prej 1000 GB (ky madhësi e kam marrë kryesisht për të rritur pak shpejtësinë, megjithëse ndoshta një SSD me madhësi të duhur do të kishte dalë më lirë) shpejtësia e ngarkimit ishte rreth ~75 MB/sec në 4 bërthama.

  • Duhet të sqaroj se punoj në Google, por kam përdorur një llogari personale dhe ky artikull nuk ka lidhje me punën time në kompaninë.

Të gjitha ilustruarat do t'i prodhoj pikërisht me këtë dataset, pasi kjo është gjithçka që kam pasur në dorë.

Tregon përparimin e skanimit të të dhënave

Pasi në ClickHouse do të përdorim skanimin e plotë të tabelës me logjet, dhe kjo operacion mund të zgjasë një kohë të konsiderueshme dhe të mos japë asnjë rezultat të menjëhershëm, nëse ka pak përputhje, është e dëshirueshme të mund të tregojmë përparimin e ekzekutimit të kërkesës deri në marrjen e rreshtave të parë me rezultat. Për këtë, në ndërfaqen HTTP ka një parametër që lejon kthimin e përparimit në titujt HTTP: send_progress_in_http_headers=1. Fatke, standardi i bibliotekës Go nuk është në gjendje të lexojë titujt gjatë marrjes së tyre, por interfaca HTTP 1.0 (mos e ngatërroni me 1.1!) mbështetet nga ClickHouse, prandaj është e mundur të hapni një lidhje TCP të papërpunuar me ClickHouse dhe t'i dërgoni atij GET /?query=... HTTP/1.0nn dhe të merrni përgjigje me tituj dhe trupin e përgjigjes pa asnjë ekranuar dhe enkriptim, kështu që në këtë rast nuk na nevojitet as standardi i bibliotekës.

Streaming logëve nga ClickHouse

Që nga viti 2019, ClickHouse ka një optimizim për kërkesat me ORDER BY, kështu që kërkesa e këtij tipi

SELECT time, millis, message
FROM logs
WHERE message LIKE '%something%'
ORDER BY time DESC, millis DESC

do të fillojë të kthejë menjëherë rreshtat që kanë në mesazhin e tyre substrat "something", pa pritur përfundimin e skanimit.

Gjithashtu, do të ishte shumë praktike nëse ClickHouse do të anulonte automatikisht kërkesën kur lidhja me të mbyllet, por kjo nuk është një sjellje e paracaktuar. Anulimi automatik i kërkesës mund të aktivizohet me opsionin cancel_http_readonly_queries_on_client_close=1.

Shtimi i saktë i SIGPIPE në Go

Kur ju ekzekutoni, për shembull, komandën some_cmd | head -n 10, si do ta ndalojë komandën some_cmd ekzekutimin e saj, kur head ke ke lexuar 10 rreshta? Përshtypja është e thjeshtë: kur head përfundon, pipe mbyllet, dhe stdout i komandës some_cmd fillon të tregojë, thënë ndryshe, «në asnjë vend». Kur some_cmd përdoruesi përpiqet të shkruajë në një pipe të mbyllur, ai merr një sinjal SIGPIPE, i cili në mënyrë të paracaktuar përfundon heshtazi programin.

Në Go kjo ndodh po ashtu, por procesori i sinjalit SIGPIPE në fund gjithashtu printon "sinjal: SIGPIPE" ose një mesazh të ngjashëm, dhe për ta hequr këtë mesazh, thjesht duhet ta trajtosh vetë SIGPIPE ashtu siç dëshiron, pra thjesht të dalësh heshtazi:

ch := make(chan os.Signal)
signal.Notify(ch, syscall.SIGPIPE)
go func() {
    <-ch
    os.Exit(0)
}()

Shfaqja e kontekstit të mesazhit

Shpesh dëshirohet të shihet konteksti në të cilin ndodhi ndonjë gabim (për shembull, cili kërkesë shkaktoi panik, apo cilat probleme shoqëruese ishin të dukshme para rënies), dhe në grep këtë qëllim shërbejnë opsionet -A, -B dhe -C, të cilat tregojnë numrin e caktuar të rreshtave pas, para dhe rreth mesazhit përkatës.

Fatkeqësisht, nuk gjetëm një mënyrë të thjeshtë për të bërë të njëjtën gjë në ClickHouse, prandaj, për të treguar kontekstin, për çdo rresht rezultati dërgohet një kërkesë shtesë e tipit më poshtë (detajet varen nga renditja dhe nëse tregohet konteksti para ose pas):

SELECT time,millis,review_body FROM amazon
WHERE (time = 'KOHË_E_NGJARJES' AND millis < MILLISEKUNDAT_E_NGJARJES) OR (time < 'KOHË_E_NGJARJES')
ORDER BY time DESC, millis DESC
LIMIT NUMRI_I_RRESHTAVE_TË_KONTEKSTIT
SETTINGS max_threads=1

Për shkak se kërkesa dërgohet pothuajse menjëherë pasi ClickHouse ka kthyer rreshtin përkatës, ai hyn në cache dhe në përgjithësi kërkesa ekzekutohet mjaft shpejt dhe konsumon pak CPU (zakonisht që kërkesa zgjat rreth ~6 ms në makinen time virtuale).

Shfaqja e mesazheve të reja në kohë reale

Për të shfaqur mesazhet që po vijnë në mënyrë (të pothuaj) reale, thjesht ekzekutojmë kërkesën çdo disa sekonda, duke mbajtur mend timestampin e fundit që takuam më parë.

Shembuj komandash

Si duken komandat tipike logscli në praktikë?

Nëse keni ngarkuar datasetin Amazon, që përmenda në fillim të artikullit, atëherë mund të ekzekutoni komandat e mëposhtme:

# Показать строки, где встречается слово walmart
$ logscli -F 'walmart' | less

# Показать самые свежие 10 строк, где встречается "terrible"
$ logscli -F terrible -limit 10

# То же самое без -limit:
$ logscli -F terrible | head -n 10

# Показать все строки, подходящие под /times [0-9]/, написанные для vine и у которых высокий рейтинг
$ logscli -E 'times [0-9]' -where="vine='Y' AND star_rating>4" | less

# Показать все строки со словом "panic" и 3 строки контекста вокруг
$ logscli -F 'panic' -C 3 | less

# Непрерывно показывать новые строки со словом "5-star"
$ logscli -F '5-star' -tailf

Linke

Kodi i utilitetit (pa dokumentacion) është i disponueshëm në github në adresën https://github.com/YuriyNasretdinov/logscli. Do të isha i lumtur të dëgjoja mendimet tuaja rreth ideës time për një ndërfaqe konsolë për shikimin e logeve të bazuara në ClickHouse.

Burimi: habr.com

Bli një hosting të besueshëm për faqet me mbrojtje DDoS, VPS VDS serverë 🔥 Bli një hosting të besueshëm për faqet me mbrojtje DDoS, VPS VDS serverë | ProHoster