Logging with charm colorful logger

This commit is contained in:
Maciej Krzyżanowski 2024-03-24 17:10:02 +01:00
parent 361b84aac4
commit 4da29dc45b
7 changed files with 119 additions and 40 deletions

View File

@ -1,100 +1,116 @@
package client package client
import ( import (
"log"
"net/url" "net/url"
"os"
"time" "time"
"github.com/charmbracelet/log"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
cm "krzyzanowski.dev/p2pchat/common" 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() { func RunClient() {
u := url.URL{Scheme: "ws", Host: ":8080", Path: "/wsapi"} u := url.URL{Scheme: "ws", Host: ":8080", Path: "/wsapi"}
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil) c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil { if err != nil {
log.Println("[Client] could not connect to websocket") logger.Error("could not connect to websocket")
return return
} }
defer c.Close() defer c.Close()
log.Println("[Client] authenticating...") logger.Info("authenticating...")
rf, _ := cm.RequestFrameFrom(cm.AuthRequest{Nickname: "krzmaciek", Password: "9maciek1"}) rf, _ := cm.RequestFrameFrom(cm.AuthRequest{Nickname: "krzmaciek", Password: "9maciek1"})
err = c.WriteJSON(rf) err = c.WriteJSON(rf)
if err != nil { if err != nil {
log.Fatalln(err) logger.Fatal(err)
} }
var authResFrame cm.ResponseFrame var authResFrame cm.ResponseFrame
err = c.ReadJSON(&authResFrame) err = c.ReadJSON(&authResFrame)
if err != nil { if err != nil {
log.Fatalln(err) logger.Fatal(err)
} }
authRes, err := cm.ResponseFromFrame[cm.AuthResponse](authResFrame) authRes, err := cm.ResponseFromFrame[cm.AuthResponse](authResFrame)
if err != nil { 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) time.Sleep(time.Second * 1)
log.Println("[Client] sending echo...") logger.Info("sending echo...")
echoByte := 123 echoByte := 123
rf, err = cm.RequestFrameFrom(cm.EchoRequest{EchoByte: byte(echoByte)}) rf, err = cm.RequestFrameFrom(cm.EchoRequest{EchoByte: byte(echoByte)})
if err != nil { if err != nil {
log.Fatalln(err) logger.Fatal(err)
} }
err = c.WriteJSON(rf) err = c.WriteJSON(rf)
if err != nil { if err != nil {
log.Fatalln(err) logger.Fatal(err)
} }
var echoResFrame cm.ResponseFrame var echoResFrame cm.ResponseFrame
err = c.ReadJSON(&echoResFrame) err = c.ReadJSON(&echoResFrame)
if err != nil { if err != nil {
log.Fatalln(err) logger.Fatal(err)
} }
echoRes, err := cm.ResponseFromFrame[cm.EchoResponse](echoResFrame) echoRes, err := cm.ResponseFromFrame[cm.EchoResponse](echoResFrame)
if err != nil { 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) 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{}) rf, err = cm.RequestFrameFrom(cm.ListPeersRequest{})
if err != nil { if err != nil {
log.Fatalln(err) logger.Fatal(err)
} }
err = c.WriteJSON(rf) err = c.WriteJSON(rf)
if err != nil { if err != nil {
log.Fatalln(err) logger.Fatal(err)
} }
var listPeersResFrame cm.ResponseFrame var listPeersResFrame cm.ResponseFrame
err = c.ReadJSON(&listPeersResFrame) err = c.ReadJSON(&listPeersResFrame)
if err != nil { if err != nil {
log.Fatalln(err) logger.Fatal(err)
} }
listPeersRes, err := cm.ResponseFromFrame[cm.ListPeersResponse](listPeersResFrame) listPeersRes, err := cm.ResponseFromFrame[cm.ListPeersResponse](listPeersResFrame)
if err != nil { 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 { for _, p := range listPeersRes.PeersInfo {
log.Printf("[Client] %+v\n", p) logger.Infof("%+v", p)
} }
time.Sleep(time.Second * 5) time.Sleep(time.Second * 5)
logger.Info("closing connection...")
c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
} }

View File

@ -4,7 +4,7 @@ import (
"encoding/json" "encoding/json"
) )
// Constants: // Constants
const ( const (
EchoRID = 1 EchoRID = 1

3
common/settings.go Normal file
View File

@ -0,0 +1,3 @@
package common
const IsProd = false

16
go.mod
View File

@ -7,4 +7,18 @@ require (
golang.org/x/crypto v0.21.0 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
)

28
go.sum
View File

@ -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 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= 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 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= 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 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= 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=

View File

@ -8,6 +8,8 @@ import (
"krzyzanowski.dev/p2pchat/server" "krzyzanowski.dev/p2pchat/server"
) )
const IsProd = false
func main() { func main() {
args := os.Args[1:] args := os.Args[1:]

View File

@ -2,12 +2,13 @@ package server
import ( import (
"encoding/json" "encoding/json"
"log"
"net/http" "net/http"
"os"
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/charmbracelet/log"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
"krzyzanowski.dev/p2pchat/common" "krzyzanowski.dev/p2pchat/common"
@ -39,6 +40,20 @@ type Peer struct {
account *Account 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 { func NewPeer(conn *websocket.Conn) *Peer {
return &Peer{-1, conn, false, nil} return &Peer{-1, conn, false, nil}
} }
@ -67,13 +82,13 @@ func (srvCtx *ServerContext) removePeer(peer *Peer) {
func handleDisconnection(handlerCtx *HandlerContext) { func handleDisconnection(handlerCtx *HandlerContext) {
handlerCtx.removePeer(handlerCtx.peer) 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) { func (hdlCtx *HandlerContext) handleEcho(reqFrame *common.RequestFrame) (res common.Response, err error) {
echoReq, err := common.RequestFromFrame[common.EchoRequest](*reqFrame) echoReq, err := common.RequestFromFrame[common.EchoRequest](*reqFrame)
if err != nil { if err != nil {
log.Println("[Server] could not read request from frame") logger.Error("could not read request from frame")
return nil, err 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 // Currently list peers request is empty, so we can ignore it - we won't use it
_, err = common.RequestFromFrame[common.ListPeersRequest](*reqFrame) _, err = common.RequestFromFrame[common.ListPeersRequest](*reqFrame)
if err != nil { if err != nil {
log.Println("[Server] could not read request from frame") logger.Error("could not read request from frame")
return nil, err 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) { func (hdlCtx *HandlerContext) handleAuth(reqFrame *common.RequestFrame) (res common.Response, err error) {
authReq, err := common.RequestFromFrame[common.AuthRequest](*reqFrame) authReq, err := common.RequestFromFrame[common.AuthRequest](*reqFrame)
if err != nil { if err != nil {
log.Println("[Server] could not read request from frame") logger.Error("could not read request from frame")
return nil, err return nil, err
} }
@ -157,7 +172,7 @@ func (hdlCtx *HandlerContext) handleAuth(reqFrame *common.RequestFrame) (res com
func (srvCtx *ServerContext) printConnectedPeers() { func (srvCtx *ServerContext) printConnectedPeers() {
srvCtx.peersListLock.RLock() srvCtx.peersListLock.RLock()
log.Println("[Server] displaying all connections:") logger.Debug("displaying all connections:")
for _, p := range srvCtx.peersList { for _, p := range srvCtx.peersList {
nick := "-" nick := "-"
@ -166,17 +181,17 @@ func (srvCtx *ServerContext) printConnectedPeers() {
nick = p.account.nickname 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() srvCtx.peersListLock.RUnlock()
} }
func (hdlCtx *HandlerContext) handleRequest(reqJsonBytes []byte) error { 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 var reqFrame common.RequestFrame
json.Unmarshal(reqJsonBytes, &reqFrame) 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 res common.Response
var err error var err error
@ -189,26 +204,26 @@ func (hdlCtx *HandlerContext) handleRequest(reqJsonBytes []byte) error {
} }
if err != nil { 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 return err
} }
resFrame, err := common.ResponseFrameFrom(res) resFrame, err := common.ResponseFrameFrom(res)
if err != nil { if err != nil {
log.Println("[Server] could not create frame from response") logger.Errorf("could not create frame from response")
return err return err
} }
resJsonBytes, err := json.Marshal(resFrame) resJsonBytes, err := json.Marshal(resFrame)
if err != nil { if err != nil {
log.Println("[Server] error marshalling frame to json") logger.Errorf("error marshalling frame to json")
return err return err
} }
log.Printf("[Server] sending %s\n", string(resJsonBytes)) logger.Debugf("sending %s", string(resJsonBytes))
err = hdlCtx.peer.conn.WriteMessage(websocket.TextMessage, resJsonBytes) err = hdlCtx.peer.conn.WriteMessage(websocket.TextMessage, resJsonBytes)
if err != nil { if err != nil {
log.Println("[Server] error writing response frame") logger.Errorf("error writing response frame")
return err return err
} }
@ -229,7 +244,7 @@ func (srvCtx *ServerContext) wsapiHandler(w http.ResponseWriter, r *http.Request
upgrader := websocket.Upgrader{} upgrader := websocket.Upgrader{}
conn, err := upgrader.Upgrade(w, r, nil) conn, err := upgrader.Upgrade(w, r, nil)
if err != nil { if err != nil {
log.Println("[Server] upgrade failed") logger.Errorf("upgrade failed")
return return
} }
@ -238,7 +253,7 @@ func (srvCtx *ServerContext) wsapiHandler(w http.ResponseWriter, r *http.Request
handlerCtx := &HandlerContext{peer, srvCtx} handlerCtx := &HandlerContext{peer, srvCtx}
defer handleDisconnection(handlerCtx) defer handleDisconnection(handlerCtx)
defer conn.Close() defer conn.Close()
log.Printf("[Server] %s connected\n", conn.RemoteAddr()) logger.Infof("%s connected", conn.RemoteAddr())
for { for {
messType, messBytes, err := conn.ReadMessage() messType, messBytes, err := conn.ReadMessage()
@ -249,7 +264,7 @@ func (srvCtx *ServerContext) wsapiHandler(w http.ResponseWriter, r *http.Request
if messType != 1 { if messType != 1 {
err := conn.WriteMessage(websocket.CloseUnsupportedData, []byte("Only JSON text is supported")) err := conn.WriteMessage(websocket.CloseUnsupportedData, []byte("Only JSON text is supported"))
if err != nil { 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 return
@ -257,7 +272,7 @@ func (srvCtx *ServerContext) wsapiHandler(w http.ResponseWriter, r *http.Request
err = handlerCtx.handleRequest(messBytes) err = handlerCtx.handleRequest(messBytes)
if err != nil { if err != nil {
log.Println(err) logger.Debug(err)
break break
} }
} }
@ -274,5 +289,6 @@ func RunServer() {
}() }()
http.HandleFunc("/wsapi", srvCtx.wsapiHandler) http.HandleFunc("/wsapi", srvCtx.wsapiHandler)
logger.Info("Starting server...")
http.ListenAndServe(":8080", nil) http.ListenAndServe(":8080", nil)
} }