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
Ü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: (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:
- Minden napló megtekintése, szűrés nélkül.
- Olyan sorok megtartása, amelyek egy rögzített karakterláncot tartalmaznak (flag
-Fsa-logic-subsets-canary-vs.yamlgrep). - Olyan sorok megtartása, amelyek megfelelnek a reguláris kifejezésnek (flag
-Esa-logic-subsets-canary-vs.yamlgrep). - 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.
- Környezet megjelenítése minden sor körül (paraméterek
-A,-Bés-Csa-logic-subsets-canary-vs.yamlgrep, N sor nyomtatása előtt, után és a megfelelések körül). - Bejövő naplók valós idejű megtekintése, szűréssel és anélkül (tulajdonképpen
tail -f | grep). - 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 jelSIGPIPEné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 és , valamint .
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 . 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=8192Az 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'
doneA 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 DESCwill 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. .
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=1Mivel 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' -tailfHivatkozások
A segédeszköz kódja (dokumentáció nélkül) elérhető a githubon a címen . Ö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
