ما در حال توسعه راحت‌ترین رابط کاربری در جهان* برای مشاهده گزارش‌ها هستیم

ما در حال توسعه راحت‌ترین رابط کاربری در جهان* برای مشاهده گزارش‌ها هستیم اگر تا به حال از رابط های وب برای مشاهده گزارش ها استفاده کرده اید، احتمالاً متوجه شده اید که چگونه، به عنوان یک قاعده، این رابط ها دست و پا گیر هستند و (اغلب) خیلی راحت و پاسخگو نیستند. می توانید به برخی از آنها عادت کنید، برخی کاملاً وحشتناک هستند، اما به نظر من دلیل همه مشکلات این است که ما به کار مشاهده گزارش ها به اشتباه نزدیک می شویم: ما سعی می کنیم یک رابط وب ایجاد کنیم که در آن CLI (واسط خط فرمان) باشد. بهتر کار می کند من شخصاً کار کردن با tail، grep، awk و دیگران بسیار راحت هستم، و بنابراین برای من رابط ایده‌آل برای کار با logها چیزی شبیه به tail و grep است، اما می‌توان از آن برای خواندن گزارش‌هایی که از بسیاری از سرورها آمده‌اند نیز استفاده کرد. که البته، آنها را از ClickHouse بخوانید!

*طبق نظر شخصی کاربر habra تو شاهکاری

با logscli آشنا شوید

من نامی برای رابط کاربری خود پیدا نکردم، و صادقانه بگویم، به شکل یک نمونه اولیه وجود دارد، اما اگر می‌خواهید فوراً کد منبع را ببینید، خوش آمدید: https://github.com/YuriyNasretdinov/logscli (350 خط کد Go انتخاب شده).

توانمندی ها

هدف من ایجاد رابطی بود که برای کسانی که از tail/grep استفاده می کنند آشنا به نظر برسد، یعنی پشتیبانی از موارد زیر:

  1. مشاهده همه گزارش‌ها، بدون فیلتر کردن.
  2. خطوط حاوی یک رشته فرعی ثابت (پرچم -F у grep).
  3. خطوطی را بگذارید که با عبارت منظم مطابقت دارند (پرچم -E у grep).
  4. به‌طور پیش‌فرض، مشاهده به ترتیب زمانی معکوس است، زیرا آخرین گزارش‌ها معمولاً ابتدا مورد توجه هستند.
  5. نمایش زمینه در کنار هر خط (گزینه‌ها -A, -B и -C у grepچاپ N خط به ترتیب قبل، بعد و اطراف هر خط منطبق).
  6. گزارش‌های دریافتی را در زمان واقعی، با یا بدون فیلتر (در اصل tail -f | grep).
  7. رابط باید با less, head, tail و دیگران - به طور پیش فرض، نتایج باید بدون محدودیت در تعداد آنها بازگردانده شوند. خطوط به عنوان یک جریان چاپ می شوند تا زمانی که کاربر علاقه مند به دریافت آنها باشد. علامت SIGPIPE باید بدون صدا جریان گزارش را قطع کند، درست مثل آنها tail, grep و سایر ابزارهای یونیکس.

اجرا

من فرض می کنم که شما قبلاً به نوعی می دانید که چگونه گزارش ها را به ClickHouse تحویل دهید. اگر نه، توصیه می کنم آن را امتحان کنید LSD и بچه گربه خانهو این مقاله در مورد تحویل سیاهه.

ابتدا باید در مورد طرح پایه تصمیم بگیرید. از آنجایی که شما معمولاً می خواهید لاگ های مرتب شده بر اساس زمان را دریافت کنید، منطقی به نظر می رسد که آنها را به این ترتیب ذخیره کنید. اگر دسته های گزارش زیادی وجود دارد و همه آنها از یک نوع هستند، می توانید یک دسته گزارش را به عنوان اولین ستون کلید اصلی بسازید - این به شما امکان می دهد به جای چندین جدول یک جدول داشته باشید، که در زمانی که درج در ClickHouse (در سرورهای دارای هارد دیسک، توصیه می شود اطلاعات را بیش از 1 بار در ثانیه وارد کنید. برای کل سرور).

یعنی تقریباً به طرح جدول زیر نیاز داریم:

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

متأسفانه، نمی‌توانم فوراً هیچ منبع باز با گزارش‌های واقعی را پیدا کنم که بتوانم آن را بگیرم و دانلود کنم، بنابراین به جای آن این را به عنوان مثال در نظر گرفتم. بررسی محصولات آمازون قبل از سال 2015. البته ساختار آنها دقیقاً مشابه لاگ های متنی نیست، اما برای مصورسازی این مهم نیست.

دستورالعمل برای آپلود نظرات آمازون در ClickHouse

بیایید یک جدول ایجاد کنیم:

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

در مجموعه داده آمازون فقط یک تاریخ برای بررسی وجود دارد، اما زمان دقیقی وجود ندارد، بنابراین بیایید این داده ها را با یک تصادف پر کنیم.

لازم نیست همه فایل‌های tsv را دانلود کنید و خود را به 10-20 عدد اول محدود کنید تا مجموعه نسبتاً بزرگی از داده‌ها را به دست آورید که در 16 گیگابایت رم جا نمی‌شوند. برای آپلود فایل های TSV از دستور زیر استفاده کردم:

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

در یک دیسک ثابت استاندارد (که یک HDD است) در Google Cloud با حجم 1000 گیگابایت (من این اندازه را عمدتاً به این دلیل انتخاب کردم که سرعت کمی بالاتر بود، اگرچه شاید یک SSD با اندازه لازم ارزانتر بود) آپلود سرعت تقریباً 75 مگابایت بر ثانیه روی 4 هسته بود.

  • من باید رزرو کنم که در گوگل کار می کنم، اما از یک حساب شخصی استفاده کردم و این مقاله ربطی به کار من در شرکت ندارد.

من تمام تصاویر را با این مجموعه داده خاص تولید خواهم کرد، زیرا این تنها چیزی است که در دست داشتم.

نمایش پیشرفت اسکن داده ها

از آنجایی که در ClickHouse ما از یک اسکن کامل روی یک جدول با گزارش‌ها استفاده می‌کنیم و این عملیات می‌تواند زمان قابل‌توجهی طول بکشد و در صورت یافتن موارد منطبق ممکن است برای مدت طولانی نتیجه‌ای نداشته باشد، توصیه می‌شود بتوانیم پیشرفت پرس و جو تا دریافت اولین سطرها با نتیجه. برای انجام این کار، یک پارامتر در رابط HTTP وجود دارد که به شما امکان می دهد پیشرفت را در هدرهای HTTP ارسال کنید: send_progress_in_http_headers=1. متأسفانه، کتابخانه استاندارد Go نمی‌تواند سرصفحه‌ها را همانطور که دریافت می‌کند بخواند، اما رابط HTTP 1.0 (با 1.1 اشتباه نشود!) توسط ClickHouse پشتیبانی می‌شود، بنابراین می‌توانید یک اتصال TCP خام را به ClickHouse باز کنید و آن را به آنجا ارسال کنید. GET /?query=... HTTP/1.0nn و سرصفحه و بدنه پاسخ را بدون هیچ گونه فرار یا رمزگذاری دریافت کنید، بنابراین در این مورد ما حتی نیازی به استفاده از کتابخانه استاندارد نداریم.

استریم لاگ ها از ClickHouse

ClickHouse برای مدت نسبتاً طولانی (از سال 2019؟) برای پرس و جوها با ORDER BY بهینه سازی داشته است، بنابراین یک پرس و جو مانند

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

بلافاصله شروع به بازگرداندن خطوطی می کند که زیر رشته "چیزی" را در پیام خود دارند، بدون اینکه منتظر پایان اسکن باشند.

همچنین، بسیار راحت خواهد بود اگر ClickHouse خود درخواست را زمانی که اتصال به آن بسته شد لغو کند، اما این رفتار پیش‌فرض نیست. لغو خودکار درخواست را می توان با استفاده از گزینه فعال کرد cancel_http_readonly_queries_on_client_close=1.

مدیریت صحیح SIGPIPE در Go

وقتی دستور را اجرا می کنید، بگویید some_cmd | head -n 10، دقیقا چگونه دستور some_cmd زمانی که اجرا را متوقف می کند head 10 خط کم کردی؟ پاسخ ساده است: چه زمانی head به پایان می رسد، لوله بسته می شود، و stdout دستور some_cmd شروع به نشان دادن، به طور مشروط، "به هیچ جا" می کند. چه زمانی some_cmd سعی می کند به یک لوله بسته بنویسد، یک سیگنال SIGPIPE دریافت می کند که به طور پیش فرض برنامه را به طور بی صدا خاتمه می دهد.

در Go نیز به طور پیش فرض این اتفاق می افتد، اما کنترل کننده سیگنال SIGPIPE نیز "signal: SIGPIPE" یا پیامی مشابه را در پایان چاپ می کند و برای پاک کردن این پیام فقط باید SIGPIPE را همانطور که می خواهیم مدیریت کنیم، یعنی فقط بی صدا. خروج:

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

نمایش متن پیام

اغلب می‌خواهید زمینه‌ای را ببینید که در آن برخی از خطاها رخ داده است (مثلاً، کدام درخواست باعث ایجاد هراس می‌شود، یا چه مشکلات مرتبطی قبل از خرابی قابل مشاهده بود)، و در grep این کار با استفاده از گزینه های -A، -B و -C انجام می شود که تعداد خطوط مشخص شده را به ترتیب بعد، قبل و اطراف پیام نشان می دهند.

متأسفانه، من راه آسانی برای انجام همین کار در ClickHouse پیدا نکرده‌ام، بنابراین برای نمایش متن، یک درخواست اضافی مانند این به هر خط از نتیجه ارسال می‌شود (جزئیات بستگی به مرتب‌سازی و اینکه آیا زمینه قبل نشان داده شده است یا خیر یا بعد از آن):

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

از آنجایی که درخواست تقریباً بلافاصله پس از اینکه ClickHouse خط مربوطه را برمی گرداند ارسال می شود، در کش ختم می شود و به طور کلی درخواست بسیار سریع اجرا می شود و CPU کمی مصرف می کند (معمولاً درخواست در ماشین مجازی من حدود ~6 میلی ثانیه طول می کشد).

نمایش پیام های جدید در زمان واقعی

برای نمایش پیام های دریافتی در زمان واقعی (تقریباً)، ما به سادگی هر چند ثانیه یک بار درخواست را اجرا می کنیم و آخرین مهر زمانی را که قبلاً با آن مواجه شده ایم به خاطر می آوریم.

نمونه های دستوری

دستورات معمولی logscli در عمل چگونه به نظر می رسند؟

اگر مجموعه داده آمازون را که در ابتدای مقاله ذکر کردم دانلود کرده اید، می توانید دستورات زیر را اجرا کنید:

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

مراجع

کد ابزار (بدون مستندات) در github در دسترس است https://github.com/YuriyNasretdinov/logscli. خوشحال می شوم نظرات شما را در مورد ایده من برای رابط کنسول برای مشاهده گزارش ها بر اساس ClickHouse بشنوم.

منبع: www.habr.com

اضافه کردن نظر