Chúng tôi đang phát triển giao diện thuận tiện nhất trên thế giới* để xem nhật ký

Chúng tôi đang phát triển giao diện thuận tiện nhất trên thế giới* để xem nhật ký Nếu bạn đã từng sử dụng giao diện web để xem nhật ký, thì có lẽ bạn đã nhận thấy, theo quy luật, các giao diện này rất cồng kềnh và (thường) không thuận tiện và phản hồi nhanh. Một số bạn có thể quen, một số thì hoàn toàn khủng khiếp, nhưng đối với tôi, có vẻ như lý do của tất cả các vấn đề là do chúng ta tiếp cận nhiệm vụ xem nhật ký không chính xác: chúng ta cố gắng tạo một giao diện web trong đó CLI (giao diện dòng lệnh) hoạt động tốt hơn Cá nhân tôi rất thoải mái khi làm việc với tail, grep, awk và những thứ khác, và do đó, đối với tôi, giao diện lý tưởng để làm việc với nhật ký sẽ giống như tail và grep, nhưng cũng có thể được sử dụng để đọc nhật ký đến từ nhiều máy chủ. Tất nhiên, đó là đọc chúng từ ClickHouse!

*theo ý kiến ​​cá nhân của người dùng habra youROCK

Gặp logscli

Tôi chưa nghĩ ra tên cho giao diện của mình và thành thật mà nói, nó tồn tại ở dạng nguyên mẫu, nhưng nếu bạn muốn xem ngay mã nguồn thì xin vui lòng: https://github.com/YuriyNasretdinov/logscli (350 dòng mã Go đã chọn).

Khả năng

Mục tiêu của tôi là tạo ra một giao diện có vẻ quen thuộc với những người đã quen với tail/grep, nghĩa là để hỗ trợ những điều sau:

  1. Xem tất cả nhật ký mà không cần lọc.
  2. Để lại các dòng chứa một chuỗi con cố định (cờ -F у grep).
  3. Để lại các dòng khớp với biểu thức chính quy (cờ -E у grep).
  4. Theo mặc định, việc xem theo thứ tự thời gian đảo ngược, vì nhật ký gần đây nhất thường được quan tâm đầu tiên.
  5. Hiển thị ngữ cảnh bên cạnh mỗi dòng (tùy chọn -A, -B и -C у grep, in N dòng trước, sau và xung quanh mỗi dòng tương ứng).
  6. Xem nhật ký đến trong thời gian thực, có hoặc không có lọc (về cơ bản tail -f | grep).
  7. Giao diện phải tương thích với less, head, tail và những thứ khác - theo mặc định, kết quả sẽ được trả về mà không bị hạn chế về số lượng; các dòng được in dưới dạng luồng miễn là người dùng muốn nhận chúng; tín hiệu SIGPIPE nên âm thầm làm gián đoạn việc truyền nhật ký, giống như họ đã làm tail, grep và các tiện ích UNIX khác.

Thực hiện

Tôi sẽ cho rằng bằng cách nào đó bạn đã biết cách gửi nhật ký đến ClickHouse. Nếu không, tôi khuyên bạn nên thử nó lsd и chuồng mèo conbài viết này về việc phân phối nhật ký.

Đầu tiên bạn cần quyết định sơ đồ cơ sở. Vì bạn thường muốn nhận nhật ký được sắp xếp theo thời gian nên việc lưu trữ chúng theo cách đó có vẻ hợp lý. Nếu có nhiều danh mục nhật ký và tất cả chúng đều cùng loại, thì bạn có thể tạo một danh mục nhật ký làm cột đầu tiên của khóa chính - điều này sẽ cho phép bạn có một bảng thay vì nhiều bảng, đây sẽ là một điểm cộng lớn khi chèn vào ClickHouse (trên máy chủ có ổ cứng, nên chèn dữ liệu không quá ~1 lần mỗi giây cho toàn bộ máy chủ).

Nghĩa là, chúng ta cần sơ đồ bảng sau:

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

Thật không may, tôi không thể tìm thấy ngay bất kỳ nguồn mở nào có nhật ký thực tế mà tôi có thể lấy và tải xuống, vì vậy tôi lấy nguồn này làm ví dụ. đánh giá các sản phẩm từ Amazon cho đến năm 2015. Tất nhiên, cấu trúc của chúng không hoàn toàn giống với cấu trúc của nhật ký văn bản, nhưng vì mục đích minh họa nên điều này không quan trọng.

hướng dẫn upload đánh giá Amazon lên ClickHouse

Hãy tạo một bảng:

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

Trong tập dữ liệu của Amazon chỉ có ngày đánh giá nhưng không có thời gian chính xác, vì vậy hãy điền dữ liệu này bằng một randon.

Bạn không cần phải tải xuống tất cả các tệp tsv và giới hạn ở ~ 10-20 đầu tiên để có được một tập dữ liệu khá lớn không vừa với 16 GB RAM. Để tải lên tệp TSV, tôi đã sử dụng lệnh sau:

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

Trên Đĩa liên tục tiêu chuẩn (là ổ cứng HDD) trong Google Cloud có kích thước 1000 GB (tôi chủ yếu lấy kích thước này để tốc độ cao hơn một chút, mặc dù có lẽ ổ SSD có kích thước yêu cầu sẽ rẻ hơn) tải lên tốc độ xấp xỉ ~ 75 MB/giây trên 4 lõi.

  • Tôi phải đặt chỗ trước rằng tôi làm việc tại Google nhưng tôi đã sử dụng tài khoản cá nhân và bài viết này không liên quan gì đến công việc của tôi tại công ty

Tôi sẽ tạo tất cả các hình minh họa với tập dữ liệu cụ thể này vì đây là tất cả những gì tôi có trong tay.

Hiển thị tiến trình quét dữ liệu

Vì trong ClickHouse, chúng tôi sẽ sử dụng tính năng quét toàn bộ trên một bảng có nhật ký và thao tác này có thể mất một lượng thời gian đáng kể và có thể không tạo ra bất kỳ kết quả nào trong một thời gian dài nếu tìm thấy ít kết quả phù hợp, nên có thể hiển thị tiến trình truy vấn cho đến khi nhận được hàng đầu tiên có kết quả. Để thực hiện việc này, có một tham số trong giao diện HTTP cho phép bạn gửi tiến trình trong tiêu đề HTTP: send_progress_in_http_headers=1. Thật không may, thư viện Go tiêu chuẩn không thể đọc các tiêu đề khi chúng được nhận, nhưng giao diện HTTP 1.0 (đừng nhầm với 1.1!) Được ClickHouse hỗ trợ, vì vậy bạn có thể mở kết nối TCP thô tới ClickHouse và gửi nó đến đó GET /?query=... HTTP/1.0nn và nhận các tiêu đề và nội dung phản hồi mà không cần thoát hoặc mã hóa, vì vậy trong trường hợp này, chúng tôi thậm chí không cần sử dụng thư viện chuẩn.

Truyền nhật ký từ ClickHouse

ClickHouse đã tối ưu hóa các truy vấn bằng ORDER BY trong một thời gian tương đối dài (kể từ năm 2019?), vì vậy một truy vấn như

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

Nó sẽ ngay lập tức bắt đầu trả về các dòng có chuỗi con "thứ gì đó" trong tin nhắn của chúng mà không cần đợi quá trình quét kết thúc.

Ngoài ra, sẽ rất thuận tiện nếu ClickHouse tự hủy yêu cầu khi kết nối với nó bị đóng, nhưng đây không phải là hành vi mặc định. Việc hủy yêu cầu tự động có thể được bật bằng tùy chọn cancel_http_readonly_queries_on_client_close=1.

Xử lý đúng SIGPIPE trong Go

Khi bạn thực thi lệnh some_cmd | head -n 10, lệnh chính xác như thế nào some_cmd dừng thực thi khi head trừ đi 10 dòng? Câu trả lời rất đơn giản: khi head kết thúc, đường ống đóng lại và thiết bị xuất chuẩn của lệnh some_cmd bắt đầu trỏ, có điều kiện, "đến hư không". Khi some_cmd cố gắng ghi vào một đường ống kín, nó nhận được tín hiệu SIGPIPE, tín hiệu này sẽ âm thầm chấm dứt chương trình theo mặc định.

Trong Go, điều này cũng xảy ra theo mặc định, nhưng trình xử lý tín hiệu SIGPIPE cũng in "signal: SIGPIPE" hoặc một thông báo tương tự ở cuối và để xóa thông báo này, chúng ta chỉ cần tự xử lý SIGPIPE theo cách mình muốn, tức là chỉ âm thầm lối ra:

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

Hiển thị ngữ cảnh tin nhắn

Thông thường, bạn muốn xem bối cảnh trong đó một số lỗi đã xảy ra (ví dụ: yêu cầu nào đã gây ra sự hoảng loạn hoặc những vấn đề liên quan nào có thể nhìn thấy trước khi xảy ra sự cố) và trong grep Điều này được thực hiện bằng cách sử dụng các tùy chọn -A, -B và -C, tương ứng hiển thị số dòng được chỉ định sau, trước và xung quanh tin nhắn.

Thật không may, tôi chưa tìm thấy cách dễ dàng để thực hiện điều tương tự trong ClickHouse, vì vậy để hiển thị ngữ cảnh, một yêu cầu bổ sung như thế này sẽ được gửi đến từng dòng của kết quả (chi tiết phụ thuộc vào cách sắp xếp và liệu ngữ cảnh có được hiển thị trước đó hay không). hoặc sau):

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

Vì yêu cầu được gửi gần như ngay lập tức sau khi ClickHouse trả về dòng tương ứng nên nó sẽ nằm trong bộ đệm và nhìn chung yêu cầu được thực thi khá nhanh và tiêu tốn một ít CPU (thường yêu cầu này mất khoảng ~6 mili giây trên máy ảo của tôi).

Hiển thị tin nhắn mới trong thời gian thực

Để hiển thị các tin nhắn đến trong (gần như) thời gian thực, chúng tôi chỉ cần thực hiện yêu cầu vài giây một lần, ghi nhớ dấu thời gian cuối cùng mà chúng tôi gặp trước đó.

Ví dụ lệnh

Các lệnh logscli điển hình trông như thế nào trong thực tế?

Nếu bạn đã tải xuống tập dữ liệu Amazon mà tôi đã đề cập ở đầu bài viết, bạn có thể chạy các lệnh sau:

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

tài liệu tham khảo

Mã tiện ích (không có tài liệu) có sẵn trên github tại https://github.com/YuriyNasretdinov/logscli. Tôi rất vui khi biết suy nghĩ của bạn về ý tưởng của tôi về giao diện bảng điều khiển để xem nhật ký dựa trên ClickHouse.

Nguồn: www.habr.com

Thêm một lời nhận xét