Skip to content

Commit 4fdcde8

Browse files
chore: enable dumping the container logs of the forked environment
Dump the container logs when the CLDF_CONTAINER_LOGS environment variables is set. If the environment variable is set to an absolute filesystem path, CLDF tries to save the logs to a folder at the given path. If it's set to a _truish_ value ("true", "on", "enabled", "1"), it saves the logs to a temporary folder.
1 parent b7c8d06 commit 4fdcde8

File tree

6 files changed

+99
-6
lines changed

6 files changed

+99
-6
lines changed

chain/evm/provider/ctf_anvil_provider.go

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,9 @@ import (
208208
"fmt"
209209
"math/big"
210210
"net/http"
211+
"os"
212+
"path"
213+
"slices"
211214
"strconv"
212215
"strings"
213216
"sync"
@@ -217,9 +220,11 @@ import (
217220
"github.com/avast/retry-go/v4"
218221
"github.com/ethereum/go-ethereum/accounts/abi/bind"
219222
"github.com/ethereum/go-ethereum/crypto"
223+
"github.com/rs/zerolog"
220224
chainsel "github.com/smartcontractkit/chain-selectors"
221225
"github.com/smartcontractkit/chainlink-testing-framework/framework"
222226
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain"
227+
ctfdocker "github.com/smartcontractkit/chainlink-testing-framework/lib/docker"
223228
"github.com/smartcontractkit/freeport"
224229
"github.com/testcontainers/testcontainers-go"
225230

@@ -516,7 +521,18 @@ func (p *CTFAnvilChainProvider) GetNodeHTTPURL() string {
516521
// Returns an error if the container termination fails.
517522
func (p *CTFAnvilChainProvider) Cleanup(ctx context.Context) error {
518523
if p.container != nil {
519-
err := p.container.Terminate(ctx)
524+
shouldSave, path, err := shouldSaveCtfContainerLogs(os.Getenv(saveContainerLogsEnvVar))
525+
if err != nil {
526+
return fmt.Errorf("failed to check if we should save the container logs: %w", err)
527+
}
528+
529+
if shouldSave {
530+
zlogger := zerolog.New(os.Stdout)
531+
ctfdocker.WriteAllContainersLogs(zlogger, path)
532+
zlogger.Info().Msgf("container logs saved to %q", path)
533+
}
534+
535+
err = p.container.Terminate(ctx)
520536
if err != nil {
521537
return fmt.Errorf("failed to terminate Anvil container: %w", err)
522538
}
@@ -714,3 +730,41 @@ func (p *CTFAnvilChainProvider) waitForAnvilReady(ctx context.Context, httpURL s
714730
retry.DelayType(retry.FixedDelay),
715731
)
716732
}
733+
734+
const saveContainerLogsEnvVar = "CLDF_CONTAINER_LOGS"
735+
736+
func shouldSaveCtfContainerLogs(envVarValue string) (bool, string, error) {
737+
if envVarValue == "" {
738+
return false, "", nil
739+
}
740+
741+
if path.IsAbs(envVarValue) {
742+
if isDirectory(envVarValue) {
743+
return true, envVarValue, nil
744+
}
745+
746+
err := os.MkdirAll(envVarValue, 0o700)
747+
if err != nil {
748+
return false, "", fmt.Errorf("failed to create container logs dir: %w", err)
749+
}
750+
751+
return true, envVarValue, nil
752+
}
753+
754+
trueValues := []string{"1", "true", "on", "enabled"}
755+
if slices.Contains(trueValues, strings.ToLower(envVarValue)) {
756+
tmpDirPath, err := os.MkdirTemp("", "cldf-container-logs-*")
757+
if err != nil {
758+
return false, "", fmt.Errorf("failed to create temporary dir: %w", err)
759+
}
760+
761+
return true, tmpDirPath, nil
762+
}
763+
764+
return false, "", fmt.Errorf("invalid value for %s variable: %v", saveContainerLogsEnvVar, envVarValue)
765+
}
766+
767+
func isDirectory(path string) bool {
768+
fileInfo, err := os.Stat(path)
769+
return err == nil && fileInfo.IsDir()
770+
}

chain/evm/provider/ctf_anvil_provider_test.go

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@ import (
77
"testing"
88
"time"
99

10+
"github.com/smartcontractkit/chainlink-deployments-framework/chain/evm"
11+
"github.com/smartcontractkit/chainlink-deployments-framework/chain/evm/provider/rpcclient"
1012
"github.com/smartcontractkit/freeport"
1113
"github.com/stretchr/testify/assert"
1214
"github.com/stretchr/testify/require"
13-
14-
"github.com/smartcontractkit/chainlink-deployments-framework/chain/evm"
15-
"github.com/smartcontractkit/chainlink-deployments-framework/chain/evm/provider/rpcclient"
1615
)
1716

1817
func TestCTFAnvilChainProvider_Initialize(t *testing.T) {
@@ -517,3 +516,32 @@ func TestCTFAnvilChainProvider_Cleanup(t *testing.T) {
517516
assert.Nil(t, provider.container, "Container reference should remain nil after second cleanup")
518517
})
519518
}
519+
520+
func Test_shouldSaveCtfContainerLogs(t *testing.T) {
521+
tests := []struct {
522+
name string
523+
envvar string
524+
wantShouldSave bool
525+
wantPath string
526+
assertion assert.ErrorAssertionFunc
527+
}{
528+
{
529+
name: "environment variable not set",
530+
envvar: "",
531+
wantShouldSave: false,
532+
wantPath: "",
533+
assertion: assert.NoError,
534+
},
535+
}
536+
for _, tt := range tests {
537+
t.Run(tt.name, func(t *testing.T) {
538+
t.Setenv(saveContainerLogsEnvVar, tt.envvar)
539+
540+
gotShouldSave, gotPath, err := shouldSaveCtfContainerLogs()
541+
542+
tt.assertion(t, err)
543+
assert.Equal(t, tt.wantShouldSave, gotShouldSave)
544+
assert.Equal(t, tt.wantPath, gotPath)
545+
})
546+
}
547+
}

engine/cld/environment/anvil.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ type RPCs struct {
117117
type ChainConfig struct {
118118
ChainID string // chain id as per EIP-155
119119
HTTPRPCs []RPCs // http rpcs to connect to the chain
120+
Provider *evmprov.CTFAnvilChainProvider
120121
}
121122

122123
// AnvilChainsOutput represents the output of the newAnvilChains function.
@@ -287,6 +288,7 @@ func newAnvilChains(
287288

288289
chainConfigsBySelector[chainSelector] = ChainConfig{
289290
ChainID: chainIDStr,
291+
Provider: provider,
290292
HTTPRPCs: []RPCs{
291293
{
292294
External: provider.GetNodeHTTPURL(),

engine/cld/legacy/cli/mcmsv2/mcms_v2.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,13 @@ func buildExecuteForkCommand(lggr logger.Logger, domain cldf_domain.Domain, prop
619619
if err != nil {
620620
return fmt.Errorf("error creating config: %w", err)
621621
}
622+
defer func() {
623+
for _, chainConfig := range cfg.forkedEnv.ChainConfigs {
624+
if chainConfig.Provider != nil {
625+
chainConfig.Provider.Cleanup(cmd.Context())
626+
}
627+
}
628+
}()
622629

623630
// get the chain URL, chain ID and MCM contract address
624631
url := cfg.forkedEnv.ChainConfigs[cfg.chainSelector].HTTPRPCs[0].External

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ require (
3434
github.com/smartcontractkit/chainlink-protos/job-distributor v0.17.0
3535
github.com/smartcontractkit/chainlink-protos/op-catalog v0.0.4
3636
github.com/smartcontractkit/chainlink-testing-framework/framework v0.11.3
37+
github.com/smartcontractkit/chainlink-testing-framework/lib v1.54.6
3738
github.com/smartcontractkit/chainlink-testing-framework/seth v1.51.2
3839
github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20250815105909-75499abc4335
3940
github.com/smartcontractkit/freeport v0.1.2
@@ -227,7 +228,7 @@ require (
227228
github.com/rivo/uniseg v0.4.7 // indirect
228229
github.com/rogpeppe/go-internal v1.13.1 // indirect
229230
github.com/rs/cors v1.11.1 // indirect
230-
github.com/rs/zerolog v1.33.0 // indirect
231+
github.com/rs/zerolog v1.33.0
231232
github.com/russross/blackfriday/v2 v2.1.0 // indirect
232233
github.com/sagikazarmark/locafero v0.11.0 // indirect
233234
github.com/samber/lo v1.49.1 // indirect
@@ -284,7 +285,6 @@ require (
284285
go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect
285286
go.opentelemetry.io/otel/trace v1.37.0 // indirect
286287
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
287-
go.uber.org/atomic v1.11.0 // indirect
288288
go.uber.org/multierr v1.11.0 // indirect
289289
go.uber.org/ratelimit v0.3.1 // indirect
290290
golang.org/x/net v0.43.0 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,8 @@ github.com/smartcontractkit/chainlink-sui v0.0.0-20251013155034-5f85c5f450ab h1:
703703
github.com/smartcontractkit/chainlink-sui v0.0.0-20251013155034-5f85c5f450ab/go.mod h1:VlyZhVw+a93Sk8rVHOIH6tpiXrMzuWLZrjs1eTIExW8=
704704
github.com/smartcontractkit/chainlink-testing-framework/framework v0.11.3 h1:crYKFHTxxt1TNYuPOptjVyJdW4wO15aV5vVuEeLhICY=
705705
github.com/smartcontractkit/chainlink-testing-framework/framework v0.11.3/go.mod h1:ssfyl4ynbxSyASGztjuAxhsum5i6uZSHM7Dd0v2p8sc=
706+
github.com/smartcontractkit/chainlink-testing-framework/lib v1.54.6 h1:t1db5+sEbmw/26xQVDqyeY448V4RW8xtAl4eNGpd0uw=
707+
github.com/smartcontractkit/chainlink-testing-framework/lib v1.54.6/go.mod h1:dgwtcefGr+0i+C2S6V/Xgntzm7E5CPxXMyi2OnQvnHI=
706708
github.com/smartcontractkit/chainlink-testing-framework/seth v1.51.2 h1:ZJ/8Jx6Be5//TyjPi1pS1uotnmcYq5vVkSyISIymSj8=
707709
github.com/smartcontractkit/chainlink-testing-framework/seth v1.51.2/go.mod h1:kHYJnZUqiPF7/xN5273prV+srrLJkS77GbBXHLKQpx0=
708710
github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20250815105909-75499abc4335 h1:7bxYNrPpygn8PUSBiEKn8riMd7CXMi/4bjTy0fHhcrY=

0 commit comments

Comments
 (0)