我們正在開發世界上最方便的介面*用於查看日誌

我們正在開發世界上最方便的介面*用於查看日誌 如果您曾經使用 Web 介面查看日誌,那麼您可能已經注意到,這些介面通常很麻煩,而且(通常)不太方便且響應速度不快。 有些你可以習慣,有些絕對糟糕,但在我看來,所有問題的原因是我們錯誤地處理了查看日誌的任務:我們嘗試創建一個 Web 介面,其中 CLI(命令列介面)效果更好。 我個人非常喜歡使用 tail、grep、awk 等,因此對我來說,處理日誌的理想介面是類似於 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 和其他 UNIX 實用程式。

履行

我假設您已經以某種方式知道如何將日誌傳遞到 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 GB RAM 無法容納的相當大的資料集。 為了上傳 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

在 Google Cloud 中大小為 1000 GB 的標準持久性磁碟(HDD)上(我選擇這個大小主要是為了速​​度更高一點,儘管所需大小的 SSD 可能會更便宜)上傳75 核心上的速度約為4 MB /秒。

  • 我必須預約我在Google工作,但我使用的是個人帳戶,本文與我在公司的工作無關

我將用這個特定的數據集製作所有插圖,因為這是我手頭上的全部。

顯示資料掃描進度

由於在 ClickHouse 中,我們將對帶有日誌的表使用完整掃描,並且此操作可能會花費大量時間,並且如果找到很少的匹配項,則可能很長時間不會產生任何結果,因此建議能夠顯示查詢的進度,直到收到結果的第一行。 為此,HTTP 介面中有一個參數可讓您在 HTTP 標頭中傳送進度: send_progress_in_http_headers=1。 不幸的是,標準 Go 庫無法讀取收到的標頭,但 ClickHouse 支援 HTTP 1.0 介面(不要與 1.1 混淆!),因此您可以打開到 ClickHouse 的原始 TCP 連接並將其發送到那裡 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

它將立即開始傳回訊息中包含子字串「something」的行,而無需等待掃描完成。

另外,如果 ClickHouse 本身在連線關閉時取消請求,那會非常方便,但這不是預設行為。 可以使用以下選項啟用自動請求取消 cancel_http_readonly_queries_on_client_close=1.

Go 中 SIGPIPE 的正確處理

當你執行命令時 some_cmd | head -n 10,具體如何命令 some_cmd 停止執行時 head 減去10行? 答案很簡單:當 head 結束,管道關閉,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指令在實務上是什麼樣子的?

如果您下載了我在文章開頭提到的 Amazon 資料集,則可以執行以下命令:

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

添加評論