Mēs izstrādājam ērtāko interfeisu pasaulē* žurnālu apskatei

Mēs izstrādājam ērtāko interfeisu pasaulē* žurnālu apskatei Ja kādreiz esat izmantojis tīmekļa saskarnes, lai skatītu žurnālus, tad droši vien esat pamanījis, ka šīs saskarnes parasti ir apgrūtinošas un (bieži) ne pārāk ērtas un atsaucīgas. Pie dažām var pierast, dažas ir absolūti briesmīgas, taču man šķiet, ka visu problēmu iemesls ir tas, ka mēs nepareizi pieietam žurnālu apskates uzdevumam: mēs cenšamies izveidot tīmekļa saskarni, kurā CLI (komandrindas saskarne) darbojas labāk. Man personīgi ir ļoti ērti strādāt ar tail, grep, awk un citiem, un tāpēc man ideāls interfeiss darbam ar žurnāliem būtu kaut kas līdzīgs tail un grep, bet ko varētu izmantot arī, lai lasītu žurnālus, kas nāk no daudziem serveriem . Tas ir, protams, izlasiet tos no ClickHouse!

*pēc habras lietotāja personīgā viedokļa tu rullē

Iepazīstieties ar logscli

Es neizdomāju savai saskarnei nosaukumu, un, godīgi sakot, tas drīzāk pastāv prototipa formā, taču, ja vēlaties nekavējoties redzēt avota kodu, laipni lūdzam: https://github.com/YuriyNasretdinov/logscli (350 rindiņas atlasītā Go koda).

Spējas

Mans mērķis bija izveidot interfeisu, kas šķist pazīstams tiem, kuri ir pieraduši pie tail/grep, tas ir, lai atbalstītu šādas lietas:

  1. Skatīt visus žurnālus bez filtrēšanas.
  2. Atstājiet rindas, kurās ir fiksēta apakšvirkne (karodziņa -F у grep).
  3. Atstājiet rindas, kas atbilst regulārajai izteiksmei (karodziņa -E у grep).
  4. Pēc noklusējuma skatīšanās notiek apgrieztā hronoloģiskā secībā, jo jaunākie žurnāli parasti interesē vispirms.
  5. Rādīt kontekstu blakus katrai rindai (opcijas -A, -B и -C у grep, drukājot N rindiņas attiecīgi pirms, pēc un ap katru atbilstošo līniju).
  6. Skatiet ienākošos žurnālus reāllaikā ar vai bez filtrēšanas (būtībā tail -f | grep).
  7. Interfeisam jābūt saderīgam ar less, head, tail un citi - pēc noklusējuma rezultāti ir jāatgriež bez ierobežojumiem to skaitam; rindas tiek drukātas kā straume, ja vien lietotājs ir ieinteresēts tās saņemt; signāls SIGPIPE vajadzētu klusībā pārtraukt žurnālu straumēšanu, tāpat kā viņi to dara tail, grep un citas UNIX utilītas.

Ieviešana

Es pieņemu, ka jūs jau kaut kā zināt, kā piegādāt žurnālus ClickHouse. Ja nē, iesaku izmēģināt LSD и kaķēnu mājaun šis raksts par baļķu piegādi.

Vispirms jums jāizlemj par bāzes shēmu. Tā kā parasti vēlaties saņemt žurnālus, kas sakārtoti pēc laika, šķiet loģiski tos saglabāt šādā veidā. Ja žurnālu kategoriju ir daudz un tās visas ir viena veida, tad varat izveidot žurnāla kategoriju kā primārās atslēgas pirmo kolonnu – tas ļaus jums izveidot vienu tabulu vairāku vietā, kas būs liels pluss ievietošana ClickHouse (serveros ar cietajiem diskiem ieteicams ievietot datus ne vairāk kā ~1 reizi sekundē visam serverim).

Tas ir, mums ir nepieciešama aptuveni šāda tabulas shēma:

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

Diemžēl es nevarēju uzreiz atrast nevienu atvērto avotu ar reālistiskiem žurnāliem, kurus varētu paķert un lejupielādēt, tāpēc es ņēmu šo kā piemēru. atsauksmes par Amazon produktiem pirms 2015. gada. Protams, to struktūra nav gluži tāda pati kā teksta žurnāliem, taču ilustrācijas nolūkos tas nav svarīgi.

norādījumi par Amazon atsauksmju augšupielādi vietnē ClickHouse

Izveidosim tabulu:

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

Amazon datu kopā ir tikai pārskatīšanas datums, bet precīza laika nav, tāpēc aizpildīsim šos datus ar nejaušību.

Jums nav jālejupielādē visi tsv faili un jāierobežo sevi ar pirmajiem ~ 10-20, lai iegūtu diezgan lielu datu kopu, kas neietilpst 16 GB RAM. Lai augšupielādētu TSV failus, es izmantoju šādu komandu:

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

Standarta pastāvīgā diskā (kas ir HDD) Google Cloud ar 1000 GB lielumu (šo izmēru ņēmu galvenokārt tāpēc, lai ātrums būtu nedaudz lielāks, lai gan, iespējams, vajadzīgā izmēra SSD būtu bijis lētāks) augšupielāde ātrums bija aptuveni ~ 75 MB/sek uz 4 kodoliem.

  • Man ir jārezervē, ka strādāju Google, taču izmantoju personīgo kontu, un šim rakstam nav nekāda sakara ar manu darbu uzņēmumā

Es izveidošu visas ilustrācijas ar šo konkrēto datu kopu, jo tas ir viss, kas man bija pieejams.

Rādīt datu skenēšanas gaitu

Tā kā ClickHouse mēs izmantosim pilnu skenēšanu tabulā ar žurnāliem, un šī darbība var aizņemt ievērojamu laiku un var ilgstoši nesniegt nekādus rezultātus, ja tiek atrastas dažas atbilstības, ir ieteicams parādīt vaicājuma norise, līdz tiek saņemtas pirmās rindas ar rezultātu. Lai to izdarītu, HTTP saskarnē ir parametrs, kas ļauj nosūtīt progresu HTTP galvenēs: send_progress_in_http_headers=1. Diemžēl standarta Go bibliotēka nevar nolasīt galvenes, kad tās tiek saņemtas, bet HTTP 1.0 saskarni (nejaukt ar 1.1!) atbalsta ClickHouse, lai jūs varētu atvērt neapstrādātu TCP savienojumu ar ClickHouse un nosūtīt to tur. GET /?query=... HTTP/1.0nn un saņemt atbildes galvenes un pamattekstu bez izspiešanas vai šifrēšanas, tāpēc šajā gadījumā mums pat nav jāizmanto standarta bibliotēka.

Straumēšanas žurnāli no ClickHouse

ClickHouse jau salīdzinoši ilgu laiku (kopš 2019?

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

Tas nekavējoties sāks atgriezt rindas, kuru ziņojumā ir apakšvirkne "kaut kas", negaidot skenēšanas pabeigšanu.

Tāpat būtu ļoti ērti, ja ClickHouse pati atceltu pieprasījumu, kad savienojums ar to tika slēgts, taču tā nav noklusējuma darbība. Automātisko pieprasījuma atcelšanu var iespējot, izmantojot opciju cancel_http_readonly_queries_on_client_close=1.

Pareiza SIGPIPE apstrāde Go

Kad jūs izpildāt, teiksim, komandu some_cmd | head -n 10, tieši tā, kā komanda some_cmd pārtrauc izpildi, kad head atņēma 10 rindas? Atbilde ir vienkārša: kad head beidzas, caurule aizveras, un komandas some_cmd stdout sāk nosacīti norādīt “uz nekurieni”. Kad some_cmd mēģina rakstīt slēgtā caurulē, tas saņem SIGPIPE signālu, kas pēc noklusējuma klusi pārtrauc programmas darbību.

Programmā Go tas notiek arī pēc noklusējuma, taču SIGPIPE signāla apstrādātājs beigās arī izdrukā "signal: SIGPIPE" vai līdzīgu ziņojumu, un, lai notīrītu šo ziņojumu, mums pašiem ir jārīkojas SIGPIPE tā, kā mēs vēlamies, tas ir, tikai klusi. Izeja:

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

Rādīt ziņojuma kontekstu

Bieži vien vēlaties redzēt kontekstu, kurā radās kāda kļūda (piemēram, kurš pieprasījums izraisīja paniku vai kādas saistītas problēmas bija redzamas pirms avārijas), un grep Tas tiek darīts, izmantojot opcijas -A, -B un -C, kas attiecīgi parāda norādīto rindu skaitu pēc ziņojuma, pirms un ap to.

Diemžēl neesmu atradis vienkāršu veidu, kā to pašu izdarīt ClickHouse, tāpēc, lai parādītu kontekstu, katrai rezultāta rindiņai tiek nosūtīts šāds papildu pieprasījums (detaļas ir atkarīgas no kārtošanas un no tā, vai konteksts tiek parādīts iepriekš vai pēc):

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

Tā kā pieprasījums tiek nosūtīts gandrīz uzreiz pēc tam, kad ClickHouse atgriež atbilstošo rindiņu, tas nonāk kešatmiņā un kopumā pieprasījums tiek izpildīts diezgan ātri un patērē nedaudz CPU (parasti pieprasījums manā virtuālajā mašīnā aizņem apmēram ~6 ms).

Rādīt jaunus ziņojumus reāllaikā

Lai parādītu ienākošos ziņojumus (gandrīz) reāllaikā, mēs vienkārši izpildām pieprasījumu reizi pāris sekundēs, atceroties pēdējo iepriekš sastapto laikspiedolu.

Komandu piemēri

Kā praksē izskatās tipiskas logscli komandas?

Ja lejupielādējāt Amazon datu kopu, ko minēju raksta sākumā, varat palaist šādas komandas:

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

atsauces

Lietderības kods (bez dokumentācijas) ir pieejams github vietnē https://github.com/YuriyNasretdinov/logscli. Priecāšos dzirdēt jūsu domas par manu ideju par konsoles interfeisu žurnālu skatīšanai, pamatojoties uz ClickHouse.

Avots: www.habr.com

Pievieno komentāru