-
Notifications
You must be signed in to change notification settings - Fork 949
[MAINT] Tracking issue for refactoring logging to use tflog instead of log #3070
Description
Summary
This issue tracks the migration from Go's standard log package to HashiCorp's structured logging package tflog across the provider codebase.
Resolves #2629
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
Metadata
Metadata
Assignees
Labels
Type
Projects
Status