| @@ -5,6 +5,10 @@ import ( | |||||
| "context" | "context" | ||||
| "encoding/hex" | "encoding/hex" | ||||
| "fmt" | "fmt" | ||||
| "io" | |||||
| "log" | |||||
| "log/slog" | |||||
| "os" | |||||
| "os/signal" | "os/signal" | ||||
| "strings" | "strings" | ||||
| "sync" | "sync" | ||||
| @@ -25,6 +29,16 @@ func main() { | |||||
| appState := appcontext.NewAppState() | appState := appcontext.NewAppState() | ||||
| cfg := config.Load() | cfg := config.Load() | ||||
| // Create log file | |||||
| logFile, err := os.OpenFile("server.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) | |||||
| if err != nil { | |||||
| log.Fatalf("Failed to open log file: %v\n", err) | |||||
| } | |||||
| // shell and log file multiwriter | |||||
| w := io.MultiWriter(os.Stderr, logFile) | |||||
| logger := slog.New(slog.NewJSONHandler(w, nil)) | |||||
| slog.SetDefault(logger) | |||||
| // define context | // define context | ||||
| ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT) | ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT) | ||||
| defer stop() | defer stop() | ||||
| @@ -34,7 +48,7 @@ func main() { | |||||
| alertWriter := appState.AddKafkaWriter(cfg.KafkaURL, "alertbeacons") | alertWriter := appState.AddKafkaWriter(cfg.KafkaURL, "alertbeacons") | ||||
| fmt.Println("Decoder initialized, subscribed to Kafka topics") | |||||
| slog.Info("Decoder initialized, subscribed to Kafka topics") | |||||
| chRaw := make(chan model.BeaconAdvertisement, 2000) | chRaw := make(chan model.BeaconAdvertisement, 2000) | ||||
| chApi := make(chan model.ApiUpdate, 200) | chApi := make(chan model.ApiUpdate, 200) | ||||
| @@ -55,18 +69,21 @@ eventloop: | |||||
| case "POST": | case "POST": | ||||
| id := msg.Beacon.ID | id := msg.Beacon.ID | ||||
| appState.AddBeaconToLookup(id) | appState.AddBeaconToLookup(id) | ||||
| lMsg := fmt.Sprintf("Beacon added to lookup: %s", id) | |||||
| slog.Info(lMsg) | |||||
| case "DELETE": | case "DELETE": | ||||
| id := msg.Beacon.ID | id := msg.Beacon.ID | ||||
| appState.RemoveBeaconFromLookup(id) | appState.RemoveBeaconFromLookup(id) | ||||
| fmt.Println("Beacon removed from lookup: ", id) | |||||
| lMsg := fmt.Sprintf("Beacon removed from lookup: %s", id) | |||||
| slog.Info(lMsg) | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| fmt.Println("broken out of the main event loop") | |||||
| slog.Info("broken out of the main event loop") | |||||
| wg.Wait() | wg.Wait() | ||||
| fmt.Println("All go routines have stopped, Beggining to close Kafka connections") | |||||
| slog.Info("All go routines have stopped, Beggining to close Kafka connections") | |||||
| appState.CleanKafkaReaders() | appState.CleanKafkaReaders() | ||||
| appState.CleanKafkaWriters() | appState.CleanKafkaWriters() | ||||
| } | } | ||||
| @@ -80,7 +97,8 @@ func processIncoming(adv model.BeaconAdvertisement, appState *appcontext.AppStat | |||||
| err := decodeBeacon(adv, appState, writer) | err := decodeBeacon(adv, appState, writer) | ||||
| if err != nil { | if err != nil { | ||||
| fmt.Println("error in decoding") | |||||
| eMsg := fmt.Sprintf("Error in decoding: %v", err) | |||||
| fmt.Println(eMsg) | |||||
| return | return | ||||
| } | } | ||||
| } | } | ||||
| @@ -4,6 +4,10 @@ import ( | |||||
| "context" | "context" | ||||
| "encoding/json" | "encoding/json" | ||||
| "fmt" | "fmt" | ||||
| "io" | |||||
| "log" | |||||
| "log/slog" | |||||
| "os" | |||||
| "os/signal" | "os/signal" | ||||
| "sync" | "sync" | ||||
| "syscall" | "syscall" | ||||
| @@ -24,6 +28,16 @@ func main() { | |||||
| appState := appcontext.NewAppState() | appState := appcontext.NewAppState() | ||||
| cfg := config.Load() | cfg := config.Load() | ||||
| // Create log file | |||||
| logFile, err := os.OpenFile("server.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) | |||||
| if err != nil { | |||||
| log.Fatalf("Failed to open log file: %v\n", err) | |||||
| } | |||||
| // shell and log file multiwriter | |||||
| w := io.MultiWriter(os.Stderr, logFile) | |||||
| logger := slog.New(slog.NewJSONHandler(w, nil)) | |||||
| slog.SetDefault(logger) | |||||
| // Define context | // Define context | ||||
| ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT) | ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT) | ||||
| defer stop() | defer stop() | ||||
| @@ -34,7 +48,7 @@ func main() { | |||||
| writer := appState.AddKafkaWriter(cfg.KafkaURL, "locevents") | writer := appState.AddKafkaWriter(cfg.KafkaURL, "locevents") | ||||
| fmt.Println("Locations algorithm initialized, subscribed to Kafka topics") | |||||
| slog.Info("Locations algorithm initialized, subscribed to Kafka topics") | |||||
| locTicker := time.NewTicker(1 * time.Second) | locTicker := time.NewTicker(1 * time.Second) | ||||
| defer locTicker.Stop() | defer locTicker.Stop() | ||||
| @@ -61,22 +75,24 @@ eventLoop: | |||||
| switch msg.Method { | switch msg.Method { | ||||
| case "POST": | case "POST": | ||||
| id := msg.Beacon.ID | id := msg.Beacon.ID | ||||
| fmt.Println("Beacon added to lookup: ", id) | |||||
| lMsg := fmt.Sprintf("Beacon added to lookup: %s", id) | |||||
| slog.Info(lMsg) | |||||
| appState.AddBeaconToLookup(id) | appState.AddBeaconToLookup(id) | ||||
| case "DELETE": | case "DELETE": | ||||
| id := msg.Beacon.ID | id := msg.Beacon.ID | ||||
| appState.RemoveBeaconFromLookup(id) | appState.RemoveBeaconFromLookup(id) | ||||
| fmt.Println("Beacon removed from lookup: ", id) | |||||
| lMsg := fmt.Sprintf("Beacon removed from lookup: %s", id) | |||||
| slog.Info(lMsg) | |||||
| } | } | ||||
| case msg := <-chSettings: | case msg := <-chSettings: | ||||
| appState.UpdateSettings(msg) | appState.UpdateSettings(msg) | ||||
| } | } | ||||
| } | } | ||||
| fmt.Println("broken out of the main event loop") | |||||
| slog.Info("broken out of the main event loop") | |||||
| wg.Wait() | wg.Wait() | ||||
| fmt.Println("All go routines have stopped, Beggining to close Kafka connections") | |||||
| slog.Info("All go routines have stopped, Beggining to close Kafka connections") | |||||
| appState.CleanKafkaReaders() | appState.CleanKafkaReaders() | ||||
| appState.CleanKafkaWriters() | appState.CleanKafkaWriters() | ||||
| } | } | ||||
| @@ -98,7 +114,7 @@ func getLikelyLocations(appState *appcontext.AppState, writer *kafka.Writer) { | |||||
| mSize := len(beacon.BeaconMetrics) | mSize := len(beacon.BeaconMetrics) | ||||
| if (int64(time.Now().Unix()) - (beacon.BeaconMetrics[mSize-1].Timestamp)) > settings.LastSeenThreshold { | if (int64(time.Now().Unix()) - (beacon.BeaconMetrics[mSize-1].Timestamp)) > settings.LastSeenThreshold { | ||||
| fmt.Println("Beacon is too old") | |||||
| slog.Warn("beacon is too old") | |||||
| continue | continue | ||||
| } | } | ||||
| @@ -133,7 +149,6 @@ func getLikelyLocations(appState *appcontext.AppState, writer *kafka.Writer) { | |||||
| beacon.LocationConfidence = 0 | beacon.LocationConfidence = 0 | ||||
| // Why do I need this if I am sending entire structure anyways? who knows | // Why do I need this if I am sending entire structure anyways? who knows | ||||
| fmt.Println("this is called") | |||||
| js, err := json.Marshal(model.LocationChange{ | js, err := json.Marshal(model.LocationChange{ | ||||
| Method: "LocationChange", | Method: "LocationChange", | ||||
| BeaconRef: beacon, | BeaconRef: beacon, | ||||
| @@ -144,7 +159,8 @@ func getLikelyLocations(appState *appcontext.AppState, writer *kafka.Writer) { | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| fmt.Println("This error happens: ", err) | |||||
| eMsg := fmt.Sprintf("Error in marshaling: %v", err) | |||||
| slog.Error(eMsg) | |||||
| beacon.PreviousConfidentLocation = bestLocName | beacon.PreviousConfidentLocation = bestLocName | ||||
| beacon.PreviousLocation = bestLocName | beacon.PreviousLocation = bestLocName | ||||
| appState.UpdateBeacon(beacon.ID, beacon) | appState.UpdateBeacon(beacon.ID, beacon) | ||||
| @@ -166,7 +182,8 @@ func getLikelyLocations(appState *appcontext.AppState, writer *kafka.Writer) { | |||||
| js, err := json.Marshal(r) | js, err := json.Marshal(r) | ||||
| if err != nil { | if err != nil { | ||||
| fmt.Println("Error in marshaling location: ", err) | |||||
| eMsg := fmt.Sprintf("Error in marshaling location: %v", err) | |||||
| slog.Error(eMsg) | |||||
| continue | continue | ||||
| } | } | ||||
| @@ -176,7 +193,8 @@ func getLikelyLocations(appState *appcontext.AppState, writer *kafka.Writer) { | |||||
| err = writer.WriteMessages(context.Background(), msg) | err = writer.WriteMessages(context.Background(), msg) | ||||
| if err != nil { | if err != nil { | ||||
| fmt.Println("Error in sending Kafka message: ", err) | |||||
| eMsg := fmt.Sprintf("Error in sending Kafka message: %v", err) | |||||
| slog.Error(eMsg) | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -194,7 +212,7 @@ func assignBeaconToList(adv model.BeaconAdvertisement, appState *appcontext.AppS | |||||
| settings := appState.GetSettingsValue() | settings := appState.GetSettingsValue() | ||||
| if settings.RSSIEnforceThreshold && (int64(adv.RSSI) < settings.RSSIMinThreshold) { | if settings.RSSIEnforceThreshold && (int64(adv.RSSI) < settings.RSSIMinThreshold) { | ||||
| fmt.Println("Settings returns") | |||||
| slog.Info("Settings returns") | |||||
| return | return | ||||
| } | } | ||||
| @@ -4,8 +4,11 @@ import ( | |||||
| "context" | "context" | ||||
| "encoding/json" | "encoding/json" | ||||
| "fmt" | "fmt" | ||||
| "io" | |||||
| "log" | "log" | ||||
| "log/slog" | |||||
| "net/http" | "net/http" | ||||
| "os" | |||||
| "os/signal" | "os/signal" | ||||
| "strings" | "strings" | ||||
| "sync" | "sync" | ||||
| @@ -28,12 +31,24 @@ var upgrader = websocket.Upgrader{ | |||||
| WriteBufferSize: 1024, | WriteBufferSize: 1024, | ||||
| } | } | ||||
| var _ io.Writer = (*os.File)(nil) | |||||
| var wg sync.WaitGroup | var wg sync.WaitGroup | ||||
| func main() { | func main() { | ||||
| cfg := config.Load() | cfg := config.Load() | ||||
| appState := appcontext.NewAppState() | appState := appcontext.NewAppState() | ||||
| // Create log file | |||||
| logFile, err := os.OpenFile("server.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) | |||||
| if err != nil { | |||||
| log.Fatalf("Failed to open log file: %v\n", err) | |||||
| } | |||||
| // shell and log file multiwriter | |||||
| w := io.MultiWriter(os.Stderr, logFile) | |||||
| logger := slog.New(slog.NewJSONHandler(w, nil)) | |||||
| slog.SetDefault(logger) | |||||
| // define context | // define context | ||||
| ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT) | ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT) | ||||
| defer stop() | defer stop() | ||||
| @@ -44,12 +59,14 @@ func main() { | |||||
| writer := appState.AddKafkaWriter(cfg.KafkaURL, "apibeacons") | writer := appState.AddKafkaWriter(cfg.KafkaURL, "apibeacons") | ||||
| settingsWriter := appState.AddKafkaWriter(cfg.KafkaURL, "settings") | settingsWriter := appState.AddKafkaWriter(cfg.KafkaURL, "settings") | ||||
| slog.Info("Kafka writers topics: apibeacons, settings initialized") | |||||
| locationReader := appState.AddKafkaReader(cfg.KafkaURL, "locevents", "gid-loc-server") | locationReader := appState.AddKafkaReader(cfg.KafkaURL, "locevents", "gid-loc-server") | ||||
| alertsReader := appState.AddKafkaReader(cfg.KafkaURL, "alertbeacons", "gid-alert-serv") | alertsReader := appState.AddKafkaReader(cfg.KafkaURL, "alertbeacons", "gid-alert-serv") | ||||
| slog.Info("Kafka readers topics: locevents, alertbeacons initialized") | |||||
| client := appState.AddValkeyClient(cfg.ValkeyURL) | client := appState.AddValkeyClient(cfg.ValkeyURL) | ||||
| fmt.Println("Init of kafka writers and readers done") | |||||
| slog.Info("Valkey DB client created") | |||||
| chLoc := make(chan model.HTTPLocation, 200) | chLoc := make(chan model.HTTPLocation, 200) | ||||
| chEvents := make(chan model.BeaconEvent, 500) | chEvents := make(chan model.BeaconEvent, 500) | ||||
| @@ -60,9 +77,6 @@ func main() { | |||||
| r := mux.NewRouter() | r := mux.NewRouter() | ||||
| fmt.Println("new print") | |||||
| fmt.Println("new print") | |||||
| // For now just add beacon DELETE / GET / POST / PUT methods | |||||
| r.HandleFunc("/api/beacons/{beacon_id}", controller.BeaconsDeleteController(writer, ctx, appState)).Methods("DELETE") | r.HandleFunc("/api/beacons/{beacon_id}", controller.BeaconsDeleteController(writer, ctx, appState)).Methods("DELETE") | ||||
| r.HandleFunc("/api/beacons", controller.BeaconsListController(appState)).Methods("GET") | r.HandleFunc("/api/beacons", controller.BeaconsListController(appState)).Methods("GET") | ||||
| r.HandleFunc("/api/beacons/{beacon_id}", controller.BeaconsListSingleController(appState)).Methods("GET") | r.HandleFunc("/api/beacons/{beacon_id}", controller.BeaconsListSingleController(appState)).Methods("GET") | ||||
| @@ -97,27 +111,35 @@ eventLoop: | |||||
| break eventLoop | break eventLoop | ||||
| case msg := <-chLoc: | case msg := <-chLoc: | ||||
| if err := service.LocationToBeaconService(msg, appState, client, ctx); err != nil { | if err := service.LocationToBeaconService(msg, appState, client, ctx); err != nil { | ||||
| fmt.Printf("Error in writing location change to beacon: %v\n", err) | |||||
| eMsg := fmt.Sprintf("Error in writing location change to beacon: %v\n", err) | |||||
| slog.Error(eMsg) | |||||
| } | } | ||||
| case msg := <-chEvents: | case msg := <-chEvents: | ||||
| if err := service.EventToBeaconService(msg, appState, client, ctx); err != nil { | if err := service.EventToBeaconService(msg, appState, client, ctx); err != nil { | ||||
| fmt.Printf("Error in writing event change to beacon: %v\n", err) | |||||
| eMsg := fmt.Sprintf("Error in writing event change to beacon: %v\n", err) | |||||
| slog.Error(eMsg) | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if err := server.Shutdown(context.Background()); err != nil { | if err := server.Shutdown(context.Background()); err != nil { | ||||
| fmt.Printf("could not shutdown: %v\n", err) | |||||
| eMsg := fmt.Sprintf("could not shutdown: %v\n", err) | |||||
| slog.Error(eMsg) | |||||
| } | } | ||||
| fmt.Println("broken out of the main event loop and HTTP server shutdown") | |||||
| slog.Info("API SERVER: \n") | |||||
| slog.Warn("broken out of the main event loop and HTTP server shutdown\n") | |||||
| wg.Wait() | wg.Wait() | ||||
| fmt.Println("All go routines have stopped, Beggining to close Kafka connections") | |||||
| slog.Info("All go routines have stopped, Beggining to close Kafka connections\n") | |||||
| appState.CleanKafkaReaders() | appState.CleanKafkaReaders() | ||||
| appState.CleanKafkaWriters() | appState.CleanKafkaWriters() | ||||
| fmt.Println("All kafka clients shutdown, starting shutdown of valkey client") | |||||
| slog.Info("All kafka clients shutdown, starting shutdown of valkey client") | |||||
| appState.CleanValkeyClient() | appState.CleanValkeyClient() | ||||
| slog.Info("API server shutting down") | |||||
| logFile.Close() | |||||
| } | } | ||||
| func serveWs(appstate *appcontext.AppState, ctx context.Context) http.HandlerFunc { | func serveWs(appstate *appcontext.AppState, ctx context.Context) http.HandlerFunc { | ||||
| @@ -125,7 +147,8 @@ func serveWs(appstate *appcontext.AppState, ctx context.Context) http.HandlerFun | |||||
| ws, err := upgrader.Upgrade(w, r, nil) | ws, err := upgrader.Upgrade(w, r, nil) | ||||
| if err != nil { | if err != nil { | ||||
| if _, ok := err.(websocket.HandshakeError); !ok { | if _, ok := err.(websocket.HandshakeError); !ok { | ||||
| log.Println(err) | |||||
| eMsg := fmt.Sprintf("could not upgrade ws connection: %v\n", err) | |||||
| slog.Error(eMsg) | |||||
| } | } | ||||
| return | return | ||||
| } | } | ||||
| @@ -147,7 +170,7 @@ func writer(ws *websocket.Conn, appstate *appcontext.AppState, ctx context.Conte | |||||
| for { | for { | ||||
| select { | select { | ||||
| case <-ctx.Done(): | case <-ctx.Done(): | ||||
| log.Println("WebSocket writer received shutdown signal.") | |||||
| slog.Info("WebSocket writer received shutdown signal.") | |||||
| ws.SetWriteDeadline(time.Now().Add(10 * time.Second)) | ws.SetWriteDeadline(time.Now().Add(10 * time.Second)) | ||||
| ws.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) | ws.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) | ||||
| return | return | ||||
| @@ -180,10 +203,9 @@ func reader(ws *websocket.Conn, ctx context.Context) { | |||||
| ws.SetReadDeadline(time.Now().Add((60 * 9) / 10 * time.Second)) | ws.SetReadDeadline(time.Now().Add((60 * 9) / 10 * time.Second)) | ||||
| ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add((60 * 9) / 10 * time.Second)); return nil }) | ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add((60 * 9) / 10 * time.Second)); return nil }) | ||||
| for { | for { | ||||
| fmt.Println("this is called") | |||||
| select { | select { | ||||
| case <-ctx.Done(): | case <-ctx.Done(): | ||||
| fmt.Println("closing websocket reader") | |||||
| slog.Info("closing ws reader") | |||||
| return | return | ||||
| default: | default: | ||||
| _, _, err := ws.ReadMessage() | _, _, err := ws.ReadMessage() | ||||