Vyvíjame najpohodlnejšie rozhranie na svete* na prezeranie denníkov

Vyvíjame najpohodlnejšie rozhranie na svete* na prezeranie denníkov Ak ste niekedy používali webové rozhrania na prezeranie protokolov, pravdepodobne ste si všimli, že tieto rozhrania sú spravidla ťažkopádne a (často) nie príliš pohodlné a citlivé. Na niektoré sa dá zvyknúť, niektoré sú úplne hrozné, ale zdá sa mi, že dôvodom všetkých problémov je, že nesprávne pristupujeme k úlohe prezerania protokolov: snažíme sa vytvoriť webové rozhranie, v ktorom je CLI (rozhranie príkazového riadku) funguje lepšie. Mne osobne veľmi vyhovuje práca s tail, grep, awk a ďalšími, a preto by pre mňa bolo ideálne rozhranie pre prácu s logami niečo podobné ako tail a grep, ktoré by sa však dalo použiť aj na čítanie logov, ktoré prišli z mnohých serverov. To je, samozrejme, prečítajte si ich z ClickHouse!

*podľa osobného názoru používateľa habra ide ti to

Zoznámte sa s logscli

Názov pre svoje rozhranie som nevymyslel a, úprimne povedané, existuje skôr vo forme prototypu, ale ak chcete okamžite vidieť zdrojový kód, ste vítaní: https://github.com/YuriyNasretdinov/logscli (350 riadkov zvoleného Go kódu).

Možnosti

Mojím cieľom bolo vytvoriť rozhranie, ktoré by sa zdalo známe tým, ktorí sú zvyknutí na tail/grep, teda na podporu nasledujúcich vecí:

  1. Zobraziť všetky denníky bez filtrovania.
  2. Ponechajte riadky obsahujúce pevný podreťazec (príznak -F у grep).
  3. Nechajte riadky, ktoré zodpovedajú regulárnemu výrazu (príznak -E у grep).
  4. V predvolenom nastavení je prezeranie v obrátenom chronologickom poradí, pretože ako prvé sú zvyčajne zaujímavé najnovšie protokoly.
  5. Zobraziť kontext vedľa každého riadku (možnosti -A, -B и -C у greptlač N riadkov pred, za a okolo každého zodpovedajúceho riadku).
  6. Prezerajte si prichádzajúce denníky v reálnom čase, s filtrovaním alebo bez filtrovania (v podstate tail -f | grep).
  7. Rozhranie musí byť kompatibilné s less, head, tail a iné - štandardne by sa výsledky mali vracať bez obmedzenia ich počtu; riadky sa tlačia ako prúd, pokiaľ má používateľ záujem o ich príjem; signál SIGPIPE by mali ticho prerušiť streamovanie denníka, rovnako ako oni tail, grep a ďalšie nástroje UNIX.

Реализация

Budem predpokladať, že už nejako viete, ako doručiť protokoly do ClickHouse. Ak nie, odporúčam vyskúšať LSD и mačiatkoa tento článok o doručení denníka.

Najprv sa musíte rozhodnúť pre základnú schému. Keďže zvyčajne chcete dostávať protokoly zoradené podľa času, zdá sa logické ich uchovávať týmto spôsobom. Ak existuje veľa kategórií denníkov a všetky sú rovnakého typu, potom môžete vytvoriť kategóriu denníka ako prvý stĺpec primárneho kľúča – to vám umožní mať jednu tabuľku namiesto niekoľkých, čo bude veľké plus, keď vkladanie do ClickHouse (na serveroch s pevnými diskami sa odporúča vkladať dáta nie viac ako ~1-krát za sekundu pre celý server).

To znamená, že potrebujeme približne nasledujúcu schému tabuľky:

CREATE TABLE logs(
    category LowCardinality(String), -- категория логов (опционально)
    time DateTime, -- время события
    millis UInt16, -- миллисекунды (могут быть и микросекунды, и т.д.): рекомендуется хранить, если событий много, чтобы было легче различать события между собой
    ..., -- ваши собственные поля, например имя сервера, уровень логирования, и так далее
    message String -- текст сообщения
) ENGINE=MergeTree()
ORDER BY (category, time, millis)

Žiaľ, nemohol som okamžite nájsť žiadne otvorené zdroje s realistickými protokolmi, ktoré by som mohol chytiť a stiahnuť, takže som namiesto toho vzal toto ako príklad recenzie produktov od Amazonu pred rokom 2015. Samozrejme, ich štruktúra nie je úplne rovnaká ako štruktúra textových protokolov, ale pre ilustráciu to nie je dôležité.

pokyny na nahrávanie recenzií Amazonu do ClickHouse

Vytvorme si tabuľku:

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

V súbore údajov Amazonu je len dátum na kontrolu, ale nie je tam presný čas, takže vyplňte tieto údaje náhodne.

Nemusíte sťahovať všetky súbory tsv a obmedzovať sa na prvých ~10-20, aby ste získali pomerne veľký súbor údajov, ktoré sa nezmestia do 16 GB pamäte RAM. Na nahranie súborov TSV som použil nasledujúci príkaz:

for i in *.tsv; do
    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

Na štandardný perzistentný disk (čo je HDD) v Google Cloud s veľkosťou 1000 GB (túto veľkosť som bral hlavne preto, aby bola rýchlosť trochu vyššia, aj keď možno SSD požadovanej veľkosti by bolo lacnejšie) upload rýchlosť bola približne ~ 75 MB/s na 4 jadrách.

  • Musím si rezervovať, že pracujem v Google, ale použil som osobný účet a tento článok nemá nič spoločné s mojou prácou v spoločnosti

Vyrobím všetky ilustrácie s týmto konkrétnym súborom údajov, pretože toto je všetko, čo som mal po ruke.

Zobraziť priebeh skenovania údajov

Keďže v ClickHouse použijeme úplné skenovanie tabuľky s protokolmi a táto operácia môže trvať veľa času a nemusí dlho prinášať žiadne výsledky, ak sa nájde málo zhôd, odporúča sa mať možnosť zobraziť priebeh dotazu až do prijatia prvých riadkov s výsledkom. Na tento účel je v rozhraní HTTP parameter, ktorý vám umožňuje odosielať priebeh v hlavičkách HTTP: send_progress_in_http_headers=1. Žiaľ, štandardná knižnica Go nedokáže čítať hlavičky tak, ako sú prijímané, ale rozhranie HTTP 1.0 (nezamieňať s 1.1!) je podporované službou ClickHouse, takže môžete otvoriť surové pripojenie TCP do ClickHouse a odoslať ho tam. GET /?query=... HTTP/1.0nn a prijímať hlavičky a telo odpovede bez akéhokoľvek escapovania alebo šifrovania, takže v tomto prípade ani nemusíme používať štandardnú knižnicu.

Streamovanie protokolov z ClickHouse

ClickHouse má optimalizáciu pre dopyty s ORDER BY relatívne dlho (od roku 2019?), takže dopyt ako

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

Okamžite začne vracať riadky, ktoré majú v správe podreťazec „niečo“, bez čakania na dokončenie skenovania.

Tiež by bolo veľmi výhodné, keby ClickHouse sám zrušil požiadavku, keď bolo pripojenie k nemu uzavreté, ale toto nie je predvolené správanie. Pomocou voľby je možné povoliť automatické zrušenie požiadavky cancel_http_readonly_queries_on_client_close=1.

Správna manipulácia so SIGPIPE v režime Go

Keď vykonáte, povedzme, príkaz some_cmd | head -n 10, presne ako príkaz some_cmd zastaví vykonávanie, keď head odčítal 10 riadkov? Odpoveď je jednoduchá: kedy head skončí, potrubie sa uzavrie a stdout príkazu some_cmd začne podmienečne ukazovať „nikam“. Kedy some_cmd pokúša sa písať do uzavretej trubice, prijíma signál SIGPIPE, ktorý štandardne ticho ukončí program.

V Go sa to tiež deje štandardne, ale obslužný program signálu SIGPIPE tiež na konci vypíše „signál: SIGPIPE“ alebo podobnú správu a na vymazanie tejto správy stačí, aby sme si so SIGPIPE sami zaobchádzali tak, ako chceme, teda len potichu. VÝCHOD:

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

Zobraziť kontext správy

Často chcete vidieť kontext, v ktorom sa vyskytla nejaká chyba (napríklad, ktorá požiadavka spôsobila paniku alebo aké súvisiace problémy boli viditeľné pred pádom) a grep To sa vykonáva pomocou volieb -A, -B a -C, ktoré zobrazujú zadaný počet riadkov za, pred a okolo správy.

Bohužiaľ som nenašiel jednoduchý spôsob, ako urobiť to isté v ClickHouse, takže na zobrazenie kontextu sa na každý riadok výsledku odošle dodatočná požiadavka, ako je táto (podrobnosti závisia od zoradenia a od toho, či je kontext zobrazený pred alebo potom):

SELECT time,millis,review_body FROM amazon
WHERE (time = 'ВРЕМЯ_СОБЫТИЯ' AND millis < МИЛЛИСЕКУНДЫ_СОБЫТИЯ) OR (time < 'ВРЕМЯ_СОБЫТИЯ')
ORDER BY time DESC, millis DESC
LIMIT КОЛИЧЕСТВО_СТРОК_КОНТЕКСТА
SETTINGS max_threads=1

Keďže požiadavka je odoslaná takmer okamžite po tom, čo ClickHouse vráti príslušný riadok, skončí vo vyrovnávacej pamäti a vo všeobecnosti je požiadavka vykonaná pomerne rýchlo a spotrebuje trochu CPU (zvyčajne žiadosť trvá asi ~6 ms na mojom virtuálnom počítači).

Zobrazte nové správy v reálnom čase

Aby sme mohli zobraziť prichádzajúce správy v (takmer) reálnom čase, jednoducho vykonáme požiadavku každých pár sekúnd, pričom si pamätáme poslednú časovú pečiatku, s ktorou sme sa predtým stretli.

Príklady príkazov

Ako vyzerajú typické príkazy logscli v praxi?

Ak ste si stiahli súbor údajov Amazon, ktorý som spomenul na začiatku článku, môžete spustiť nasledujúce príkazy:

# Показать строки, где встречается слово 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

referencie

Pomocný kód (bez dokumentácie) je dostupný na github na adrese https://github.com/YuriyNasretdinov/logscli. Bol by som rád, keby ste si vypočuli váš názor na môj nápad na konzolové rozhranie na prezeranie protokolov založených na ClickHouse.

Zdroj: hab.com

Pridať komentár