From fbbb42eab5e69a739f0639df543841b61dc85876 Mon Sep 17 00:00:00 2001 From: Robin1987China <41602358+Robin1987China@users.noreply.github.com> Date: Wed, 23 Sep 2026 10:22:22 +0800 Subject: [PATCH] fix(composite): forward OnEventf format arguments to wrapped logs compositeLog.OnEventf passed the variadic arguments as a single []interface{} argument, so every wrapped log rendered the format verbs against one slice value, producing output such as "session [FIX.4.4 %!s(int=7)] seq %!d(MISSING)" instead of "session FIX.4.4 seq 7". --- log/composite/composite_log.go | 2 +- log/composite/composite_log_test.go | 56 +++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/log/composite/composite_log.go b/log/composite/composite_log.go index 8de3b85e2..549c38eb4 100644 --- a/log/composite/composite_log.go +++ b/log/composite/composite_log.go @@ -43,7 +43,7 @@ func (l compositeLog) OnEvent(s string) { func (l compositeLog) OnEventf(format string, a ...interface{}) { for _, log := range l.logs { - log.OnEventf(format, a) + log.OnEventf(format, a...) } } diff --git a/log/composite/composite_log_test.go b/log/composite/composite_log_test.go index 690b10a44..894d1a44a 100644 --- a/log/composite/composite_log_test.go +++ b/log/composite/composite_log_test.go @@ -107,3 +107,59 @@ func (suite *CompositeLogTestSuite) TearDownTest() { func TestCompositeLogTestSuite(t *testing.T) { suite.Run(t, new(CompositeLogTestSuite)) } + +// recordingLog records the events it is handed so a test can assert on what the +// composite log forwarded to its wrapped logs. +type recordingLog struct { + events []string +} + +func (r *recordingLog) OnIncoming([]byte) {} + +func (r *recordingLog) OnOutgoing([]byte) {} + +func (r *recordingLog) OnEvent(s string) { r.events = append(r.events, s) } + +func (r *recordingLog) OnEventf(format string, a ...interface{}) { + r.events = append(r.events, fmt.Sprintf(format, a...)) +} + +// recordingLogFactory hands out one pre-built recordingLog. +type recordingLogFactory struct { + log *recordingLog +} + +func (f recordingLogFactory) Create() (quickfix.Log, error) { return f.log, nil } + +func (f recordingLogFactory) CreateSessionLog(quickfix.SessionID) (quickfix.Log, error) { + return f.log, nil +} + +func TestCompositeLogOnEventfExpandsFormatArgs(t *testing.T) { + tests := []struct { + name string + format string + args []interface{} + expected string + }{ + {"single string arg", "session %s", []interface{}{"FIX.4.4"}, "session FIX.4.4"}, + {"mixed args", "session %s seq %d", []interface{}{"FIX.4.4", 7}, "session FIX.4.4 seq 7"}, + {"slice arg", "tags %v count %d", []interface{}{[]int{7, 9}, 2}, "tags [7 9] count 2"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + first, second := &recordingLog{}, &recordingLog{} + l, err := NewLogFactory([]quickfix.LogFactory{ + recordingLogFactory{first}, + recordingLogFactory{second}, + }).Create() + require.NoError(t, err) + + l.OnEventf(tt.format, tt.args...) + + require.Equal(t, []string{tt.expected}, first.events) + require.Equal(t, []string{tt.expected}, second.events) + }) + } +}