精通日誌查詢: 如何翻頁獲取日誌和計算結果

日誌服務提供一站式的日誌採集、存儲、查詢、計算功能。互動式的日誌採集體驗,釋放用戶的運維壓力,解放用戶的雙手; 互動式的查詢分析體驗,讓用戶自由的構建數據模型、探索式分析挖掘數據深層。

用戶使用日誌服務的查詢分析能力,不僅可以在控制台互動式查詢,也可以使用SDK,在程序中使用查詢分析。 當計算結果比較大時,怎麼把全量結果讀取到本地,是一個比較比較頭疼的問題。幸好,日誌服務提供了翻頁的功能,不僅可以翻頁讀取原始日誌內容,也可以把SQL的計算結果翻頁讀取到本地。開發者可以通過日誌服務提供的SDK,或者Cli,通過讀數據介面翻頁讀取日誌。

查詢和分析使用不同的分頁方式

日誌服務提供一個統一的查詢日誌入口:GetLogstoreLogs,既可以根據關鍵字查詢日誌原始內容,也可以提交SQL計算,獲取計算結果。

  • 使用關鍵字查詢,獲取原始內容,可以通過API中的offset和lines參數來翻頁獲取所有內容。
  • 使用SQL計算,獲取SQL的計算結果,使用SQL的limit語法來達到翻頁的目的。

查詢翻頁使用案例

在GetLogStoreLogs api中,包含offset和lines兩個參數

  • offset : 用於指定從第一行開始讀取日誌
  • lines : 用於指定當前的請求讀取多少行,該參數最大100行,如果設置該參數大於100行,則仍然返回100行。

在翻頁讀取時,不停的增大offset,知道讀取到某個offset後,獲取的結果行數為0,並且結果的progress為complete狀態,則認為讀取到了全部數據,可以結束了。

翻頁代碼樣例

翻頁的偽代碼:

offset = 0 // 從第0行開始讀取
lines = 100 //每次讀取100行
query = "status:200" //查詢status欄位包含200的所有日誌
while True:
response = get_logstore_logs(query, offset, lines) // 執行讀取請求
process (response) //調用自定義邏輯,處理返回的結果
如果 response.get_count() == 0 && response.is_complete()
則讀取結束,跳出當前循環
否則
offset += 100 offset增加100,讀取下一個100行

python 翻頁讀取樣例

更詳細案例參考文檔:

endpoint = # 選擇與上面步驟創建Project所屬區域匹配的Endpoint
accessKeyId = # 使用您的阿里雲訪問密鑰AccessKeyId
accessKey = # 使用您的阿里雲訪問密鑰AccessKeySecret
project = # 上面步驟創建的項目名稱
logstore = # 上面步驟創建的日誌庫名稱
client = LogClient(endpoint, accessKeyId, accessKey)
topic = ""
query = "index"
From = int(time.time()) - 600
To = int(time.time())
log_line = 100
offset = 0
while True:
res4 = None
for retry_time in range(0, 3):
req4 = GetLogsRequest(project, logstore, From, To, topic, query, log_line, offset, False)
res4 = client.get_logs(req4)
if res4 is not None and res4.is_completed():
break
time.sleep(1)
offset += 100
if res4.is_completed() && res4.get_count() == 0:
break;
if res4 is not None:
res4.log_print() # 這裡處理結果

Java 翻頁讀取樣例

更詳細的案例參考文檔

int log_offset = 0;
int log_line = 100;//log_line 最大值為100,每次獲取100行數據。若需要讀取更多數據,請使用offset翻頁。offset和lines只對關鍵字查詢有效,若使用SQL查詢,則無效。在SQL查詢中返回更多數據,請使用limit語法。
while (true) {
GetLogsResponse res4 = null;
// 對於每個 log offset,一次讀取 10 行 log,如果讀取失敗,最多重複讀取 3 次。
for (int retry_time = 0; retry_time < 3; retry_time++) {
GetLogsRequest req4 = new GetLogsRequest(project, logstore, from, to, topic, query, log_offset,
log_line, false);
res4 = client.GetLogs(req4);

if (res4 != null && res4.IsCompleted()) {
break;
}
Thread.sleep(200);
}
System.out.println("Read log count:" + String.valueOf(res4.GetCount()));
log_offset += log_line;
if (res4.IsCompleted() && res4.GetCount() == 0) {
break;
}

}

SQL分析結果翻頁讀取

在SQL分析中,GetLogStoreLogs API 參數中的offset 和lines是無效的,填寫。也就是說,如果按照上文翻頁讀取原始內容的方式,遍歷offset翻頁,那麼每次SQL執行的結果都是一樣的。理論上,我們可以在一次調用中,獲取全部的計算結果,但是如果結果集太大,可能會產生以下問題:

  • 網路上傳輸大量數據延時比較高。
  • 客戶端的內存要保存大量的結果,供進一步處理。

為了解決SQL翻頁的問題,我們提供了標準SQL的limit翻頁語法

limit Offset, Line

  • Offset表示從第幾行開始讀取結果
  • Line表示讀取多少行,Line沒有大小限制;但是如果一次讀取太多,會影響網路延時和客戶端的處理。

一個典型案例,假如以下SQL共產生2000條日誌

* | select count(1) , url group by url

那麼可以翻頁,每次讀取500行,共4次讀取完成:

* | select count(1) , url group by url limit 0, 500
* | select count(1) , url group by url limit 500, 500
* | select count(1) , url group by url limit 1000, 500
* | select count(1) , url group by url limit 1500, 500

SQL翻頁樣例

在程序中,SQL翻頁的偽代碼這樣寫:

offset = 0 // 從第0行開始讀取
lines = 500 //每次讀取500行
query = "* | select count(1) , url group by url limit "
while True:
real_query = query + offset + "," + lines
response = get_logstore_logs(real_query) // 執行讀取請求
process (response) //調用自定義邏輯,處理返回的結果
如果 response.get_count() == 0
則讀取結束,跳出當前循環
否則
offset += 500 offset增加100,讀取下一個500行

Python程序樣例:

endpoint = # 選擇與上面步驟創建Project所屬區域匹配的Endpoint
accessKeyId = # 使用您的阿里雲訪問密鑰AccessKeyId
accessKey = # 使用您的阿里雲訪問密鑰AccessKeySecret
project = # 上面步驟創建的項目名稱
logstore = # 上面步驟創建的日誌庫名稱
client = LogClient(endpoint, accessKeyId, accessKey)
topic = ""
origin_query = "* | select count(1) , url group by url limit "
From = int(time.time()) - 600
To = int(time.time())
log_line = 100
offset = 0
while True:
res4 = None
query = origin_query + str(offset) + " , " + str(log_line)
for retry_time in range(0, 3):
req4 = GetLogsRequest(project, logstore, From, To, topic, query)
res4 = client.get_logs(req4)
if res4 is not None and res4.is_completed():
break
time.sleep(1)
offset += 100
if res4.is_completed() && res4.get_count() == 0:
break;
if res4 is not None:
res4.log_print() # 這裡處理結果

Java程序樣例:

int log_offset = 0;
int log_line = 500;
String origin_query = "* | select count(1) , url group by url limit "
while (true) {
GetLogsResponse res4 = null;
// 對於每個 log offset,一次讀取 500 行 log,如果讀取失敗,最多重複讀取 3 次。
query = origin_query + log_offset + "," + log_line;
for (int retry_time = 0; retry_time < 3; retry_time++) {
GetLogsRequest req4 = new GetLogsRequest(project, logstore, from, to, topic, query);
res4 = client.GetLogs(req4);

if (res4 != null && res4.IsCompleted()) {
break;
}
Thread.sleep(200);
}
System.out.println("Read log count:" + String.valueOf(res4.GetCount()));
log_offset += log_line;
if (res4.GetCount() == 0) {
break;
}

}

本文作者:雲雷

原文鏈接

更多技術乾貨敬請關注云棲社區知乎機構號:阿里云云棲社區 - 知乎

本文為雲棲社區原創內容,未經允許不得轉載。


推薦閱讀:
相关文章