-
Notifications
You must be signed in to change notification settings - Fork 927
Description
Summary
This issue tracks the migration from Go's standard log package to HashiCorp's structured logging package tflog across the provider codebase.
Why?
The tflog package provides several benefits over standard log:
- Structured logging - Separate log messages from filterable field data for programmatic parsing
- Better integration - Works properly with Terraform's logging system (
TF_LOG,TF_LOG_PROVIDER) - Filtering capabilities - Users can filter logs by fields, making debugging easier
- Consistent patterns - Aligns with HashiCorp's official Terraform provider development practices
- Sensitive data masking - Built-in support for masking sensitive values in logs
Related Issues
- [MAINT] Migrate all resources and data sources to Context-aware CRUD functions #2996 - [MAINT] Migrate all resources and data sources to Context-aware CRUD functions - Should be paired with this work (see note below)
- [BUG]: Insufficient logging #2679 - [BUG]: Insufficient logging - Requests more logging output; better structured logging framework would help address this
- Provider hangs, without giving any logging or feedback #1226 - Provider hangs, without giving any logging or feedback - Rate limit logging would be improved with tflog in
transport.go - [MAINT]: Update transport implementation #2925 - [MAINT]: Update transport implementation - Transport changes may want to coordinate with logging refactoring
Important: The
tflogpackage requires acontext.Contextparameter. Files that still use legacy CRUD functions (e.g.,Create,Readinstead ofCreateContext,ReadContext) should be migrated to Context-aware functions as part of the same PR. See #2996 for details on the Context migration.
Best Practices (from HashiCorp Documentation)
Log Levels (least to most verbose)
- Error - Unexpected conditions before halting execution
- Warn - Unexpected conditions that don't stop execution (deprecations, external changes)
- Info - Documents logic conditions or events (state changes, decisions)
- Debug - Operational milestones and behaviors
- Trace - Intra-function steps and raw data details
Structured Fields
Use structured log fields instead of embedding values in message strings:
// Good: Structured fields for filtering
tflog.Debug(ctx, "Deleting secret", map[string]any{
"repository": repoName,
"secret_name": secretName,
})
// Bad: Embedded values
log.Printf("[DEBUG] Deleting secret: %s/%s", repoName, secretName)Persistent Context
Use tflog.SetField() to attach fields to all subsequent logs in a function:
ctx = tflog.SetField(ctx, "repository", repoName)
tflog.Debug(ctx, "Reading secret") // includes repository field automaticallyBefore/After Examples
Before (current pattern)
import (
"log"
)
func resourceGithubDependabotSecretRead(d *schema.ResourceData, meta any) error {
// ...
if ghErr.Response.StatusCode == http.StatusNotFound {
log.Printf("[WARN] Removing actions secret %s from state because it no longer exists in GitHub",
d.Id())
d.SetId("")
return nil
}
// ...
log.Printf("[DEBUG] Deleting secret: %s", d.Id())
}After (target pattern)
import (
"github.com/hashicorp/terraform-plugin-log/tflog"
)
func resourceGithubDependabotSecretRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
// ...
if ghErr.Response.StatusCode == http.StatusNotFound {
tflog.Warn(ctx, "Removing secret from state because it no longer exists in GitHub", map[string]any{
"secret_id": d.Id(),
"repository": repoName,
})
d.SetId("")
return nil
}
// ...
tflog.Debug(ctx, "Deleting secret", map[string]any{
"secret_id": d.Id(),
"repository": repoName,
"secret_name": secretName,
})
}Files to Refactor
Already Completed ✅
-
resource_github_membership.go -
resource_github_organization_ruleset.go
Resources (50 files)
-
resource_github_actions_environment_secret.go -
resource_github_actions_environment_variable.go -
resource_github_actions_hosted_runner.go -
resource_github_actions_organization_permissions.go -
resource_github_actions_organization_secret_repository.go -
resource_github_actions_organization_secret.go -
resource_github_actions_organization_variable.go -
resource_github_actions_repository_permissions.go -
resource_github_actions_runner_group.go -
resource_github_actions_secret.go -
resource_github_actions_variable.go -
resource_github_app_installation_repositories.go -
resource_github_app_installation_repository.go -
resource_github_branch_default.go -
resource_github_branch_protection_v3.go -
resource_github_branch_protection.go -
resource_github_branch.go -
resource_github_codespaces_organization_secret.go -
resource_github_codespaces_secret.go -
resource_github_codespaces_user_secret.go -
resource_github_dependabot_organization_secret.go -
resource_github_dependabot_secret.go -
resource_github_enterprise_actions_runner_group.go -
resource_github_enterprise_actions_workflow_permissions.go -
resource_github_enterprise_organization.go -
resource_github_enterprise_security_analysis_settings.go -
resource_github_issue_label.go -
resource_github_issue_labels.go -
resource_github_issue.go -
resource_github_organization_custom_role.go -
resource_github_organization_repository_role.go -
resource_github_organization_role_team_assignment.go -
resource_github_organization_role_team.go -
resource_github_organization_role_user.go -
resource_github_organization_role.go -
resource_github_organization_security_manager.go -
resource_github_organization_settings.go -
resource_github_organization_webhook.go -
resource_github_release.go -
resource_github_repository_autolink_reference.go -
resource_github_repository_collaborator.go -
resource_github_repository_collaborators.go -
resource_github_repository_deploy_key.go -
resource_github_repository_deployment_branch_policy.go -
resource_github_repository_environment_deployment_policy.go -
resource_github_repository_environment.go -
resource_github_repository_file.go -
resource_github_repository_milestone.go -
resource_github_repository_pull_request.go -
resource_github_repository_ruleset.go -
resource_github_repository_topics.go -
resource_github_repository_webhook.go -
resource_github_repository.go -
resource_github_team_members.go -
resource_github_team_membership.go -
resource_github_team_repository.go -
resource_github_team_sync_group_mapping.go -
resource_github_team.go -
resource_github_user_gpg_key.go -
resource_github_user_ssh_key.go -
resource_organization_block.go
Data Sources (9 files)
-
data_source_github_actions_organization_registration_token.go -
data_source_github_actions_registration_token.go -
data_source_github_branch.go -
data_source_github_codespaces_public_key.go -
data_source_github_dependabot_public_key.go -
data_source_github_organization_custom_role.go -
data_source_github_ref.go -
data_source_github_repository_file.go -
data_source_github_repository.go
Utilities & Core (10 files)
-
provider.go -
transport.go -
repository_utils.go -
util.go -
util_rules.go -
util_v4_branch_protection.go -
resource_github_branch_protection_v3_utils.go
Migrations (4 files)
-
migrate_github_actions_organization_secret.go -
migrate_github_actions_secret.go -
migrate_github_repository_webhook.go -
migrate_github_repository.go
Implementation Notes
- Context requirement: All
tflogfunctions require acontext.Contextfrom the SDK - Pair with Context migration: If a file uses legacy CRUD functions, migrate to Context-aware functions ([MAINT] Migrate all resources and data sources to Context-aware CRUD functions #2996) in the same PR
- Import change: Replace
"log"with"github.com/hashicorp/terraform-plugin-log/tflog" - Field naming: Use consistent field names across the codebase (e.g.,
repository,owner,team_slug) - Message format: Don't use
fmt.Sprintf()for complex messages, instead use the map for all data inputs
References
- HashiCorp: Writing Log Output
- HashiCorp: Managing Log Output
- HashiCorp: Filtering Log Output
- tflog Package Documentation
- AWS Provider Issue #24165 - Similar refactoring discussion
Contributing
This is a good first issue for contributors! Each file can be refactored independently. When contributing:
- Pick a file from the list above
- Check if the file uses legacy CRUD functions - if so, migrate to Context-aware functions first ([MAINT] Migrate all resources and data sources to Context-aware CRUD functions #2996)
- Replace
logimports withtflog - Convert
log.Printf("[LEVEL] ...")calls totflog.Level(ctx, ..., map[string]any{...}) - Run
make buildandmake lintto verify - Submit a PR referencing this issue
/cc @maintainers