Vi utvikler det mest praktiske grensesnittet i verden* for visning av logger

Vi utvikler det mest praktiske grensesnittet i verden* for visning av logger Hvis du noen gang har brukt nettgrensesnitt for å se logger, har du sikkert lagt merke til hvordan disse grensesnittene som regel er tungvinte og (ofte) lite praktiske og responsive. Noen kan du bli vant til, noen er helt forferdelige, men det ser ut til at årsaken til alle problemene er at vi nærmer oss oppgaven med å se logger feil: vi prøver å lage et nettgrensesnitt der CLI (kommandolinjegrensesnitt) fungerer bedre. Jeg personlig er veldig komfortabel med å jobbe med tail, grep, awk og andre, og derfor for meg ville det ideelle grensesnittet for å jobbe med logger være noe som ligner på tail og grep, men som også kan brukes til å lese logger som kom fra mange servere. Det er, selvfølgelig, les dem fra ClickHouse!

*i henhold til habra-brukerens personlige mening du rocker

Møt logscli

Jeg kom ikke opp med et navn for grensesnittet mitt, og for å være ærlig, eksisterer det heller i form av en prototype, men hvis du umiddelbart vil se kildekoden, er du velkommen: https://github.com/YuriyNasretdinov/logscli (350 linjer med valgt Go-kode).

Evner

Målet mitt var å lage et grensesnitt som ville virke kjent for de som er vant til tail/grep, det vil si å støtte følgende ting:

  1. Se alle logger uten filtrering.
  2. La linjer inneholde en fast delstreng (flagg -F у grep).
  3. La linjer som samsvarer med det regulære uttrykket (flag -E у grep).
  4. Som standard er visningen i omvendt kronologisk rekkefølge, siden de nyeste loggene vanligvis er av interesse først.
  5. Vis kontekst ved siden av hver linje (alternativer -A, -B и -C у grep, utskrift av henholdsvis N linjer før, etter og rundt hver samsvarende linje).
  6. Se innkommende logger i sanntid, med eller uten filtrering (i hovedsak tail -f | grep).
  7. Grensesnittet må være kompatibelt med less, head, tail og andre - som standard skal resultater returneres uten begrensninger på antallet; linjer skrives ut som en strøm så lenge brukeren er interessert i å motta dem; signal SIGPIPE bør avbryte loggstrømming i det stille, akkurat som de gjør tail, grep og andre UNIX-verktøy.

implementering

Jeg vil anta at du allerede på en eller annen måte vet hvordan du leverer logger til ClickHouse. Hvis ikke, anbefaler jeg å prøve det lsd и kattungehusOg denne artikkelen om logglevering.

Først må du bestemme deg for basisordningen. Siden du vanligvis ønsker å motta logger sortert etter tid, virker det logisk å lagre dem på den måten. Hvis det er mange loggkategorier og alle er av samme type, kan du lage en loggkategori som den første kolonnen i primærnøkkelen - dette vil tillate deg å ha én tabell i stedet for flere, noe som vil være et stort pluss når innsetting i ClickHouse (på servere med harddisker anbefales det å sette inn data ikke mer enn ~1 ganger per sekund for hele serveren).

Det vil si at vi trenger omtrent følgende tabellskjema:

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

Dessverre kunne jeg ikke umiddelbart finne noen åpne kilder med realistiske logger som jeg kunne hente og laste ned, så jeg tok dette i stedet som et eksempel anmeldelser av produkter fra Amazon frem til 2015. Naturligvis er strukturen deres ikke helt den samme som for tekstlogger, men for illustrasjonsformål er dette ikke viktig.

instruksjoner for opplasting av Amazon-anmeldelser til ClickHouse

La oss lage en tabell:

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

I Amazon-datasettet er det bare en dato for en anmeldelse, men det er ingen nøyaktig tid, så la oss fylle ut disse dataene med en randon.

Du trenger ikke å laste ned alle tsv-filene og begrense deg til de første ~10-20 for å få et ganske stort sett med data som ikke passer inn i 16 GB RAM. For å laste opp TSV-filer brukte jeg følgende kommando:

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

På en standard Persistent Disk (som er en HDD) i Google Cloud med en størrelse på 1000 GB (jeg tok denne størrelsen hovedsakelig slik at hastigheten var litt høyere, selv om kanskje en SSD i ønsket størrelse ville vært billigere) hastigheten var omtrent ~ 75 MB/sek på 4 kjerner.

  • Jeg må reservere at jeg jobber hos Google, men jeg brukte en personlig konto og denne artikkelen har ingenting å gjøre med arbeidet mitt i selskapet

Jeg vil produsere alle illustrasjoner med dette spesielle datasettet, siden dette er alt jeg hadde for hånden.

Vis fremdriften for dataskanning

Siden vi i ClickHouse vil bruke en full skanning på en tabell med logger, og denne operasjonen kan ta betydelig tid og kanskje ikke gi noen resultater på lang tid hvis få treff blir funnet, er det tilrådelig å kunne vise fremdriften av spørringen til de første radene med resultatet er mottatt. For å gjøre dette er det en parameter i HTTP-grensesnittet som lar deg sende fremdrift i HTTP-hoder: send_progress_in_http_headers=1. Dessverre kan ikke standard Go-biblioteket lese overskrifter etter hvert som de mottas, men HTTP 1.0-grensesnittet (må ikke forveksles med 1.1!) støttes av ClickHouse, så du kan åpne en rå TCP-tilkobling til ClickHouse og sende den dit GET /?query=... HTTP/1.0nn og motta svarhodene og brødteksten uten escape eller kryptering, så i dette tilfellet trenger vi ikke engang å bruke standardbiblioteket.

Streaming av logger fra ClickHouse

ClickHouse har hatt optimalisering for spørringer med ORDER BY i relativt lang tid (siden 2019?), så en spørring som

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

Den vil umiddelbart begynne å returnere linjer som har delstrengen "noe" i meldingen, uten å vente på at skanningen skal fullføres.

Dessuten ville det være veldig praktisk hvis ClickHouse selv kansellerte forespørselen når tilkoblingen til den ble lukket, men dette er ikke standardoppførselen. Automatisk kansellering av forespørsel kan aktiveres ved å bruke alternativet cancel_http_readonly_queries_on_client_close=1.

Riktig håndtering av SIGPIPE in Go

Når du utfører, si, kommandoen some_cmd | head -n 10, nøyaktig hvordan kommandoen some_cmd stopper utførelse når head trukket 10 linjer? Svaret er enkelt: når head slutter, røret lukkes, og stdouten til some_cmd-kommandoen begynner å peke, betinget, "til ingensteds". Når some_cmd prøver å skrive til et lukket rør, den mottar et SIGPIPE-signal, som stille avslutter programmet som standard.

I Go skjer dette også som standard, men SIGPIPE-signalbehandleren skriver også "signal: SIGPIPE" eller en lignende melding på slutten, og for å fjerne denne meldingen trenger vi bare å håndtere SIGPIPE selv slik vi vil, det vil si bare stille exit:

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

Vis meldingskontekst

Ofte vil du se konteksten som en feil oppstod i (for eksempel hvilken forespørsel som forårsaket panikk, eller hvilke relaterte problemer som var synlige før krasjen), og i grep Dette gjøres ved å bruke alternativene -A, -B og -C, som viser det angitte antall linjer henholdsvis etter, før og rundt meldingen.

Dessverre har jeg ikke funnet en enkel måte å gjøre det samme i ClickHouse, så for å vise konteksten sendes en ekstra forespørsel som denne til hver linje i resultatet (detaljene avhenger av sorteringen og om konteksten vises før eller etter):

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

Siden forespørselen sendes nesten umiddelbart etter at ClickHouse returnerer den tilsvarende linjen, havner den i cachen og generelt blir forespørselen utført ganske raskt og bruker litt CPU (vanligvis tar forespørselen ca. ~6 ms på min virtuelle maskin).

Vis nye meldinger i sanntid

For å vise innkommende meldinger i (nesten) sanntid, utfører vi ganske enkelt forespørselen med noen sekunders mellomrom, og husker det siste tidsstemplet vi møtte før.

Eksempler på kommandoer

Hvordan ser typiske logscli-kommandoer ut i praksis?

Hvis du lastet ned Amazon-datasettet som jeg nevnte i begynnelsen av artikkelen, kan du kjøre følgende kommandoer:

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

referanser

Verktøykoden (uten dokumentasjon) er tilgjengelig på github på https://github.com/YuriyNasretdinov/logscli. Jeg vil gjerne høre dine tanker om ideen min om et konsollgrensesnitt for visning av logger basert på ClickHouse.

Kilde: www.habr.com

Kjøp pålitelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere 🔥 Kjøp pålitelig webhotell med DDoS-beskyttelse, VPS VDS-servere | ProHoster