精通日志查詢: 如何翻頁擷取日志和計算結果
日志服務提供一站式的日志采集、存儲、查詢、計算功能。互動式的日志采集體驗,釋放使用者的運維壓力,解放使用者的雙手; 互動式的查詢分析體驗,讓使用者自由的建構資料模型、探索式分析挖掘資料深層。
使用者使用日志服務的查詢分析能力,不僅可以在控制台互動式查詢,也可以使用SDK,在程式中使用查詢分析。 當計算結果比較大時,怎麼把全量結果讀取到本地,是一個比較比較頭疼的問題。幸好,日志服務提供了翻頁的功能,不僅可以翻頁讀取原始日志内容,也可以把SQL的計算結果翻頁讀取到本地。開發者可以通過日志服務提供的SDK,或者Cli,通過讀資料接口翻頁讀取日志。
查詢和分析使用不同的分頁方式
日志服務提供一個統一的查詢日志入口:GetLogstoreLogs,既可以根據關鍵字查詢日志原始内容,也可以送出SQL計算,擷取計算結果。
查詢翻頁使用案例
在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;
}
}