Kami sedang mengembangkan antarmuka paling nyaman di dunia* untuk melihat log

Kami sedang mengembangkan antarmuka paling nyaman di dunia* untuk melihat log Jika Anda pernah menggunakan antarmuka web untuk melihat log, Anda mungkin memperhatikan bagaimana, pada umumnya, antarmuka ini rumit dan (seringkali) tidak terlalu nyaman dan responsif. Beberapa mungkin sudah biasa bagi Anda, beberapa benar-benar buruk, tetapi menurut saya alasan dari semua masalah ini adalah karena kami melakukan pendekatan yang salah terhadap tugas melihat log: kami mencoba membuat antarmuka web di mana CLI (antarmuka baris perintah) bekerja lebih baik. Saya pribadi sangat nyaman bekerja dengan tail, grep, awk dan lain-lain, dan oleh karena itu bagi saya antarmuka yang ideal untuk bekerja dengan log adalah sesuatu yang mirip dengan tail dan grep, tetapi juga dapat digunakan untuk membaca log yang berasal dari banyak server. Tentu saja, membacanya dari ClickHouse!

*menurut pendapat pribadi pengguna habra kamu keren

Temui logscli

Saya tidak menemukan nama untuk antarmuka saya, dan sejujurnya, ini ada dalam bentuk prototipe, tetapi jika Anda ingin segera melihat kode sumbernya, silakan: https://github.com/YuriyNasretdinov/logscli (350 baris kode Go yang dipilih).

Kemampuan

Я ставил перед собой цель сделать интерфейс, который будет казаться знакомым тем, кто привык к tail/grep, то есть поддерживать следующие вещи:

  1. Lihat semua log, tanpa memfilter.
  2. Tinggalkan baris yang berisi substring tetap (flag -F у grep).
  3. Tinggalkan baris yang cocok dengan ekspresi reguler (flag -E у grep).
  4. Secara default, tampilan dilakukan dalam urutan kronologis terbalik, karena log terbaru biasanya menjadi perhatian terlebih dahulu.
  5. Tampilkan konteks di samping setiap baris (opsi -A, -B и -C у grep, masing-masing mencetak N baris sebelum, sesudah, dan di sekitar setiap baris yang cocok).
  6. Lihat log masuk secara real time, dengan atau tanpa pemfilteran (intinya tail -f | grep).
  7. Antarmuka harus kompatibel dengan less, head, tail dan lainnya - secara default, hasil harus dikembalikan tanpa batasan jumlahnya; garis dicetak sebagai aliran selama pengguna tertarik untuk menerimanya; sinyal SIGPIPE harus secara diam-diam mengganggu streaming log, sama seperti yang mereka lakukan tail, grep dan utilitas UNIX lainnya.

Implementasi

Saya berasumsi bahwa Anda sudah mengetahui cara mengirimkan log ke ClickHouse. Jika belum, saya sarankan untuk mencobanya LSD и rumah kucingDan artikel ini tentang pengiriman log.

Pertama, Anda perlu memutuskan skema dasar. Karena Anda biasanya ingin menerima log yang diurutkan berdasarkan waktu, tampaknya logis untuk menyimpannya seperti itu. Jika ada banyak kategori log dan semuanya memiliki tipe yang sama, maka Anda dapat menjadikan kategori log sebagai kolom pertama dari kunci utama - ini akan memungkinkan Anda memiliki satu tabel, bukan beberapa, yang akan menjadi nilai tambah yang besar ketika memasukkan ke ClickHouse (pada server dengan hard drive, disarankan untuk memasukkan data tidak lebih dari ~1 kali per detik untuk seluruh server).

Artinya, kita membutuhkan kira-kira skema tabel berikut:

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

Sayangnya, saya tidak dapat segera menemukan sumber terbuka dengan log realistis yang dapat saya ambil dan unduh, jadi saya mengambil ini sebagai contoh. review produk dari Amazon hingga tahun 2015. Tentu saja, strukturnya tidak persis sama dengan log teks, namun untuk tujuan ilustrasi hal ini tidak penting.

instruksi untuk mengunggah ulasan Amazon ke ClickHouse

Mari buat tabel:

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

Pada dataset Amazon hanya ada tanggal peninjauannya, namun belum ada waktu pastinya, jadi mari kita isi data ini dengan randon.

Anda tidak perlu mengunduh semua file tsv dan membatasi diri Anda pada ~10-20 file pertama untuk mendapatkan kumpulan data yang cukup besar yang tidak dapat dimasukkan ke dalam RAM 16 GB. Untuk mengunggah file TSV saya menggunakan perintah berikut:

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

Pada Persistent Disk standar (yang merupakan HDD) di Google Cloud dengan ukuran 1000 GB (saya mengambil ukuran ini terutama agar kecepatannya sedikit lebih tinggi, meskipun mungkin SSD dengan ukuran yang diperlukan akan lebih murah) unggahan kecepatannya sekitar ~ 75 MB/detik pada 4 core.

  • Saya harus membuat reservasi bahwa saya bekerja di Google, tetapi saya menggunakan akun pribadi dan artikel ini tidak ada hubungannya dengan pekerjaan saya di perusahaan

Saya akan membuat semua ilustrasi dengan kumpulan data khusus ini, karena hanya ini yang saya miliki.

Tampilkan kemajuan pemindaian data

Karena di ClickHouse kita akan menggunakan pemindaian penuh pada tabel dengan log, dan operasi ini dapat memakan banyak waktu dan mungkin tidak memberikan hasil apa pun untuk waktu yang lama jika ditemukan sedikit kecocokan, disarankan untuk dapat menampilkan kemajuan kueri hingga baris pertama dengan hasilnya diterima. Untuk melakukan ini, ada parameter di antarmuka HTTP yang memungkinkan Anda mengirim kemajuan dalam header HTTP: send_progress_in_http_headers=1. Sayangnya, pustaka Go standar tidak dapat membaca header saat diterima, namun antarmuka HTTP 1.0 (jangan bingung dengan 1.1!) didukung oleh ClickHouse, sehingga Anda dapat membuka koneksi TCP mentah ke ClickHouse dan mengirimkannya ke sana GET /?query=... HTTP/1.0nn dan menerima header dan isi respons tanpa pelolosan atau enkripsi apa pun, jadi dalam hal ini kita bahkan tidak perlu menggunakan perpustakaan standar.

Streaming log dari ClickHouse

ClickHouse telah melakukan optimasi untuk query dengan ORDER BY dalam waktu yang relatif lama (sejak 2019?), jadi query seperti

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

Ini akan segera mulai mengembalikan baris yang memiliki substring "sesuatu" dalam pesannya, tanpa menunggu pemindaian selesai.

Selain itu, akan sangat mudah jika ClickHouse sendiri membatalkan permintaan saat koneksi ditutup, tetapi ini bukan perilaku default. Pembatalan permintaan otomatis dapat diaktifkan menggunakan opsi ini cancel_http_readonly_queries_on_client_close=1.

Penanganan SIGPIPE yang benar di Go

Saat Anda menjalankan, katakanlah, perintah some_cmd | head -n 10, persis bagaimana perintahnya some_cmd menghentikan eksekusi kapan head dikurangi 10 baris? Jawabannya sederhana: kapan head berakhir, pipa menutup, dan stdout dari perintah some_cmd mulai menunjuk, dengan syarat, "ke mana-mana". Kapan some_cmd mencoba menulis ke pipa tertutup, ia menerima sinyal SIGPIPE, yang secara diam-diam menghentikan program secara default.

Di Go, hal ini juga terjadi secara default, tetapi pengendali sinyal SIGPIPE juga mencetak "sinyal: SIGPIPE" atau pesan serupa di akhir, dan untuk menghapus pesan ini kita hanya perlu menangani SIGPIPE sendiri sesuai keinginan kita, yaitu diam-diam KELUAR:

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

Tampilkan konteks pesan

Seringkali Anda ingin melihat konteks di mana beberapa kesalahan terjadi (misalnya, permintaan mana yang menyebabkan kepanikan, atau masalah terkait apa yang terlihat sebelum kerusakan), dan di grep Hal ini dilakukan dengan menggunakan opsi -A, -B, dan -C, yang masing-masing menampilkan jumlah baris tertentu setelah, sebelum, dan di sekitar pesan.

Sayangnya, saya belum menemukan cara mudah untuk melakukan hal yang sama di ClickHouse, jadi untuk menampilkan konteksnya, permintaan tambahan seperti ini dikirim ke setiap baris hasil (detailnya bergantung pada penyortiran dan apakah konteksnya ditampilkan sebelumnya atau setelahnya):

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

Karena permintaan dikirim segera setelah ClickHouse mengembalikan baris yang sesuai, permintaan tersebut berakhir di cache dan secara umum permintaan dijalankan cukup cepat dan menghabiskan sedikit CPU (biasanya permintaan memerlukan waktu sekitar ~6 ms di mesin virtual saya).

Tampilkan pesan baru secara real time

Untuk menampilkan pesan masuk (hampir) real-time, kita cukup menjalankan permintaan setiap beberapa detik sekali, mengingat stempel waktu terakhir yang kita temui sebelumnya.

Contoh perintah

Seperti apa perintah logscli pada umumnya dalam praktiknya?

Jika Anda mengunduh kumpulan data Amazon yang saya sebutkan di awal artikel, Anda dapat menjalankan perintah berikut:

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

referensi

Kode utilitas (tanpa dokumentasi) tersedia di github di https://github.com/YuriyNasretdinov/logscli. Saya akan senang mendengar pendapat Anda tentang ide saya untuk antarmuka konsol untuk melihat log berdasarkan ClickHouse.

Sumber: www.habr.com

Tambah komentar