tencentcloud-cls
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTencent Cloud CLS (Log Service) — Search & Analysis
腾讯云CLS(日志服务)——搜索与分析
Search and run CQL / SQL analytics over Tencent Cloud CLS log topics.
Setup: See tencentcloud authentication. The SDK reads/TENCENTCLOUD_SECRET_ID/TENCENTCLOUD_SECRET_KEYfrom the environment.TENCENTCLOUD_REGIONCompanion skill: Usefor alarm policy / notice group / shield management. This skill is only about searching log content.tencentcloud-cls-alarm
搜索并对腾讯云CLS日志主题执行CQL/SQL分析。
设置说明: 请查看腾讯云认证。SDK会从环境变量中读取、TENCENTCLOUD_SECRET_ID和TENCENTCLOUD_SECRET_KEY。TENCENTCLOUD_REGION配套技能: 使用进行告警策略、通知组、屏蔽规则管理。本技能仅专注于日志内容搜索。tencentcloud-cls-alarm
CLI (preferred)
CLI(推荐方式)
The skill ships — a self-contained CLI for the most common operations.
scripts/cls.pybash
CLS=$SKILL_DIR/scripts/cls.py
python3 $CLS topics # list topics
python3 $CLS search --topic <topic-id> --query 'level:ERROR' --time 1h
python3 $CLS search --topic <topic-id> --trace-id <uuid>
python3 $CLS search --topic <topic-id> --time 1d \
--query '* | SELECT api_name, count(*) AS cnt GROUP BY api_name ORDER BY cnt DESC LIMIT 20' \
--format json--time30m / 1h / 6h / 1d / 7d--query--lucene| SELECT ... GROUP BY ...For anything beyond what the CLI exposes (custom field projections, raw paginated walks, -based tailing) drop down to the SDK calls below.
Context本技能附带了——一个独立的CLI工具,支持最常用的操作。
scripts/cls.pybash
CLS=$SKILL_DIR/scripts/cls.py
python3 $CLS topics # 列出所有日志主题
python3 $CLS search --topic <topic-id> --query 'level:ERROR' --time 1h
python3 $CLS search --topic <topic-id> --trace-id <uuid>
python3 $CLS search --topic <topic-id> --time 1d \
--query '* | SELECT api_name, count(*) AS cnt GROUP BY api_name ORDER BY cnt DESC LIMIT 20' \
--format json--time30m / 1h / 6h / 1d / 7d--query--lucene| SELECT ... GROUP BY ...如果需要CLI未覆盖的功能(自定义字段投影、原始分页遍历、基于的日志实时尾追),可使用下方的SDK调用方式。
ContextWhen to Use
适用场景
- Find recent errors / 5xx responses for a service
- Look up a single request by trace ID across multiple topics
- Run CQL filters ()
status_code:>=500 AND service:"openai" - Run SQL analytics ()
SELECT api_name, COUNT(*) GROUP BY api_name - Chain trace logs to reconstruct a request lifecycle
- Extract specific fields for billing / audit reports
- 查找服务近期的错误/5xx响应
- 通过Trace ID在多个主题中查询单个请求
- 执行CQL过滤(如)
status_code:>=500 AND service:"openai" - 执行SQL分析(如)
SELECT api_name, COUNT(*) GROUP BY api_name - 串联追踪日志以重构请求生命周期
- 提取特定字段用于账单/审计报告
Dependencies
依赖安装
bash
pip install tencentcloud-sdk-pythonbash
pip install tencentcloud-sdk-pythonQuick start
快速开始
python
import os
import json
from tencentcloud.common import credential
from tencentcloud.cls.v20201016 import cls_client, models
cred = credential.EnvironmentVariableCredential().get_credential()
client = cls_client.ClsClient(cred, os.environ["TENCENTCLOUD_REGION"])python
import os
import json
from tencentcloud.common import credential
from tencentcloud.cls.v20201016 import cls_client, models
cred = credential.EnvironmentVariableCredential().get_credential()
client = cls_client.ClsClient(cred, os.environ["TENCENTCLOUD_REGION"])Workflows
工作流示例
Discover topics
发现日志主题
python
req = models.DescribeTopicsRequest()
resp = client.DescribeTopics(req)
for t in resp.Topics:
print(t.TopicId, t.TopicName, t.LogsetId)Tip: ask the user for the topic ID up front. Topic IDs look likeand aren't guessable from a service name.751a7350-dc5d-41c3-a6ca-c178bae05807
python
req = models.DescribeTopicsRequest()
resp = client.DescribeTopics(req)
for t in resp.Topics:
print(t.TopicId, t.TopicName, t.LogsetId)提示:建议先向用户获取主题ID。主题ID格式类似,无法通过服务名称猜测。751a7350-dc5d-41c3-a6ca-c178bae05807
Search logs (CQL)
搜索日志(CQL语法)
python
import time
req = models.SearchLogRequest()
req.TopicId = "<topic-id>"
req.From = int((time.time() - 3600) * 1000) # 1 hour ago, ms epoch
req.To = int(time.time() * 1000)
req.Query = 'status_code:>=500 AND service:"openai"'
req.Limit = 100
req.Sort = "desc"
req.SyntaxRule = 1 # 1 = CQL, 0 = Lucene
resp = client.SearchLog(req)
for line in resp.Results:
fields = {f.Key: f.Value for f in line.LogJson and []} # see below
print(line.Time, line.PkgLogId, fields.get("status_code"), fields.get("api_name"))CLS hands youwithResultsas a JSON string per record. Decode withLogJsonto get a flat dict of all the indexed fields the topic stores.json.loads(line.LogJson)
python
import time
req = models.SearchLogRequest()
req.TopicId = "<topic-id>"
req.From = int((time.time() - 3600) * 1000) # 1小时前,毫秒级时间戳
req.To = int(time.time() * 1000)
req.Query = 'status_code:>=500 AND service:"openai"'
req.Limit = 100
req.Sort = "desc"
req.SyntaxRule = 1 # 1 = CQL语法,0 = Lucene语法
resp = client.SearchLog(req)
for line in resp.Results:
fields = {f.Key: f.Value for f in line.LogJson and []} # 见下方说明
print(line.Time, line.PkgLogId, fields.get("status_code"), fields.get("api_name"))CLS返回的中,每条记录的Results是一个JSON字符串。使用LogJson解码后可得到该主题存储的所有索引字段的扁平字典。json.loads(line.LogJson)
Look up a trace ID across multiple topics
通过Trace ID跨多个主题查询
python
TRACE_ID = "34341776-0835-422a-956d-ac8d5b404db1"
TOPICS = {
"trace": "<trace-topic-id>",
"api-usages": "<api-usages-topic-id>",
}
for label, topic_id in TOPICS.items():
req = models.SearchLogRequest()
req.TopicId = topic_id
req.From = int((time.time() - 86400) * 1000)
req.To = int(time.time() * 1000)
req.Query = f'trace_id:"{TRACE_ID}"'
req.Limit = 100
req.SyntaxRule = 1
resp = client.SearchLog(req)
print(f"--- {label}: {len(resp.Results)} records ---")
for line in resp.Results:
print(line.Time, line.LogJson)python
TRACE_ID = "34341776-0835-422a-956d-ac8d5b404db1"
TOPICS = {
"trace": "<trace-topic-id>",
"api-usages": "<api-usages-topic-id>",
}
for label, topic_id in TOPICS.items():
req = models.SearchLogRequest()
req.TopicId = topic_id
req.From = int((time.time() - 86400) * 1000)
req.To = int(time.time() * 1000)
req.Query = f'trace_id:"{TRACE_ID}"'
req.Limit = 100
req.SyntaxRule = 1
resp = client.SearchLog(req)
print(f"--- {label}: {len(resp.Results)} 条记录 ---")
for line in resp.Results:
print(line.Time, line.LogJson)SQL analytics
SQL分析
CLS supports a SQL-on-logs subset for aggregation. Append to a CQL filter:
| <SQL>python
req.Query = '* | SELECT api_name, count(*) AS cnt GROUP BY api_name ORDER BY cnt DESC LIMIT 20'
req.SyntaxRule = 1
resp = client.SearchLog(req)CLS支持日志SQL子集用于聚合分析。在CQL过滤条件后追加即可:
| <SQL>python
req.Query = '* | SELECT api_name, count(*) AS cnt GROUP BY api_name ORDER BY cnt DESC LIMIT 20'
req.SyntaxRule = 1
resp = client.SearchLog(req)When the query has a |
, results land in resp.Analysis (rows of column→value)
|当查询包含|
时,结果会存入resp.AnalysisResults(每行是列→值的映射)
|for row in resp.AnalysisResults or []:
print(row)
undefinedfor row in resp.AnalysisResults or []:
print(row)
undefinedTail recent logs
实时尾追日志
python
undefinedpython
undefinedPoll every 5s for new lines after the last cursor
每5秒轮询一次,获取上次游标之后的新日志
last_cursor = None
while True:
req = models.SearchLogRequest()
req.TopicId = topic_id
req.From = int((time.time() - 30) * 1000)
req.To = int(time.time() * 1000)
req.Query = 'level:ERROR'
req.Limit = 100
req.Sort = "asc"
req.SyntaxRule = 1
if last_cursor:
req.Context = last_cursor
resp = client.SearchLog(req)
for line in resp.Results:
print(line.Time, line.LogJson)
last_cursor = resp.Context
time.sleep(5)
undefinedlast_cursor = None
while True:
req = models.SearchLogRequest()
req.TopicId = topic_id
req.From = int((time.time() - 30) * 1000)
req.To = int(time.time() * 1000)
req.Query = 'level:ERROR'
req.Limit = 100
req.Sort = "asc"
req.SyntaxRule = 1
if last_cursor:
req.Context = last_cursor
resp = client.SearchLog(req)
for line in resp.Results:
print(line.Time, line.LogJson)
last_cursor = resp.Context
time.sleep(5)
undefinedCQL cheatsheet
CQL语法速查
| Pattern | Meaning |
|---|---|
| exact match |
| range |
| range with bounds |
| quoted phrase (use for values containing spaces) |
| negation |
| conjunction |
| grouping |
| `* | SELECT ... GROUP BY ...` |
| 语法模式 | 含义 |
|---|---|
| 精确匹配 |
| 范围匹配 |
| 带边界的范围匹配 |
| 带引号的短语匹配(适用于包含空格的值) |
| 否定匹配 |
| 逻辑与匹配 |
| 分组逻辑或匹配 |
| `* | SELECT ... GROUP BY ...` |
Pagination
分页处理
CLS returns up to 1000 records per call. For larger result sets, iterate with :
Contextpython
all_records = []
context = None
while True:
req = models.SearchLogRequest()
req.TopicId = topic_id
req.From = ...
req.To = ...
req.Query = '...'
req.Limit = 1000
req.SyntaxRule = 1
if context:
req.Context = context
resp = client.SearchLog(req)
all_records.extend(resp.Results)
context = resp.Context
if not context or len(resp.Results) < 1000:
breakCLS每次调用最多返回1000条记录。对于更大的结果集,可使用参数进行迭代:
Contextpython
all_records = []
context = None
while True:
req = models.SearchLogRequest()
req.TopicId = topic_id
req.From = ...
req.To = ...
req.Query = '...'
req.Limit = 1000
req.SyntaxRule = 1
if context:
req.Context = context
resp = client.SearchLog(req)
all_records.extend(resp.Results)
context = resp.Context
if not context or len(resp.Results) < 1000:
breakError patterns
错误排查
| Symptom | Likely cause |
|---|---|
| Quote phrases that contain |
| Concurrent |
| CLS service is suspended for billing — check the console |
Empty | Time range is wrong ( |
| 症状 | 可能原因 |
|---|---|
| 对包含 |
| 并发 |
| CLS服务因欠费暂停——请查看控制台 |
控制台可见日志但 | 时间范围错误( |
Console links
控制台链接
- CLS console: https://console.cloud.tencent.com/cls/topic
- CQL syntax: https://www.tencentcloud.com/document/product/614/47044
- SQL analytics syntax: https://www.tencentcloud.com/document/product/614/58978