Estem desenvolupant la interfície més còmoda del món* per visualitzar els registres

Estem desenvolupant la interfície més còmoda del món* per visualitzar els registres Si alguna vegada heu utilitzat interfícies web per veure els registres, probablement haureu notat com, per regla general, aquestes interfícies són feixugues i (sovint) poc còmodes i sensibles. Algunes us podeu acostumar, algunes són absolutament terribles, però em sembla que la raó de tots els problemes és que ens apropem de manera incorrecta a la tasca de visualitzar els registres: intentem crear una interfície web on la CLI (interfície de línia d'ordres) funciona millor. Personalment em sento molt còmode treballant amb tail, grep, awk i altres, i per tant per a mi la interfície ideal per treballar amb registres seria una cosa semblant a tail i grep, però que també es podria utilitzar per llegir els registres que provenen de molts servidors. És a dir, per descomptat, llegiu-los a ClickHouse!

*segons l'opinió personal de l'usuari d'habra el teu ROCK

Coneix logscli

No he creat un nom per a la meva interfície i, per ser sincer, més aviat existeix en forma de prototip, però si voleu veure immediatament el codi font, sou benvinguts: https://github.com/YuriyNasretdinov/logscli (350 línies del codi Go seleccionat).

Capacitats

El meu objectiu era fer una interfície que semblés familiar als que estan acostumats a tail/grep, és a dir, donar suport a les coses següents:

  1. Veure tots els registres, sense filtrar.
  2. Deixeu línies que continguin una subcadena fixa (flag -F у grep).
  3. Deixeu línies que coincideixin amb l'expressió regular (bandera -E у grep).
  4. Per defecte, la visualització es fa en ordre cronològic invers, ja que els registres més recents solen interessar primer.
  5. Mostra el context al costat de cada línia (opcions -A, -B и -C у grep, imprimint N línies abans, després i al voltant de cada línia coincident, respectivament).
  6. Consulteu els registres entrants en temps real, amb o sense filtratge (essencialment tail -f | grep).
  7. La interfície ha de ser compatible amb less, head, tail i altres: per defecte, els resultats s'han de retornar sense restriccions sobre el seu nombre; les línies s'imprimeixen com un flux sempre que l'usuari estigui interessat a rebre-les; senyal SIGPIPE hauria d'interrompre en silenci la transmissió del registre, tal com ho fan tail, grep i altres utilitats UNIX.

Implementació

Suposo que d'alguna manera ja sabeu com enviar registres a ClickHouse. Si no, us recomano provar-ho lsd и gatethouseI aquest article sobre el lliurament de registres.

Primer heu de decidir l'esquema base. Com que normalment voleu rebre registres ordenats per temps, sembla lògic emmagatzemar-los d'aquesta manera. Si hi ha moltes categories de registre i totes són del mateix tipus, podeu crear una categoria de registre com a primera columna de la clau primària; això us permetrà tenir una taula en lloc de diverses, cosa que serà un gran avantatge quan inserint a ClickHouse (en servidors amb discs durs, es recomana inserir dades no més d'~1 vegades per segon per a tot el servidor).

És a dir, necessitem aproximadament el següent esquema de taula:

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

Malauradament, no vaig trobar immediatament cap font oberta amb registres realistes que pogués agafar i descarregar, així que ho vaig prendre com a exemple. ressenyes de productes d'Amazon abans del 2015. Per descomptat, la seva estructura no és exactament la mateixa que la dels registres de text, però a efectes d'il·lustració això no és important.

instruccions per carregar ressenyes d'Amazon a ClickHouse

Creem una taula:

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

Al conjunt de dades d'Amazon només hi ha una data per a una revisió, però no hi ha hora exacta, així que omplim aquestes dades amb un aleatori.

No heu de descarregar tots els fitxers tsv i limitar-vos als primers ~ 10-20 per obtenir un conjunt de dades bastant gran que no caben en 16 GB de RAM. Per carregar fitxers TSV he utilitzat l'ordre següent:

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

En un disc persistent estàndard (que és un HDD) a Google Cloud amb una mida de 1000 GB (vaig agafar aquesta mida principalment perquè la velocitat fos una mica més alta, tot i que potser un SSD de la mida requerida hauria estat més barat) la pujada. la velocitat era d'aproximadament ~ 75 MB/s en 4 nuclis.

  • He de fer una reserva perquè treballo a Google, però he utilitzat un compte personal i aquest article no té res a veure amb el meu treball a l'empresa

Produiré totes les il·lustracions amb aquest conjunt de dades en particular, ja que això és tot el que tenia a mà.

Mostra el progrés de l'escaneig de dades

Atès que a ClickHouse utilitzarem una exploració completa en una taula amb registres, i aquesta operació pot trigar molt de temps i pot no produir cap resultat durant molt de temps si es troben poques coincidències, és recomanable poder mostrar el progrés de la consulta fins que es rebin les primeres files amb el resultat. Per fer-ho, hi ha un paràmetre a la interfície HTTP que permet enviar el progrés a les capçaleres HTTP: send_progress_in_http_headers=1. Malauradament, la biblioteca Go estàndard no pot llegir les capçaleres a mesura que es reben, però ClickHouse admet la interfície HTTP 1.0 (que no s'ha de confondre amb 1.1!), de manera que podeu obrir una connexió TCP en brut a ClickHouse i enviar-la allà. GET /?query=... HTTP/1.0nn i rebre les capçaleres i el cos de la resposta sense cap escapada ni xifratge, de manera que en aquest cas ni tan sols necessitem utilitzar la biblioteca estàndard.

Transmissió de registres des de ClickHouse

ClickHouse ha tingut una optimització per a consultes amb ORDER BY durant un temps relativament llarg (des del 2019?), així que una consulta com

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

De seguida començarà a retornar línies que tinguin la subcadena "alguna cosa" al missatge, sense esperar que finalitzi l'exploració.

A més, seria molt convenient que el mateix ClickHouse cancel·lés la sol·licitud quan es tanqués la connexió, però aquest no és el comportament predeterminat. La cancel·lació automàtica de la sol·licitud es pot activar mitjançant l'opció cancel_http_readonly_queries_on_client_close=1.

Tractament correcte de SIGPIPE a Go

Quan executeu, per exemple, l'ordre some_cmd | head -n 10, exactament com l'ordre some_cmd atura l'execució quan head restar 10 línies? La resposta és senzilla: quan head s'acaba, la canonada es tanca i el stdout de l'ordre some_cmd comença a apuntar, condicionalment, "enlloc". Quan some_cmd intenta escriure a una canonada tancada, rep un senyal SIGPIPE, que finalitza silenciosament el programa per defecte.

A Go, això també passa per defecte, però el controlador de senyal SIGPIPE també imprimeix "senyal: SIGPIPE" o un missatge similar al final, i per esborrar aquest missatge només hem de manejar SIGPIPE nosaltres mateixos com volem, és a dir, en silenci. sortida:

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

Mostra el context del missatge

Sovint, voleu veure el context en què s'ha produït algun error (per exemple, quina sol·licitud va causar pànic o quins problemes relacionats eren visibles abans de l'accident) i en grep Això es fa utilitzant les opcions -A, -B i -C, que mostren el nombre especificat de línies després, abans i al voltant del missatge, respectivament.

Malauradament, no he trobat una manera fàcil de fer el mateix a ClickHouse, de manera que per mostrar el context, s'envia una sol·licitud addicional com aquesta a cada línia del resultat (els detalls depenen de l'ordenació i de si el context es mostra abans). o després):

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

Com que la sol·licitud s'envia gairebé immediatament després que ClickHouse retorni la línia corresponent, acaba a la memòria cau i, en general, la sol·licitud s'executa amb força rapidesa i consumeix una mica de CPU (normalment la sol·licitud triga uns ~6 ms a la meva màquina virtual).

Mostra missatges nous en temps real

Per mostrar els missatges entrants en (gairebé) temps real, simplement executem la sol·licitud una vegada cada pocs segons, recordant la darrera marca de temps que hem trobat abans.

Exemples de comandaments

Com són les ordres típiques de logscli a la pràctica?

Si heu baixat el conjunt de dades d'Amazon que he esmentat al principi de l'article, podeu executar les ordres següents:

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

Referències

El codi d'utilitat (sense documentació) està disponible a github a https://github.com/YuriyNasretdinov/logscli. M'agradaria escoltar els vostres pensaments sobre la meva idea d'una interfície de consola per veure els registres basats en ClickHouse.

Font: www.habr.com

Afegeix comentari