CLS的探索:Python如何讓日誌免費雲化
- 2021 年 5 月 18 日
- 筆記
- CLS, protobuf, Cloud Log Service
前言
日誌服務(Cloud Log Service,CLS)是騰訊雲提供的一站式日誌服務平台,提供了從日誌採集、日誌存儲到日誌檢索,圖表分析、監控告警、日誌投遞等多項服務,協助用戶通過日誌來解決業務運維、服務監控、日誌審計等場景問題。
簡言之就是CLS提供了日誌的雲化存儲,並提供了查詢、分析、監控,告警等功能。所以今天就抱著好奇之心,來探索一下使用python如何將本機日誌寫入到CLS上。
環境配置
官方文檔提供了詳細的使用步驟使用步驟,文檔鏈接如下://cloud.tencent.com/document/product/614/34340
1. 服務開通
點擊//cloud.tencent.com/product/cls進入頁面,可以點擊立即使用開通服務;

當然也可以點擊活動公告來查看免費的使用額度:

可以看出,免費額度流量額度是5GB/日,活動截止於2021年底。
開通服務後,進入clk服務頁面。可以看到,提供了多種日誌的接入方案。

2. 創建日誌集和日誌主題
日誌集(Logset)是日誌服務的項目管理單元,用於區分不同項目的日誌。日誌主題(Topic)是日誌服務的基本管理單元,用來存儲日誌文件。一個日誌集可以包含多個日誌主題。
點擊//console.cloud.tencent.com/cls/overviewCLS配置頁面。
點擊側欄日誌主題 ,點擊創建日誌主題。

可能是文檔過舊,官方文檔寫的是先要創建日誌集,但是沒找到這個按鈕。其實在第一次創建時主題時輸入一個日誌集,就會自動創建。
創建好的日誌主題如下,這裡需要的是主題ID,以為寫入時通過ID來將日誌寫到這個topic。

3. 創建機器組
CLS使用機器組來統一管理一組日誌源機器。。同時我也理解成白名單,只有這些機器能訪問CLS服務。

Python日誌寫入CLS
在剛開始CLS的概覽頁面,可以看到CLS提供了多種快速接入方案,很多需要安裝Loglistener來採集日誌,這裡使用Python利用API寫入接入方案來將日誌寫入,無需安裝。
點擊每種接入方案都會進入相應的開發文檔,這裡我點擊API寫入進入開發文檔。
官方提供了API寫入規範:
POST /structuredlog?topic_id=xxxxxxxx-xxxx-xxxx-xxxx HTTP/1.1
Host: <Region>.cls.tencentyun.com
Authorization: <AuthorizationString>
Content-Type: application/x-protobuf
x-cls-compress-type:lz4
<LogGroupList 的 PB 格式打包內容>
從上面可以看出有兩個參數,一個是topic_id,即日誌主題id;一個是LogGroupList,即日誌傳輸協議內容。這裡PB指的是使用protobuf進行序列化,所以必須先安裝protobuf。
安裝protobuf
protobuf是一種二進位的序列化格式,相對於json來說體積更小,傳輸更快。安裝protobuf的目的主要用來將proto文件編譯成python、c、Java可調用的介面。
# 如果gcc版本較低,需要升級gcc
wget //main.qcloudimg.com/raw/d7810aaf8b3073fbbc9d4049c21532aa/protobuf-2.6.1.tar.gz
tar -zxvf protobuf-2.6.1.tar.gz -C /usr/local/ && cd /usr/local/protobuf-2.6.1
./configure
make && make install
# 可以在/etc/profile或者~/.bash_profile末尾設置永久有效
export PATH=$PATH:/usr/local/protobuf-2.6.1/bin
使用下面命令查看是否安裝成功。
protoc --version
構建python可調用的PB
創建cls.proto文件,定義序列化結構:
package cls;
message Log
{
message Content
{
required string key = 1; // 每組欄位的 key
required string value = 2; // 每組欄位的 value
}
required int64 time = 1; // 時間戳,UNIX時間格式
repeated Content contents = 2; // 一條日誌里的多個kv組合
}
message LogTag
{
required string key = 1;
required string value = 2;
}
message LogGroup
{
repeated Log logs = 1; // 多條日誌合成的日誌數組
optional string contextFlow = 2; // 目前暫無效用
optional string filename = 3; // 日誌文件名
optional string source = 4; // 日誌來源,一般使用機器IP
repeated LogTag logTags = 5;
}
message LogGroupList
{
repeated LogGroup logGroupList = 1; // 日誌組列表
}
只用下面命令將proto文件轉換為python可調用的介面。
protoc cls.proto --python_out=./
執行完後,在此目錄下生成cls_pb2.py。
python程式碼開發
程式碼的開發主要分為三個部分:Protobuf結構構造、Authorization加密構造和請求上傳日誌。前兩個部分細節太多,尤其是Authorization構造涉及sha1加密、hmac-sha1簽名以及四個加密參數的構造。:
1. Protobuf結構構造
import cls_pb2 as cls
import time
import requests
from hashlib import sha1
import hmac
# 構建protoBuf日誌內容
LogLogGroupList = cls.LogGroupList()
LogGroup = LogLogGroupList.logGroupList.add()
LogGroup.contextFlow = "1"
LogGroup.filename = "python.log"
LogGroup.source = "localhost"
LogTag = LogGroup.logTags.add()
LogTag.key = "key"
LogTag.value = "value"
Log = LogGroup.logs.add()
Log.time = int(round(time.time() * 1000000))
Content = Log.contents.add()
Content.key = "Hello"
Content.value = "World"
print(LogLogGroupList)
# 序列化
LogLogGroupList = LogLogGroupList.SerializeToString()
2. Authorization加密構造
查看文檔://cloud.tencent.com/document/product/614/12445,裡面有詳細的參數生成步驟和樣例。
這部分的程式碼開發絕對考驗個人的耐心和細心,適合在夜深人靜自己搞。
# 公共參數部分
secretId = '替換成你的secretId'
secretKey = '替換成你的secretKey'
region = 'ap-nanjing'
host = f'{region}.cls.tencentyun.com'
start = int(time.time())
end = start + 1000
uri = 'structuredlog'
method = 'post'
params = 'topic'
# 構建HttpRequestInfo
HttpRequestInfo = f'{method}\n' + f'/{uri}\n' + '\n\n'
sha1_info = sha1()
sha1_info.update(HttpRequestInfo.encode('utf-8'))
print(sha1_info.hexdigest())
# 根據HttpRequestInfo構建StringToSign
StringToSign = 'sha1\n' + f'{start};{end}\n' + sha1_info.hexdigest() + '\n'
key = secretKey.encode('utf-8')
value = f'{start};{end}'.encode('utf-8')
SignKey = hmac.new(key, value, 'sha1')
print(SignKey.hexdigest())
# 根據StringToSign構建Signature
key = SignKey.hexdigest().encode('utf-8')
value = StringToSign.encode('utf-8')
Signature = hmac.new(key, value, 'sha1').hexdigest()
print(Signature)
# 構建Authorization
Authorization = f'q-sign-algorithm=sha1&q-ak={secretId}&q-sign-time={start};{end}&q-key-time={start};{end}&q-header-list=&q-url-param-list=&q-signature={Signature}'
這一塊是讓我感覺最難的,裡面的坑太多,一個參數套一個參數,容易讓人云里霧裡,所以大部分時間都花在了測試參數生成這部分。

如圖,一直提示我簽名計算錯誤,原因總結如下:1.參數拼接不對;2.hmac的kv弄反。
本來我也在請求頭裡添加了lz4壓縮格式,但是運行發現程式碼中未實現lz4的壓縮,所以報了以下錯誤。

最後捨棄了lz4請求頭,壓縮功能也沒有實現。有興趣的可以搞一下。
3. 上傳日誌
其實就是構造一個post請求,將日誌序列化成protobuf格式上傳到伺服器。
# 發起請求
url = f'//{host}/{uri}?topic_id=717eba7d-85bb-4cd5-9c68-dfaa9f672bc6'
headers = {'Authorization': Authorization, 'Host': host, 'Content-Type': 'application/x-protobuf'}
response = requests.post(url, headers=headers, data=LogLogGroupList)
print(response.status_code, response.text)
print(LogLogGroupList)
運行測試
python3運行程式:

列印了日誌的protobuf結構資訊、二進位數據,以及加密參數和請求狀態碼。

接著進入CLS頁面查看,日誌已經寫入。
結語
跟著文檔從學習CLS、python開發到收集素材、整理成文章差不多用了五、六個小時,下班就在搞,寫到這的時候已經凌晨一點了,本來還想用Java寫一版,但是實在是肝不動了。

希望這篇文章能夠幫助你了解CLS,期待下一次相遇。
95後小程式設計師,寫的都是日常工作中的親身實踐,置身於初學者的角度從0寫到1,詳細且認真。文章會在公眾號 [入門到放棄之路] 首發,期待你的關注。


