Skip to content

Commit c2cd79a

Browse files
authored
Merge pull request #672 from ackleymi/new-log-impls
Adds SQL, Mongo, and Composite Log Implementations
2 parents b7d706f + b781a85 commit c2cd79a

22 files changed

+1036
-29
lines changed

_test/test-server/main.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/quickfixgo/quickfix/config"
1818
field "github.com/quickfixgo/quickfix/gen/field"
1919
tag "github.com/quickfixgo/quickfix/gen/tag"
20+
filelog "github.com/quickfixgo/quickfix/log/file"
2021
"github.com/quickfixgo/quickfix/store/file"
2122
"github.com/quickfixgo/quickfix/store/mongo"
2223
)
@@ -132,7 +133,7 @@ func main() {
132133
return
133134
}
134135

135-
fileLogFactory, err := quickfix.NewFileLogFactory(appSettings)
136+
fileLogFactory, err := filelog.NewLogFactory(appSettings)
136137
if err != nil {
137138
fmt.Println("Error creating file log factory:", err)
138139
return

accepter_test.go renamed to acceptor_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ func TestAcceptor_SetTLSConfig(t *testing.T) {
9898
_, err := genericSettings.AddSession(sessionSettings)
9999
require.NoError(t, err)
100100

101-
logger, err := NewScreenLogFactory().Create()
101+
logger, err := NewNullLogFactory().Create()
102102
require.NoError(t, err)
103103
acceptor := &Acceptor{settings: genericSettings, globalLog: logger}
104104
defer acceptor.Stop()

config/configuration.go

+99-5
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,100 @@ const (
849849
// Valid Values:
850850
// - A valid path
851851
FileLogPath string = "FileLogPath"
852+
853+
// SQLLogDriver sets the name of the database driver to use for application logs (see https://go.dev/wiki/SQLDrivers for the list of available drivers).
854+
// SQLLogDriver is only relevant if also using sql.NewLogFactory(..) in code
855+
// when creating your LogFactory for your initiator or acceptor.
856+
//
857+
// Required: Only if using a sql db as your Log
858+
//
859+
// Default: N/A
860+
//
861+
// Valid Values:
862+
// - See https://go.dev/wiki/SQLDrivers
863+
SQLLogDriver string = "SQLLogDriver"
864+
865+
// SQLLogDataSourceName sets the driver-specific data source name of the database to use for application logs.
866+
// This usually consists of at least a database name and connection information.
867+
// SQLLogDataSourceName is only relevant if also using sql.NewLogFactory(..) in code
868+
// when creating your LogFactory for your initiator or acceptor.
869+
//
870+
// See https://pkg.go.dev/database/sql#Open for more information.
871+
//
872+
// Required: Only if using a sql db as your Log.
873+
//
874+
// Default: N/A
875+
//
876+
// Valid Values:
877+
// - A string correspondinng to a datasource
878+
SQLLogDataSourceName string = "SQLLogDataSourceName"
879+
880+
// SQLLogConnMaxLifetime sets the maximum duration of time that a database connection may be reused.
881+
// See https://pkg.go.dev/database/sql#DB.SetConnMaxLifetime for more information.
882+
//
883+
// If your database server has a config option to close inactive connections after some duration (e.g. MySQL "wait_timeout"),
884+
// set SQLLogConnMaxLifetime to a value less than that duration.
885+
//
886+
// Example Values:
887+
// - SQLLogConnMaxLifetime=14400s # 14400 seconds
888+
// - SQLLogConnMaxLifetime=2h45m # 2 hours and 45 minutes
889+
//
890+
// SQLLogConnMaxLifetime is only relevant if also using sql.NewLogFactory(..) in code
891+
// when creating your LogFactory for your initiator or acceptor.
892+
//
893+
// Required: No
894+
//
895+
// Default: 0 (forever)
896+
//
897+
// Valid Values:
898+
// - A valid go time.Duration
899+
SQLLogConnMaxLifetime string = "SQLLogConnMaxLifetime"
900+
901+
// MongoLogConnection sets the MongoDB connection URL to use for application logs.
902+
//
903+
// See https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo#Connect for more information.
904+
//
905+
// MongoLogConnection is only relevant if also using mongo.NewLogFactory(..) in code
906+
// when creating your LogFactory for your initiator or acceptor.
907+
//
908+
// Required: Only if using MongoDB as your Log.
909+
//
910+
// Default: N/A
911+
//
912+
// Valid Values:
913+
// - A string representing a MongoDB connection
914+
MongoLogConnection string = "MongoLogConnection"
915+
916+
// MongoLogDatabase sets the MongoDB-specific name of the database to use for application logs.
917+
//
918+
// See https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo#Connect for more information.
919+
//
920+
// MongoLogDatabase is only relevant if also using mongo.NewLogFactory(..) in code
921+
// when creating your LogFactory for your initiator or acceptor.
922+
//
923+
// Required: Only if using MongoDB as your Log.
924+
//
925+
// Default: N/A
926+
//
927+
// Valid Values:
928+
// - A string corresponding to a MongoDB database
929+
MongoLogDatabase string = "MongoLogDatabase"
930+
931+
// MongoLogReplicaSet sets the MongoDB replica set to use for application logs.
932+
// This is optional.
933+
//
934+
// See https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo#Connect for more information.
935+
//
936+
// MongoLogReplicaSet is only relevant if also using mongo.NewLogFactory(..) in code
937+
// when creating your LogFactory for your initiator or acceptor.
938+
//
939+
// Required: No
940+
//
941+
// Default: N/A
942+
//
943+
// Valid Values:
944+
// - A string corresponding to a MongoDB replica set
945+
MongoLogReplicaSet string = "MongoLogReplicaSet"
852946
)
853947

854948
const (
@@ -895,7 +989,7 @@ const (
895989
// - N
896990
FileStoreSync string = "FileStoreSync"
897991

898-
// SQLStoreDriver sets the name of the database driver to use (see https://go.dev/wiki/SQLDrivers for the list of available drivers).
992+
// SQLStoreDriver sets the name of the database driver to use for message storage (see https://go.dev/wiki/SQLDrivers for the list of available drivers).
899993
// SQLStoreDriver is only relevant if also using sql.NewStoreFactory(..) in code
900994
// when creating your MessageStoreFactory for your initiator or acceptor.
901995
//
@@ -907,7 +1001,7 @@ const (
9071001
// - See https://go.dev/wiki/SQLDrivers
9081002
SQLStoreDriver string = "SQLStoreDriver"
9091003

910-
// SQLStoreDataSourceName sets the driver-specific data source name of the database to use.
1004+
// SQLStoreDataSourceName sets the driver-specific data source name of the database to use for messagge storage.
9111005
// This usually consists of at least a database name and connection information.
9121006
// SQLStoreDataSourceName is only relevant if also using sql.NewStoreFactory(..) in code
9131007
// when creating your MessageStoreFactory for your initiator or acceptor.
@@ -943,7 +1037,7 @@ const (
9431037
// - A valid go time.Duration
9441038
SQLStoreConnMaxLifetime string = "SQLStoreConnMaxLifetime"
9451039

946-
// MongoStoreConnection sets the MongoDB connection URL to use.
1040+
// MongoStoreConnection sets the MongoDB connection URL to use for message storage.
9471041
//
9481042
// See https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo#Connect for more information.
9491043
//
@@ -958,7 +1052,7 @@ const (
9581052
// - A string representing a MongoDB connection
9591053
MongoStoreConnection string = "MongoStoreConnection"
9601054

961-
// MongoStoreDatabase sets the MongoDB-specific name of the database to use.
1055+
// MongoStoreDatabase sets the MongoDB-specific name of the database to use for message storage.
9621056
//
9631057
// See https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo#Connect for more information.
9641058
//
@@ -973,7 +1067,7 @@ const (
9731067
// - A string corresponding to a MongoDB database
9741068
MongoStoreDatabase string = "MongoStoreDatabase"
9751069

976-
// MongoStoreReplicaSet sets the MongoDB replica set to use.
1070+
// MongoStoreReplicaSet sets the MongoDB replica set to use for message storage.
9771071
// This is optional.
9781072
//
9791073
// See https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo#Connect for more information.

log/composite/composite_log.go

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright (c) quickfixengine.org All rights reserved.
2+
//
3+
// This file may be distributed under the terms of the quickfixengine.org
4+
// license as defined by quickfixengine.org and appearing in the file
5+
// LICENSE included in the packaging of this file.
6+
//
7+
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
8+
// THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
9+
// PARTICULAR PURPOSE.
10+
//
11+
// See http://www.quickfixengine.org/LICENSE for licensing information.
12+
//
13+
// Contact [email protected] if any conditions of this licensing
14+
// are not clear to you.
15+
16+
package composite
17+
18+
import (
19+
"github.com/quickfixgo/quickfix"
20+
)
21+
22+
type compositeLog struct {
23+
logs []quickfix.Log
24+
}
25+
26+
func (l compositeLog) OnIncoming(s []byte) {
27+
for _, log := range l.logs {
28+
log.OnIncoming(s)
29+
}
30+
}
31+
32+
func (l compositeLog) OnOutgoing(s []byte) {
33+
for _, log := range l.logs {
34+
log.OnOutgoing(s)
35+
}
36+
}
37+
38+
func (l compositeLog) OnEvent(s string) {
39+
for _, log := range l.logs {
40+
log.OnEvent(s)
41+
}
42+
}
43+
44+
func (l compositeLog) OnEventf(format string, a ...interface{}) {
45+
for _, log := range l.logs {
46+
log.OnEventf(format, a)
47+
}
48+
}
49+
50+
type compositeLogFactory struct {
51+
logFactories []quickfix.LogFactory
52+
}
53+
54+
func (clf compositeLogFactory) Create() (quickfix.Log, error) {
55+
logs := []quickfix.Log{}
56+
for _, lf := range clf.logFactories {
57+
log, err := lf.Create()
58+
if err != nil {
59+
return nil, err
60+
}
61+
logs = append(logs, log)
62+
}
63+
return compositeLog{logs}, nil
64+
}
65+
66+
func (clf compositeLogFactory) CreateSessionLog(sessionID quickfix.SessionID) (quickfix.Log, error) {
67+
logs := []quickfix.Log{}
68+
for _, lf := range clf.logFactories {
69+
log, err := lf.CreateSessionLog(sessionID)
70+
if err != nil {
71+
return nil, err
72+
}
73+
logs = append(logs, log)
74+
}
75+
return compositeLog{logs}, nil
76+
}
77+
78+
// NewLogFactory creates an instance of LogFactory that writes messages and events to stdout.
79+
func NewLogFactory(logfactories []quickfix.LogFactory) quickfix.LogFactory {
80+
return compositeLogFactory{logfactories}
81+
}

log/composite/composite_log_test.go

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright (c) quickfixengine.org All rights reserved.
2+
//
3+
// This file may be distributed under the terms of the quickfixengine.org
4+
// license as defined by quickfixengine.org and appearing in the file
5+
// LICENSE included in the packaging of this file.
6+
//
7+
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
8+
// THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
9+
// PARTICULAR PURPOSE.
10+
//
11+
// See http://www.quickfixengine.org/LICENSE for licensing information.
12+
//
13+
// Contact [email protected] if any conditions of this licensing
14+
// are not clear to you.
15+
16+
package composite
17+
18+
import (
19+
"fmt"
20+
"log"
21+
"os"
22+
"path"
23+
"strings"
24+
"testing"
25+
"time"
26+
27+
_ "github.com/mattn/go-sqlite3"
28+
"github.com/quickfixgo/quickfix"
29+
"github.com/quickfixgo/quickfix/log/file"
30+
"github.com/quickfixgo/quickfix/log/mongo"
31+
"github.com/quickfixgo/quickfix/log/screen"
32+
"github.com/quickfixgo/quickfix/log/sql"
33+
"github.com/stretchr/testify/require"
34+
"github.com/stretchr/testify/suite"
35+
)
36+
37+
// CompositeLogTestSuite runs tests for the MongoLog impl of Log.
38+
type CompositeLogTestSuite struct {
39+
suite.Suite
40+
sqlLogRootPath string
41+
settings *quickfix.Settings
42+
sessionID quickfix.SessionID
43+
}
44+
45+
func (suite *CompositeLogTestSuite) SetupTest() {
46+
mongoDbCxn := os.Getenv("MONGODB_TEST_CXN")
47+
if len(mongoDbCxn) <= 0 {
48+
log.Println("MONGODB_TEST_CXN environment arg is not provided, skipping...")
49+
suite.T().SkipNow()
50+
}
51+
mongoDatabase := "automated_testing_database"
52+
mongoReplicaSet := "replicaset"
53+
54+
// create settings
55+
sessionID := quickfix.SessionID{BeginString: "FIX.4.4", SenderCompID: "SENDER", TargetCompID: "TARGET"}
56+
logPath := path.Join(os.TempDir(), fmt.Sprintf("TestLogStore-%d", os.Getpid()))
57+
suite.sqlLogRootPath = path.Join(os.TempDir(), fmt.Sprintf("SQLLogTestSuite-%d", os.Getpid()))
58+
err := os.MkdirAll(suite.sqlLogRootPath, os.ModePerm)
59+
require.Nil(suite.T(), err)
60+
sqlDriver := "sqlite3"
61+
sqlDsn := path.Join(suite.sqlLogRootPath, fmt.Sprintf("%d.db", time.Now().UnixNano()))
62+
63+
settings, err := quickfix.ParseSettings(strings.NewReader(fmt.Sprintf(`
64+
[DEFAULT]
65+
MongoLogConnection=%s
66+
MongoLogDatabase=%s
67+
MongoLogReplicaSet=%s
68+
FileLogPath=%s
69+
SQLLogDriver=%s
70+
SQLLogDataSourceName=%s
71+
SQLLogConnMaxLifetime=14400s
72+
73+
[SESSION]
74+
BeginString=%s
75+
SenderCompID=%s
76+
TargetCompID=%s`, mongoDbCxn, mongoDatabase, mongoReplicaSet, logPath, sqlDriver, sqlDsn, sessionID.BeginString, sessionID.SenderCompID, sessionID.TargetCompID)))
77+
require.Nil(suite.T(), err)
78+
79+
suite.sessionID = sessionID
80+
suite.settings = settings
81+
}
82+
83+
func (suite *CompositeLogTestSuite) TestCreateLogNoSession() {
84+
85+
mngoLogFactory := mongo.NewLogFactory(suite.settings)
86+
sqlLogFactory := sql.NewLogFactory(suite.settings)
87+
// create log
88+
_, err := NewLogFactory([]quickfix.LogFactory{mngoLogFactory, sqlLogFactory}).Create()
89+
require.Nil(suite.T(), err)
90+
}
91+
92+
func (suite *CompositeLogTestSuite) TestCreateLogSession() {
93+
94+
screenLogFactory := screen.NewLogFactory()
95+
fileLogFactory, err := file.NewLogFactory(suite.settings)
96+
require.Nil(suite.T(), err)
97+
98+
// create log
99+
_, err = NewLogFactory([]quickfix.LogFactory{screenLogFactory, fileLogFactory}).CreateSessionLog(suite.sessionID)
100+
require.Nil(suite.T(), err)
101+
}
102+
103+
func (suite *CompositeLogTestSuite) TearDownTest() {
104+
os.RemoveAll(suite.sqlLogRootPath)
105+
}
106+
107+
func TestCompositeLogTestSuite(t *testing.T) {
108+
suite.Run(t, new(CompositeLogTestSuite))
109+
}

0 commit comments

Comments
 (0)