Install
openclaw skills install alibabacloud-sls-queryAlibaba Cloud SLS (Simple Log Service) log query & analysis skill. Use this skill to help users write, explain, optimize, execute, or troubleshoot SLS index search, SQL analytics, and SPL scan/pipeline statements through the aliyun CLI. Triggers: "SLS 查询", "SLS 分析", "日志查询", "日志分析", "log query", "analyze sls logs", "aliyun log query".
openclaw skills install alibabacloud-sls-queryUse this skill when the user wants to:
Run aliyun version to verify if version >= 3.3.8. If not installed or outdated, follow the doc references/cli-installation-guide.md to install or update.
Before executing any CLI commands, enable AI-Mode, set User-Agent, and update plugins:
aliyun configure ai-mode enable
aliyun configure ai-mode set-user-agent --user-agent "AlibabaCloud-Agent-Skills/alibabacloud-sls-query"
aliyun plugin update
Run aliyun configure list to check if credentials configured.
If no valid profile is shown, STOP here and ask the user to run aliyun configure outside of this session.
Security rules:
aliyun configure list to check credential status| API | CLI | Action | Purpose |
|---|---|---|---|
| GetLogsV2 | get-logs-v2 | log:GetLogStoreLogs | Run query / SQL / SPL and read results |
| GetIndex | get-index | log:GetIndex | Read index config to verify prerequisites |
For the minimum and complete RAM policy JSON, see references/ram-policies.md.
Permission failure handling: If a call returns
Unauthorizedpermission error, stop and surface references/ram-policies.md to the user. Do not retry with a different account without explicit user confirmation.
Always call get-index first — the index config decides which query modes are available in Step 2.
aliyun sls get-index \
--project <project> --logstore <logstore>
Two sections in the response drive every later decision:
| Section | Meaning |
|---|---|
line | Full-text index — absence means full-text search is disabled |
keys | Field indexes — map of field → { type, doc_value, token, caseSensitive, chn, ... }. doc_value: true means statistics are enabled on that field |
If the call returns IndexConfigNotExist (HTTP 404), or the response has neither line nor keys populated, the Logstore has no index at all — stop immediately and tell the user they must create an index before any query / SQL / SPL can run.
logstore and reuse within the session.For field types, tokenization, and how get-index maps to capabilities, see references/related-apis.md and references/query-analysis.md.
The query statement takes one of the following forms:
| Priority | Mode | Statement Form | Use when | Requires |
|---|---|---|---|---|
| 1 | Index search | <index-search> | Filtering raw logs; return time-ordered and paginated logs | Full-text (line) or any field index (keys.<field>) |
| 2 | SQL | <index-search> | <SQL> | Aggregation, GROUP BY, sort, window, top-N, projection, and other analytical operations | Target field has keys.<field> with doc_value: true |
| 3 | SQL scan | <index-search> | <SQL scan> | User requested | None |
| 4 | SPL | <index-search> | <SPL> | User requested | None |
Selection rule:
GROUP BY, sorting, window analysis, top-N, or returning only the required fields/columns.For the full decision guide, see references/query-analysis.md.
|)Collect every filter that can be expressed in index-search syntax and place it before the first |. Use * if no filter applies.
* and "payment failed" and status: "500" and not path: "/healthz"
* matches all; "..." is full-text (needs full-text index).key: "value" is a field filter (needs field index).and / or / not; group with parentheses.key: * means field exists. Range (>, >=, [a, b]) works only on long / double.If the requirement can be fully answered without aggregation or row-level processing, stop here — this is already a complete index search. For full index-search syntax, see references/query-analysis.md.
status: 500 | SELECT date_trunc('minute', __time__) AS minute,
count(*) AS errors
FROM log
GROUP BY minute
ORDER BY minute
log (recommended to omit).get-index — a long / double field can be compared directly (status >= 500). Cast only when a field is indexed as text but numeric semantics are needed (try_cast to suppress errors).status: 500 and service: payment
| where try_cast(latency as BIGINT) > 1000
| extend latency_ms = try_cast(latency as BIGINT)
| project service, latency_ms, message
For SPL syntax, pipeline commands, and field-handling rules, read references/spl-guide.md.
Syntax follows regular SQL (see 3.2), with one difference: every field is varchar, so always cast() / try_cast() before numeric comparison or arithmetic. See references/query-analysis.md for scan semantics.
* | set session mode=scan; SELECT api, count(1) AS pv FROM log GROUP BY api
Generate --from / --to as Unix timestamps in seconds before building the CLI command. --from is inclusive and --to is exclusive.
Choose one of three input patterns:
YYYY-MM-DD HH:MM:SS, then parse using the machine's local timezone.1. Relative time
# recent 15 minutes
FROM=$(($(date +%s) - 900))
TO=$(date +%s)
2. Natural-language absolute time without timezone
If the user gives a date/time but no timezone, use the machine's local timezone. First normalize natural language such as 2026年3月13日12点 to 2026-03-13 12:00:00, then parse it as local time.
# Example: 2026年3月13日12点 -> 2026-03-13 12:00:00
# Linux (GNU date): local timezone
FROM=$(date -d "2026-03-13 12:00:00" +%s)
# macOS (BSD date): local timezone
FROM=$(date -j -f "%Y-%m-%d %H:%M:%S" "2026-03-13 12:00:00" +%s)
For a time range such as "2026年3月13日12点到13点", compute both endpoints the same way. For a single point-in-time request, infer a practical window from the user's intent; if unclear, ask for the range before executing.
3. Absolute time with explicit timezone
To convert a local date/time to a Unix timestamp: parse the input as UTC with date -u, then subtract the timezone's UTC offset in seconds.
Formula: unix_ts = date_utc_parse(input) − (UTC_offset_hours × 3600)
# Example: 2025-01-15 10:30:00 Beijing Time (UTC+8)
# Beijing is UTC+8, so subtract 8 × 3600 = 28800
# Linux (GNU date)
FROM=$(( $(date -u -d "2025-01-15 10:30:00" +%s) - 28800 ))
# macOS (BSD date)
FROM=$(( $(date -u -j -f "%Y-%m-%d %H:%M:%S" "2025-01-15 10:30:00" +%s) - 28800 ))
# Example: 2025-01-15 10:30:00 New York Time (UTC-5)
# New York is UTC-5, so subtract -5 × 3600 = subtract -18000 = add 18000
# Linux (GNU date)
FROM=$(( $(date -u -d "2025-01-15 10:30:00" +%s) + 18000 ))
# macOS (BSD date)
FROM=$(( $(date -u -j -f "%Y-%m-%d %H:%M:%S" "2025-01-15 10:30:00" +%s) + 18000 ))
Common UTC offsets (value to subtract):
| Timezone | UTC offset hours | Seconds to subtract |
|---|---|---|
| Beijing (UTC+8) | +8 | 28800 |
| Tokyo (UTC+9) | +9 | 32400 |
| London (UTC) | 0 | 0 |
| New York (UTC-5) | -5 | -18000 |
get-logs-v2Use aliyun sls get-logs-v2 to execute queries. Run aliyun help sls get-logs-v2 to see CLI parameter usage; read references/related-apis.md for detailed API parameter descriptions.
Required CLI flags:
--project: SLS project name--logstore: Logstore name within the project--from: Start of time range, Unix timestamp in seconds (inclusive)--to: End of time range, Unix timestamp in seconds (exclusive)--query: Statement built in Step 3Pagination works differently depending on whether the statement has a |:
--offset / --linealiyun sls get-logs-v2 \
--project my-project --logstore my-logstore \
--from 1740000000 --to 1740003600 \
--query '* and "payment failed" and status: "500"' \
--line 100 --offset 0 --reverse true
--line is page size (1–100, required); --offset is the start row (optional, default 0).--reverse true returns newest first; default false is oldest first.LIMIT inside the statementaliyun sls get-logs-v2 \
--project my-project --logstore my-logstore \
--from 1740000000 --to 1740003600 \
--query 'status: "500" | SELECT request_uri, count(*) AS cnt FROM log GROUP BY request_uri ORDER BY cnt DESC LIMIT 20'
LIMIT count — raise the cap (e.g., LIMIT 500 returns up to 500 rows)LIMIT offset, count — paginate (e.g., LIMIT 20, 20 for rows 21–40; LIMIT 40, 20 for rows 41–60). Max offset+count is 1000000.LIMIT count OFFSET offset syntax — it is not supported. Always use LIMIT offset, count.ORDER BY <field> DESC/ASC to sort.Result completeness check: every response contains meta.progress. If it is Incomplete, re-issue the same request until it returns Complete.
get-logs-v2 returns:
{
"meta": { "progress": "Complete", "count": 10, ... },
"data": [ { "field1": "value1", ... }, ... ]
}
| Field | Meaning |
|---|---|
meta.progress | Complete or Incomplete (see Step 5) |
meta.count | Number of rows returned |
data | Array of log entries or aggregation rows; may contain __time__ (Unix seconds, string) |
Use jq (preferred) or --cli-query (JMESPath) to extract the fields the user needs:
| Extract | jq | --cli-query (JMESPath) |
|---|---|---|
| Data rows | | jq '.data' | --cli-query 'data' |
| Progress | | jq '.meta.progress' | --cli-query 'meta.progress' |
| Row count | | jq '.meta.count' | --cli-query 'meta.count' |
| Specific fields | | jq '.data[] | {LogStore, read_mb}' | --cli-query 'data[].{LogStore: LogStore, read_mb: read_mb}' |
CLI command — always show the full, copy-paste-ready aliyun sls get-logs-v2 ... command. Redact any AK/SK. If the query was not executed (write / explain scenario), present the command the user should run.
Results — when a query was executed, use Step 6 to extract data and format according to the user's request (table, list, summary, etc.). Append one sentence explaining the query mode choice.
Whether operations succeed or fail, you MUST disable AI-Mode before ending the session:
aliyun configure ai-mode disable
SELECT to project them rather than fetching full raw logs — this reduces network overhead. Requires doc_value: true on the target fields (confirmed in Step 1).__time__ filters — pass time range via --from / --to.get-logs; always use get-logs-v2.When the user reports "no data", "wrong result", or a CLI error, walk through the checklist in this exact order:
--from/--to? Milliseconds instead of seconds? Recent writes still indexing?keys?text field? SQL on a field without doc_value?* in fuzzy match? SPL string escaping?meta.progress = Incomplete, caller did not retry (see Step 5).For the full catalog of failure modes and error codes, see references/troubleshooting.md and the Common Errors table in references/related-apis.md.
| Document | Description |
|---|---|
| references/query-analysis.md | Mode decision, index-search / SQL rules, scan semantics |
| references/spl-guide.md | SPL pipeline syntax, common commands, field handling |
| references/functions-guide.md | Function categories, SQL/SPL differences, templates |
| references/troubleshooting.md | "No data / wrong result / error" playbook |
| references/related-apis.md | GetLogsV2 and GetIndex API & CLI reference |
| references/ram-policies.md | Minimum and complete RAM policies |
| references/cli-installation-guide.md | Aliyun CLI install, auth modes, profiles |
| references/regions.md | Region / endpoint configuration, internal endpoint, ProjectNotExist troubleshooting |
| references/acceptance-criteria.md | CLI invocation acceptance tests |
references/query_analysis/*.yaml · references/spl/*.yaml · references/functions/*.yaml | Source-of-truth YAMLs bundled with this skill |