tfc-run-logs

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Terraform Cloud Run Logs

Terraform Cloud 运行日志

Retrieve and display plan and/or apply logs from Terraform Cloud runs directly in the terminal.
直接在终端中获取并展示Terraform Cloud运行任务的计划(plan)和/或执行(apply)日志。

Prerequisites

前提条件

bash
undefined
bash
undefined

Required environment variables

Required environment variables

export TFE_TOKEN="your-api-token" # User or team token (not organization token) export TFE_ADDRESS="app.terraform.io" # Optional, defaults to app.terraform.io
undefined
export TFE_TOKEN="your-api-token" # User or team token (not organization token) export TFE_ADDRESS="app.terraform.io" # Optional, defaults to app.terraform.io
undefined

Core Workflow

核心工作流程

Get Both Plan and Apply Logs

同时获取计划和执行日志

bash
#!/bin/bash
set -euo pipefail

TOKEN="${TFE_TOKEN:?TFE_TOKEN not set}"
BASE_URL="https://${TFE_ADDRESS:-app.terraform.io}/api/v2"
RUN_ID="${1:?Usage: $0 <run-id>}"
bash
#!/bin/bash
set -euo pipefail

TOKEN="${TFE_TOKEN:?TFE_TOKEN not set}"
BASE_URL="https://${TFE_ADDRESS:-app.terraform.io}/api/v2"
RUN_ID="${1:?Usage: $0 <run-id>}"

Get run with plan and apply relationships

Get run with plan and apply relationships

RUN_DATA=$(curl -sf --header "Authorization: Bearer $TOKEN"
"$BASE_URL/runs/$RUN_ID?include=plan,apply")
RUN_DATA=$(curl -sf --header "Authorization: Bearer $TOKEN"
"$BASE_URL/runs/$RUN_ID?include=plan,apply")

Extract IDs

Extract IDs

PLAN_ID=$(echo "$RUN_DATA" | jq -r '.data.relationships.plan.data.id') APPLY_ID=$(echo "$RUN_DATA" | jq -r '.data.relationships.apply.data.id // empty')
PLAN_ID=$(echo "$RUN_DATA" | jq -r '.data.relationships.plan.data.id') APPLY_ID=$(echo "$RUN_DATA" | jq -r '.data.relationships.apply.data.id // empty')

Get and display plan logs

Get and display plan logs

PLAN_LOG_URL=$(curl -sf --header "Authorization: Bearer $TOKEN"
"$BASE_URL/plans/$PLAN_ID" | jq -r '.data.attributes."log-read-url"')
echo "=== PLAN OUTPUT ===" curl -sf "$PLAN_LOG_URL" | sed 's/\x1b[[0-9;]*m//g' # Strip ANSI codes
PLAN_LOG_URL=$(curl -sf --header "Authorization: Bearer $TOKEN"
"$BASE_URL/plans/$PLAN_ID" | jq -r '.data.attributes."log-read-url"')
echo "=== PLAN OUTPUT ===" curl -sf "$PLAN_LOG_URL" | sed 's/\x1b[[0-9;]*m//g' # Strip ANSI codes

Get apply logs if exists

Get apply logs if exists

if [ -n "$APPLY_ID" ]; then APPLY_LOG_URL=$(curl -sf --header "Authorization: Bearer $TOKEN"
"$BASE_URL/applies/$APPLY_ID" | jq -r '.data.attributes."log-read-url"')
echo "" echo "=== APPLY OUTPUT ===" curl -sf "$APPLY_LOG_URL" | sed 's/\x1b[[0-9;]*m//g' fi
undefined
if [ -n "$APPLY_ID" ]; then APPLY_LOG_URL=$(curl -sf --header "Authorization: Bearer $TOKEN"
"$BASE_URL/applies/$APPLY_ID" | jq -r '.data.attributes."log-read-url"')
echo "" echo "=== APPLY OUTPUT ===" curl -sf "$APPLY_LOG_URL" | sed 's/\x1b[[0-9;]*m//g' fi
undefined

Get Plan Logs Only

仅获取计划日志

bash
TOKEN="${TFE_TOKEN:?TFE_TOKEN not set}"
BASE_URL="https://${TFE_ADDRESS:-app.terraform.io}/api/v2"
RUN_ID="run-abc123"
bash
TOKEN="${TFE_TOKEN:?TFE_TOKEN not set}"
BASE_URL="https://${TFE_ADDRESS:-app.terraform.io}/api/v2"
RUN_ID="run-abc123"

Get plan ID from run

Get plan ID from run

PLAN_ID=$(curl -sf --header "Authorization: Bearer $TOKEN"
"$BASE_URL/runs/$RUN_ID" | jq -r '.data.relationships.plan.data.id')
PLAN_ID=$(curl -sf --header "Authorization: Bearer $TOKEN"
"$BASE_URL/runs/$RUN_ID" | jq -r '.data.relationships.plan.data.id')

Get log URL and fetch logs

Get log URL and fetch logs

PLAN_LOG_URL=$(curl -sf --header "Authorization: Bearer $TOKEN"
"$BASE_URL/plans/$PLAN_ID" | jq -r '.data.attributes."log-read-url"')
curl -sf "$PLAN_LOG_URL"
undefined
PLAN_LOG_URL=$(curl -sf --header "Authorization: Bearer $TOKEN"
"$BASE_URL/plans/$PLAN_ID" | jq -r '.data.attributes."log-read-url"')
curl -sf "$PLAN_LOG_URL"
undefined

Get Apply Logs Only

仅获取执行日志

bash
TOKEN="${TFE_TOKEN:?TFE_TOKEN not set}"
BASE_URL="https://${TFE_ADDRESS:-app.terraform.io}/api/v2"
RUN_ID="run-abc123"
bash
TOKEN="${TFE_TOKEN:?TFE_TOKEN not set}"
BASE_URL="https://${TFE_ADDRESS:-app.terraform.io}/api/v2"
RUN_ID="run-abc123"

Get apply ID from run

Get apply ID from run

APPLY_ID=$(curl -sf --header "Authorization: Bearer $TOKEN"
"$BASE_URL/runs/$RUN_ID" | jq -r '.data.relationships.apply.data.id')
if [ -n "$APPLY_ID" ] && [ "$APPLY_ID" != "null" ]; then

Get log URL and fetch logs

APPLY_LOG_URL=$(curl -sf --header "Authorization: Bearer $TOKEN"
"$BASE_URL/applies/$APPLY_ID" | jq -r '.data.attributes."log-read-url"')
curl -sf "$APPLY_LOG_URL" else echo "No apply for this run" fi
undefined
APPLY_ID=$(curl -sf --header "Authorization: Bearer $TOKEN"
"$BASE_URL/runs/$RUN_ID" | jq -r '.data.relationships.apply.data.id')
if [ -n "$APPLY_ID" ] && [ "$APPLY_ID" != "null" ]; then

Get log URL and fetch logs

APPLY_LOG_URL=$(curl -sf --header "Authorization: Bearer $TOKEN"
"$BASE_URL/applies/$APPLY_ID" | jq -r '.data.attributes."log-read-url"')
curl -sf "$APPLY_LOG_URL" else echo "No apply for this run" fi
undefined

Quick One-Liners

快速单行命令

Plan Logs (with ANSI colors)

计划日志(保留ANSI颜色)

bash
curl -sf -H "Authorization: Bearer $TFE_TOKEN" \
  "https://app.terraform.io/api/v2/runs/run-abc123?include=plan" | \
  jq -r '.included[0].attributes."log-read-url"' | xargs curl -sf
bash
curl -sf -H "Authorization: Bearer $TFE_TOKEN" \
  "https://app.terraform.io/api/v2/runs/run-abc123?include=plan" | \
  jq -r '.included[0].attributes."log-read-url"' | xargs curl -sf

Plan Logs (clean text)

计划日志(纯文本)

bash
curl -sf -H "Authorization: Bearer $TFE_TOKEN" \
  "https://app.terraform.io/api/v2/runs/run-abc123?include=plan" | \
  jq -r '.included[0].attributes."log-read-url"' | \
  xargs curl -sf | sed 's/\x1b\[[0-9;]*m//g'
bash
curl -sf -H "Authorization: Bearer $TFE_TOKEN" \
  "https://app.terraform.io/api/v2/runs/run-abc123?include=plan" | \
  jq -r '.included[0].attributes."log-read-url"' | \
  xargs curl -sf | sed 's/\x1b\[[0-9;]*m//g'

Important Notes

重要说明

  • Log URLs are secrets: Archivist URLs contain embedded authentication - don't log them
  • URLs expire: Log URLs are valid for 25 hours
  • No auth needed for logs: Once you have the archivist URL, no bearer token is required
  • ANSI codes: Logs contain color codes; use
    sed
    to strip them for clean output
  • Rate limits:
    /runs
    endpoint is limited to 30 requests/minute
  • 日志URL为敏感信息:归档URL包含内置认证信息 - 请勿记录这些URL
  • URL会过期:日志URL的有效期为25小时
  • 日志无需额外认证:获取归档URL后,无需再使用Bearer令牌即可访问日志
  • ANSI代码:日志中包含颜色代码;可使用
    sed
    命令去除以得到纯文本输出
  • 速率限制
    /runs
    接口的请求限制为每分钟30次

Common Errors

常见错误

404 Not Found

404 Not Found(未找到)

  • Run ID doesn't exist OR you don't have permission
  • TFC returns 404 for both cases (security measure)
  • 运行ID不存在,或者您无访问权限
  • TFC对这两种情况均返回404(安全机制)

401 Unauthorized

401 Unauthorized(未授权)

  • Token is invalid or expired
  • Organization tokens cannot access run data - use user/team token
  • 令牌无效或已过期
  • 组织令牌无法访问运行数据 - 请使用用户/团队令牌

No Apply Logs

无执行日志

  • Run may be plan-only, not yet applied, or discarded
  • Check run status first
  • 运行任务可能仅执行了计划,尚未执行,或已被丢弃
  • 请先检查运行任务状态

See Also

相关工具

  • tfc-run-status
    : Quick status check for a run
  • tfc-list-runs
    : List recent runs in a workspace
  • tfc-plan-json
    : Get structured plan JSON output
  • tfc-run-status
    :快速检查运行任务状态
  • tfc-list-runs
    :列出工作区中的近期运行任务
  • tfc-plan-json
    :获取结构化的计划JSON输出