diff --git a/cmd/management.go b/cmd/management.go index f5115a7..4295779 100644 --- a/cmd/management.go +++ b/cmd/management.go @@ -5,14 +5,12 @@ import ( "os/signal" "syscall" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/netbirdio/management-refactor/internals/server" - "github.com/netbirdio/management-refactor/pkg/logging" ) -var log = logging.LoggerForThisPackage - var newServer = func() server.Server { return server.NewServer() } @@ -26,17 +24,12 @@ var mgmtCmd = &cobra.Command{ Use: "management", Short: "start NetBird Management Server", RunE: func(cmd *cobra.Command, args []string) error { - err := logging.Init("logging.yaml") - if err != nil { - log().Debugf("Failed to init logging: %v", err) - } - srv := newServer() go func() { - log().Info("Starting server on :8080") + log.Info("Starting server on :8080") if err := srv.Start(); err != nil { - log().Fatalf("Server error: %v", err) + log.Fatalf("Server error: %v", err) } }() @@ -44,11 +37,11 @@ var mgmtCmd = &cobra.Command{ signal.Notify(stopChan, os.Interrupt, syscall.SIGTERM) <-stopChan - log().Info("Shutting down server...") + log.Info("Shutting down server...") if err := srv.Stop(); err != nil { - log().Errorf("Error stopping server: %v", err) + log.Errorf("Error stopping server: %v", err) } - log().Info("Server stopped gracefully.") + log.Info("Server stopped gracefully.") return nil }, diff --git a/internals/controllers/network_map/controller/controller.go b/internals/controllers/network_map/controller/controller.go index ddc46fb..d888e45 100644 --- a/internals/controllers/network_map/controller/controller.go +++ b/internals/controllers/network_map/controller/controller.go @@ -3,14 +3,13 @@ package controller import ( "context" + log "github.com/sirupsen/logrus" + "github.com/netbirdio/management-refactor/internals/controllers/network_map" "github.com/netbirdio/management-refactor/internals/shared/db" appmetrics "github.com/netbirdio/management-refactor/internals/shared/metrics" - "github.com/netbirdio/management-refactor/pkg/logging" ) -var log = logging.LoggerForThisPackage - type Controller struct { repo Repository metrics *metrics @@ -20,7 +19,7 @@ type Controller struct { func NewController(store *db.Store, metrics *appmetrics.AppMetrics, updateChannel network_map.UpdateChannel) *Controller { cMetrics, err := appmetrics.RegisterMetrics(metrics, newMetrics) if err != nil { - log().Fatalf("Failed to register app metrics: %v", err) + log.Fatalf("Failed to register app metrics: %v", err) } return &Controller{ repo: newRepository(store, cMetrics), @@ -37,7 +36,7 @@ func (c *Controller) CalculateNetworkMap(accountID string) (*network_map.Network // Do calc on data - log().Tracef("Calculating network map for account on public") + log.Tracef("Calculating network map for account on public") return &network_map.NetworkMap{}, nil } @@ -45,7 +44,7 @@ func (c *Controller) CalculateNetworkMap(accountID string) (*network_map.Network func (c *Controller) UpdatePeers(ctx context.Context, accountID string) error { _, err := c.CalculateNetworkMap(accountID) if err != nil { - log().Errorf("Failed to calculate network map for account %s: %v", accountID, err) + log.Errorf("Failed to calculate network map for account %s: %v", accountID, err) return err } c.UpdateChannel.SendUpdate(ctx, accountID, &network_map.UpdateMessage{}) diff --git a/internals/controllers/network_map/update_channel/updatechannel.go b/internals/controllers/network_map/update_channel/updatechannel.go index 8d9c3c5..e635515 100644 --- a/internals/controllers/network_map/update_channel/updatechannel.go +++ b/internals/controllers/network_map/update_channel/updatechannel.go @@ -5,15 +5,14 @@ import ( "sync" "time" + log "github.com/sirupsen/logrus" + "github.com/netbirdio/management-refactor/internals/controllers/network_map" appmetrics "github.com/netbirdio/management-refactor/internals/shared/metrics" - "github.com/netbirdio/management-refactor/pkg/logging" ) const channelBufferSize = 100 -var log = logging.LoggerForThisPackage - type UpdateChannel struct { // peerChannels is an update channel indexed by Peer.ID peerChannels map[string]chan *network_map.UpdateMessage @@ -27,7 +26,7 @@ type UpdateChannel struct { func NewUpdateChannel(metrics *appmetrics.AppMetrics) *UpdateChannel { cMetrics, err := appmetrics.RegisterMetrics(metrics, newMetrics) if err != nil { - log().Fatalf("Failed to register updatechannel metrics: %v", err) + log.Fatalf("Failed to register updatechannel metrics: %v", err) } return &UpdateChannel{ peerChannels: make(map[string]chan *network_map.UpdateMessage), @@ -38,7 +37,7 @@ func NewUpdateChannel(metrics *appmetrics.AppMetrics) *UpdateChannel { // SendUpdate sends update message to the peer's channel func (p *UpdateChannel) SendUpdate(ctx context.Context, peerID string, update *network_map.UpdateMessage) { - log().Debugf("Sending update message to peer %s on public update channel", peerID) + log.Debugf("Sending update message to peer %s on public update channel", peerID) start := time.Now() var found, dropped bool @@ -54,13 +53,13 @@ func (p *UpdateChannel) SendUpdate(ctx context.Context, peerID string, update *n found = true select { case channel <- update: - log().WithContext(ctx).Debugf("update was sent to channel for peer %s", peerID) + log.WithContext(ctx).Debugf("update was sent to channel for peer %s", peerID) default: dropped = true - log().WithContext(ctx).Warnf("channel for peer %s is %d full or closed", peerID, len(channel)) + log.WithContext(ctx).Warnf("channel for peer %s is %d full or closed", peerID, len(channel)) } } else { - log().WithContext(ctx).Debugf("peer %s has no channel", peerID) + log.WithContext(ctx).Debugf("peer %s has no channel", peerID) } } @@ -85,7 +84,7 @@ func (p *UpdateChannel) CreateChannel(ctx context.Context, peerID string) chan * channel := make(chan *network_map.UpdateMessage, channelBufferSize) p.peerChannels[peerID] = channel - log().WithContext(ctx).Debugf("opened updates channel for a peer %s", peerID) + log.WithContext(ctx).Debugf("opened updates channel for a peer %s", peerID) return channel } @@ -95,11 +94,11 @@ func (p *UpdateChannel) closeChannel(ctx context.Context, peerID string) { delete(p.peerChannels, peerID) close(channel) - log().WithContext(ctx).Debugf("closed updates channel of a peer %s", peerID) + log.WithContext(ctx).Debugf("closed updates channel of a peer %s", peerID) return } - log().WithContext(ctx).Debugf("closing updates channel: peer %s has no channel", peerID) + log.WithContext(ctx).Debugf("closing updates channel: peer %s has no channel", peerID) } // CloseChannels closes updates channel for each given peer diff --git a/internals/modules/networks/manager/manager.go b/internals/modules/networks/manager/manager.go index bb21f50..2fe733b 100644 --- a/internals/modules/networks/manager/manager.go +++ b/internals/modules/networks/manager/manager.go @@ -15,12 +15,12 @@ import ( type managerImpl struct { repo Repository - activityManager activity.Manager + activityManager *activity.Manager resourceManager resources.Manager routerManager routers.Manager } -func NewManager(repo Repository, activityManager activity.Manager, resourceManager resources.Manager, routerManager routers.Manager) networks.Manager { +func NewManager(repo Repository, activityManager *activity.Manager, resourceManager resources.Manager, routerManager routers.Manager) networks.Manager { return &managerImpl{ repo: repo, activityManager: activityManager, diff --git a/internals/modules/networks/resources/manager.go b/internals/modules/networks/resources/manager.go index 399feda..d988bdc 100644 --- a/internals/modules/networks/resources/manager.go +++ b/internals/modules/networks/resources/manager.go @@ -3,7 +3,6 @@ package resources import ( "context" - "github.com/netbirdio/management-refactor/internals/modules/networks" "github.com/netbirdio/management-refactor/internals/shared/db" ) @@ -11,7 +10,7 @@ type Manager interface { // Create // Read - GetNetworkResourcesByNetID(ctx context.Context, tx db.Transaction, lockingStrength db.LockingStrength, network *networks.Network) ([]*NetworkResource, error) + GetNetworkResourcesByNetID(ctx context.Context, tx db.Transaction, lockingStrength db.LockingStrength, id string) ([]*NetworkResource, error) // Update diff --git a/internals/modules/networks/resources/manager/manager.go b/internals/modules/networks/resources/manager/manager.go index d1eb250..a57a6fa 100644 --- a/internals/modules/networks/resources/manager/manager.go +++ b/internals/modules/networks/resources/manager/manager.go @@ -23,12 +23,12 @@ func NewManager(repo Repository, router *mux.Router, networkManager networks.Man } } -func (m *managerImpl) GetNetworkResourcesByNetID(ctx context.Context, tx db.Transaction, lockingStrength db.LockingStrength, network *networks.Network) ([]*resources.NetworkResource, error) { - return m.repo.GetResourcesByNetworkID(tx, lockingStrength, network.ID) +func (m *managerImpl) GetNetworkResourcesByNetID(ctx context.Context, tx db.Transaction, lockingStrength db.LockingStrength, id string) ([]*resources.NetworkResource, error) { + return m.repo.GetResourcesByNetworkID(tx, lockingStrength, id) } -func (m *managerImpl) DeleteResourcesInNetwork(ctx context.Context, tx db.Transaction, network *networks.Network) error { - resources, err := m.GetNetworkResourcesByNetID(ctx, tx, db.LockingStrengthUpdate, network) +func (m *managerImpl) DeleteResourcesInNetwork(ctx context.Context, tx db.Transaction, accountID string, userID string, id string) error { + resources, err := m.GetNetworkResourcesByNetID(ctx, tx, db.LockingStrengthUpdate, id) if err != nil { return err } diff --git a/internals/modules/networks/routers/manager/manager.go b/internals/modules/networks/routers/manager/manager.go index 5d04392..47d8712 100644 --- a/internals/modules/networks/routers/manager/manager.go +++ b/internals/modules/networks/routers/manager/manager.go @@ -1 +1,33 @@ package manager + +import ( + "context" + + "github.com/netbirdio/management-refactor/internals/modules/networks/routers" + "github.com/netbirdio/management-refactor/internals/shared/db" +) + +type managerImpl struct { + repo Repository +} + +func NewManager(repo Repository) routers.Manager { + return &managerImpl{ + repo: repo, + } +} + +func (m managerImpl) GetNetworkRoutersByNetID(ctx context.Context, tx db.Transaction, lockingStrength db.LockingStrength, accountID, userID, networkID string) ([]*routers.NetworkRouter, error) { + // TODO implement me + panic("implement me") +} + +func (m managerImpl) DeleteRouter(ctx context.Context, tx db.Transaction, accountID, userID, networkID, routerID string) error { + // TODO implement me + panic("implement me") +} + +func (m managerImpl) DeleteRoutersInNetwork(ctx context.Context, tx db.Transaction, accountID, userID, networkID string) error { + // TODO implement me + panic("implement me") +} diff --git a/internals/modules/networks/routers/manager/repository.go b/internals/modules/networks/routers/manager/repository.go index 5d04392..2d6ceb7 100644 --- a/internals/modules/networks/routers/manager/repository.go +++ b/internals/modules/networks/routers/manager/repository.go @@ -1 +1,21 @@ package manager + +import ( + "github.com/netbirdio/management-refactor/internals/shared/db" +) + +type Repository interface { + Store() *db.Store +} + +type repository struct { + store *db.Store +} + +func NewRepository(s *db.Store) Repository { + return &repository{store: s} +} + +func (r *repository) Store() *db.Store { + return r.store +} diff --git a/internals/modules/peers/manager/manager.go b/internals/modules/peers/manager/manager.go index bc3a3eb..bde0a91 100644 --- a/internals/modules/peers/manager/manager.go +++ b/internals/modules/peers/manager/manager.go @@ -3,15 +3,14 @@ package manager import ( "context" + log "github.com/sirupsen/logrus" + "github.com/netbirdio/management-refactor/internals/controllers/network_map" "github.com/netbirdio/management-refactor/internals/modules/peers" "github.com/netbirdio/management-refactor/internals/shared/activity" "github.com/netbirdio/management-refactor/internals/shared/db" - "github.com/netbirdio/management-refactor/pkg/logging" ) -var log = logging.LoggerForThisPackage - var _ peers.Manager = (*Manager)(nil) type Manager struct { @@ -25,7 +24,7 @@ func NewManager(repo Repository) *Manager { } func (m *Manager) SetNetworkMapController(networkMapController network_map.Controller) { - log().Tracef("Setting network map controller for peers manager") + log.Tracef("Setting network map controller for peers manager") m.networkMapController = networkMapController } diff --git a/internals/modules/users/manager/manager.go b/internals/modules/users/manager/manager.go index 08c2c80..8eec930 100644 --- a/internals/modules/users/manager/manager.go +++ b/internals/modules/users/manager/manager.go @@ -5,11 +5,8 @@ import ( "github.com/netbirdio/management-refactor/internals/modules/users" "github.com/netbirdio/management-refactor/internals/shared/db" - "github.com/netbirdio/management-refactor/pkg/logging" ) -var log = logging.LoggerForThisPackage() - type Manager struct { repo Repository } diff --git a/internals/modules/users/manager/repository.go b/internals/modules/users/manager/repository.go index 14d2c6a..1ba8e2e 100644 --- a/internals/modules/users/manager/repository.go +++ b/internals/modules/users/manager/repository.go @@ -1,6 +1,8 @@ package manager import ( + log "github.com/sirupsen/logrus" + "github.com/netbirdio/management-refactor/internals/modules/users" "github.com/netbirdio/management-refactor/internals/shared/db" ) diff --git a/internals/server/boot.go b/internals/server/boot.go index d28028a..1f3d33d 100644 --- a/internals/server/boot.go +++ b/internals/server/boot.go @@ -7,6 +7,7 @@ import ( "net/http" "github.com/gorilla/mux" + log "github.com/sirupsen/logrus" "github.com/netbirdio/management-refactor/internals/shared/activity" "github.com/netbirdio/management-refactor/internals/shared/activity/sqlite" @@ -54,13 +55,14 @@ func (s *BaseServer) Router() *mux.Router { }) } -func (s *BaseServer) EventStore() activity.Store { - return Create(s, func() activity.Store { +func (s *BaseServer) ActivityManager() *activity.Manager { + return Create(s, func() *activity.Manager { ctx := context.Background() store, err := sqlite.NewSQLiteStore(ctx, "dataDir", "encryptionKey") if err != nil { log.Fatalf("error while creating event store: %s", err) } - return store + + return activity.NewManager(store) }) } diff --git a/internals/server/modules.go b/internals/server/modules.go index 0c539b0..29143ac 100644 --- a/internals/server/modules.go +++ b/internals/server/modules.go @@ -5,6 +5,8 @@ import ( "github.com/netbirdio/management-refactor/internals/modules/networks/manager" "github.com/netbirdio/management-refactor/internals/modules/networks/resources" resourcesManager "github.com/netbirdio/management-refactor/internals/modules/networks/resources/manager" + "github.com/netbirdio/management-refactor/internals/modules/networks/routers" + routersManager "github.com/netbirdio/management-refactor/internals/modules/networks/routers/manager" "github.com/netbirdio/management-refactor/internals/modules/peers" peersManager "github.com/netbirdio/management-refactor/internals/modules/peers/manager" "github.com/netbirdio/management-refactor/internals/modules/users" @@ -15,7 +17,7 @@ import ( func (s *BaseServer) NetworksManager() networks.Manager { return Create(s, func() networks.Manager { repo := manager.NewRepository(s.Store()) - return manager.NewManager(repo) + return manager.NewManager(repo, s.ActivityManager(), s.ResourcesManager(), s.RoutersManager()) }) } @@ -27,6 +29,14 @@ func (s *BaseServer) ResourcesManager() resources.Manager { }) } +func (s *BaseServer) RoutersManager() routers.Manager { + return Create(s, func() routers.Manager { + repo := routersManager.NewRepository(s.Store()) + manager := routersManager.NewManager(repo) + return manager + }) +} + func (s *BaseServer) PermissionsManager() permissions.Manager { return Create(s, func() permissions.Manager { return permissions.NewManager(s.UsersManager()) diff --git a/internals/server/server.go b/internals/server/server.go index c552dc5..e7182de 100644 --- a/internals/server/server.go +++ b/internals/server/server.go @@ -4,6 +4,8 @@ import ( "context" "time" + log "github.com/sirupsen/logrus" + "github.com/netbirdio/management-refactor/pkg/logging" ) @@ -23,10 +25,9 @@ type BaseServer struct { afterInit []func(s *BaseServer) } -var log = logging.LoggerForThisPackage() - // NewServer initializes and configures a new Server instance func NewServer() *BaseServer { + logging.InitFromFile("../management-refactor/pkg/logging/logging.properties") return &BaseServer{ container: make(map[string]any), } diff --git a/internals/shared/activity/manager.go b/internals/shared/activity/manager.go index 8d74c58..46b0b0e 100644 --- a/internals/shared/activity/manager.go +++ b/internals/shared/activity/manager.go @@ -4,13 +4,12 @@ import ( "context" "time" + log "github.com/sirupsen/logrus" + "github.com/netbirdio/management-refactor/internals/shared/db" "github.com/netbirdio/management-refactor/pkg/configuration" - "github.com/netbirdio/management-refactor/pkg/logging" ) -var log = logging.LoggerForThisPackage() - type Manager struct { cfg *config // eventStore is the event store diff --git a/internals/shared/api/rest/middleware/auth_middleware.go b/internals/shared/api/rest/middleware/auth_middleware.go index b2a5132..3244706 100644 --- a/internals/shared/api/rest/middleware/auth_middleware.go +++ b/internals/shared/api/rest/middleware/auth_middleware.go @@ -7,11 +7,10 @@ import ( "time" "github.com/google/uuid" + "github.com/netbirdio/netbird/formatter/hook" "github.com/netbirdio/netbird/management/server/auth" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/http/middleware/bypass" - - "github.com/netbirdio/management-refactor/pkg/logging/hook" ) // AuthMiddleware middleware to verify personal access tokens (PAT) and JWT tokens diff --git a/internals/shared/db/database_connection.go b/internals/shared/db/database_connection.go index e1d6a95..7716a0f 100644 --- a/internals/shared/db/database_connection.go +++ b/internals/shared/db/database_connection.go @@ -6,6 +6,7 @@ import ( "path/filepath" "runtime" + log "github.com/sirupsen/logrus" "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/gorm" @@ -28,10 +29,10 @@ type DatabaseConn struct { func NewDatabaseConn(ctx context.Context) (*DatabaseConn, error) { cfg, err := configuration.Parse[config]() if err != nil { - log().Fatalf("failed to parse config: %v", err) + log.Fatalf("failed to parse config: %v", err) } - log().WithContext(ctx).Infof("using %s store engine", cfg.Engine) + log.WithContext(ctx).Infof("using %s store engine", cfg.Engine) var db *gorm.DB switch Engine(cfg.Engine) { diff --git a/internals/shared/db/store.go b/internals/shared/db/store.go index e7662af..4de795c 100644 --- a/internals/shared/db/store.go +++ b/internals/shared/db/store.go @@ -5,12 +5,8 @@ import ( "gorm.io/gorm" "gorm.io/gorm/clause" - - "github.com/netbirdio/management-refactor/pkg/logging" ) -var log = logging.LoggerForThisPackage - type Store struct { db *gorm.DB } diff --git a/internals/shared/permissions/manager.go b/internals/shared/permissions/manager.go index 02c610a..0a9fb2a 100644 --- a/internals/shared/permissions/manager.go +++ b/internals/shared/permissions/manager.go @@ -9,6 +9,7 @@ import ( nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/http/util" "github.com/netbirdio/netbird/management/server/status" + log "github.com/sirupsen/logrus" "github.com/netbirdio/management-refactor/internals/modules/users" "github.com/netbirdio/management-refactor/internals/shared/activity" @@ -16,11 +17,8 @@ import ( "github.com/netbirdio/management-refactor/internals/shared/permissions/modules" "github.com/netbirdio/management-refactor/internals/shared/permissions/operations" "github.com/netbirdio/management-refactor/internals/shared/permissions/roles" - "github.com/netbirdio/management-refactor/pkg/logging" ) -var log = logging.LoggerForThisPackage() - type Manager interface { WithPermission(module modules.Module, operation operations.Operation, handlerFunc func(w http.ResponseWriter, r *http.Request, auth *nbcontext.UserAuth)) http.HandlerFunc ValidateUserPermissions(ctx context.Context, accountID, userID string, module modules.Module, operation operations.Operation) (bool, error) diff --git a/main.go b/main.go index 8384875..05aabe0 100644 --- a/main.go +++ b/main.go @@ -1,11 +1,26 @@ package main import ( + _ "embed" "os" + "strings" "github.com/netbirdio/management-refactor/cmd" ) +//go:embed go.mod +var GoMod string + +func ModulePath() string { + lines := strings.Split(GoMod, "\n") + for _, line := range lines { + if strings.HasPrefix(line, "module ") { + return strings.TrimSpace(strings.TrimPrefix(line, "module ")) + } + } + return "" +} + func main() { if err := cmd.Execute(); err != nil { os.Exit(1) diff --git a/pkg/logging/config.go b/pkg/logging/config.go deleted file mode 100644 index 256a7fc..0000000 --- a/pkg/logging/config.go +++ /dev/null @@ -1,5 +0,0 @@ -package logging - -type LoggingConfig struct { - LogLevels map[string]string `mapstructure:"log_levels"` -} diff --git a/pkg/logging/hook/additional_empty.go b/pkg/logging/hook/additional_empty.go deleted file mode 100644 index 4f50694..0000000 --- a/pkg/logging/hook/additional_empty.go +++ /dev/null @@ -1,9 +0,0 @@ -//go:build !loggoroutine - -package hook - -import log "github.com/sirupsen/logrus" - -func additionalEntries(_ *log.Entry) { - // This function is empty and is used to demonstrate the use of additional hooks. -} diff --git a/pkg/logging/hook/additional_goroutine.go b/pkg/logging/hook/additional_goroutine.go deleted file mode 100644 index fb4e09f..0000000 --- a/pkg/logging/hook/additional_goroutine.go +++ /dev/null @@ -1,12 +0,0 @@ -//go:build loggoroutine - -package hook - -import ( - "github.com/petermattis/goid" - log "github.com/sirupsen/logrus" -) - -func additionalEntries(entry *log.Entry) { - entry.Data[EntryKeyGoroutineID] = goid.Get() -} diff --git a/pkg/logging/hook/hook.go b/pkg/logging/hook/hook.go deleted file mode 100644 index 290c337..0000000 --- a/pkg/logging/hook/hook.go +++ /dev/null @@ -1,139 +0,0 @@ -package hook - -import ( - "fmt" - "path" - "runtime" - "runtime/debug" - "strings" - - "github.com/sirupsen/logrus" - - "github.com/netbirdio/netbird/management/server/context" -) - -type ExecutionContext string - -const ( - ExecutionContextKey = "executionContext" - - HTTPSource ExecutionContext = "HTTP" - GRPCSource ExecutionContext = "GRPC" - SystemSource ExecutionContext = "SYSTEM" -) - -// ContextHook is a custom hook for add the source information for the entry -type ContextHook struct { - goModuleName string -} - -// NewContextHook instantiate a new context hook -func NewContextHook() *ContextHook { - hook := &ContextHook{} - hook.goModuleName = hook.moduleName() + "/" - return hook -} - -// Levels set the supported levels for this hook -func (hook ContextHook) Levels() []logrus.Level { - return logrus.AllLevels -} - -// Fire extend with the source information the entry.Data -func (hook ContextHook) Fire(entry *logrus.Entry) error { - caller := &runtime.Frame{Line: 0, File: "caller_not_available"} - if entry.Caller != nil { - caller = entry.Caller - } - src := hook.parseSrc(caller.File) - entry.Data[EntryKeySource] = fmt.Sprintf("%s:%v", src, caller.Line) - additionalEntries(entry) - - if entry.Context == nil { - return nil - } - - source, ok := entry.Context.Value(ExecutionContextKey).(ExecutionContext) - if !ok { - return nil - } - - entry.Data["context"] = source - - switch source { - case HTTPSource: - addHTTPFields(entry) - case GRPCSource: - addGRPCFields(entry) - case SystemSource: - addSystemFields(entry) - } - - return nil -} - -func (hook ContextHook) moduleName() string { - info, ok := debug.ReadBuildInfo() - if ok && info.Main.Path != "" { - return info.Main.Path - } - - return "netbird" -} - -func (hook ContextHook) parseSrc(filePath string) string { - netbirdPath := strings.SplitAfter(filePath, hook.goModuleName) - if len(netbirdPath) > 1 { - return netbirdPath[len(netbirdPath)-1] - } - - // in case of forked repo - netbirdPath = strings.SplitAfter(filePath, "netbird/") - if len(netbirdPath) > 1 { - return netbirdPath[len(netbirdPath)-1] - } - - // in case if log entry is come from external pkg - _, pkg := path.Split(path.Dir(filePath)) - file := path.Base(filePath) - return fmt.Sprintf("%s/%s", pkg, file) -} - -func addHTTPFields(entry *logrus.Entry) { - if ctxReqID, ok := entry.Context.Value(context.RequestIDKey).(string); ok { - entry.Data[context.RequestIDKey] = ctxReqID - } - if ctxAccountID, ok := entry.Context.Value(context.AccountIDKey).(string); ok { - entry.Data[context.AccountIDKey] = ctxAccountID - } - if ctxInitiatorID, ok := entry.Context.Value(context.UserIDKey).(string); ok { - entry.Data[context.UserIDKey] = ctxInitiatorID - } -} - -func addGRPCFields(entry *logrus.Entry) { - if ctxReqID, ok := entry.Context.Value(context.RequestIDKey).(string); ok { - entry.Data[context.RequestIDKey] = ctxReqID - } - if ctxAccountID, ok := entry.Context.Value(context.AccountIDKey).(string); ok { - entry.Data[context.AccountIDKey] = ctxAccountID - } - if ctxDeviceID, ok := entry.Context.Value(context.PeerIDKey).(string); ok { - entry.Data[context.PeerIDKey] = ctxDeviceID - } -} - -func addSystemFields(entry *logrus.Entry) { - if ctxReqID, ok := entry.Context.Value(context.RequestIDKey).(string); ok { - entry.Data[context.RequestIDKey] = ctxReqID - } - if ctxInitiatorID, ok := entry.Context.Value(context.UserIDKey).(string); ok { - entry.Data[context.UserIDKey] = ctxInitiatorID - } - if ctxAccountID, ok := entry.Context.Value(context.AccountIDKey).(string); ok { - entry.Data[context.AccountIDKey] = ctxAccountID - } - if ctxDeviceID, ok := entry.Context.Value(context.PeerIDKey).(string); ok { - entry.Data[context.PeerIDKey] = ctxDeviceID - } -} diff --git a/pkg/logging/hook/hook_test.go b/pkg/logging/hook/hook_test.go deleted file mode 100644 index 09e925f..0000000 --- a/pkg/logging/hook/hook_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package hook - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestFilePathParsing(t *testing.T) { - - testCases := []struct { - filePath string - expectedFileName string - }{ - // locally cloned repo - { - filePath: "/Users/user/Github/management-refactor/netbird/formatter/formatter.go", - expectedFileName: "formatter/formatter.go", - }, - // locally cloned repo with duplicated name in path - { - filePath: "/Users/user/management-refactor/repos/management-refactor/formatter/formatter.go", - expectedFileName: "formatter/formatter.go", - }, - // locally cloned repo with renamed package root - { - filePath: "/Users/user/Github/MyOwnNetbirdClient/formatter/formatter.go", - expectedFileName: "formatter/formatter.go", - }, - } - - hook := NewContextHook() - - for _, testCase := range testCases { - parsedString := hook.parseSrc(testCase.filePath) - assert.Equal(t, testCase.expectedFileName, parsedString, "Parsed filepath does not match expected for %s", testCase.filePath) - } - -} diff --git a/pkg/logging/hook/keys.go b/pkg/logging/hook/keys.go deleted file mode 100644 index 09781a8..0000000 --- a/pkg/logging/hook/keys.go +++ /dev/null @@ -1,6 +0,0 @@ -package hook - -const ( - EntryKeySource = "source" - EntryKeyGoroutineID = "goroutine_id" -) diff --git a/pkg/logging/init.go b/pkg/logging/init.go deleted file mode 100644 index cba80b5..0000000 --- a/pkg/logging/init.go +++ /dev/null @@ -1,230 +0,0 @@ -package logging - -import ( - "fmt" - "io" - "log/syslog" - "os" - "path/filepath" - "runtime" - "slices" - "strconv" - "strings" - "sync" - - "github.com/sirupsen/logrus" - lSyslog "github.com/sirupsen/logrus/hooks/syslog" - "github.com/spf13/viper" - "google.golang.org/grpc/grpclog" - "gopkg.in/natefinch/lumberjack.v2" -) - -const defaultLogSize = 5 - -// global map of package paths to *logrus.Logger -var ( - mu sync.RWMutex - loggers = map[string]*logrus.Logger{} -) - -const basePrefix = "github.com/netbirdio/" - -// Init reads the logging config from a YAML file and sets up per-package loggers. -func Init(configFilePath string) error { - v := viper.New() - v.SetConfigFile(configFilePath) - - // Read the YAML - if err := v.ReadInConfig(); err != nil { - return fmt.Errorf("failed to read logging config: %w", err) - } - - var cfg LoggingConfig - if err := v.Unmarshal(&cfg); err != nil { - return fmt.Errorf("failed to unmarshal logging config: %w", err) - } - - mu.Lock() - defer mu.Unlock() - - // For each package in our config, create a logger at the given level - for pkgPath, levelStr := range cfg.LogLevels { - l := logrus.New() // each package gets its own *logrus.Logger - l.SetLevel(parseLogrusLevel(levelStr)) - - // Optionally, set the formatter, output, etc.: - // l.SetFormatter(&logrus.JSONFormatter{}) - // l.SetOutput(os.Stdout) - - loggers[pkgPath] = l - } - - // Optionally, define a default logger for packages not explicitly listed - if _, ok := loggers["default"]; !ok { - defaultLogger := logrus.New() - defaultLogger.SetLevel(logrus.TraceLevel) - loggers["default"] = defaultLogger - } - - return nil -} - -// parseLogrusLevel is a helper that converts a string (e.g. "debug") to a logrus.Level. -func parseLogrusLevel(levelStr string) logrus.Level { - switch strings.ToLower(levelStr) { - case "trace": - return logrus.TraceLevel - case "debug": - return logrus.DebugLevel - case "info": - return logrus.InfoLevel - case "warn", "warning": - return logrus.WarnLevel - case "error": - return logrus.ErrorLevel - case "fatal": - return logrus.FatalLevel - case "panic": - return logrus.PanicLevel - } - // default - return logrus.InfoLevel -} - -// LoggerFor returns a *logrus.Logger for the specified package path. -// If there's no explicit logger, we return the "default" logger. -func LoggerFor(pkgPath string) *logrus.Logger { - mu.RLock() - defer mu.RUnlock() - - if l, ok := loggers[pkgPath]; ok { - return l - } - if l, ok := loggers["default"]; ok { - return l - } - - logrus.Tracef("No logger configured for %q; using fallback (info-level) logger", pkgPath) - fallback := logrus.New() - fallback.SetLevel(logrus.InfoLevel) - return fallback -} - -func LoggerForThisPackage() *logrus.Logger { - pc, _, _, ok := runtime.Caller(1) - if !ok { - return LoggerFor("default") - } - fn := runtime.FuncForPC(pc) - if fn == nil { - return LoggerFor("default") - } - - fullFuncName := fn.Name() - pkgPath := parsePackageFromFuncName(fullFuncName) - - if strings.HasPrefix(pkgPath, basePrefix) { - pkgPath = strings.TrimPrefix(pkgPath, basePrefix) - } - - return LoggerFor(pkgPath) -} - -func parsePackageFromFuncName(funcName string) string { - parts := strings.Split(funcName, "/") - if len(parts) == 0 { - return "default" - } - last := parts[len(parts)-1] - - base := strings.Join(parts[:len(parts)-1], "/") - - dotIdx := strings.IndexByte(last, '.') - var pkgName string - if dotIdx == -1 { - pkgName = last - } else { - pkgName = last[:dotIdx] - } - - return base + "/" + pkgName -} - -// InitLog parses and sets log-level input -func InitLog(logLevel string, logPath string) error { - level, err := logrus.ParseLevel(logLevel) - if err != nil { - logrus.Errorf("Failed parsing log-level %s: %s", logLevel, err) - return err - } - customOutputs := []string{"console", "syslog"} - - if logPath != "" && !slices.Contains(customOutputs, logPath) { - maxLogSize := getLogMaxSize() - lumberjackLogger := &lumberjack.Logger{ - // Log file absolute path, os agnostic - Filename: filepath.ToSlash(logPath), - MaxSize: maxLogSize, // MB - MaxBackups: 10, - MaxAge: 30, // days - Compress: true, - } - logrus.SetOutput(io.Writer(lumberjackLogger)) - } else if logPath == "syslog" { - addSyslogHook() - } - - //nolint:gocritic - if os.Getenv("NB_LOG_FORMAT") == "json" { - SetJSONFormatter(logrus.StandardLogger()) - } else if logPath == "syslog" { - SetSyslogFormatter(logrus.StandardLogger()) - } else { - SetTextFormatter(logrus.StandardLogger()) - } - logrus.SetLevel(level) - - setGRPCLibLogger() - - return nil -} - -func setGRPCLibLogger() { - logOut := logrus.StandardLogger().Writer() - if os.Getenv("GRPC_GO_LOG_SEVERITY_LEVEL") != "info" { - grpclog.SetLoggerV2(grpclog.NewLoggerV2(io.Discard, logOut, logOut)) - return - } - - var v int - vLevel := os.Getenv("GRPC_GO_LOG_VERBOSITY_LEVEL") - if vl, err := strconv.Atoi(vLevel); err == nil { - v = vl - } - - grpclog.SetLoggerV2(grpclog.NewLoggerV2WithVerbosity(logOut, logOut, logOut, v)) -} - -func getLogMaxSize() int { - if sizeVar, ok := os.LookupEnv("NB_LOG_MAX_SIZE_MB"); ok { - size, err := strconv.ParseInt(sizeVar, 10, 64) - if err != nil { - logrus.Errorf("Failed parsing log-size %s: %s. Should be just an integer", sizeVar, err) - return defaultLogSize - } - - logrus.Infof("Setting log file max size to %d MB", size) - - return int(size) - } - return defaultLogSize -} - -func addSyslogHook() { - hook, err := lSyslog.NewSyslogHook("", "", syslog.LOG_INFO, "") - - if err != nil { - logrus.Errorf("Failed creating syslog hook: %s", err) - } - logrus.AddHook(hook) -} diff --git a/pkg/logging/log.go b/pkg/logging/log.go new file mode 100755 index 0000000..675d014 --- /dev/null +++ b/pkg/logging/log.go @@ -0,0 +1,108 @@ +// Copyright 2024 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package logging + +import ( + _ "embed" + "io" + "os" + "runtime" + "strings" + + "github.com/magiconair/properties" + "github.com/sirupsen/logrus" +) + +func InitFromFile(configFile string) { + file, err := os.ReadFile(configFile) + if err != nil { + panic(err) + } + + props, err := properties.Load(file, properties.UTF8) + if err != nil { + return + } + + logrus.SetReportCaller(true) + rootLogLevel, ok := props.Get("rootLogger") + var level logrus.Level + if ok { + level, err = logrus.ParseLevel(rootLogLevel) + if err != nil { + panic(err) + } + } else { + level = logrus.InfoLevel + } + + // We need the lowest level possible or our hook won't be invoked on all log messages + logrus.SetLevel(logrus.TraceLevel) + logrus.SetOutput(io.Discard) + + // clear hooks before adding ours, we only want one + logrus.StandardLogger().Hooks = make(logrus.LevelHooks) + // logWriter, err := os.Create("output.log") + // if err != nil { + // panic(err) + // } + + logrus.AddHook(Hook{props: props, level: level, wr: os.Stdout}) +} + +type Hook struct { + props *properties.Properties + level logrus.Level + wr io.Writer +} + +var _ logrus.Hook = (*Hook)(nil) + +func (p Hook) Levels() []logrus.Level { + return logrus.AllLevels +} + +var formatter = &logrus.JSONFormatter{ + FieldMap: logrus.FieldMap{ + logrus.FieldKeyTime: "ts", + logrus.FieldKeyLevel: "level", + logrus.FieldKeyMsg: "msg", + logrus.FieldKeyFile: "", + }, + CallerPrettyfier: func(frame *runtime.Frame) (function string, file string) { + return frame.Function, "" + }, +} + +func (p Hook) Fire(entry *logrus.Entry) error { + f := entry.Caller.Function + f = f[21:] + f = f[:strings.Index(f, ".")] + loglevel, ok := p.props.Get(f) + if !ok { + if entry.Level <= p.level { + format, _ := formatter.Format(entry) + p.wr.Write(format) + } + } else { + if level, err := logrus.ParseLevel(loglevel); err == nil { + if entry.Level <= level { + format, _ := formatter.Format(entry) + p.wr.Write(format) + } + } + } + return nil +} diff --git a/pkg/logging/logcat/logcat.go b/pkg/logging/logcat/logcat.go deleted file mode 100644 index c561d32..0000000 --- a/pkg/logging/logcat/logcat.go +++ /dev/null @@ -1,50 +0,0 @@ -package logcat - -import ( - "fmt" - "strings" - - "github.com/sirupsen/logrus" - - "github.com/netbirdio/netbird/formatter/levels" -) - -// Formatter formats logs into text what is fit for logcat -type Formatter struct { - levelDesc []string -} - -// NewLogcatFormatter create new LogcatFormatter instance -func NewLogcatFormatter() *Formatter { - return &Formatter{ - levelDesc: levels.ValidLevelDesc, - } -} - -// Format renders a single log entry -func (f *Formatter) Format(entry *logrus.Entry) ([]byte, error) { - var fields string - keys := make([]string, 0, len(entry.Data)) - for k, v := range entry.Data { - if k == "source" { - continue - } - keys = append(keys, fmt.Sprintf("%s: %v", k, v)) - } - - if len(keys) > 0 { - fields = fmt.Sprintf("[%s] ", strings.Join(keys, ", ")) - } - - level := f.parseLevel(entry.Level) - - return []byte(fmt.Sprintf("[%s] %s%s %s\n", level, fields, entry.Data["source"], entry.Message)), nil -} - -func (f *Formatter) parseLevel(level logrus.Level) string { - if len(f.levelDesc) < int(level) { - return "" - } - - return f.levelDesc[level] -} diff --git a/pkg/logging/logcat/logcat_test.go b/pkg/logging/logcat/logcat_test.go deleted file mode 100644 index fd4d928..0000000 --- a/pkg/logging/logcat/logcat_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package logcat - -import ( - "testing" - "time" - - "github.com/sirupsen/logrus" -) - -func TestLogcatMessageFormat(t *testing.T) { - - someEntry := &logrus.Entry{ - Data: logrus.Fields{"att1": 1, "att2": 2, "source": "some/fancy/path.go:46"}, - Time: time.Date(2021, time.Month(2), 21, 1, 10, 30, 0, time.UTC), - Level: 3, - Message: "Some Message", - } - - formatter := NewLogcatFormatter() - result, _ := formatter.Format(someEntry) - - expectedString := "[WARN] [att1: 1, att2: 2] some/fancy/path.go:46 Some Message\n" - expectedStringVariant := "[WARN] [att2: 2, att1: 1] some/fancy/path.go:46 Some Message\n" - parsedString := string(result) - if parsedString != expectedString && parsedString != expectedStringVariant { - t.Errorf("The log messages don't match. Expected: '%s', got: '%s'", expectedString, parsedString) - } - -} diff --git a/pkg/logging/logging.properties b/pkg/logging/logging.properties new file mode 100755 index 0000000..fd4eb55 --- /dev/null +++ b/pkg/logging/logging.properties @@ -0,0 +1,3 @@ +rootLogger=ERROR + +management-refactor/integrations/server=ERROR \ No newline at end of file diff --git a/pkg/logging/set.go b/pkg/logging/set.go deleted file mode 100644 index 6484a1a..0000000 --- a/pkg/logging/set.go +++ /dev/null @@ -1,38 +0,0 @@ -package logging - -import ( - "github.com/sirupsen/logrus" - - "github.com/netbirdio/management-refactor/pkg/logging/hook" - "github.com/netbirdio/management-refactor/pkg/logging/logcat" - "github.com/netbirdio/management-refactor/pkg/logging/syslog" - "github.com/netbirdio/management-refactor/pkg/logging/txt" -) - -// SetTextFormatter set the text formatter for given logger. -func SetTextFormatter(logger *logrus.Logger) { - logger.Formatter = txt.NewTextFormatter() - logger.ReportCaller = true - logger.AddHook(hook.NewContextHook()) -} - -// SetSyslogFormatter set the text formatter for given logger. -func SetSyslogFormatter(logger *logrus.Logger) { - logger.Formatter = syslog.NewSyslogFormatter() - logger.ReportCaller = true - logger.AddHook(hook.NewContextHook()) -} - -// SetJSONFormatter set the JSON formatter for given logger. -func SetJSONFormatter(logger *logrus.Logger) { - logger.Formatter = &logrus.JSONFormatter{} - logger.ReportCaller = true - logger.AddHook(hook.NewContextHook()) -} - -// SetLogcatFormatter set the logcat formatter for given logger. -func SetLogcatFormatter(logger *logrus.Logger) { - logger.Formatter = logcat.NewLogcatFormatter() - logger.ReportCaller = true - logger.AddHook(hook.NewContextHook()) -} diff --git a/pkg/logging/syslog/formatter.go b/pkg/logging/syslog/formatter.go deleted file mode 100644 index e72c303..0000000 --- a/pkg/logging/syslog/formatter.go +++ /dev/null @@ -1,39 +0,0 @@ -package syslog - -import ( - "fmt" - "strings" - - "github.com/sirupsen/logrus" - - "github.com/netbirdio/netbird/formatter/levels" -) - -// Formatter formats logs into text -type Formatter struct { - levelDesc []string -} - -// NewSyslogFormatter create new MySyslogFormatter instance -func NewSyslogFormatter() *Formatter { - return &Formatter{ - levelDesc: levels.ValidLevelDesc, - } -} - -// Format renders a single log entry -func (f *Formatter) Format(entry *logrus.Entry) ([]byte, error) { - var fields string - keys := make([]string, 0, len(entry.Data)) - for k, v := range entry.Data { - if k == "source" { - continue - } - keys = append(keys, fmt.Sprintf("%s: %v", k, v)) - } - - if len(keys) > 0 { - fields = fmt.Sprintf("[%s] ", strings.Join(keys, ", ")) - } - return []byte(fmt.Sprintf("%s%s\n", fields, entry.Message)), nil -} diff --git a/pkg/logging/syslog/formatter_test.go b/pkg/logging/syslog/formatter_test.go deleted file mode 100644 index 110a339..0000000 --- a/pkg/logging/syslog/formatter_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package syslog - -import ( - "testing" - "time" - - "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" -) - -func TestLogSyslogFormat(t *testing.T) { - - someEntry := &logrus.Entry{ - Data: logrus.Fields{"att1": 1, "att2": 2, "source": "some/fancy/path.go:46"}, - Time: time.Date(2021, time.Month(2), 21, 1, 10, 30, 0, time.UTC), - Level: 3, - Message: "Some Message", - } - - formatter := NewSyslogFormatter() - result, _ := formatter.Format(someEntry) - - parsedString := string(result) - expectedString := "^\\[(att1: 1, att2: 2|att2: 2, att1: 1)\\] Some Message\\s+$" - assert.Regexp(t, expectedString, parsedString) -} diff --git a/pkg/logging/txt/format.go b/pkg/logging/txt/format.go deleted file mode 100644 index a88c410..0000000 --- a/pkg/logging/txt/format.go +++ /dev/null @@ -1,31 +0,0 @@ -//go:build !loggoroutine - -package txt - -import ( - "fmt" - "strings" - - "github.com/sirupsen/logrus" - - "github.com/netbirdio/netbird/formatter/hook" -) - -func (f *TextFormatter) Format(entry *logrus.Entry) ([]byte, error) { - var fields string - keys := make([]string, 0, len(entry.Data)) - for k, v := range entry.Data { - if k == hook.EntryKeySource { - continue - } - keys = append(keys, fmt.Sprintf("%s: %v", k, v)) - } - - if len(keys) > 0 { - fields = fmt.Sprintf("[%s] ", strings.Join(keys, ", ")) - } - - level := f.parseLevel(entry.Level) - - return []byte(fmt.Sprintf("%s %s %s%s: %s\n", entry.Time.Format(f.timestampFormat), level, fields, entry.Data[hook.EntryKeySource], entry.Message)), nil -} diff --git a/pkg/logging/txt/format_gorutines.go b/pkg/logging/txt/format_gorutines.go deleted file mode 100644 index cbef038..0000000 --- a/pkg/logging/txt/format_gorutines.go +++ /dev/null @@ -1,35 +0,0 @@ -//go:build loggoroutine - -package txt - -import ( - "fmt" - "strings" - - "github.com/sirupsen/logrus" - - "github.com/netbirdio/management-refactor/pkg/logging/hook" -) - -func (f *TextFormatter) Format(entry *logrus.Entry) ([]byte, error) { - var fields string - keys := make([]string, 0, len(entry.Data)) - for k, v := range entry.Data { - if k == hook.EntryKeySource { - continue - } - - if k == hook.EntryKeyGoroutineID { - continue - } - keys = append(keys, fmt.Sprintf("%s: %v", k, v)) - } - - if len(keys) > 0 { - fields = fmt.Sprintf("[%s] ", strings.Join(keys, ", ")) - } - - level := f.parseLevel(entry.Level) - - return []byte(fmt.Sprintf("%s %s %d %s%s: %s\n", entry.Time.Format(f.timestampFormat), level, entry.Data[hook.EntryKeyGoroutineID], fields, entry.Data[hook.EntryKeySource], entry.Message)), nil -} diff --git a/pkg/logging/txt/formatter.go b/pkg/logging/txt/formatter.go deleted file mode 100644 index 3b2a3fb..0000000 --- a/pkg/logging/txt/formatter.go +++ /dev/null @@ -1,31 +0,0 @@ -package txt - -import ( - "time" - - "github.com/sirupsen/logrus" - - "github.com/netbirdio/netbird/formatter/levels" -) - -// TextFormatter formats logs into text with included source code's path -type TextFormatter struct { - timestampFormat string - levelDesc []string -} - -// NewTextFormatter create new MyTextFormatter instance -func NewTextFormatter() *TextFormatter { - return &TextFormatter{ - levelDesc: levels.ValidLevelDesc, - timestampFormat: time.RFC3339, // or RFC3339 - } -} - -func (f *TextFormatter) parseLevel(level logrus.Level) string { - if len(f.levelDesc) < int(level) { - return "" - } - - return f.levelDesc[level] -} diff --git a/pkg/logging/txt/formatter_test.go b/pkg/logging/txt/formatter_test.go deleted file mode 100644 index 590af5d..0000000 --- a/pkg/logging/txt/formatter_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package txt - -import ( - "testing" - "time" - - "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" -) - -func TestLogTextFormat(t *testing.T) { - - someEntry := &logrus.Entry{ - Data: logrus.Fields{"att1": 1, "att2": 2, "source": "some/fancy/path.go:46"}, - Time: time.Date(2021, time.Month(2), 21, 1, 10, 30, 0, time.UTC), - Level: 3, - Message: "Some Message", - } - - formatter := NewTextFormatter() - result, _ := formatter.Format(someEntry) - - parsedString := string(result) - expectedString := "^2021-02-21T01:10:30Z WARN \\[(att1: 1, att2: 2|att2: 2, att1: 1)\\] some/fancy/path.go:46: Some Message\\s+$" - assert.Regexp(t, expectedString, parsedString) -}