diff --git a/.gitignore b/.gitignore index 3855db3..d963bec 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ # Folders /bin/ -/pkg/ +# /pkg/ /build/ # Architecture specific extensions/prefixes @@ -28,7 +28,7 @@ ehthumbs.db Thumbs.db # Go specific -go.sum +# go.sum go.mod # Test binary, built with `go test -c` @@ -38,7 +38,7 @@ go.mod *.out # Project-specific -configs/*.toml +# configs/*.toml # Logs *.log diff --git a/cmd/main/main.go b/cmd/main/main.go index 3c10d16..35626c9 100644 --- a/cmd/main/main.go +++ b/cmd/main/main.go @@ -3,20 +3,23 @@ package main import ( "caatsm/internal/config" "caatsm/internal/nats" - "caatsm/pkg/utils" + + "fmt" ) func main() { cfg, err := config.LoadConfig() if err != nil { - utils.Logger.WithError(err).Fatal("Error loading config") + fmt.Printf("Error loading configuration: %v\n", err) + return } if err := config.ValidateConfig(cfg); err != nil { - utils.Logger.WithError(err).Fatal("Config validation error") + fmt.Printf("Invalid configuration: %v\n", err) + return } - utils.Logger.Info("Loaded configuration successfully") + fmt.Println("Loaded configuration successfully") subscribe := nats.NewNatsHandler(cfg) subscribe.Subscribe() diff --git a/configs/.env b/configs/.env new file mode 100644 index 0000000..64d75e9 --- /dev/null +++ b/configs/.env @@ -0,0 +1 @@ +GO_ENV=dev \ No newline at end of file diff --git a/configs/config.dev.toml b/configs/config.dev.toml new file mode 100644 index 0000000..daa7635 --- /dev/null +++ b/configs/config.dev.toml @@ -0,0 +1,14 @@ +[nats] +url = "nats://localhost:4222" +client = "serial-client" +cluster = "tele-cluster" + +[subscription] +topic = "Telegram.Serial" +queue = "tele-queue" + +[timeouts] +server = "5s" +reconnect_wait = "5s" +close = "10s" +ack_wait = "5s" \ No newline at end of file diff --git a/configs/logger.dev.json b/configs/logger.dev.json new file mode 100644 index 0000000..d21309a --- /dev/null +++ b/configs/logger.dev.json @@ -0,0 +1,22 @@ +{ + "zapConfig": { + "level": "debug", + "encoding": "json", + "outputPaths": ["stdout"], + "errorOutputPaths": ["stderr"], + "encoderConfig": { + "messageKey": "message", + "levelKey": "level", + "timeKey": "time", + "nameKey": "logger", + "callerKey": "caller", + "stacktraceKey": "stacktrace", + "lineEnding": "\n", + "levelEncoder": "lowercase", + "timeEncoder": "iso8601", + "durationEncoder": "string", + "callerEncoder": "short" + } + }, + "lumberjackConfig": {} +} \ No newline at end of file diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..533a7fd --- /dev/null +++ b/go.sum @@ -0,0 +1,117 @@ +github.com/ThreeDotsLabs/watermill v1.3.5 h1:50JEPEhMGZQMh08ct0tfO1PsgMOAOhV3zxK2WofkbXg= +github.com/ThreeDotsLabs/watermill v1.3.5/go.mod h1:O/u/Ptyrk5MPTxSeWM5vzTtZcZfxXfO9PK9eXTYiFZY= +github.com/ThreeDotsLabs/watermill-nats/v2 v2.0.2 h1:/87LcdSzUEdCKbJptaLE987hOVOs852b+v5pukegggo= +github.com/ThreeDotsLabs/watermill-nats/v2 v2.0.2/go.mod h1:uslCjpuzANBzawXYlwx2IDyGjpv9M42U2TQH6JMMQis= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +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/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lithammer/shortuuid/v3 v3.0.7 h1:trX0KTHy4Pbwo/6ia8fscyHoGA+mf1jWbPJVuvyJQQ8= +github.com/lithammer/shortuuid/v3 v3.0.7/go.mod h1:vMk8ke37EmiewwolSO1NLW8vP4ZaKlRuDIi8tWWmAts= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/nats-io/nats.go v1.36.0 h1:suEUPuWzTSse/XhESwqLxXGuj8vGRuPRoG7MoRN/qyU= +github.com/nats-io/nats.go v1.36.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= +github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= +github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= +golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/config/config.go b/internal/config/config.go index 05729f6..ae57c86 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,6 +1,7 @@ package config import ( + "caatsm/pkg/utils" "fmt" "os" "regexp" @@ -8,6 +9,9 @@ import ( "time" "github.com/spf13/viper" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "gopkg.in/natefinch/lumberjack.v2" ) var MyConfig *Config @@ -30,10 +34,10 @@ type SubscriptionConfig struct { } type TimeoutsConfig struct { - ServerTimeout time.Duration `mapstructure:"server_timeout"` - ReconnectWait time.Duration `mapstructure:"reconnect_wait"` - CloseTimeout time.Duration `mapstructure:"close_timeout"` - AckWaitTimeout time.Duration `mapstructure:"ack_wait_timeout"` + Server time.Duration `mapstructure:"server"` + ReconnectWait time.Duration `mapstructure:"reconnect_wait"` + Close time.Duration `mapstructure:"close"` + AckWait time.Duration `mapstructure:"ack_wait"` } type BodyConfig struct { @@ -46,7 +50,24 @@ type PatternConfig struct { Expression *regexp.Regexp } +// LoggerConfig represents the configuration for the logger. +type LoggerConfig struct { + ZapConfig zap.Config `json:"zapConfig"` + LumberjackConfig LumberjackConfig `json:"lumberjackConfig"` +} + +// LumberjackConfig represents the configuration for lumberjack logging. +type LumberjackConfig struct { + Filename string `json:"filename"` + MaxSize int `json:"maxSize"` + MaxBackups int `json:"maxBackups"` + MaxAge int `json:"maxAge"` + Compress bool `json:"compress"` +} + const ( + EnvProd = "prod" + // logConfigFile = "configs/log_config.json" // arrPatternString represents the regular expression pattern used to match arrival patterns. // The pattern matches strings in the format: "(TYPE-NUMBER-SSR-DEPARTURE-ARRIVAL)". // The pattern captures the following named groups: @@ -66,7 +87,7 @@ const ( // - departure: the four-letter departure airport code // - departure_time: the four-digit departure time // - arrival: the four-letter arrival airport code - depPatternString = `^\((?P[A-Z]{3})-(?P[A-Z0-9]+)-(?P[A-Z0-9]+)-(?P[A-Z]{4})-(?P\d{4})-(?P[A-Z]{4})\)$` + depPatternString = `^\((?P[A-Z]{3})-(?P[A-Z0-9]+)(\/(?P[A-Z0-9]+))?-(?P[A-Z]{4})(?P\d{4})-(?P[A-Z]{4})\)$` // fplPatternString is a regular expression designed to parse and extract detailed information from formatted flight plan strings. // The flight plan string is expected to follow a specific format, encapsulated by parentheses and containing various segments separated by hyphens. @@ -185,6 +206,7 @@ func LoadConfig() (*Config, error) { // log.Error(errMsg) return nil, fmt.Errorf(errMsg) } + // loadLoggerConfig() // log.Debugf("Config loaded: %+v", config) return &config, nil @@ -206,3 +228,83 @@ func ValidateConfig(cfg *Config) error { // fmt.Println("config validation passed") return nil } + +func loadLoggerConfig() { + // log := utils.Logger + env := os.Getenv("GO_ENV") + if env == "" { + env = "dev" + } + // log.Infof("Environment: %s", env) + + viper.SetConfigType("json") + viper.SetConfigName("logger." + env) + viper.AddConfigPath("configs") + // viper.SetEnvPrefix("tele") + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + + if err := viper.ReadInConfig(); err != nil { + errMsg := fmt.Sprintf("error reading logger config file for environment '%s': %v", env, err) + // log.Error(errMsg) + panic(errMsg) + } + + // log.Debug("Logger config file read successfully") + // log.Debugf("Logger config keys: %v", viper.AllKeys()) + + var config LoggerConfig + if err := viper.Unmarshal(&config); err != nil { + errMsg := fmt.Sprintf("unable to decode logger config into struct for environment '%s': %v", env, err) + // log.Error(errMsg) + // return nil, fmt.Errorf(errMsg) + panic(errMsg) + } + var logWriter zapcore.WriteSyncer + if env == EnvProd { + logWriter = zapcore.AddSync(&lumberjack.Logger{ + Filename: config.LumberjackConfig.Filename, + MaxSize: config.LumberjackConfig.MaxSize, + MaxBackups: config.LumberjackConfig.MaxBackups, + MaxAge: config.LumberjackConfig.MaxAge, + Compress: config.LumberjackConfig.Compress, + }) + } else { + logWriter = zapcore.AddSync(os.Stdout) + } + + encoder := zapcore.NewJSONEncoder(config.ZapConfig.EncoderConfig) + level := parseLogLevel(config.ZapConfig.Level.String()) + + core := zapcore.NewCore( + encoder, + logWriter, + level, + ) + + log := zap.New(core, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel)) + utils.Logger = log.Sugar() + // log.Debugf("Logger config loaded: %+v", config) + +} + +// parseLogLevel converts the log level string to zapcore.Level. +func parseLogLevel(level string) zapcore.Level { + switch level { + case "debug": + return zapcore.DebugLevel + case "info": + return zapcore.InfoLevel + case "warn": + return zapcore.WarnLevel + case "error": + return zapcore.ErrorLevel + case "dpanic": + return zapcore.DPanicLevel + case "panic": + return zapcore.PanicLevel + case "fatal": + return zapcore.FatalLevel + default: + return zapcore.InfoLevel + } +} diff --git a/internal/nats/sub.go b/internal/nats/sub.go index 6bf78f3..edf4895 100644 --- a/internal/nats/sub.go +++ b/internal/nats/sub.go @@ -27,7 +27,7 @@ func (n *NatsHandler) Subscribe() { logger := watermill.NewStdLogger(false, false) options := []nc.Option{ nc.RetryOnFailedConnect(true), - nc.Timeout(n.config.Timeouts.ServerTimeout), + nc.Timeout(n.config.Timeouts.Server), nc.ReconnectWait(n.config.Timeouts.ReconnectWait), } jsConfig := nats.JetStreamConfig{Disabled: true} @@ -35,8 +35,8 @@ func (n *NatsHandler) Subscribe() { subscriber, err := nats.NewSubscriber( nats.SubscriberConfig{ URL: n.config.Nats.URL, - CloseTimeout: n.config.Timeouts.CloseTimeout, - AckWaitTimeout: n.config.Timeouts.AckWaitTimeout, + CloseTimeout: n.config.Timeouts.Close, + AckWaitTimeout: n.config.Timeouts.AckWait, NatsOptions: options, Unmarshaler: marshaler, JetStream: jsConfig, diff --git a/internal/parsers/aviation_parser.go b/internal/parsers/aviation_parser.go index a6c1566..71110e1 100644 --- a/internal/parsers/aviation_parser.go +++ b/internal/parsers/aviation_parser.go @@ -3,7 +3,6 @@ package parsers import ( "caatsm/internal/config" "caatsm/internal/domain" - "caatsm/pkg/utils" "fmt" "regexp" "strings" @@ -17,9 +16,9 @@ const ( ) var ( - categoryRegex = regexp.MustCompile(`\(([A-Z]{3})(.*)\)`) + categoryRegex = regexp.MustCompile(`\((?P[A-Z]+)-`) emptyLineRemove = regexp.MustCompile(`(?m)^\s*$`) - bodyOnly = regexp.MustCompile(`^(ZCZC(.|\n)*)NNNN$`) + bodyOnly = regexp.MustCompile(`(.|\n)?((ZCZC(.|\n)*))NNNN$`) ) type BodyParser struct { @@ -43,30 +42,30 @@ func (bp *BodyParser) SetBodyPatterns(patterns map[string]config.BodyConfig) { // Parse attempts to parse the body text using the configured patterns. func (bp *BodyParser) Parse(body string) (interface{}, error) { - log := utils.Logger + // log := utils.Logger body = strings.TrimSpace(body) - log.Info("Parsing body text", body) + // log.Info("Parsing body text", body) category := findCategory(body) if category == "" { - log.Error("No category found in body text") + // log.Error("No category found in body text") return nil, fmt.Errorf("no category found in body text") } patters := bp.GetBodyPatterns() - log.Infof("body config [%s] %v\n", category, patters[category]) + // log.Infof("body config [%s] %v\n", category, patters[category]) if patterConfig := patters[category]; patterConfig.Patterns != nil { for _, p := range patterConfig.Patterns { - log.Infof("Trying pattern %s\n%s\n", p.Comments, p.Pattern) + // log.Infof("Trying pattern %s\n%s\n", p.Comments, p.Pattern) re := p.Expression match := re.FindStringSubmatch(body) - log.Info("Match: ", match) + // log.Info("Match: ", match) if match != nil { - log.Infof("Matched: %v\n", match) + // log.Infof("Matched: %v\n", match) data := extractData(match, re) return createBodyData(data) } - log.Infof("No match for pattern %s\n", p.Comments) + // log.Infof("No match for pattern %s\n", p.Comments) } } @@ -75,9 +74,14 @@ func (bp *BodyParser) Parse(body string) (interface{}, error) { func findCategory(body string) string { match := categoryRegex.FindStringSubmatch(body) - utils.Logger.Infof("Match: %v\n", match) + // utils.Logger.Infof("Match: %v\n", match) if match != nil { - return match[1] + groups := categoryRegex.SubexpNames() + for i, name := range groups { + if i != 0 && name == "category" { + return match[i] + } + } } return "" } @@ -168,7 +172,7 @@ func clean(text string) string { if bodyOnly != nil { match := bodyOnly.FindStringSubmatch(cleanText) if len(match) > 1 { - bodyOnly := match[1] + bodyOnly := match[2] if bodyOnly[len(bodyOnly)-1] == '\n' { return bodyOnly[:len(bodyOnly)-1] } diff --git a/internal/parsers/aviation_parser_test.go b/internal/parsers/aviation_parser_test.go index 3f18c30..76c578b 100644 --- a/internal/parsers/aviation_parser_test.go +++ b/internal/parsers/aviation_parser_test.go @@ -109,44 +109,6 @@ NNNN` }) - Context("with NOTAM message", func() { - It("should parse the header correctly", func() { - message := ` -ZCZC NOTAM1234 230715 -GG EDDNZEZN -. -GG EDDNYNYX -.BERLINTWR 230714 - -Q) EDMM/QOATT/IV/BO/A/000/999/4814N01120E005 -A) EDDM -B) 2307150600 C) 2307151800 -E) AERODROME CONTROL TOWER HOURS OF SERVICE - 0600-1800 DUE TO MAINTENANCE -NNNN -` - - parsedMessage, err := ParseHeader(message) - Expect(err).ToNot(HaveOccurred()) - Expect(parsedMessage.StartIndicator).To(Equal("ZCZC")) - Expect(parsedMessage.MessageID).To(Equal("NOTAM1234")) - Expect(parsedMessage.DateTime).To(Equal("230715")) - Expect(parsedMessage.PriorityIndicator).To(Equal("GG")) - Expect(parsedMessage.PrimaryAddress).To(Equal("EDDNZEZN")) - Expect(parsedMessage.SecondaryAddresses).To(Equal([]string{"GG EDDNYNYX"})) - Expect(parsedMessage.Originator).To(Equal("BERLINTWR")) - Expect(parsedMessage.OriginatorDateTime).To(Equal("230714")) - // fmt.Print(parsedMessage.BodyAndFooter) - Expect(parsedMessage.BodyAndFooter).To(Equal(` -Q) EDMM/QOATT/IV/BO/A/000/999/4814N01120E005 -A) EDDM -B) 2307150600 C) 2307151800 -E) AERODROME CONTROL TOWER HOURS OF SERVICE -0600-1800 DUE TO MAINTENANCE -NNNN -`)) - }) - }) Describe("ParseBody", func() { Context("with ARR body (ARR-CES5470-ZBTJ-ZSHC1614)", func() { @@ -187,19 +149,19 @@ NNNN Context("with DEP body", func() { parser := NewBodyParser() - It("should parse the body (DEP-AB123-SSR1234-KJFK-1500-KLAX) correctly", func() { - body := "(DEP-AB123-SSR1234-KJFK-1500-KLAX)" + It("should parse the body (DEP-CYZ9017/A5633-ZBTJ1638-ZSPD) correctly", func() { + body := "(DEP-CYZ9017/A5633-ZBTJ1638-ZSPD)" parsedBody, err := parser.Parse(body) Expect(err).ToNot(HaveOccurred()) Expect(parsedBody).ToNot(BeNil()) Expect(parsedBody).To(BeAssignableToTypeOf(&domain.DEP{})) depMessage := parsedBody.(*domain.DEP) Expect(depMessage.Category).To(Equal("DEP")) - Expect(depMessage.AircraftID).To(Equal("AB123")) - Expect(depMessage.SSRModeAndCode).To(Equal("SSR1234")) - Expect(depMessage.DepartureAirport).To(Equal("KJFK")) - Expect(depMessage.DepartureTime).To(Equal("1500")) - Expect(depMessage.Destination).To(Equal("KLAX")) + Expect(depMessage.AircraftID).To(Equal("CYZ9017")) + Expect(depMessage.SSRModeAndCode).To(Equal("A5633")) + Expect(depMessage.DepartureAirport).To(Equal("ZBTJ")) + Expect(depMessage.DepartureTime).To(Equal("1638")) + Expect(depMessage.Destination).To(Equal("ZSPD")) }) }) diff --git a/pkg/utils/log.go b/pkg/utils/log.go new file mode 100644 index 0000000..4d2ab80 --- /dev/null +++ b/pkg/utils/log.go @@ -0,0 +1,7 @@ +package utils + +import ( + "go.uber.org/zap" +) + +var Logger *zap.SugaredLogger