Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TT-1952] Write application logs for in-memory tests to file and safe in artifacts #16029

Merged
merged 29 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
692754d
try to split logs by level in in-memory tests
Tofel Jan 22, 2025
a9a605c
pass split logger to CL node
Tofel Jan 22, 2025
b10043d
sync logs only if it's supported
Tofel Jan 22, 2025
3c0a1fc
add Sync() debug
Tofel Jan 22, 2025
db92c9e
add logger name to debug
Tofel Jan 22, 2025
afa34e7
do not add console writer
Tofel Jan 22, 2025
e869f7c
Merge branch 'develop' into tt-1952-split-in-memory-logs
gheorghestrimtu Feb 3, 2025
fe06c18
single file logger
gheorghestrimtu Feb 4, 2025
3d63e44
use different path for logs file, use new version for run-integration…
gheorghestrimtu Feb 4, 2025
97ac64b
add missing secrets to run-integration-tests.yml invocation
gheorghestrimtu Feb 4, 2025
07fc8e6
update to relative path
gheorghestrimtu Feb 4, 2025
d084a9b
modify action version and path of logs file
gheorghestrimtu Feb 4, 2025
3e29a52
update version of action and use abs path
gheorghestrimtu Feb 5, 2025
4ed7516
pulled develop
gheorghestrimtu Feb 5, 2025
5cc893e
update action version
gheorghestrimtu Feb 5, 2025
a1a426a
develop version of action
gheorghestrimtu Feb 5, 2025
b085237
revert some changes, delete old logger
gheorghestrimtu Feb 5, 2025
4d5e3f9
use experimental version of action
gheorghestrimtu Feb 5, 2025
756ab53
change version
gheorghestrimtu Feb 5, 2025
9b6fdac
change version
gheorghestrimtu Feb 5, 2025
36803cb
change version
gheorghestrimtu Feb 5, 2025
f3ca358
change version
gheorghestrimtu Feb 5, 2025
a3c6f11
update version
gheorghestrimtu Feb 5, 2025
63a2c8f
Merge branch 'develop' of github.com:smartcontractkit/chainlink into …
gheorghestrimtu Feb 6, 2025
7220018
clean up
gheorghestrimtu Feb 6, 2025
5d5b187
remove new tests
gheorghestrimtu Feb 6, 2025
9cc8781
take into account dir from test name
gheorghestrimtu Feb 6, 2025
42ae099
fix typo
gheorghestrimtu Feb 6, 2025
c5bb3a5
fix the lint error
gheorghestrimtu Feb 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .github/integration-in-memory-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ runner-test-matrix:
triggers:
- PR Integration CCIP Tests
test_cmd: cd integration-tests/smoke/ccip && go test ccip_messaging_test.go -timeout 12m -test.parallel=2 -count=1 -json

- id: smoke/ccip/ccip_message_limitations_test.go:*
path: integration-tests/smoke/ccip/ccip_message_limitations_test.go
test_env_type: in-memory
Expand All @@ -46,15 +45,14 @@ runner-test-matrix:
triggers:
- PR Integration CCIP Tests
test_cmd: cd integration-tests/smoke/ccip && go test ccip_fee_boosting_test.go -timeout 12m -test.parallel=2 -count=1 -json

- id: smoke/ccip/ccip_batching_test.go:*
path: integration-tests/smoke/ccip/ccip_batching_test.go
test_env_type: in-memory
runs_on: ubuntu-latest
triggers:
- PR Integration CCIP Tests
test_cmd: cd integration-tests/smoke/ccip && go test ccip_batching_test.go -timeout 25m -test.parallel=2 -count=1 -json

- id: smoke/ccip/ccip_add_chain_test.go:*
path: integration-tests/smoke/ccip/ccip_add_chain_test.go
test_env_type: in-memory
Expand Down Expand Up @@ -119,5 +117,4 @@ runner-test-matrix:
- PR Integration CCIP Tests
test_cmd: cd integration-tests/smoke/ccip/ && go test ccip_disable_lane_test.go -timeout 10m -test.parallel=1 -count=1 -json


# END: CCIP tests
4 changes: 2 additions & 2 deletions deployment/environment/memory/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ import (
solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config"

"github.com/smartcontractkit/chainlink/deployment"
"github.com/smartcontractkit/chainlink/deployment/logger"

"github.com/smartcontractkit/chainlink/v2/core/capabilities"
"github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
configv2 "github.com/smartcontractkit/chainlink/v2/core/config/toml"
"github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/logger/audit"
"github.com/smartcontractkit/chainlink/v2/core/services/chainlink"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore"
Expand Down Expand Up @@ -147,7 +147,7 @@ func NewNode(
})

// Set logging.
lggr := logger.TestLogger(t)
lggr := logger.NewSingleFileLogger(t)
lggr.SetLogLevel(logLevel)

// Create clients for the core node backed by sim.
Expand Down
150 changes: 150 additions & 0 deletions deployment/logger/single_file_logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package logger

import (
"fmt"
"log"
"os"
"path/filepath"
"runtime/debug"
"testing"
"time"

"go.uber.org/zap"
"go.uber.org/zap/zapcore"

// The Chainlink logger interface we're implementing:
corelogger "github.com/smartcontractkit/chainlink/v2/core/logger"
)

// SingleFileLogger is a wrapper around a zap SugaredLogger that implements
// Chainlink’s corelogger.Logger interface.
type SingleFileLogger struct {
*zap.SugaredLogger
}

// Ensure it truly implements the interface at compile time:
var _ corelogger.Logger = (*SingleFileLogger)(nil)

// NewSingleFileLogger creates a zap-based logger that writes everything to one file.
// The file name includes the test name + timestamp so that parallel tests don’t collide.
func NewSingleFileLogger(tb testing.TB) *SingleFileLogger {
// Our logs will go here so GH can upload them:
baseDir := "logs"

// For uniqueness, include test name + timestamp
filename := fmt.Sprintf("%s_%d.log", tb.Name(), time.Now().UnixNano())
dirOfFilename := filepath.Dir(filename)

dir, err := filepath.Abs(filepath.Join(baseDir, dirOfFilename))
if err != nil {
log.Fatalf("Failed to get absolute path for %q: %v", filepath.Join(baseDir, dirOfFilename), err)
}
if err := os.MkdirAll(dir, 0o755); err != nil {
log.Fatalf("Failed to create logs dir %q: %v", dir, err)
}

fullPath, err := filepath.Abs(filepath.Join(baseDir, filename))
if err != nil {
log.Fatalf("Failed to get absolute path for %q: %v", fullPath, err)
}
// Log the full path
log.Printf("Logging to %q", fullPath)
f, err := os.Create(fullPath)
if err != nil {
log.Fatalf("Failed to create %q: %v", fullPath, err)
}

// Auto-flush writer so we don't lose logs if the test fails abruptly
writer := &autoFlushWriter{file: f}

encCfg := zap.NewDevelopmentEncoderConfig()
encCfg.EncodeTime = zapcore.TimeEncoderOfLayout("15:04:05.000000000")

core := zapcore.NewCore(
zapcore.NewJSONEncoder(encCfg),
zapcore.AddSync(writer),
zap.DebugLevel,
)

zapLogger := zap.New(core, zap.AddCaller())
return &SingleFileLogger{zapLogger.Sugar()}
}

// autoFlushWriter flushes on every log write, so we don’t lose logs if the test crashes.
type autoFlushWriter struct {
file *os.File
}

func (w *autoFlushWriter) Write(p []byte) (n int, err error) {
n, err = w.file.Write(p)
if err == nil {
_ = w.file.Sync()
}
return n, err
}

func (w *autoFlushWriter) Sync() error {
return w.file.Sync()
}

// ----------------------------------------------------------------------------
// Implement the corelogger.Logger interface
// ----------------------------------------------------------------------------

func (l *SingleFileLogger) Name() string {
return l.Desugar().Name()
}

func (l *SingleFileLogger) Named(name string) corelogger.Logger {
// zap’s Named(...) returns a new *zap.Logger. We return a new SingleFileLogger wrapping it.
return &SingleFileLogger{l.SugaredLogger.Named(name)}
}

func (l *SingleFileLogger) Trace(args ...interface{}) {
// “Trace” in Chainlink’s interface is basically a debug-level call
l.Debug(args...)
}

func (l *SingleFileLogger) Tracef(format string, values ...interface{}) {
l.Debugf(format, values...)
}

func (l *SingleFileLogger) Tracew(msg string, keysAndValues ...interface{}) {
l.Debugw(msg, keysAndValues...)
}

func (l *SingleFileLogger) Critical(args ...interface{}) {
// “Critical” is typically mapped to an error-level call or fatal if you prefer
l.Error(args...)
}

func (l *SingleFileLogger) Criticalf(format string, values ...interface{}) {
l.Errorf(format, values...)
}

func (l *SingleFileLogger) Criticalw(msg string, keysAndValues ...interface{}) {
l.Errorw(msg, keysAndValues...)
}

func (l *SingleFileLogger) Helper(skip int) corelogger.Logger {
// Helper() is for skipping extra stack frames in error logs. We can do AddCallerSkip here:
return &SingleFileLogger{l.SugaredLogger.Desugar().WithOptions(zap.AddCallerSkip(skip)).Sugar()}
}

func (l *SingleFileLogger) Recover(panicErr interface{}) {
// Called on panics, typically you might add custom logic or stacktrace
if panicErr != nil {
l.Errorf("Recovering from panic: %v", panicErr)
debug.PrintStack()
}
}

func (l *SingleFileLogger) SetLogLevel(zapLevel zapcore.Level) {
// If you need dynamic level changes, you can store an AtomicLevel.
// If not, you can just do nothing or rebuild a new logger.
}

func (l *SingleFileLogger) With(args ...interface{}) corelogger.Logger {
// Adds extra fields to the logger. Return a new instance with them.
return &SingleFileLogger{l.SugaredLogger.With(args...)}
}
Loading