From 4da29dc45b85c5011ecef4c6ffaa0f946302fd55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Krzy=C5=BCanowski?= Date: Sun, 24 Mar 2024 17:10:02 +0100 Subject: [PATCH] Logging with charm colorful logger --- client/client.go | 56 +++++++++++++++++++++++++++++----------------- common/common.go | 2 +- common/settings.go | 3 +++ go.mod | 16 ++++++++++++- go.sum | 28 +++++++++++++++++++++++ main.go | 2 ++ server/server.go | 52 +++++++++++++++++++++++++++--------------- 7 files changed, 119 insertions(+), 40 deletions(-) create mode 100644 common/settings.go diff --git a/client/client.go b/client/client.go index d0daac1..a9d778e 100644 --- a/client/client.go +++ b/client/client.go @@ -1,100 +1,116 @@ package client import ( - "log" "net/url" + "os" "time" + "github.com/charmbracelet/log" "github.com/gorilla/websocket" cm "krzyzanowski.dev/p2pchat/common" ) +var logger = log.NewWithOptions(os.Stdout, log.Options{ + ReportTimestamp: true, + TimeFormat: time.TimeOnly, + Prefix: "👤 Client", +}) + +func init() { + if cm.IsProd { + logger.SetLevel(log.InfoLevel) + } else { + logger.SetLevel(log.DebugLevel) + } +} + func RunClient() { u := url.URL{Scheme: "ws", Host: ":8080", Path: "/wsapi"} c, _, err := websocket.DefaultDialer.Dial(u.String(), nil) if err != nil { - log.Println("[Client] could not connect to websocket") + logger.Error("could not connect to websocket") return } defer c.Close() - log.Println("[Client] authenticating...") + logger.Info("authenticating...") rf, _ := cm.RequestFrameFrom(cm.AuthRequest{Nickname: "krzmaciek", Password: "9maciek1"}) err = c.WriteJSON(rf) if err != nil { - log.Fatalln(err) + logger.Fatal(err) } var authResFrame cm.ResponseFrame err = c.ReadJSON(&authResFrame) if err != nil { - log.Fatalln(err) + logger.Fatal(err) } authRes, err := cm.ResponseFromFrame[cm.AuthResponse](authResFrame) if err != nil { - log.Fatalln(err) + logger.Fatal(err) } - log.Printf("[Client] authentication result: %t\n", authRes.IsSuccess) + logger.Infof("authentication result: %t", authRes.IsSuccess) time.Sleep(time.Second * 1) - log.Println("[Client] sending echo...") + logger.Info("sending echo...") echoByte := 123 rf, err = cm.RequestFrameFrom(cm.EchoRequest{EchoByte: byte(echoByte)}) if err != nil { - log.Fatalln(err) + logger.Fatal(err) } err = c.WriteJSON(rf) if err != nil { - log.Fatalln(err) + logger.Fatal(err) } var echoResFrame cm.ResponseFrame err = c.ReadJSON(&echoResFrame) if err != nil { - log.Fatalln(err) + logger.Fatal(err) } echoRes, err := cm.ResponseFromFrame[cm.EchoResponse](echoResFrame) if err != nil { - log.Fatalln(err) + logger.Fatal(err) } - log.Printf("[Client] sent echo of %d, got %d in return\n", echoByte, echoRes.EchoByte) + logger.Infof("sent echo of %d, got %d in return", echoByte, echoRes.EchoByte) time.Sleep(time.Second) - log.Println("[Client] i want list of peers...") + logger.Infof("i want list of peers...") rf, err = cm.RequestFrameFrom(cm.ListPeersRequest{}) if err != nil { - log.Fatalln(err) + logger.Fatal(err) } err = c.WriteJSON(rf) if err != nil { - log.Fatalln(err) + logger.Fatal(err) } var listPeersResFrame cm.ResponseFrame err = c.ReadJSON(&listPeersResFrame) if err != nil { - log.Fatalln(err) + logger.Fatal(err) } listPeersRes, err := cm.ResponseFromFrame[cm.ListPeersResponse](listPeersResFrame) if err != nil { - log.Fatalln(err) + logger.Fatal(err) } - log.Println("[Client] printing list of peers:") + logger.Info("printing list of peers:") for _, p := range listPeersRes.PeersInfo { - log.Printf("[Client] %+v\n", p) + logger.Infof("%+v", p) } time.Sleep(time.Second * 5) + logger.Info("closing connection...") c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) } diff --git a/common/common.go b/common/common.go index 74c690e..cb43b74 100644 --- a/common/common.go +++ b/common/common.go @@ -4,7 +4,7 @@ import ( "encoding/json" ) -// Constants: +// Constants const ( EchoRID = 1 diff --git a/common/settings.go b/common/settings.go new file mode 100644 index 0000000..c3bce24 --- /dev/null +++ b/common/settings.go @@ -0,0 +1,3 @@ +package common + +const IsProd = false diff --git a/go.mod b/go.mod index 5d4b78e..2ee3c42 100644 --- a/go.mod +++ b/go.mod @@ -7,4 +7,18 @@ require ( golang.org/x/crypto v0.21.0 ) -require golang.org/x/net v0.21.0 // indirect +require ( + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/charmbracelet/lipgloss v0.10.0 // indirect + github.com/charmbracelet/log v0.4.0 // indirect + github.com/go-logfmt/logfmt v0.6.0 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.18 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/muesli/reflow v0.3.0 // indirect + github.com/muesli/termenv v0.15.2 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sys v0.18.0 // indirect +) diff --git a/go.sum b/go.sum index fe24a7c..bd66e3d 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,34 @@ +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s= +github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE= +github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM= +github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= +github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/main.go b/main.go index a627668..f09d76a 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,8 @@ import ( "krzyzanowski.dev/p2pchat/server" ) +const IsProd = false + func main() { args := os.Args[1:] diff --git a/server/server.go b/server/server.go index 26a10fc..1067d26 100644 --- a/server/server.go +++ b/server/server.go @@ -2,12 +2,13 @@ package server import ( "encoding/json" - "log" "net/http" + "os" "strings" "sync" "time" + "github.com/charmbracelet/log" "github.com/gorilla/websocket" "golang.org/x/crypto/bcrypt" "krzyzanowski.dev/p2pchat/common" @@ -39,6 +40,20 @@ type Peer struct { account *Account } +var logger = log.NewWithOptions(os.Stdout, log.Options{ + ReportTimestamp: true, + TimeFormat: time.TimeOnly, + Prefix: "⚙️ Server", +}) + +func init() { + if common.IsProd { + logger.SetLevel(log.InfoLevel) + } else { + logger.SetLevel(log.DebugLevel) + } +} + func NewPeer(conn *websocket.Conn) *Peer { return &Peer{-1, conn, false, nil} } @@ -67,13 +82,13 @@ func (srvCtx *ServerContext) removePeer(peer *Peer) { func handleDisconnection(handlerCtx *HandlerContext) { handlerCtx.removePeer(handlerCtx.peer) - log.Printf("[Server] %s disconnected\n", handlerCtx.peer.conn.RemoteAddr()) + logger.Infof("%s disconnected", handlerCtx.peer.conn.RemoteAddr()) } func (hdlCtx *HandlerContext) handleEcho(reqFrame *common.RequestFrame) (res common.Response, err error) { echoReq, err := common.RequestFromFrame[common.EchoRequest](*reqFrame) if err != nil { - log.Println("[Server] could not read request from frame") + logger.Error("could not read request from frame") return nil, err } @@ -85,7 +100,7 @@ func (hdlCtx *HandlerContext) handleListPeers(reqFrame *common.RequestFrame) (re // Currently list peers request is empty, so we can ignore it - we won't use it _, err = common.RequestFromFrame[common.ListPeersRequest](*reqFrame) if err != nil { - log.Println("[Server] could not read request from frame") + logger.Error("could not read request from frame") return nil, err } @@ -113,7 +128,7 @@ func (hdlCtx *HandlerContext) handleListPeers(reqFrame *common.RequestFrame) (re func (hdlCtx *HandlerContext) handleAuth(reqFrame *common.RequestFrame) (res common.Response, err error) { authReq, err := common.RequestFromFrame[common.AuthRequest](*reqFrame) if err != nil { - log.Println("[Server] could not read request from frame") + logger.Error("could not read request from frame") return nil, err } @@ -157,7 +172,7 @@ func (hdlCtx *HandlerContext) handleAuth(reqFrame *common.RequestFrame) (res com func (srvCtx *ServerContext) printConnectedPeers() { srvCtx.peersListLock.RLock() - log.Println("[Server] displaying all connections:") + logger.Debug("displaying all connections:") for _, p := range srvCtx.peersList { nick := "-" @@ -166,17 +181,17 @@ func (srvCtx *ServerContext) printConnectedPeers() { nick = p.account.nickname } - log.Printf("[Server] ID#%d, Addr:%s, Auth:%t, Nick:%s\n", p.id, p.conn.RemoteAddr(), p.hasAccount, nick) + log.Debugf("ID#%d, Addr:%s, Auth:%t, Nick:%s", p.id, p.conn.RemoteAddr(), p.hasAccount, nick) } srvCtx.peersListLock.RUnlock() } func (hdlCtx *HandlerContext) handleRequest(reqJsonBytes []byte) error { - log.Printf("[Server] got message text: %s\n", strings.Trim(string(reqJsonBytes), "\n")) + logger.Debugf("got message text: %s", strings.Trim(string(reqJsonBytes), "\n")) var reqFrame common.RequestFrame json.Unmarshal(reqJsonBytes, &reqFrame) - log.Printf("[Server] unmarshalled request frame (ID=%d)\n", reqFrame.ID) + log.Debugf("unmarshalled request frame (ID=%d)", reqFrame.ID) var res common.Response var err error @@ -189,26 +204,26 @@ func (hdlCtx *HandlerContext) handleRequest(reqJsonBytes []byte) error { } if err != nil { - log.Printf("[Server] could not handle request ID=%d\n", reqFrame.ID) + logger.Errorf("could not handle request ID=%d", reqFrame.ID) return err } resFrame, err := common.ResponseFrameFrom(res) if err != nil { - log.Println("[Server] could not create frame from response") + logger.Errorf("could not create frame from response") return err } resJsonBytes, err := json.Marshal(resFrame) if err != nil { - log.Println("[Server] error marshalling frame to json") + logger.Errorf("error marshalling frame to json") return err } - log.Printf("[Server] sending %s\n", string(resJsonBytes)) + logger.Debugf("sending %s", string(resJsonBytes)) err = hdlCtx.peer.conn.WriteMessage(websocket.TextMessage, resJsonBytes) if err != nil { - log.Println("[Server] error writing response frame") + logger.Errorf("error writing response frame") return err } @@ -229,7 +244,7 @@ func (srvCtx *ServerContext) wsapiHandler(w http.ResponseWriter, r *http.Request upgrader := websocket.Upgrader{} conn, err := upgrader.Upgrade(w, r, nil) if err != nil { - log.Println("[Server] upgrade failed") + logger.Errorf("upgrade failed") return } @@ -238,7 +253,7 @@ func (srvCtx *ServerContext) wsapiHandler(w http.ResponseWriter, r *http.Request handlerCtx := &HandlerContext{peer, srvCtx} defer handleDisconnection(handlerCtx) defer conn.Close() - log.Printf("[Server] %s connected\n", conn.RemoteAddr()) + logger.Infof("%s connected", conn.RemoteAddr()) for { messType, messBytes, err := conn.ReadMessage() @@ -249,7 +264,7 @@ func (srvCtx *ServerContext) wsapiHandler(w http.ResponseWriter, r *http.Request if messType != 1 { err := conn.WriteMessage(websocket.CloseUnsupportedData, []byte("Only JSON text is supported")) if err != nil { - log.Println("[Server] error sending close message due to unsupported data") + logger.Debugf("[Server] error sending close message due to unsupported data") } return @@ -257,7 +272,7 @@ func (srvCtx *ServerContext) wsapiHandler(w http.ResponseWriter, r *http.Request err = handlerCtx.handleRequest(messBytes) if err != nil { - log.Println(err) + logger.Debug(err) break } } @@ -274,5 +289,6 @@ func RunServer() { }() http.HandleFunc("/wsapi", srvCtx.wsapiHandler) + logger.Info("Starting server...") http.ListenAndServe(":8080", nil) }