关于 eventstream-consumption-cli
为 Fabric 的实时 Eventstream 提供命令行操作指引,面向需要检查和排错事件流的操作者。涵盖发现资源、检查拓扑、连接信息获取与配置验证。
主要功能
- 01列出和查找 Eventstream
- 02解码定义并检查拓扑
- 03检查运行状态与连接信息
- 04验证源、目标和事件流配置
适用场景
- 01盘点工作区中的 Eventstream
- 02追踪事件流的源、算子和目标
- 03检查源与目标配置是否有效
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ microsoft/ skills-for-fabric --skill eventstream-consumption-cli安装后在 Claude Code 中输入/eventstream-consumption-cli确认已加载。
详细介绍
更新检查 — 每个会话仅检查一次(必须) 首次在会话中使用此技能时,继续操作前先运行 check-updates 技能。
- GitHub Copilot CLI / VS Code:调用
check-updates技能。- Claude Code / Cowork / Cursor / Windsurf / Codex:比较本地与远程的 package.json 版本。
- 如果本会话中已执行过检查,则跳过。
重要说明
- 若要根据工作区名称查找工作区详情(包括其 ID):列出所有工作区,然后使用 JMESPath 进行筛选
- 若要根据工作区 ID、项目类型和项目名称查找项目详情(包括其 ID):列出该工作区中此类型的所有项目,然后使用 JMESPath 进行筛选
- Eventstream ≠ Eventhouse。Eventstream 是实时事件摄取和路由管道。对于 KQL 查询,请使用
eventhouse-consumption-cli。
Eventstream 消耗 — CLI 技能
目录
列出 Eventstream
列出工作区中的所有 Eventstream
az rest --method GET \
--url "https://api.fabric.microsoft.com/v1/workspaces/${WORKSPACE_ID}/eventstreams" \
--resource "https://api.fabric.microsoft.com"
返回 Eventstream 项目数组。使用 JMESPath 按名称筛选:
az rest --method GET \
--url "https://api.fabric.microsoft.com/v1/workspaces/${WORKSPACE_ID}/eventstreams" \
--resource "https://api.fabric.microsoft.com" \
--query "value[?displayName=='my-eventstream']"
获取 Eventstream 详细信息
az rest --method GET \
--url "https://api.fabric.microsoft.com/v1/workspaces/${WORKSPACE_ID}/eventstreams/${EVENTSTREAM_ID}" \
--resource "https://api.fabric.microsoft.com"
检查 Eventstream 拓扑
提示:拓扑 API(
GET .../eventstreams/{id}/topology)无需进行 base64 解码,即可返回运行时状态、错误信息和节点 ID。对于运行状况检查、连接信息检索等运行检查,请优先使用此 API。需要完整的创作时图结构以修改拓扑时,请使用下方的POST .../getDefinition。
获取 Eventstream 定义并对其解码,以检查完整的图拓扑。
步骤 1:获取定义
API 说明:Eventstream 定义 API 使用
POST .../getDefinition,而不是GET .../definition。这遵循 Fabric Items 定义模式。请参阅官方文档。
az rest --method POST \
--url "https://api.fabric.microsoft.com/v1/workspaces/${WORKSPACE_ID}/eventstreams/${EVENTSTREAM_ID}/getDefinition" \
--resource "https://api.fabric.microsoft.com" \
--body '{}'
步骤 2:解码拓扑
提取 eventstream.json 部分的 payload 字段并进行 base64 解码:
# Using jq + base64 (Linux; on macOS use base64 -D instead of -d)
az rest --method POST \
--url "https://api.fabric.microsoft.com/v1/workspaces/${WORKSPACE_ID}/eventstreams/${EVENTSTREAM_ID}/getDefinition" \
--resource "https://api.fabric.microsoft.com" \
--body '{}' \
| jq -r '.definition.parts[] | select(.path=="eventstream.json") | .payload' \
| base64 -d | jq .
# PowerShell (Windows)
$def = az rest --method POST `
--url "https://api.fabric.microsoft.com/v1/workspaces/$WORKSPACE_ID/eventstreams/$EVENTSTREAM_ID/getDefinition" `
--resource "https://api.fabric.microsoft.com" `
--body '{}' | ConvertFrom-Json
$payload = ($def.definition.parts | Where-Object { $_.path -eq 'eventstream.json' }).payload
[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($payload)) | ConvertFrom-Json | ConvertTo-Json -Depth 10
步骤 3:汇总拓扑
解码后,统计并列出每种节点类型:
| 指标 | 解码后 JSON 中的路径 |
|---|---|
| 源 | .sources[] | .name, .type |
| 目标 | .destinations[] | .name, .type |
| 运算符 | .operators[] | .name, .type |
| 流 | .streams[] | .name, .type |
获取自定义终结点连接字符串
POST .../getDefinition 终结点会为自定义终结点源返回空属性。要检索 Kafka/Event Hub 连接信息,请使用拓扑 API 的 /connection 终结点。
重要提示:此终结点需要
Eventstream.ReadWrite.All权限范围(不仅仅是 Read)。
步骤 1:获取拓扑以查找源 ID
az rest --method GET \
--url "https://api.fabric.microsoft.com/v1/workspaces/${WORKSPACE_ID}/eventstreams/${EVENTSTREAM_ID}/topology" \
--resource "https://api.fabric.microsoft.com"
在响应中找到自定义终结点源节点,并提取其 id:
# Extract the sourceId for a Custom Endpoint source (use name filter if multiple exist)
SOURCE_ID=$(az rest --method GET \
--url "https://api.fabric.microsoft.com/v1/workspaces/${WORKSPACE_ID}/eventstreams/${EVENTSTREAM_ID}/topology" \
--resource "https://api.fabric.microsoft.com" \
| jq -r '[.sources[] | select(.type=="CustomEndpoint")] | if length == 0 then error("No Custom Endpoint sources found in this Eventstream") elif length > 1 then error("Multiple Custom Endpoint sources found — filter by .name") else .[0].id end') \
|| { echo "Failed to resolve Custom Endpoint source ID"; exit 1; }
if [ -z "$SOURCE_ID" ]; then echo "SOURCE_ID is empty — check topology output"; exit 1; fi
# PowerShell — extract sourceId for Custom Endpoint (fails clearly if multiple exist)
$topology = az rest --method GET `
--url "https://api.fabric.microsoft.com/v1/workspaces/$WORKSPACE_ID/eventstreams/$EVENTSTREAM_ID/topology" `
--resource "https://api.fabric.microsoft.com" | ConvertFrom-Json
$customSources = @($topology.sources | Where-Object { $_.type -eq 'CustomEndpoint' })
if ($customSources.Count -eq 0) { throw "No Custom Endpoint sources found in this Eventstream" }
if ($customSources.Count -gt 1) { throw "Multiple Custom Endpoint sources found. Filter by name: $($customSources.name -join ', ')" }
$sourceId = $customSources[0].id
步骤 2:获取连接详细信息
⚠️ 安全:此终结点会返回访问密钥和连接字符串。调用前请先征得用户明确确认。除非用户明确要求在安全上下文中获取机密值,否则请从所有显示的输出中隐去
primaryKey、secondaryKey、primaryConnectionString和secondaryConnectionString。避免记录原始凭据;请安全存储并按需轮换。
az rest --method GET \
--url "https://api.fabric.microsoft.com/v1/workspaces/${WORKSPACE_ID}/eventstreams/${EVENTSTREAM_ID}/sources/${SOURCE_ID}/connection" \
--resource "https://api.fabric.microsoft.com"
az rest --method GET `
--url "https://api.fabric.microsoft.com/v1/workspaces/$WORKSPACE_ID/eventstreams/$EVENTSTREAM_ID/sources/$sourceId/connection" `
--resource "https://api.fabric.microsoft.com" | ConvertFrom-Json
预期响应
{
"fullyQualifiedNamespace": "namespace.servicebus.windows.net",
"eventHubName": "es_<guid>",
"accessKeys": {
"primaryKey": "...",
"secondaryKey": "...",
"primaryConnectionString": "Endpoint=sb://namespace.servicebus.windows.net/;...",
"secondaryConnectionString": "..."
}
}
Kafka 生产者配置
使用响应配置 Kafka 生产者:
| 设置 | 值 |
|---|---|
bootstrap_servers | {fullyQualifiedNamespace}:9093 |
topic | {eventHubName} |
security_protocol | SASL_SSL |
sasl_mechanism | PLAIN |
sasl_plain_username | $ConnectionString(固定字面值,不是变量) |
sasl_plain_password | {primaryConnectionString} |
限制:
/connection终结点仅支持自定义终结点源(返回 Kafka/Event Hub 凭据)。其他源类型(Event Hub、IoT Hub 等)会将其连接配置(例如dataConnectionId、consumerGroup)直接存储在解码后的定义属性中。
验证 Eventstream 配置
检查解码后的 Eventstream 拓扑中的关键配置项:
源验证清单
| 检查项 | 方法 |
|---|---|
| 源类型受 API 支持 | 与 25 个已知类型枚举值进行比较 |
| 云连接存在 | 验证 dataConnectionId GUID 是否可解析 |
| 已设置消费者组 | Event Hub、IoT Hub、Kafka 源的必需项 |
| 序列化格式与源匹配 | inputSerialization.type = Json、Csv 或 Avro |
目标验证清单
| 检查项 | 方法 |
|---|---|
| 目标类型有效 | 必须为 Lakehouse、Eventhouse、Activator 或 CustomEndpoint |
| 可访问目标项 | 验证 workspaceId + itemId 能否通过 GET 解析 |
| 已连接输入 | inputNodes 数组不得为空 |
| Eventhouse 直接引入 | 已设置 connectionName 和 mappingRuleName |
EventstreamProperties 验证
解码 eventstreamProperties.json 并检查:
retentionTimeInDays的值在 1–90 之间eventThroughputLevel为Low、Medium或High
注意事项、规则和故障排除
必须执行
- 使用
az rest调用时,始终传入--resource https://api.fabric.microsoft.com - 始终使用 JMESPath 筛选,将工作区名称解析为 ID,将项名称解析为 ID
- 检查拓扑前,始终对定义负载进行 Base64 解码(Topology API 不需要这样做,因为它直接返回 JSON)
- 获取 Custom Endpoint 连接详情时,使用 Topology API——
POST .../getDefinition会返回空属性;调用GET .../topology获取 sourceId,然后调用GET .../sources/{sourceId}/connection - 定义端点使用 POST——
POST .../getDefinition(而非 GET)、POST .../updateDefinition(而非 PUT)。请参阅官方文档。 - 处理分页——检查列表响应中是否存在
continuationUri - 轮询 LRO 响应——Get Definition 可能会返回
202 Accepted
建议做法
- 将拓扑 JSON 解码为结构化输出,以便生成易读的摘要
- 使用
jq(bash)或ConvertFrom-Json(PowerShell)进行解析 - 向用户报告问题前,先验证配置
- 将目标与下游技能(eventhouse、sqldw、spark)交叉核对
避免
- 不要混淆 Eventstream 和 Eventhouse——它们是 Fabric 中彼此独立的工作负载
- 不要对工作区或项 ID 进行硬编码——始终通过 API 发现这些 ID
- 不要假设所有源类型都出现在 API 枚举中——预览版源仅存在于 UI 中
- 不要使用此消费技能修改 Eventstream 拓扑——写入操作请使用
eventstream-authoring-cli - 不要尝试通过 Eventstream API 查询事件数据——查询已写入的数据请使用下游技能(eventhouse-consumption-cli、sqldw-consumption-cli)
示例
平台说明——示例使用 PowerShell。请始终通过
[IO.File]::WriteAllText()(不带 BOM)将 JSON 正文写入临时文件,并将--body "@$file"传给az rest,而不要使用内联的--body "...",因为cmd.exe可能会对其造成破坏。使用ConvertTo-Json的-Compress参数,避免换行问题。唯一安全的内联例外是用于空正文的--body '{}'。 对于大型工作区,请检查列表响应中是否存在continuationUri,以处理分页。
示例 1:列出工作区中的所有 Eventstream
提示词:“列出我的分析工作区中的所有 Eventstream,并显示其名称和 ID。”
# 1. Discover workspace ID
$wsId = (az rest --method get `
--url "https://api.fabric.microsoft.com/v1/workspaces" `
--resource "https://api.fabric.microsoft.com" `
--query "value[?displayName=='analytics'] | [0].id" -o tsv)
if (-not $wsId) { throw "Workspace 'analytics' not found" }
# 2. List Eventstreams (handles pagination)
$allItems = @()
$resp = az rest --method get `
--url "https://api.fabric.microsoft.com/v1/workspaces/$wsId/eventstreams" `
--resource "https://api.fabric.microsoft.com" | ConvertFrom-Json
$allItems += $resp.value
while ($resp.continuationUri) {
$resp = az rest --method get `
--url $resp.continuationUri `
--resource "https://api.fabric.microsoft.com" | ConvertFrom-Json
$allItems += $resp.value
}
$allItems | Select-Object displayName, id, description | Format-Table
示例 2:检查 Eventstream 拓扑
提示词:“显示我的 SensorIngestion Eventstream 的拓扑,包括所有源、运算符和目标。”
# 1. Discover workspace + Eventstream IDs
$wsId = (az rest --method get `
--url "https://api.fabric.microsoft.com/v1/workspaces" `
--resource "https://api.fabric.microsoft.com" `
--query "value[?displayName=='analytics'] | [0].id" -o tsv)
if (-not $wsId) { throw "Workspace 'analytics' not found" }
$esId = (az rest --method get `
--url "https://api.fabric.microsoft.com/v1/workspaces/$wsId/eventstreams" `
--resource "https://api.fabric.microsoft.com" `
--query "value[?displayName=='SensorIngestion'] | [0].id" -o tsv)
if (-not $esId) { throw "Eventstream 'SensorIngestion' not found" }
# 2. Get topology (returns JSON directly — no base64 decoding needed)
$topo = az rest --method get `
--url "https://api.fabric.microsoft.com/v1/workspaces/$wsId/eventstreams/$esId/topology" `
--resource "https://api.fabric.microsoft.com" | ConvertFrom-Json
# 3. Summarize nodes (filter nulls from arrays)
Write-Host "Sources:"
@($topo.sources | Where-Object { $_ -ne $null }) | ForEach-Object {
Write-Host " - $($_.name) (type: $($_.type), id: $($_.id))"
}
Write-Host "Operators:"
@($topo.operators | Where-Object { $_ -ne $null }) | ForEach-Object {
Write-Host " - $($_.name) (type: $($_.type))"
}
Write-Host "Destinations:"
@($topo.destinations | Where-Object { $_ -ne $null }) | ForEach-Object {
Write-Host " - $($_.name) (type: $($_.type))"
}
Write-Host "Streams:"
@($topo.streams | Where-Object { $_ -ne $null }) | ForEach-Object {
Write-Host " - $($_.name) (type: $($_.type))"
}
示例 3:检查保留期和吞吐量设置
提示词:“我的 SensorIngestion Eventstream 的保留期和吞吐量设置是什么?”
注意:保留期和吞吐量设置存储在定义中的
eventstreamProperties.json部分(而不是eventstream.json)。如果缺少此部分,Eventstream 将使用平台默认值。
# 1. Discover workspace + Eventstream IDs
$wsId = (az rest --method get `
--url "https://api.fabric.microsoft.com/v1/workspaces" `
--resource "https://api.fabric.microsoft.com" `
--query "value[?displayName=='analytics'] | [0].id" -o tsv)
if (-not $wsId) { throw "Workspace 'analytics' not found" }
$esId = (az rest --method get `
--url "https://api.fabric.microsoft.com/v1/workspaces/$wsId/items?type=Eventstream" `
--resource "https://api.fabric.microsoft.com" `
--query "value[?displayName=='SensorIngestion'] | [0].id" -o tsv)
if (-not $esId) { throw "Eventstream 'SensorIngestion' not found" }
# 2. Get definition (handles LRO via Location header)
$token = (az account get-access-token --resource "https://api.fabric.microsoft.com" --query accessToken -o tsv)
$ps5 = @{}; if ($PSVersionTable.PSVersion.Major -lt 6) { $ps5.UseBasicParsing = $true }
$response = Invoke-WebRequest @ps5 -Method Post `
-Uri "https://api.fabric.microsoft.com/v1/workspaces/$wsId/eventstreams/$esId/getDefinition" `
-Headers @{ Authorization = "Bearer $token"; "Content-Type" = "application/json" } `
-Body '{}'
if ($response.StatusCode -eq 202) {
$location = $response.Headers['Location']
if ($location -is [array]) { $location = $location[0] }
if (-not $location) { throw "LRO response missing Location header" }
$ra = $response.Headers['Retry-After']
if ($ra -is [array]) { $ra = $ra[0] }
$retryAfter = if ($ra) { [int]$ra } else { 5 }
$def = $null
for ($i = 0; $i -lt 12; $i++) {
Start-Sleep -Seconds $retryAfter
$poll = Invoke-RestMethod -Uri $location -Headers @{ Authorization = "Bearer $token" }
if ($poll.status -eq 'Succeeded') {
$def = Invoke-RestMethod -Uri "$location/result" `
-Headers @{ Authorization = "Bearer $token" }
break
} elseif ($poll.status -in @('Failed', 'Cancelled')) {
throw "getDefinition LRO $($poll.status): $($poll.error.message)"
}
}
if (-not $def -or -not $def.definition) { throw "getDefinition LRO timed out (last status: $(if ($poll) { $poll.status } else { 'unknown' }))" }
} else {
$def = $response.Content | ConvertFrom-Json
}
# 3. Decode eventstreamProperties.json part (holds retention + throughput)
$propsPart = $def.definition.parts | Where-Object { $_.path -eq 'eventstreamProperties.json' } | Select-Object -First 1
if ($propsPart) {
$props = [Text.Encoding]::UTF8.GetString(
[Convert]::FromBase64String($propsPart.payload)) | ConvertFrom-Json
Write-Host "Retention: $($props.retentionTimeInDays) days"
Write-Host "Throughput Level: $($props.eventThroughputLevel)"
} else {
# Fall back to topology-level properties (older format)
$esPart = $def.definition.parts | Where-Object { $_.path -eq 'eventstream.json' } | Select-Object -First 1
if (-not $esPart) { throw "eventstream.json part not found in definition" }
$topology = [Text.Encoding]::UTF8.GetString(
[Convert]::FromBase64String($esPart.payload)) | ConvertFrom-Json
if ($topology.properties.retentionTimeInDays) {
Write-Host "Retention: $($topology.properties.retentionTimeInDays) days"
} else {
Write-Host "Retention: (platform default — not explicitly configured)"
}
if ($topology.properties.eventThroughputLevel) {
Write-Host "Throughput Level: $($topology.properties.eventThroughputLevel)"
} else {
Write-Host "Throughput Level: (platform default — not explicitly configured)"
}
}
示例 4:获取 Custom Endpoint 连接元数据
提示词:“获取我的 SensorIngestion Eventstream 中 Custom Endpoint 源的 Kafka 连接元数据。”
安全:连接端点会返回访问密钥。调用前请征得用户确认,并避免记录原始凭据。
# 1. Discover workspace + Eventstream IDs (omitted for brevity)
# 2. Get topology to find Custom Endpoint source ID
$topo = az rest --method get `
--url "https://api.fabric.microsoft.com/v1/workspaces/$wsId/eventstreams/$esId/topology" `
--resource "https://api.fabric.microsoft.com" | ConvertFrom-Json
$ceSource = @($topo.sources | Where-Object { $_.type -eq 'CustomEndpoint' }) | Select-Object -First 1
if (-not $ceSource) { throw "No CustomEndpoint source found in this Eventstream" }
$sourceId = $ceSource.id
# 3. Get connection metadata
$conn = az rest --method get `
--url "https://api.fabric.microsoft.com/v1/workspaces/$wsId/eventstreams/$esId/sources/$sourceId/connection" `
--resource "https://api.fabric.microsoft.com" | ConvertFrom-Json
Write-Host "Fully Qualified Namespace: $($conn.fullyQualifiedNamespace)"
Write-Host "Event Hub Name: $($conn.eventHubName)"
Write-Host "Kafka Bootstrap Server: $($conn.fullyQualifiedNamespace):9093"
示例 5:验证 Eventstream 配置
提示词:“检查我的 SensorIngestion Eventstream 是否存在配置问题。”
# 1. Discover workspace + Eventstream IDs (omitted for brevity)
# 2. Get topology
$topo = az rest --method get `
--url "https://api.fabric.microsoft.com/v1/workspaces/$wsId/eventstreams/$esId/topology" `
--resource "https://api.fabric.microsoft.com" | ConvertFrom-Json
# 3. Validate sources
@($topo.sources | Where-Object { $_ -ne $null }) | ForEach-Object {
$src = $_
Write-Host "Source: $($src.name) (type: $($src.type))"
if ($src.properties.dataConnectionId) {
Write-Host " Cloud connection: $($src.properties.dataConnectionId)"
}
if ($src.type -in @('AzureEventHub','AzureEventHubExtended','AzureIoTHub','ConfluentCloud','ApacheKafka','AmazonMSKKafka') -and
-not $src.properties.consumerGroupName) {
Write-Host " WARNING: No consumer group set (required for $($src.type))"
}
}
# 4. Validate destinations
@($topo.destinations | Where-Object { $_ -ne $null }) | ForEach-Object {
$dst = $_
Write-Host "Destination: $($dst.name) (type: $($dst.type))"
if (-not $dst.inputNodes -or $dst.inputNodes.Count -eq 0) {
Write-Host " WARNING: No input wired — destination will receive no events"
}
if ($dst.type -eq 'Eventhouse' -and -not $dst.properties.tableName) {
Write-Host " WARNING: No target table configured"
}
if ($dst.type -eq 'Eventhouse' -and $dst.properties.dataIngestionMode -eq 'DirectIngestion') {
if (-not $dst.properties.connectionName -or -not $dst.properties.mappingRuleName) {
Write-Host " WARNING: DirectIngestion requires connectionName and mappingRuleName"
}
}
}
# 5. Check node count limits
$ceCount = @($topo.sources | Where-Object { $_.type -eq 'CustomEndpoint' }).Count +
@($topo.destinations | Where-Object { $_.type -eq 'CustomEndpoint' }).Count +
@($topo.destinations | Where-Object { $_.type -eq 'Eventhouse' -and
$_.properties.dataIngestionMode -eq 'DirectIngestion' }).Count
Write-Host "CustomEndpoint + DI count: $ceCount / 11 limit"
if ($ceCount -gt 11) {
Write-Host "WARNING: Exceeds limit of 11 CustomEndpoint + DirectIngestion nodes"
}