A világ legkényelmesebb* naplómegjelenítő felhasználói felületének kidolgozása

A világ legkényelmesebb* naplómegjelenítő felhasználói felületének kidolgozása Ha valaha használt webes felületeket naplók megtekintésére, akkor valószínűleg észrevette, hogy ezek a felületek általában bulkyak és (gyakran) nem túl kényelmesek és reagálóképesek. Vannak, amelyekhez lehet szokni, vannak, amelyek teljesen borzalmasak, de úgy vélem, hogy a problémák oka az, hogy rosszul közelítjük meg a naplók megtekintésének feladatát: megpróbálunk webes felületet létrehozni, ahol a CLI (parancssori felület) jobban működik. Személy szerint kényelmesen dolgozom a tail, grep, awk és egyéb eszközökkel, ezért számomra az ideális felület a naplók kezelésére valami hasonló lenne a tail és a grep-hez, de amelyet sok szerverből érkező naplók olvasásához is használhatnék. Tehát, természetesen, olvasni őket a ClickHouse-ból!

*a hágrafelhasználó személyes véleménye teROCK

Üdvözöljük a logscli-t

Nem találtam ki egy nevet az interfésznek, és őszintén szólva, inkább prototípus formájában létezik, de ha azonnal meg szeretné nézni a forrást, akkor itt van: https://github.com/YuriyNasretdinov/logscli (350 sor szűrt kód Go-ban).

Lehetőségek

Célom az volt, hogy olyan interfészt hozzak létre, amely ismerősnek tűnik azok számára, akik a tail/grep-hez szoktak, tehát a következő dolgokat támogassa:

  1. Minden napló megtekintése, szűrés nélkül.
  2. Olyan sorok megtartása, amelyek egy rögzített karakterláncot tartalmaznak (flag -F sa-logic-subsets-canary-vs.yaml grep).
  3. Olyan sorok megtartása, amelyek megfelelnek a reguláris kifejezésnek (flag -E sa-logic-subsets-canary-vs.yaml grep).
  4. Alapértelmezés szerint visszafelé időrendben történik a megtekintés, mivel általában az a legérdekesebb, hogy a legfrissebb naplók kerüljenek előtérbe.
  5. Környezet megjelenítése minden sor körül (paraméterek -A, -B és -C sa-logic-subsets-canary-vs.yaml grep, N sor nyomtatása előtt, után és a megfelelések körül).
  6. Bejövő naplók valós idejű megtekintése, szűréssel és anélkül (tulajdonképpen tail -f | grep).
  7. Az interfésznek kompatibilisnek kell lennie a ezt, head, (erről később). és másokkal — alapértelmezés szerint a találatok korlátozás nélkül vissza kell térniük; a sorok folyamatosan nyomtatva lesznek, amíg a felhasználó érdekelt a megszerzésükben; a jel SIGPIPE nélkül kellett megszakítania a naplóstreaminget, ahogy azt a (erről később)., grep és a többi UNIX segédprogram is teszi.

Megvalósítás

Feltételezem, hogy már tud valamilyen módon logokat szállítani a ClickHouse-hoz. Ha nem, akkor javaslom, hogy próbálja ki a lsd és kittenhouse, valamint ezt a naplók szállításáról szóló cikket.

Az első lépésben el kell döntenünk az adatbázis sémáját. Mivel a naplókat általában időrendben szeretnénk megkapni, logikus, hogy így is tároljuk őket. Ha sokféle naplókategória létezik, és ezek egyforma típusúak, akkor a naplókategóriát tehetjük az első oszlopba a primer kulcsnál — ez lehetővé teszi, hogy egy táblázatot használjunk több helyett, ami nagy előny a ClickHouse-ban történő beszúráskor (merevlemezes szerverek esetén ajánlott adatokat nem gyakrabban eltárolni, mint ~1 másodpercenként. az egész szerveren.).

Tehát a következő táblázatra lenne szükségünk:

CREATE TABLE logs(
    category LowCardinality(String), -- naplókategória (opcionális)
    time DateTime, -- esemény időpontja
    millis UInt16, -- milliszekundum (lehetnek mikro- és nanosekundumok is): ajánlott tárolni, ha sok esemény van, hogy könnyebb legyen megkülönböztetni az eseményeket
    ..., -- saját mezőid, például a szerver neve, a naplózási szint, és így tovább
    message String -- üzenet szövege
) ENGINE=MergeTree()
ORDER BY (category, time, millis)

Sajnos nem találtam azonnal nyilvános forrást, amely reális naplókat tartalmazott volna, amelyeket egyszerűen letölthettünk volna, ezért helyette egy példaként vettem a 2015 előtt készült Amazon termékértékeléseket.. Nyilvánvalóan a struktúrájuk nem teljesen olyan, mint a szöveges naplóké, de a bemutatáshoz ez nem alapvető.

Amazon értékelések ClickHouse-ba való betöltésének útmutatója.

Készítsük el a táblázatot:

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

Az Amazon adatbázisában csak az értékelés dátuma szerepel, de pontos idő nincs, tehát ezeket az adatokat véletlenszerűen fogjuk kitölteni.

Nem szükséges letölteni az összes tsv fájlt, elég lehet az első ~10-20, hogy már egy elég nagy adathalmazt kapjunk, ami nem fér el 16 GB RAM-on. A TSV fájlok betöltésére a következő parancsot használtam:

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

A Google Cloud 1000 GB standard Persistent Disk (which is HDD) had an upload speed of about ~75 MB/sec on 4 cores (I chose this size mainly to ensure a slightly higher speed, although an SSD of the required size might have turned out cheaper).

  • I must clarify that I work at Google, but I used a personal account and this article has no relation to my work at the company.

I will produce all illustrations using this dataset, as it is all I had on hand.

Data scanning progress display

Since in ClickHouse we will use a full scan on the log table, and this operation can take a significant amount of time and may take a long time to return any results if few matches are found, it is advisable to show the progress of the query execution until the first rows with results are received. For this, there is a parameter in the HTTP interface that allows returning progress in the HTTP headers: send_progress_in_http_headers=1. Unfortunately, the standard Go library cannot read headers as they are received, but the HTTP 1.0 interface (do not confuse with 1.1!) is supported by ClickHouse, so you can open a raw TCP connection to ClickHouse, send GET /?query=... HTTP/1.0nn and receive headers and response body in return without any escaping or encryption, so in this case, we don't even need to use the standard library.

Log streaming from ClickHouse

ClickHouse has had optimization for queries with ORDER BY for quite some time now (since 2019?), so a query like

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

will immediately start returning rows that have the substring "something" in the message without waiting for the scanning to finish.

Also, it would be very convenient if ClickHouse canceled the request itself when the connection was closed, but this is not the default behavior. The automatic cancellation of the request can be enabled with the option cancel_http_readonly_queries_on_client_close=1.

Correct handling of SIGPIPE in Go

When you run, say, the command some_cmd | head -n 10, how does the command some_cmd stop executing when it has read 10 lines? The answer is simple: when head it finishes, the pipe closes, and the stdout of the some_cmd starts pointing, conditionally, "nowhere". When head it tries to write to a closed pipe, some_cmd it receives a SIGPIPE signal, which by default silently terminates the program. ей приходит сигнал SIGPIPE, который по умолчанию молча завершает программу.

A Go-ban alapértelmezés szerint ez is így van, de a SIGPIPE jelzőkezelő végén a "signal: SIGPIPE" vagy hasonló üzenetet is kiír, és hogy ezt az üzenetet eltüntessük, egyszerűen magunknak kell kezelni a SIGPIPE-t úgy, ahogyan mi szeretnénk, vagyis egyszerűen csendben kilépni:

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

Az üzenet kontextusának megjelenítése

Gyakran szeretnénk látni azt a kontextust, amelyben egy hiba történt (például, hogy melyik kérés váltotta ki a pánikot, vagy milyen egyéb problémák voltak láthatóak a leállás előtt), és e célból grep -A, -B és -C opciók szolgálnak, amelyek a megadott számú sort mutatják az üzenet előtt, után és körül.

Sajnos nem találtam egyszerű módot arra, hogy ugyanezt megtegyem a ClickHouse-ban, ezért a kontextus megjelenítéséhez minden egyes eredmény sorhoz egy további lekérdezést kell küldeni körülbelül az alábbi formában (a részletek a rendezéstől és attól függnek, hogy a kontextust azelőtt vagy utána mutatjuk):

SELECT time,millis,review_body FROM amazon
WHERE (time = 'ESZKÖZ_IDŐ' AND millis < ESZKÖZ_MILISZEKUNDUM) OR (time < 'ESZKÖZ_IDŐ')
ORDER BY time DESC, millis DESC
LIMIT KONTEKTSOROK_SZÁMA
SETTINGS max_threads=1

Mivel a lekérdezés szinte azonnal a ClickHouse által visszaadott megfelelő sor után kerül elküldésre, az bekerül a cache-be, és összességében a lekérdezés elég gyorsan végrehajtódik, minimális CPU-t használ (a lekérdezés általában körülbelül ~6 ms-ot vesz igénybe a virtuális gépemen).

Új üzenetek megjelenítése valós időben

Ahhoz, hogy az érkező üzeneteket (majdnem) valós időben megjelenítsük, egyszerűen küldjünk el egy lekérdezést néhány másodpercenként, megjegyezve az utolsó timestamp-et, amelyet előzőleg találtunk.

Parancsminták

Hogyan néznek ki a tipikus logscli parancsok a gyakorlatban?

Ha letöltötted az Amazon adatcsomagot, amelyet az írás elején említettem, akkor a következő parancsokat futtathatod:

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

Hivatkozások

A segédeszköz kódja (dokumentáció nélkül) elérhető a githubon a címen https://github.com/YuriyNasretdinov/logscli. Örömmel várom a véleményedet az ötletünkről, amely egy konzolos interfész a ClickHouse alapú logok megtekintésére.

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster