We ontwikkelen de handigste interface ter wereld* voor het bekijken van logs

We ontwikkelen de handigste interface ter wereld* voor het bekijken van logs Als je ooit webinterfaces hebt gebruikt om logs te bekijken, dan heb je waarschijnlijk gemerkt dat deze interfaces in de regel omslachtig en (vaak) niet erg handig en responsief zijn. Aan sommige kun je wennen, sommige zijn absoluut verschrikkelijk, maar het lijkt mij dat de reden voor alle problemen is dat we de taak van het bekijken van logs verkeerd benaderen: we proberen een webinterface te maken waarin de CLI (opdrachtregelinterface) werkt beter. Persoonlijk voel ik me erg op mijn gemak bij het werken met tail, grep, awk en anderen, en daarom zou voor mij de ideale interface voor het werken met logs iets zijn dat lijkt op tail en grep, maar die ook gebruikt zou kunnen worden om logs te lezen die van veel servers kwamen. Dat wil zeggen, lees ze natuurlijk van ClickHouse!

*volgens de persoonlijke mening van de habra-gebruiker jij rockt

Maak kennis met logscli

Ik heb geen naam bedacht voor mijn interface, en eerlijk gezegd bestaat die eerder in de vorm van een prototype, maar als je meteen de broncode wilt zien, dan ben je welkom: https://github.com/YuriyNasretdinov/logscli (350 regels geselecteerde Go-code).

Mogelijkheden

Mijn doel was om een ​​interface te maken die bekend zou overkomen voor degenen die gewend zijn aan tail/grep, dat wil zeggen om de volgende dingen te ondersteunen:

  1. Bekijk alle logs, zonder filtering.
  2. Laat regels staan ​​die een vaste subtekenreeks bevatten (flag -F у grep).
  3. Laat regels staan ​​die overeenkomen met de reguliere expressie (flag -E у grep).
  4. Standaard wordt de weergave in omgekeerde chronologische volgorde weergegeven, aangezien de meest recente logboeken meestal het eerst van belang zijn.
  5. Toon context naast elke regel (options -A, -B и -C у grep, waarbij respectievelijk N regels voor, na en rond elke overeenkomende regel worden afgedrukt).
  6. Bekijk inkomende logs in realtime, met of zonder filtering (in wezen tail -f | grep).
  7. De interface moet compatibel zijn met less, head, tail en anderen - resultaten moeten standaard worden geretourneerd zonder beperkingen op hun aantal; regels worden als een stroom afgedrukt zolang de gebruiker geïnteresseerd is om ze te ontvangen; signaal SIGPIPE zouden het streamen van logbestanden stilletjes moeten onderbreken, net zoals zij dat doen tail, grep en andere UNIX-hulpprogramma's.

uitvoering

Ik ga ervan uit dat u op de een of andere manier al weet hoe u logboeken aan ClickHouse moet leveren. Zo niet, dan raad ik aan het te proberen LSD и kittenhuisEn dit artikel over de levering van logboeken.

Eerst moet u beslissen over het basisschema. Omdat je logs meestal gesorteerd op tijd wilt ontvangen, lijkt het logisch om ze op die manier op te slaan. Als er veel logcategorieën zijn en deze allemaal van hetzelfde type zijn, dan kunt u een logcategorie maken als de eerste kolom van de primaire sleutel. Hierdoor kunt u één tabel hebben in plaats van meerdere, wat een groot pluspunt zal zijn als invoegen in ClickHouse (op servers met harde schijven wordt aanbevolen om gegevens niet vaker dan ~1 keer per seconde in te voegen voor de gehele server).

Dat wil zeggen, we hebben ongeveer het volgende tabelschema nodig:

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

Helaas kon ik niet meteen open bronnen vinden met realistische logbestanden die ik kon pakken en downloaden, dus heb ik dit als voorbeeld genomen beoordelingen van producten van Amazon vóór 2015. Uiteraard is hun structuur niet precies dezelfde als die van tekstlogboeken, maar ter illustratie is dit niet belangrijk.

instructies voor het uploaden van Amazon-recensies naar ClickHouse

Laten we een tabel maken:

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

In de Amazon-dataset staat alleen een datum voor een beoordeling, maar er is geen exacte tijd, dus laten we deze gegevens invullen met een randon.

Je hoeft niet alle tsv-bestanden te downloaden en jezelf te beperken tot de eerste ~10-20 om een ​​vrij grote set gegevens te krijgen die niet in 16 GB RAM passen. Om TSV-bestanden te uploaden heb ik de volgende opdracht gebruikt:

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

Op een standaard Persistent Disk (wat een HDD is) in Google Cloud met een grootte van 1000 GB (ik heb dit formaat vooral genomen zodat de snelheid iets hoger was, hoewel misschien een SSD van het vereiste formaat goedkoper was geweest) de upload snelheid was ongeveer ~ 75 MB/sec op 4 cores.

  • Ik moet reserveren dat ik bij Google werk, maar ik heb een persoonlijk account gebruikt en dit artikel heeft niets te maken met mijn werk bij het bedrijf

Ik zal alle illustraties maken met deze specifieke dataset, aangezien dit alles is wat ik bij de hand had.

Toon de voortgang van het scannen van gegevens

Omdat we in ClickHouse een volledige scan van een tabel met logs gebruiken, en deze handeling een aanzienlijke hoeveelheid tijd kan duren en mogelijk lange tijd geen resultaten oplevert als er weinig overeenkomsten worden gevonden, is het raadzaam om de voortgang van de query totdat de eerste rijen met het resultaat zijn ontvangen. Om dit te doen, is er een parameter in de HTTP-interface waarmee u de voortgang in HTTP-headers kunt verzenden: send_progress_in_http_headers=1. Helaas kan de standaard Go-bibliotheek geen headers lezen zoals ze worden ontvangen, maar de HTTP 1.0-interface (niet te verwarren met 1.1!) wordt ondersteund door ClickHouse, dus je kunt een onbewerkte TCP-verbinding met ClickHouse openen en deze daarheen sturen GET /?query=... HTTP/1.0nn en ontvang de antwoordheaders en de hoofdtekst zonder enige ontsnapping of codering, dus in dit geval hoeven we niet eens de standaardbibliotheek te gebruiken.

Streaminglogboeken van ClickHouse

ClickHouse heeft al relatief lang (sinds 2019?) optimalisatie voor zoekopdrachten met ORDER BY, dus een zoekopdracht als

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

Het zal onmiddellijk beginnen met het retourneren van regels die de subtekenreeks "iets" in hun bericht hebben, zonder te wachten tot de scan is voltooid.

Het zou ook erg handig zijn als ClickHouse zelf het verzoek annuleerde toen de verbinding ermee werd gesloten, maar dit is niet het standaardgedrag. Automatische annulering van verzoeken kan worden ingeschakeld met behulp van deze optie cancel_http_readonly_queries_on_client_close=1.

Correcte afhandeling van SIGPIPE in Go

Wanneer u bijvoorbeeld het commando uitvoert some_cmd | head -n 10, precies hoe de opdracht some_cmd stopt de uitvoering wanneer head 10 regels afgetrokken? Het antwoord is simpel: wanneer head eindigt, de pipe sluit en de stdout van het some_cmd commando begint voorwaardelijk “naar nergens” te wijzen. Wanneer some_cmd probeert naar een gesloten pijp te schrijven, het ontvangt een SIGPIPE-signaal, dat het programma standaard stilletjes beëindigt.

In Go gebeurt dit ook standaard, maar de SIGPIPE-signaalhandler drukt aan het einde ook "signaal: SIGPIPE" of een soortgelijk bericht af, en om dit bericht te wissen moeten we SIGPIPE zelf afhandelen zoals we willen, dat wil zeggen, gewoon stil. Uitgang:

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

Toon berichtcontext

Vaak wilt u de context zien waarin een fout is opgetreden (bijvoorbeeld welk verzoek paniek veroorzaakte, of welke gerelateerde problemen zichtbaar waren vóór de crash), en in grep Dit wordt gedaan met behulp van de opties -A, -B en -C, die respectievelijk het opgegeven aantal regels na, vóór en rond het bericht weergeven.

Helaas heb ik geen gemakkelijke manier gevonden om hetzelfde te doen in ClickHouse, dus om de context weer te geven wordt een aanvullend verzoek als dit naar elke regel van het resultaat gestuurd (de details zijn afhankelijk van de sortering en of de context eerder wordt getoond of erna):

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

Omdat het verzoek vrijwel onmiddellijk wordt verzonden nadat ClickHouse de overeenkomstige regel heeft geretourneerd, komt het in de cache terecht en wordt het verzoek over het algemeen vrij snel uitgevoerd en verbruikt het een beetje CPU (meestal duurt het verzoek ongeveer ~6 ms op mijn virtuele machine).

Toon nieuwe berichten in realtime

Om inkomende berichten (bijna) realtime te tonen, voeren we het verzoek eenvoudigweg elke paar seconden uit, waarbij we de laatste tijdstempel onthouden die we eerder zijn tegengekomen.

Commandovoorbeelden

Hoe zien typische logscli-opdrachten er in de praktijk uit?

Als je de Amazon-dataset hebt gedownload die ik aan het begin van het artikel noemde, kun je de volgende opdrachten uitvoeren:

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

referenties

De hulpprogrammacode (zonder documentatie) is beschikbaar op github op https://github.com/YuriyNasretdinov/logscli. Ik zou graag uw mening horen over mijn idee voor een console-interface voor het bekijken van logs op basis van ClickHouse.

Bron: www.habr.com

Voeg een reactie