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

We ontwikkelen de meest gebruiksvriendelijke interface ter wereld* voor het bekijken van logs Als u ooit webinterfaces hebt gebruikt om logs te bekijken, heeft u ongetwijfeld gemerkt hoe vaak deze interfaces doorgaans omslachtig en (vaak) niet erg gebruiksvriendelijk en responsief zijn. Sommige kunt u gewend raken, andere zijn gewoon verschrikkelijk, maar naar mijn mening ligt de oorzaak van alle problemen in de manier waarop we de taak van logverzameling benaderen: we proberen een webinterface te creëren waar een CLI (command line interface) beter functioneert. Persoonlijk werk ik graag met tail, grep, awk en anderen, en daarom zou de ideale interface voor logbestanden iets zijn dat lijkt op tail en grep, maar het moet mogelijk zijn om logs te lezen die afkomstig zijn van verschillende servers. Dit betekent natuurlijk dat we ze uit ClickHouse moeten lezen!

*volgens de persoonlijke mening van een Habr-gebruiker youROCK

Ontmoet logscli

Ik heb geen naam bedacht voor mijn interface, en eerlijk gezegd bestaat het meer als prototype, maar als je meteen de broncode wilt bekijken, welkom: https://github.com/YuriyNasretdinov/logscli (350 regels zorgvuldig samengestelde code in Go).

Functionaliteiten

Mijn doel was om een interface te maken die vertrouwd aanvoelt voor degenen die gewend zijn aan tail/grep, dat wil zeggen dat het de volgende dingen moet ondersteunen:

  1. Bekijk alle logs zonder filtering.
  2. Houd de regels met een vaste substring (vlag -F ‘ grep).
  3. Houd de regels die overeenkomen met een reguliere expressie (vlag -E ‘ grep).
  4. Standaard leest het in omgekeerde chronologische volgorde, omdat meestal de meest recente logs het meest interessant zijn.
  5. Toon de context rond elke regel (parameters -A, -B en -C ‘ grep, print N regels ervoor, erna, en rondom elke overeenkomstige regel).
  6. Bekijk binnenkomende logs in real-time, met filtering en zonder (in wezen tail -f | grep).
  7. De interface moet compatibel zijn met less, head, tail en anderen - standaard moeten resultaten zonder limiet teruggegeven worden; regels worden continu weergegeven zolang de gebruiker geïnteresseerd is in het ontvangen ervan; het signaal SIGPIPE moet stil de streaming van logs onderbreken, net zoals dat gebeurt met tail, grep en andere UNIX-hulpprogramma's.

Implementatie

Ik ga ervan uit dat je op een of andere manier weet hoe je logs naar ClickHouse kunt sturen. Als dat niet het geval is, raad ik aan om lsd en kittenhouse, evenals dit artikel over het verzenden van logs te proberen.

Eerst moeten we beslissen over het databaseschema. Aangezien we logs meestal op tijd willen ontvangen, lijkt het logisch om ze zo op te slaan. Als er veel logcategorieën zijn en ze allemaal vergelijkbaar zijn, kunnen we de logcategorie als de eerste kolom van de primaire sleutel gebruiken — dit stelt ons in staat om één tabel in plaats van meerdere te hebben, wat bij het invoegen in ClickHouse een groot voordeel zal zijn (op servers met harde schijven wordt aanbevolen om gegevens niet vaker dan ongeveer 1 keer per seconde in te voegen. voor de hele server).

Dat wil zeggen, we hebben ongeveer het volgende schema voor tabellen nodig:

CREATE TABLE logs(
    category LowCardinality(String), -- logcategorie (optioneel)
    time DateTime, -- tijd van het evenement
    millis UInt16, -- milliseconden (het kunnen ook microseconden zijn, enz.): aanbevolen om op te slaan als er veel evenementen zijn, zodat het gemakkelijker is om evenementen van elkaar te onderscheiden
    ..., -- uw eigen velden, zoals de naam van de server, het logniveau, enz.
    message String -- tekst van het bericht
) ENGINE=MergeTree()
ORDER BY (category, time, millis)

Helaas kon ik niet onmiddellijk open bronnen vinden met realistische logs die ik kon downloaden, dus nam ik in plaats daarvan als voorbeeld reviews van producten van Amazon tot 2015. Uiteraard is hun structuur niet helemaal die van tekstlogs, maar voor illustratie is dat niet doorslaggevend.

instructies voor het uploaden van Amazon-reviews naar ClickHouse

Laten we een tabel aanmaken:

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 is er alleen een datum voor de review, maar geen exacte tijd, dus we vullen deze gegevens met willekeurige waarden in.

Het is niet nodig om alle tsv-bestanden te downloaden; u kunt zich beperken tot de eerste ~10-20 om al een voldoende grote dataset te krijgen die niet in 16 GB RAM past. Voor het uploaden van de TSV-bestanden 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

Met de standaard Persistent Disk (die HDD is) in Google Cloud van 1000 GB (ik heb deze grootte gekozen voornamelijk om de snelheid iets te verhogen, hoewel het misschien goedkoper zou zijn geweest met een SSD van de juiste grootte) was de upload snelheid ongeveer ~75 MB/sec op 4 cores.

  • Ik moet erop wijzen 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.

Alle illustraties zal ik precies met deze dataset maken, omdat dit alles is wat ik bij de hand had.

Voortgang van de gegevensscanning weergeven

Aangezien we in ClickHouse een volledige scan door de tabel met logs gaan uitvoeren, en deze operatie aanzienlijke tijd kan innemen en lang geen resultaten kan opleveren als er weinig overeenkomsten zijn, is het wenselijk om de voortgang van de query weer te geven totdat we de eerste rijen met resultaten krijgen. Hiervoor is er in de HTTP-interface een parameter die het mogelijk maakt om de voortgang in de HTTP-headers te retourneren: send_progress_in_http_headers=1. Helaas kan de standaard Go-bibliotheek geen headers lezen terwijl ze binnenkomen, maar de HTTP 1.0-interface (verwissel dit niet met 1.1!) wordt door ClickHouse ondersteund, dus we kunnen een rauwe TCP-verbinding met ClickHouse openen, daarheen sturen GET \/?query=... HTTP\/1.0nn en als antwoord headers en de lichaam van de respons ontvangen zonder enige vorm van escaping of encryptie, zodat we in dit geval de standaardbibliotheek zelfs niet hoeven te gebruiken.

Streaming logs uit ClickHouse

ClickHouse heeft al relatief lang (sinds 2019?) een optimalisatie voor queries met ORDER BY, zodat een query van de vorm

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

direct begint met het teruggeven van rijen waarin in message de substring "something" voorkomt, zonder te wachten op het einde van de scan.

Het zou ook heel handig zijn als ClickHouse zelf de query zou annuleren wanneer de verbinding wordt gesloten, maar dit is niet het standaardgedrag. Automatische annulering van de query kan ingeschakeld worden met de optie cancel_http_readonly_queries_on_client_close=1.

Correcte verwerking van SIGPIPE in Go

Wanneer je bijvoorbeeld het commando uitvoert some_cmd | head -n 10, op welke manier beëindigt het commando some_cmd zijn uitvoering wanneer head het 10 rijen heeft gelezen? Het antwoord is simpel: wanneer head het eindigt, wordt de pipe gesloten, en stdout van het commando some_cmd begint te wijzen naar, conditioneel, "nergens". Wanneer some_cmd het probeert te schrijven naar een gesloten pipe, ontvangt het een SIGPIPE-signaal dat standaard stil de programma beëindigt..

In Go, this happens by default as well, but the SIGPIPE signal handler also prints 'signal: SIGPIPE' or a similar message at the end, and to remove this message, you just need to handle SIGPIPE yourself as you wish, meaning simply exit quietly:

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

Message context display

Often, you want to see the context in which an error occurred (for instance, which request caused the panic, or what accompanying issues were visible before the crash), and grep for this, the options -A, -B, and -C serve, which show the specified number of lines after, before, and around the message, respectively.

Unfortunately, I couldn't find a simple way to do the same in ClickHouse, so to display the context, an additional query is sent for each line of the result, approximately in the following form (details depend on the sorting and whether the context is shown before or after):

SELECT time,millis,review_body FROM amazon
WHERE (time = 'EVENT_TIME' AND millis < EVENT_MILLISECONDS) OR (time < 'EVENT_TIME')
ORDER BY time DESC, millis DESC
LIMIT CONTEXT_LINES
SETTINGS max_threads=1

Since the query is sent almost immediately after ClickHouse returns the corresponding line, it hits the cache, and in general, the query executes quite quickly and uses a little CPU (usually the query takes about ~6 ms on my virtual machine).

Display new messages in real-time

To show incoming messages in (almost) real-time, simply execute the query every few seconds, remembering the last timestamp we encountered before.

Command examples

What do typical logscli commands look like in practice?

If you uploaded the Amazon dataset I mentioned at the beginning of the article, then you can execute the following commands:

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

Links

The utility code (without documentation) is available on github at https://github.com/YuriyNasretdinov/logscli. I would love to hear your thoughts on my idea for a console interface for viewing logs based on ClickHouse.

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers 🔥 Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster