diff --git a/creators/basecreator.go b/creators/basecreator.go index cd3c294..99b7d5f 100644 --- a/creators/basecreator.go +++ b/creators/basecreator.go @@ -118,3 +118,7 @@ func (br *BaseCreator) CallDepth() int { func (br *BaseCreator) Shutdown() { // No cleanup or shutdown actions needed for BaseCreator. } + +func (br *BaseCreator) IsReady() bool { + return true +} diff --git a/creators/brokerrecorder.go b/creators/brokerrecorder.go index 5178fd7..4280210 100644 --- a/creators/brokerrecorder.go +++ b/creators/brokerrecorder.go @@ -36,8 +36,21 @@ func NewBrokerCreator(brokers []string, topic string, logName types.LogCreatorNa config := sarama.NewConfig() config.Producer.RequiredAcks = sarama.WaitForLocal config.Producer.Compression = sarama.CompressionSnappy + config.ChannelBufferSize = 1024 * 10 + config.Producer.MaxMessageBytes = 1024 * 1024 * 10 + config.Producer.Retry.Max = 10 + config.Producer.Retry.Backoff = 10 * time.Second + + var producer sarama.AsyncProducer + var err error + for i := 0; i < 5; i++ { + producer, err = sarama.NewAsyncProducer(brokers, config) + if err == nil { + break + } + time.Sleep(5 * time.Second) + } - producer, err := sarama.NewAsyncProducer(brokers, config) if err != nil { return nil, err } @@ -181,3 +194,7 @@ func (br *BrokerCreator) CallDepth() int { func (br *BrokerCreator) Shutdown() { br.producer.Close() } + +func (br *BrokerCreator) IsReady() bool { + return true +} diff --git a/creators/filerecorder.go b/creators/filerecorder.go index 1e3dc0f..0c3abd0 100644 --- a/creators/filerecorder.go +++ b/creators/filerecorder.go @@ -128,3 +128,7 @@ func (fr *FileCreator) CallDepth() int { func (fr *FileCreator) Shutdown() { // No cleanup or shutdown actions needed for FileCreator. } + +func (fr *FileCreator) IsReady() bool { + return true +} diff --git a/go.mod b/go.mod index 7f7ff5a..3be8ad4 100644 --- a/go.mod +++ b/go.mod @@ -2,11 +2,11 @@ module github.com/Eyup-Devop/logtor go 1.21.4 -require github.com/IBM/sarama v1.42.1 +require github.com/IBM/sarama v1.43.3 require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/eapache/go-resiliency v1.4.0 // indirect + github.com/eapache/go-resiliency v1.7.0 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect github.com/eapache/queue v1.1.0 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -18,9 +18,9 @@ require ( github.com/jcmturner/gofork v1.7.6 // indirect github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect - github.com/klauspost/compress v1.17.2 // indirect - github.com/pierrec/lz4/v4 v4.1.18 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect - golang.org/x/crypto v0.15.0 // indirect - golang.org/x/net v0.18.0 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/net v0.28.0 // indirect ) diff --git a/go.sum b/go.sum index fcf82ad..33347ad 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,14 @@ github.com/IBM/sarama v1.42.1 h1:wugyWa15TDEHh2kvq2gAy1IHLjEjuYOYgXz/ruC/OSQ= github.com/IBM/sarama v1.42.1/go.mod h1:Xxho9HkHd4K/MDUo/T/sOqwtX/17D33++E9Wib6hUdQ= +github.com/IBM/sarama v1.43.3 h1:Yj6L2IaNvb2mRBop39N7mmJAHBVY3dTPncr3qGVkxPA= +github.com/IBM/sarama v1.43.3/go.mod h1:FVIRaLrhK3Cla/9FfRF5X9Zua2KpS3SYIXxhac1H+FQ= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/eapache/go-resiliency v1.4.0 h1:3OK9bWpPk5q6pbFAaYSEwD9CLUSHG8bnZuqX2yMt3B0= github.com/eapache/go-resiliency v1.4.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= +github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA= +github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws= github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= @@ -34,8 +38,12 @@ github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZ github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= +github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -52,6 +60,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -61,6 +71,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/handler.go b/handler.go index ec473bf..7b916f2 100644 --- a/handler.go +++ b/handler.go @@ -35,7 +35,7 @@ func (l *Logtor) GetCurrentLogCreator(w http.ResponseWriter, r *http.Request) { result := struct { CurrentLogCreator string `json:"current_log_creator"` }{ - CurrentLogCreator: string(l.activeLogCreator.LogName()), + CurrentLogCreator: string(l.currentLogCreator.LogName()), } jsonResult, err := json.Marshal(result) if err != nil { @@ -65,7 +65,7 @@ func (l *Logtor) ChangeActiveLogCreator(w http.ResponseWriter, r *http.Request) w.WriteHeader(http.StatusBadRequest) return } - oldLogCreator := string(l.activeLogCreator.LogName()) + oldLogCreator := string(l.currentLogCreator.LogName()) var currentLogCreator string if v, ok := payload["log_creator"]; ok { l.changeMutex.RUnlock() diff --git a/handler_test.go b/handler_test.go index e632a02..d6f93f0 100644 --- a/handler_test.go +++ b/handler_test.go @@ -27,7 +27,7 @@ func TestGetLogCreatorListHandlerFunc(t *testing.T) { t.Error(err) } - newLogtor := logtor.NewLogtor() + newLogtor := logtor.New() newLogtor.AddLogCreators(baseCreator, fileCreator, brokerCreator) newLogtor.SetLogLevel(types.TRACE) @@ -71,7 +71,7 @@ func TestGetCurrentLogCreatorHandlerFunc(t *testing.T) { t.Error(err) } - newLogtor := logtor.NewLogtor() + newLogtor := logtor.New() newLogtor.AddLogCreators(baseCreator, fileCreator, brokerCreator) newLogtor.SetLogLevel(types.TRACE) @@ -115,7 +115,7 @@ func TestChangeActiveLogCreatorHandlerFunc(t *testing.T) { t.Error(err) } - newLogtor := logtor.NewLogtor() + newLogtor := logtor.New() newLogtor.AddLogCreators(baseCreator, fileCreator, brokerCreator) newLogtor.SetLogLevel(types.TRACE) @@ -169,7 +169,7 @@ func TestGetLogLevelListHandlerFunc(t *testing.T) { t.Error(err) } - newLogtor := logtor.NewLogtor() + newLogtor := logtor.New() newLogtor.AddLogCreators(baseCreator, fileCreator, brokerCreator) newLogtor.SetLogLevel(types.TRACE) @@ -213,7 +213,7 @@ func TestGetActiveLogLevelHandlerFunc(t *testing.T) { t.Error(err) } - newLogtor := logtor.NewLogtor() + newLogtor := logtor.New() newLogtor.AddLogCreators(baseCreator, fileCreator, brokerCreator) newLogtor.SetLogLevel(types.TRACE) @@ -257,7 +257,7 @@ func TestSetLogLevelHandlerFunc(t *testing.T) { t.Error(err) } - newLogtor := logtor.NewLogtor() + newLogtor := logtor.New() newLogtor.AddLogCreators(baseCreator, fileCreator, brokerCreator) newLogtor.SetLogLevel(types.TRACE) diff --git a/logcreator.go b/logcreator.go index fb411e7..89c71e6 100644 --- a/logcreator.go +++ b/logcreator.go @@ -25,6 +25,9 @@ type LogCreator interface { // CallDepth returns the call depth for the log creator. CallDepth() int + // IsReady() returns true if the log creator is ready to log messages. + IsReady() bool + // Shutdown performs any necessary cleanup or shutdown operations for the log creator. Shutdown() } diff --git a/logtor.go b/logtor.go index 554f073..59fe8bd 100644 --- a/logtor.go +++ b/logtor.go @@ -17,26 +17,34 @@ package logtor import ( + "reflect" "sync" "github.com/Eyup-Devop/logtor/types" ) -// NewLogtor creates a new Logtor instance with default settings. +var defaultCreatorName string = "defaultCreator" + +// New creates a new Logtor instance with default settings. // // It initializes a Logtor with an empty list of log creators, a global log level set to NONE, -// and no active log creator selected. +// and no current log creator selected. // // Returns: // - *Logtor: A pointer to the newly created Logtor. -func NewLogtor() *Logtor { +func New() *Logtor { return &Logtor{ - logCreatorList: make(map[types.LogCreatorName]LogCreator), - logLevel: types.NONE, - activeLogCreator: nil, + logCreatorList: make(map[types.LogCreatorName]LogCreator), + logLevel: types.NONE, + currentLogCreator: nil, } } +func (l *Logtor) WithDefaultCreator(creator LogCreator) *Logtor { + l.defaultCreator = creator + return l +} + // Logtor is a central logging manager that coordinates multiple log creators and log levels. // // It manages a list of log creators, allowing you to log messages to different destinations (e.g., file, console) simultaneously. @@ -45,13 +53,14 @@ func NewLogtor() *Logtor { // Fields: // - logCreatorList: A map of LogCreatorName to LogCreator, representing registered log creator. // - logLevel: The global log level that controls which log messages are created. -// - activeLogCreator: The currently active log creator for logging messages. +// - currentLogCreator: The currently active log creator for logging messages. // - changeMutex: A read-write mutex to control concurrent access to Logtor's fields. type Logtor struct { - logCreatorList map[types.LogCreatorName]LogCreator - logLevel types.LogLevel - activeLogCreator LogCreator - changeMutex sync.RWMutex + logCreatorList map[types.LogCreatorName]LogCreator + logLevel types.LogLevel + currentLogCreator LogCreator + changeMutex sync.RWMutex + defaultCreator LogCreator } // SetLogLevel sets the global log level for the Logtor instance. @@ -62,8 +71,7 @@ type Logtor struct { // Parameters: // - logLevel: The new global log level to set for the Logtor. func (l *Logtor) SetLogLevel(logLevel types.LogLevel) bool { - switch logLevel { - case types.NONE, types.FATAL, types.ERROR, types.WARN, types.DEBUG, types.INFO, types.TRACE: + if logLevel.IsValid() { l.logLevel = logLevel return true } @@ -73,7 +81,7 @@ func (l *Logtor) SetLogLevel(logLevel types.LogLevel) bool { // LogLevel returns the current global log level of the Logtor instance. // // Use this method to retrieve the current global log level, which determines which log messages -// are recorded and displayed. The returned value is of type LogLevelType. +// are recorded or displayed. The returned value is of type LogLevelType. // // Returns: // - LogLevelType: The current global log level. @@ -96,10 +104,10 @@ func (l *Logtor) LogLevel() types.LogLevel { func (l *Logtor) ChangeLogCreator(logCreatorName types.LogCreatorName) bool { l.changeMutex.RLock() defer l.changeMutex.RUnlock() - if l.logCreatorList[logCreatorName] == nil { + if _, ok := l.logCreatorList[logCreatorName]; !ok { return false } - l.activeLogCreator = l.logCreatorList[logCreatorName] + l.currentLogCreator = l.logCreatorList[logCreatorName] return true } @@ -111,7 +119,7 @@ func (l *Logtor) ChangeLogCreator(logCreatorName types.LogCreatorName) bool { // Returns: // - LogCreator: The currently active log creator. func (l *Logtor) LogCreator() LogCreator { - return l.activeLogCreator + return l.currentLogCreator } // LogIt logs a message at the specified log level using the currently active log creator. @@ -127,8 +135,10 @@ func (l *Logtor) LogCreator() LogCreator { // Returns: // - bool: True if the message was successfully logged; false if it was skipped due to the log level. func (l *Logtor) LogIt(level types.LogLevel, logMessage interface{}) bool { - if types.IsLogLevelAcceptable(l.LogLevel(), level) { - return l.activeLogCreator.LogIt(level, logMessage) + if l.logLevel.IsLogLevelAcceptable(level) && l.currentLogCreator.IsReady() { + return l.currentLogCreator.LogIt(level, logMessage) + } else if l.logLevel.IsLogLevelAcceptable(level) && !l.currentLogCreator.IsReady() && l.defaultCreator != nil { + return l.defaultCreator.LogIt(level, logMessage) } return false } @@ -147,9 +157,10 @@ func (l *Logtor) LogIt(level types.LogLevel, logMessage interface{}) bool { // Returns: // - bool: True if the message was successfully logged; false if it was skipped due to the log level. func (l *Logtor) LogItWithCallDepth(level types.LogLevel, callDepth int, logMessage interface{}) bool { - if types.IsLogLevelAcceptable(l.LogLevel(), level) { - l.activeLogCreator.LogItWithCallDepth(level, callDepth, logMessage) - return true + if types.IsLogLevelAcceptable(l.LogLevel(), level) && l.currentLogCreator.IsReady() { + return l.currentLogCreator.LogItWithCallDepth(level, callDepth, logMessage) + } else if l.logLevel.IsLogLevelAcceptable(level) && !l.currentLogCreator.IsReady() && l.defaultCreator != nil { + return l.defaultCreator.LogItWithCallDepth(level, callDepth, logMessage) } return false } @@ -165,12 +176,12 @@ func (l *Logtor) LogItWithCallDepth(level types.LogLevel, callDepth int, logMess func (l *Logtor) AddLogCreators(logCreators ...LogCreator) { l.changeMutex.Lock() for _, logCreator := range logCreators { - if logCreator != nil { + if logCreator != nil && !reflect.ValueOf(logCreator).IsNil() { l.logCreatorList[logCreator.LogName()] = logCreator } } l.changeMutex.Unlock() - if l.activeLogCreator == nil { + if l.currentLogCreator == nil { l.ChangeLogCreator(logCreators[0].LogName()) } } diff --git a/logtor_test.go b/logtor_test.go index eb22eca..e067305 100644 --- a/logtor_test.go +++ b/logtor_test.go @@ -30,7 +30,7 @@ func TestLogtorUsingBaseCreatorWithString(t *testing.T) { t.Error(err) } - newLogtor := logtor.NewLogtor() + newLogtor := logtor.New() newLogtor.AddLogCreators(baseCreator) newLogtor.SetLogLevel(types.TRACE) @@ -55,7 +55,7 @@ func TestLogtorUsingFileCreatorWithString(t *testing.T) { t.Error(err) } - newLogtor := logtor.NewLogtor() + newLogtor := logtor.New() newLogtor.AddLogCreators(fileCreator) newLogtor.SetLogLevel(types.TRACE) @@ -81,7 +81,7 @@ func TestLogtorUsingBrokerCreatorWithString(t *testing.T) { t.Error(err) } - newLogtor := logtor.NewLogtor() + newLogtor := logtor.New() newLogtor.AddLogCreators(brokerCreator) newLogtor.SetLogLevel(types.TRACE) @@ -117,7 +117,7 @@ func TestLogtorUsingAllCreators(t *testing.T) { t.Error(err) } - newLogtor := logtor.NewLogtor() + newLogtor := logtor.New() newLogtor.AddLogCreators(baseCreator, fileCreator, brokerCreator) newLogtor.SetLogLevel(types.TRACE) diff --git a/types/types.go b/types/types.go index f670afd..432931d 100644 --- a/types/types.go +++ b/types/types.go @@ -99,3 +99,26 @@ func IsLogLevelAcceptable(selected, using LogLevel) bool { return false } } + +func (d LogLevel) IsValid() bool { + levels := GetLogLevelList() + _, ok := levels[d] + + return ok +} + +func (d LogLevel) IsLogLevelAcceptable(level LogLevel) bool { + return IsLogLevelAcceptable(d, level) +} + +func GetLogLevelList() map[LogLevel]struct{} { + return map[LogLevel]struct{}{ + FATAL: {}, + ERROR: {}, + WARN: {}, + DEBUG: {}, + INFO: {}, + TRACE: {}, + NONE: {}, + } +}