Switch to ctxlog

zikaeroh created

Change summary

go.mod                    |  2 ++
go.sum                    | 23 +++++++++++++++++++++++
internal/server/server.go | 38 ++++++++++++++++++++++----------------
main.go                   | 22 +++++++++++++++-------
4 files changed, 62 insertions(+), 23 deletions(-)

Detailed changes

go.mod 🔗

@@ -13,7 +13,9 @@ require (
 	github.com/speps/go-hashids v2.0.0+incompatible
 	github.com/tomwright/queryparam/v4 v4.1.0
 	github.com/zikaeroh/ctxjoin v0.0.0-20200613235025-e3d47af29310
+	github.com/zikaeroh/ctxlog v0.0.0-20200613043947-8791c8613223
 	go.uber.org/atomic v1.6.0
+	go.uber.org/zap v1.15.0
 	golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
 	gotest.tools/v3 v3.0.2
 	nhooyr.io/websocket v1.8.6

go.sum 🔗

@@ -1,3 +1,5 @@
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -59,6 +61,7 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
 github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
 github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/jessevdk/go-flags v1.4.1-0.20181221193153-c0795c8afcf4 h1:xKkUL6QBojwguhKKetf1SocCAKqc6W7S/mGm9xEGllo=
@@ -67,6 +70,7 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
 github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
 github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/klauspost/compress v1.10.3 h1:OP96hzwJVBIHYU52pVTI6CczrxPvrGfgqF9N5eTO0Q8=
 github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -115,6 +119,7 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R
 github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI=
 github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/speps/go-hashids v2.0.0+incompatible h1:kSfxGfESueJKTx0mpER9Y/1XHl+FVQjtCqRyYcviFbw=
@@ -135,17 +140,28 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs
 github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
 github.com/zikaeroh/ctxjoin v0.0.0-20200613235025-e3d47af29310 h1:nzMukvhYHxWxiSNaa0J7E5Wx9XPEh5K3GtVjcF3yWdM=
 github.com/zikaeroh/ctxjoin v0.0.0-20200613235025-e3d47af29310/go.mod h1:bR1HcUSJKqE19Z24xgoSc1nMAbWr+P0nuhzx2kYJv8M=
+github.com/zikaeroh/ctxlog v0.0.0-20200613043947-8791c8613223 h1:q/vMrH84j1PzDoMEWAY+82XNL377I72ePdKmEGvsUCQ=
+github.com/zikaeroh/ctxlog v0.0.0-20200613043947-8791c8613223/go.mod h1:C1CXIChfvvg4uviDtaOINYpQ5qzUxwbqE7h/MOc7IPw=
 github.com/zikaeroh/pkger v0.17.1-0.20200604025301-dceb832975ba h1:t0aP/yT6220rbPXYRf4ASwgWkynUvy+SGQqR6jNzutc=
 github.com/zikaeroh/pkger v0.17.1-0.20200604025301-dceb832975ba/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
 go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
 go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
+go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -159,6 +175,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
@@ -172,10 +189,13 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190624222133-a101b041ded4 h1:1mMox4TgefDwqluYCv677yNXwlfTkija4owZve/jr78=
 golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c h1:IGkKhmfzcztjm6gYkykvu/NiS8kaqbCWAEWWAyf8J5U=
 golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -191,6 +211,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -200,5 +221,7 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E=
 gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
+honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
 nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k=
 nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=

internal/server/server.go 🔗

@@ -4,7 +4,6 @@ import (
 	"context"
 	"encoding/json"
 	"errors"
-	"log"
 	"sync"
 	"time"
 
@@ -13,7 +12,9 @@ import (
 	"github.com/zikaeroh/codies/internal/game"
 	"github.com/zikaeroh/codies/internal/protocol"
 	"github.com/zikaeroh/ctxjoin"
+	"github.com/zikaeroh/ctxlog"
 	"go.uber.org/atomic"
+	"go.uber.org/zap"
 	"golang.org/x/sync/errgroup"
 	"nhooyr.io/websocket"
 	"nhooyr.io/websocket/wsjson"
@@ -73,10 +74,10 @@ func (s *Server) Run(ctx context.Context) error {
 			return ctx.Err()
 
 		case <-s.doPrune:
-			s.prune()
+			s.prune(ctx)
 
 		case <-ticker.C:
-			s.prune()
+			s.prune(ctx)
 		}
 	}
 }
@@ -97,7 +98,7 @@ func (s *Server) FindRoomByID(id string) *Room {
 	return s.roomIDs[id]
 }
 
-func (s *Server) CreateRoom(name, password string) (*Room, error) {
+func (s *Server) CreateRoom(ctx context.Context, name, password string) (*Room, error) {
 	<-s.ready
 
 	s.mu.Lock()
@@ -118,7 +119,7 @@ func (s *Server) CreateRoom(name, password string) (*Room, error) {
 	}
 	s.nextID++
 
-	ctx, cancel := context.WithCancel(s.ctx)
+	roomCtx, roomCancel := context.WithCancel(s.ctx)
 
 	room = &Room{
 		Name:        name,
@@ -126,8 +127,8 @@ func (s *Server) CreateRoom(name, password string) (*Room, error) {
 		ID:          id,
 		clientCount: &s.clientCount,
 		roomCount:   &s.roomCount,
-		ctx:         ctx,
-		cancel:      cancel,
+		ctx:         roomCtx,
+		cancel:      roomCancel,
 		room:        game.NewRoom(nil),
 		players:     make(map[game.PlayerID]noteSender),
 		turnSeconds: 60,
@@ -142,7 +143,7 @@ func (s *Server) CreateRoom(name, password string) (*Room, error) {
 	s.roomCount.Inc()
 	metricRooms.Inc()
 
-	log.Printf("created new room '%s' (%s)", name, room.ID)
+	ctxlog.Info(ctx, "created new room", zap.String("name", name), zap.String("id", room.ID))
 
 	if s.nextID%100 == 0 {
 		s.triggerPrune()
@@ -158,7 +159,7 @@ func (s *Server) triggerPrune() {
 	}
 }
 
-func (s *Server) prune() {
+func (s *Server) prune(ctx context.Context) {
 	s.mu.Lock()
 	defer s.mu.Unlock()
 
@@ -188,7 +189,7 @@ func (s *Server) prune() {
 		metricRooms.Dec()
 	}
 
-	log.Printf("pruned %d rooms", len(toRemove))
+	ctxlog.Info(ctx, "pruned rooms", zap.Int("count", len(toRemove)))
 }
 
 func (s *Server) Stats() (rooms, clients int) {
@@ -227,18 +228,21 @@ func (r *Room) HandleConn(ctx context.Context, playerID uuid.UUID, nickname stri
 	ctx, cancel := ctxjoin.AddCancel(ctx, r.ctx)
 	defer cancel()
 
+	ctx = ctxlog.With(ctx, zap.String("roomName", r.Name), zap.String("roomID", r.ID), zap.String("nickname", nickname))
+
 	metricClients.Inc()
 	defer metricClients.Dec()
 
 	clientCount := r.clientCount.Inc()
-	log.Printf("client connected to room '%s' (%s); %v clients currently connected to %v rooms", r.Name, r.ID, clientCount, r.roomCount.Load())
+	ctxlog.Info(ctx, "client connected", zap.Int64("clientCount", clientCount), zap.Int64("roomCount", r.roomCount.Load()))
 
 	defer func() {
 		clientCount := r.clientCount.Dec()
-		log.Printf("client disconnected from room '%s' (%s); %v clients currently connected to %v rooms", r.Name, r.ID, clientCount, r.roomCount.Load())
+		ctxlog.Info(ctx, "client disconnected", zap.Int64("clientCount", clientCount), zap.Int64("roomCount", r.roomCount.Load()))
 	}()
 
 	defer c.Close(websocket.StatusGoingAway, "going away")
+
 	g, ctx := errgroup.WithContext(ctx)
 
 	r.mu.Lock()
@@ -302,12 +306,14 @@ func (r *Room) HandleConn(ctx context.Context, playerID uuid.UUID, nickname stri
 				return err
 			}
 
+			ctx = ctxlog.With(ctx, zap.String("method", string(note.Method)))
+
 			r.lastSeen.Store(time.Now())
 			metricReceived.Inc()
 
-			if err := r.handleNote(playerID, &note); err != nil {
+			if err := r.handleNote(ctx, playerID, &note); err != nil {
 				metricHandleErrors.Inc()
-				log.Println("error handling note:", err)
+				ctxlog.Error(ctx, "error handling note", zap.Error(err))
 				return err
 			}
 		}
@@ -318,7 +324,7 @@ func (r *Room) HandleConn(ctx context.Context, playerID uuid.UUID, nickname stri
 
 var errMissingPlayer = errors.New("missing player during handleNote")
 
-func (r *Room) handleNote(playerID game.PlayerID, note *protocol.ClientNote) error {
+func (r *Room) handleNote(ctx context.Context, playerID game.PlayerID, note *protocol.ClientNote) error {
 	r.mu.Lock()
 	defer r.mu.Unlock()
 
@@ -452,7 +458,7 @@ func (r *Room) handleNote(playerID game.PlayerID, note *protocol.ClientNote) err
 		r.changeHideBomb(params.HideBomb)
 
 	default:
-		log.Printf("unhandled method: %s", note.Method)
+		ctxlog.Warn(ctx, "unhandled method")
 	}
 
 	return nil

main.go 🔗

@@ -21,6 +21,8 @@ import (
 	"github.com/zikaeroh/codies/internal/responder"
 	"github.com/zikaeroh/codies/internal/server"
 	"github.com/zikaeroh/codies/internal/version"
+	"github.com/zikaeroh/ctxlog"
+	"go.uber.org/zap"
 	"golang.org/x/sync/errgroup"
 	"nhooyr.io/websocket"
 )
@@ -38,7 +40,6 @@ var wsOpts *websocket.AcceptOptions
 
 func main() {
 	rand.Seed(time.Now().Unix())
-	log.SetFlags(log.LstdFlags | log.Lshortfile)
 
 	if _, err := flags.Parse(&args); err != nil {
 		// Default flag parser prints messages, so just exit.
@@ -51,7 +52,13 @@ func main() {
 		log.Fatal("must specify either --prod or --debug")
 	}
 
-	log.Printf("starting codies server, version %s", version.Version())
+	ctx := ctxutil.Interrupt()
+
+	logger := ctxlog.New(args.Debug)
+	defer zap.RedirectStdLog(logger)()
+	ctx = ctxlog.WithLogger(ctx, logger)
+
+	ctxlog.Info(ctx, "starting", zap.String("version", version.Version()))
 
 	wsOpts = &websocket.AcceptOptions{
 		OriginPatterns:  args.Origins,
@@ -59,15 +66,15 @@ func main() {
 	}
 
 	if args.Debug {
-		log.Println("starting in debug mode, allowing any WebSocket origin host")
+		ctxlog.Info(ctx, "starting in debug mode, allowing any WebSocket origin host")
 		wsOpts.InsecureSkipVerify = true
 	} else {
 		if !version.VersionSet() {
-			log.Fatal("running production build without version set")
+			ctxlog.Fatal(ctx, "running production build without version set")
 		}
 	}
 
-	g, ctx := errgroup.WithContext(ctxutil.Interrupt())
+	g, ctx := errgroup.WithContext(ctx)
 
 	srv := server.NewServer()
 
@@ -141,7 +148,7 @@ func main() {
 				var room *server.Room
 				if req.Create {
 					var err error
-					room, err = srv.CreateRoom(req.RoomName, req.RoomPass)
+					room, err = srv.CreateRoom(ctx, req.RoomName, req.RoomPass)
 					if err != nil {
 						switch err {
 						case server.ErrRoomExists:
@@ -227,7 +234,8 @@ func main() {
 		runServer(ctx, g, ":2112", prometheusHandler())
 	}
 
-	log.Fatal(g.Wait())
+	exitErr := g.Wait()
+	ctxlog.Fatal(ctx, "exited", zap.Error(exitErr))
 }
 
 func staticHandler() http.Handler {