Study guide
12.3 Verbose Logging and Diagnostics
HashiCorp Certified: Terraform Associate 004
Track your progress as you read
Finished sections get a check mark.
1 Introduction & Exam Overview
1.1 Current Exam Facts 1.2 Format, Delivery, Retakes, and Recertification 1.3 004 Changes, Terraform 1.12, and Study Plan
2 Infrastructure as Code with Terraform
2.1 What Infrastructure as Code Is 2.2 Advantages of IaC Patterns 2.3 Multi-Cloud, Hybrid, and Service-Agnostic Workflows
3 Terraform Fundamentals: Providers & State
3.1 Install and Version Terraform Providers 3.2 How Terraform Uses Providers 3.3 Configuration with Multiple Providers 3.4 How Terraform Uses and Manages State
4 Core Terraform Workflow: Init & Validate
4.1 The Terraform Write–Plan–Apply Workflow 4.2 Initialize a Working Directory 4.3 Validate a Configuration
5 Plan, Apply, Destroy, and Formatting
5.1 Generate and Review an Execution Plan 5.2 Apply Changes to Infrastructure 5.3 Destroy Terraform-Managed Infrastructure 5.4 Formatting and Style Adjustments
6 Resources, Data Sources, and References
6.1 Resource Blocks vs Data Blocks 6.2 Resource Attributes and Cross-Resource References 6.3 Resource Addressing and Interpolation Patterns
7 Variables, Outputs, and Complex Types
7.1 Input Variables, tfvars, and Precedence 7.2 Output Values 7.3 Complex Types: list, map, object, tuple, set
8 Dynamic Configuration and Dependencies
8.1 Expressions, count, for_each, and dynamic Blocks 8.2 Built-in Functions 8.3 Dependencies, depends_on, and Lifecycle Rules
9 Conditions, Secrets, and Sensitive Data
9.1 Custom Conditions: validation, precondition, postcondition, check 9.2 Sensitive Data Handling 9.3 Vault, Ephemeral Values, and Write-Only Arguments
10 Terraform Modules
10.1 How Terraform Sources Modules 10.2 Variable Scope within Modules 10.3 Using Modules in Configuration 10.4 Managing Module Versions
11 Terraform State Management
11.1 The Local Backend 11.2 State Locking 11.3 Remote State and the backend Block 11.4 Resource Drift and State Operations
12 Maintain Infrastructure with Terraform
12.1 Import Existing Infrastructure 12.2 Inspect State with the CLI 12.3 Verbose Logging and Diagnostics
13 HCP Terraform
13.1 Create Infrastructure with HCP Terraform 13.2 Collaboration and Governance Features 13.3 Workspaces and Projects 13.4 HCP Terraform Integrations
12.3 Verbose Logging and Diagnostics
Key Takeaways Explain This Topic AI
TF_LOG levels, from most to least verbose, are TRACE, DEBUG, INFO, WARN, and ERROR
TF_LOG_PATH appends logs to a file, but TF_LOG must still be set or nothing is written
TF_LOG_CORE and TF_LOG_PROVIDER take the same levels and split Terraform core logs from provider plugin logs
Turn logging up to diagnose provider bugs, unexpected API failures, and plugin crashes
- Never leave TRACE enabled in CI that captures logs: traces can contain credentials and other secrets
- Last updated: August 2026
12.3 Verbose Logging and Diagnostics
Quick Answer: Set TF_LOG to TRACE , DEBUG , INFO , WARN , or ERROR (most verbose to least). Logs go to stderr. TF_LOG_PATH appends the same stream to a file — but TF_LOG must still be set or nothing is logged. TF_LOG_CORE and TF_LOG_PROVIDER split Terraform-core logs from provider-plugin logs. Use this for provider bugs and API failures. Never leave TRACE on in CI that prints logs: traces can contain credentials.
Objective 7c on Terraform Associate (004) is: describe when and how to use verbose logging on Terraform 1.12 . This is an operations question, not an HCL question. Official pages: Enable Terraform logs and CLI environment variables .
Why this objective appears on 004
When apply dies with a vague provider error, the next step is not terraform destroy . It is a controlled debug log. 004 checks that you know the level names, that TF_LOG_PATH alone is not enough, that you can isolate core versus provider, and that you treat TRACE as sensitive.
TF_LOG levels
Enabling TF_LOG makes detailed logs appear on stderr . HashiCorp documents these levels, in decreasing verbosity :
- Level Relative volume What you are usually looking for
- TRACE Highest — every internal step Graph walks, plugin protocol, full request/response detail
- DEBUG High Provider setup, retries, detailed operation progress
- INFO Moderate Notable non-error events
- WARN Low Recoverable problems
- ERROR Lowest Failures only export TF_LOG=TRACE # or DEBUG, INFO, WARN, ERROR
- terraform plan
- unset TF_LOG # or: export TF_LOG=off
The environment-variables page shows export TF_LOG=trace (case is conventionally upper-case in examples; the documented disable is off or unset). Levels are the exam fact. Setting TF_LOG to JSON is a special value: logs at TRACE or higher, formatted as JSON. HashiCorp warns that this JSON encoding is not a stable interface — it may change without notice and exists to support forthcoming tooling. Do not treat TF_LOG=JSON as the same thing as terraform show -json .
None of these variables is required for normal use. They change verbosity for debugging. They do not change how plan/apply compute actions, and they do not replace terraform validate .
- TF_LOG_PATH does not enable logging by itself export TF_LOG=DEBUG
- export TF_LOG_PATH=./terraform.log
- terraform apply
TF_LOG_PATH forces the log to be appended to that file whenever logging is enabled. Official wording, repeated on both the debugging page and the environment-variables page: even when TF_LOG_PATH is set, TF_LOG must be set for any logging to be enabled. A CI job that only exports a path and then wonders why the file is empty has not turned logging on.
Use a path you control (a job artifact directory, not a world-readable shared volume). The file can grow quickly at TRACE . Delete or restrict it after you capture the failure.
Split core versus provider: TF_LOG_CORE and TF_LOG_PROVIDER
Terraform CLI ("core") and provider plugins are separate processes. A 403 from AWS and a panic inside Terraform's graph walker look similar at ERROR on the console. HashiCorp lets you enable subsets:
Variable What it turns on Same level names as TF_LOG ?
- TF_LOG Combined detailed logging (the usual switch) Yes ( TRACE … ERROR , plus JSON )
- TF_LOG_CORE Terraform itself — graph, backend, state, language Yes
- TF_LOG_PROVIDER Provider plugin logs (the binary talking to the cloud API) Yes
- TF_LOG_PATH Destination file (append); not a level Requires TF_LOG set
When the symptom is "the provider returned InvalidParameterValue / 403 / 429 ," start with TF_LOG_PROVIDER=DEBUG or TRACE so you are not drowned in core graph TRACE. When the symptom is a crash or odd behavior inside Terraform before the provider is called (backend init, state lock, malformed config evaluation), use TF_LOG_CORE . You can set both to different levels. That split is the 7c skill: isolate who is noisy. # Provider plugin only — typical cloud API failure
- export TF_LOG_PROVIDER=TRACE
- export TF_LOG_PATH=./provider-trace.log
# Official persist note: TF_LOG must also be set for file logging to start.
# Keep TF_LOG at a quiet level so CORE stays out of a provider-only capture.
export TF_LOG=ERROR
- # After the capture
- export TF_LOG=off
- unset TF_LOG_PROVIDER
Loading diagram...
When to turn it on
HashiCorp's debugging page exists so you can debug unexpected behavior and, if you file a Terraform bug, include a detailed log (they suggest a gist). Exam-level situations:
A provider operation fails with a raw API error and the human message is not enough.
A plugin exits or hangs during refresh/apply.
You need to see whether Terraform even reached the provider (core) or the provider reached the API (provider).
Support or a GitHub issue asks for a TRACE.
Situations that are not 7c:
"Make plan faster" — logging makes it slower and noisier.
"Hide secrets from state" — that is sensitive , ephemeral values, and a secrets manager (4h), not TF_LOG=ERROR .
"Pretty-print HCL" — terraform fmt .
"See what would change" — terraform plan / terraform show .
Leave logging at default (unset) for everyday laptop and production apply. Turn it up for a single reproduction, capture the file, then turn it off.
Never leave TRACE on in CI with secrets
TRACE (and often DEBUG ) can include:
- provider credentials and session tokens,
- request headers and bodies,
- resource attributes that are secrets,
backend credentials used to reach state.
If a pipeline exports TF_LOG=TRACE and the job log is world-readable (or shipped to a log vendor with broad access), you have published credentials. That is why 7c is also a safety question.
Practical rules for 004:
Do not set TF_LOG=TRACE as a standing variable in the CI image.
If you must capture a failing job, write to TF_LOG_PATH on a restricted artifact, redact before sharing, and rotate any credentials that appeared.
TF_LOG_PATH without access control is still a secret file.
TF_LOG=JSON is still TRACE-level detail in another wrapper — same secret risk.
Unset the variables or set TF_LOG=off when the debug run ends.
TF_IN_AUTOMATION only changes cosmetic "what to run next" hints. It does not enable logging and it does not redact TRACE. Do not confuse the two variables.
Scenario: the 403 that was not a VPC bug
Priya's apply fails: the AWS provider reports AccessDenied on CreateRoute . A teammate wants to apply -replace the route table. Priya instead sets TF_LOG_PROVIDER=DEBUG and TF_LOG_PATH=./aws.log with TF_LOG enabled, reproduces once, and turns logging off. The provider log shows the request used the wrong account alias, not a bad CIDR. She fixes the aliased provider credentials. She never commits aws.log . She never leaves TF_LOG=TRACE in the GitHub Actions env: block, because that workflow prints logs to a public fork pull request.
If the log had shown a Terraform core panic before any AWS HTTP, she would have captured TF_LOG_CORE=TRACE and opened a Terraform issue with that gist — the debugging page's intended use.
004 traps for objective 7c
Levels are TRACE , DEBUG , INFO , WARN , ERROR — not VERBOSE / SILENT .
TF_LOG_PATH without TF_LOG writes nothing.
TF_LOG_CORE versus TF_LOG_PROVIDER isolates Terraform versus the plugin.
TF_LOG=JSON is unstable TRACE-shaped JSON, not terraform show -json .
TRACE belongs in a controlled file for a single reproduction, not in standing CI.
Logging does not apply infrastructure and does not format configuration.