From 8696adaafa24dd086271ea8ebd0822634c053363 Mon Sep 17 00:00:00 2001 From: Ian Wahbe Date: Thu, 5 Dec 2024 17:43:39 +0100 Subject: [PATCH] Call `NewTerraformLogRedirector` for PF (#2686) Will fix (probably) https://github.com/pulumi/pulumi-ise/issues/9 Related to #2489 --- By not calling the redirect, all logs were shown directly to the user (as INFO logs). This gets PF to respect TF_LOG, similar to /pkg. --- pkg/pf/tests/logging_test.go | 63 ++++++++++++++++++++++++++++++++++++ pkg/pf/tfbridge/logging.go | 20 ++++++++++++ pkg/tfbridge/log.go | 23 +++++++++---- 3 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 pkg/pf/tests/logging_test.go diff --git a/pkg/pf/tests/logging_test.go b/pkg/pf/tests/logging_test.go new file mode 100644 index 000000000..53b8f0a46 --- /dev/null +++ b/pkg/pf/tests/logging_test.go @@ -0,0 +1,63 @@ +package tfbridgetests + +import ( + "context" + "log" + "testing" + + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/pf/tests/internal/providerbuilder" + "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/pf/tests/pulcheck" + "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/pf/tfbridge" + "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge/info" + "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge/tokens" +) + +func TestLogCaputure(t *testing.T) { + t.Setenv("TF_LOG", "WARN") + + provider := info.Provider{ + Name: "test", + Version: "0.0.1", + P: tfbridge.ShimProvider(providerbuilder.NewProvider(providerbuilder.NewProviderArgs{ + TypeName: "test", + AllResources: []providerbuilder.Resource{{ + Name: "res", + ResourceSchema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + }, + }, + }, + CreateFunc: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + require.Empty(t, resp.State.SetAttribute(ctx, path.Root("id"), "1234")) + log.Println("[INFO] This is info") + log.Println("[WARN] You have been warned") + }, + }}, + })), + MetadataInfo: info.NewProviderMetadata(nil), + } + + provider.MustComputeTokens(tokens.SingleModule("test", "index", tokens.MakeStandard("test"))) + + pt, err := pulcheck.PulCheck(t, provider, ` +name: test +runtime: yaml +resources: + mainRes: + type: test:Res +`) + + require.NoError(t, err) + result := pt.Up(t) + + assert.NotContains(t, result.StdOut, "This is info") + assert.Contains(t, result.StdOut, "You have been warned") +} diff --git a/pkg/pf/tfbridge/logging.go b/pkg/pf/tfbridge/logging.go index 504226c24..6f4e181fe 100644 --- a/pkg/pf/tfbridge/logging.go +++ b/pkg/pf/tfbridge/logging.go @@ -16,6 +16,7 @@ package tfbridge import ( "context" + "log" "github.com/pulumi/pulumi/sdk/v3/go/common/resource" @@ -29,6 +30,25 @@ import ( func (p *provider) initLogging(ctx context.Context, sink logging.Sink, urn resource.URN) context.Context { // add the resource URN to the context ctx = tfbridge.XWithUrn(ctx, urn) + + // There is no host in a testing context. + if sink == nil { + // For tests that did not call InitLogging yet, we should call it here so that + // GetLogger does not panic. + if ctx.Value(logging.CtxKey) == nil { + return logging.InitLogging(ctx, logging.LogOptions{ + URN: urn, + ProviderName: p.info.Name, + ProviderVersion: p.info.Version, + }) + } + + // Otherwise keep the context as-is. + return ctx + } + + log.SetOutput(tfbridge.NewTerraformLogRedirector(ctx, sink)) + return logging.InitLogging(ctx, logging.LogOptions{ LogSink: sink, URN: urn, diff --git a/pkg/tfbridge/log.go b/pkg/tfbridge/log.go index efe9a1a63..cc258b8e3 100644 --- a/pkg/tfbridge/log.go +++ b/pkg/tfbridge/log.go @@ -21,15 +21,23 @@ import ( "os" "strings" - "github.com/pulumi/pulumi/pkg/v3/resource/provider" "github.com/pulumi/pulumi/sdk/v3/go/common/diag" "github.com/pulumi/pulumi/sdk/v3/go/common/util/contract" "github.com/pulumi/pulumi-terraform-bridge/v3/internal/logging" ) -// LogRedirector creates a new redirection writer that takes as input plugin stderr output, and routes it to the -// correct Pulumi stream based on the standard Terraform logging output prefixes. +// LogRedirector creates a new redirection writer that takes [log] messages as input, and +// routes it to the Pulumi correct structured logging. +// +// It looks for lines that contain log level information and routes them to their Pulumi +// equivalent. A line is considered to have log level information when it contains one of: +// +// - "[TRACE]" +// - "[DEBUG]" +// - "[INFO]" +// - "[WARN]" +// - "[ERROR]" type LogRedirector struct { ctx context.Context level level // log level requested by TF_LOG @@ -74,11 +82,12 @@ const ( tfErrorPrefix = "[ERROR]" ) -func NewTerraformLogRedirector(ctx context.Context, hostClient *provider.HostClient) *LogRedirector { - lr := &LogRedirector{ctx: ctx, sink: hostClient} +// NewTerraformLogRedirector creates a [LogRedirector] that responds to the TF_LOG +// environmental variable. +func NewTerraformLogRedirector(ctx context.Context, sink logging.Sink) *LogRedirector { + lr := &LogRedirector{ctx: ctx, sink: sink} - tfLog, ok := os.LookupEnv("TF_LOG") - if ok { + if tfLog, ok := os.LookupEnv("TF_LOG"); ok { switch strings.ToLower(tfLog) { case "trace": lr.level = traceLevel