Vyvíjíme nejpohodlnější rozhraní na světě* pro prohlížení protokolů

Vyvíjíme nejpohodlnější rozhraní na světě* pro prohlížení protokolů Pokud jste někdy používali webová rozhraní k prohlížení protokolů, pak jste si pravděpodobně všimli, jak jsou tato rozhraní zpravidla těžkopádná a (často) nepříliš pohodlná a citlivá. Na některé se dá zvyknout, některé jsou naprosto příšerné, ale zdá se mi, že důvodem všech problémů je to, že nesprávně přistupujeme k úkolu prohlížení protokolů: snažíme se vytvořit webové rozhraní, kde CLI (rozhraní příkazového řádku) funguje lépe. Mně osobně velmi vyhovuje práce s tail, grep, awk a dalšími, a proto by pro mě bylo ideálním rozhraním pro práci s logy něco podobného jako tail a grep, ale které by se dalo použít i pro čtení logů pocházejících z mnoha serverů. To je, samozřejmě, přečtěte si je z ClickHouse!

*podle osobního názoru uživatele habra válíš

Seznamte se s logscli

Jméno pro své rozhraní jsem nevymyslel a, abych byl upřímný, spíše existuje ve formě prototypu, ale pokud chcete okamžitě vidět zdrojový kód, jste vítáni: https://github.com/YuriyNasretdinov/logscli (350 řádků vybraného Go kódu).

Možnosti

Mým cílem bylo vytvořit rozhraní, které by se zdálo známé těm, kteří jsou zvyklí na tail/grep, tedy podporovat následující věci:

  1. Zobrazit všechny protokoly bez filtrování.
  2. Ponechte řádky obsahující pevný podřetězec (flag -F у grep).
  3. Ponechte řádky, které odpovídají regulárnímu výrazu (flag -E у grep).
  4. Ve výchozím nastavení je prohlížení v obráceném chronologickém pořadí, protože nejnovější protokoly jsou obvykle zajímavé jako první.
  5. Zobrazit kontext vedle každého řádku (možnosti -A, -B и -C у greptiskne N řádků před, za a kolem každého odpovídajícího řádku).
  6. Zobrazení příchozích protokolů v reálném čase, s filtrováním nebo bez něj (v podstatě tail -f | grep).
  7. Rozhraní musí být kompatibilní s less, head, tail a další - ve výchozím nastavení by se výsledky měly vracet bez omezení jejich počtu; řádky se tisknou jako proud, pokud má uživatel zájem je přijímat; signál SIGPIPE by měly tiše přerušit streamování protokolu, stejně jako oni tail, grep a další unixové nástroje.

uskutečnění

Předpokládám, že už nějak víte, jak doručit protokoly do ClickHouse. Pokud ne, doporučuji vyzkoušet LSD и kotěcí důma tento článek o doručení protokolu.

Nejprve se musíte rozhodnout pro základní schéma. Protože obvykle chcete dostávat protokoly seřazené podle času, zdá se logické je takto ukládat. Pokud existuje mnoho kategorií protokolu a všechny jsou stejného typu, můžete vytvořit kategorii protokolu jako první sloupec primárního klíče – to vám umožní mít jednu tabulku místo několika, což bude velké plus, když vkládání do ClickHouse (na serverech s pevnými disky se doporučuje vkládat data maximálně ~1krát za sekundu pro celý server).

To znamená, že potřebujeme přibližně následující schéma tabulky:

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

Bohužel jsem nemohl okamžitě najít žádné otevřené zdroje s realistickými protokoly, které bych mohl uchopit a stáhnout, takže jsem vzal toto jako příklad recenze produktů od Amazonu před rokem 2015. Jejich struktura samozřejmě není úplně stejná jako u textových protokolů, ale pro ilustraci to není důležité.

pokyny pro nahrávání recenzí Amazonu do ClickHouse

Vytvoříme tabulku:

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 datovém souboru Amazonu je pouze datum pro kontrolu, ale není tam přesný čas, takže vyplňte tato data náhodně.

Nemusíte stahovat všechny soubory tsv a omezovat se na prvních ~10-20, abyste získali poměrně velkou sadu dat, která se nevejde do 16 GB RAM. K nahrání souborů TSV jsem použil následující pří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 standardním Persistent Disk (což je HDD) v Google Cloud o velikosti 1000 GB (tuto velikost jsem bral hlavně proto, aby byla rychlost trochu vyšší, i když možná by SSD požadované velikosti bylo levnější) upload rychlost byla přibližně ~ 75 MB/s na 4 jádrech.

  • Musím si rezervovat, že pracuji ve společnosti Google, ale použil jsem osobní účet a tento článek nemá nic společného s mou prací ve společnosti

Vytvořím všechny ilustrace s tímto konkrétním datovým souborem, protože to je vše, co jsem měl po ruce.

Zobrazit průběh skenování dat

Vzhledem k tomu, že v ClickHouse použijeme úplné skenování tabulky s protokoly a tato operace může trvat značnou dobu a nemusí přinášet žádné výsledky po dlouhou dobu, pokud je nalezeno málo shod, je vhodné mít možnost zobrazit průběh dotazu, dokud nejsou obdrženy první řádky s výsledkem. K tomu je v rozhraní HTTP parametr, který umožňuje posílat průběh v HTTP hlavičkách: send_progress_in_http_headers=1. Bohužel standardní knihovna Go neumí číst hlavičky tak, jak jsou přijímány, ale rozhraní HTTP 1.0 (neplést s 1.1!) je podporováno ClickHouse, takže můžete otevřít nezpracované TCP připojení ke ClickHouse a odeslat ho tam. GET /?query=... HTTP/1.0nn a přijímat hlavičky a tělo odpovědí bez jakéhokoli escapování nebo šifrování, takže v tomto případě ani nepotřebujeme používat standardní knihovnu.

Streamování protokolů z ClickHouse

ClickHouse má optimalizaci pro dotazy s ORDER BY poměrně dlouhou dobu (od roku 2019?), takže dotaz jako

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

Okamžitě začne vracet řádky, které mají ve zprávě podřetězec „něco“, aniž by čekal na dokončení skenování.

Také by bylo velmi výhodné, kdyby ClickHouse sám zrušil požadavek, když bylo připojení k němu uzavřeno, ale toto není výchozí chování. Pomocí volby lze povolit automatické zrušení požadavku cancel_http_readonly_queries_on_client_close=1.

Správná manipulace se SIGPIPE v Go

Když provedete, řekněme, příkaz some_cmd | head -n 10, přesně jak příkaz some_cmd zastaví provádění, když head odečteno 10 řádků? Odpověď je jednoduchá: kdy head skončí, roura se uzavře a stdout příkazu some_cmd začne podmíněně ukazovat „nikam“. Když some_cmd pokusí se napsat do uzavřené roury, přijímá signál SIGPIPE, který ve výchozím nastavení tiše ukončí program.

V Go se to také děje ve výchozím nastavení, ale obslužný program signálu SIGPIPE na konci také vypíše "signál: SIGPIPE" nebo podobnou zprávu, a abychom tuto zprávu vymazali, musíme sami zacházet se SIGPIPE tak, jak chceme, to znamená jen tiše výstup:

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

Zobrazit kontext zprávy

Často chcete vidět kontext, ve kterém došlo k nějaké chybě (například který požadavek způsobil paniku nebo jaké související problémy byly viditelné před havárií) a v grep To se provádí pomocí voleb -A, -B a -C, které zobrazují zadaný počet řádků za, před a kolem zprávy.

Bohužel jsem nenašel snadný způsob, jak udělat totéž v ClickHouse, takže pro zobrazení kontextu je na každý řádek výsledku odeslán další požadavek, jako je tento (podrobnosti závisí na řazení a na tom, zda je kontext zobrazen dříve nebo později):

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

Vzhledem k tomu, že požadavek je odeslán téměř okamžitě poté, co ClickHouse vrátí odpovídající řádek, skončí v mezipaměti a obecně se požadavek provede poměrně rychle a spotřebovává trochu CPU (obvykle požadavek trvá asi ~6 ms na mém virtuálním počítači).

Zobrazit nové zprávy v reálném čase

Abychom zobrazili příchozí zprávy v (téměř) reálném čase, jednoduše provedeme požadavek jednou za několik sekund a pamatujeme si poslední časové razítko, se kterým jsme se předtím setkali.

Příklady příkazů

Jak vypadají typické příkazy logscli v praxi?

Pokud jste si stáhli datovou sadu Amazon, kterou jsem zmínil na začátku článku, můžete spustit následující pří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

reference

Obslužný kód (bez dokumentace) je k dispozici na githubu na adrese https://github.com/YuriyNasretdinov/logscli. Rád bych slyšel vaše názory na můj nápad na konzolové rozhraní pro prohlížení protokolů založené na ClickHouse.

Zdroj: www.habr.com

Přidat komentář