From f5d370c6fedf99627af6ca6cf74977b2389df814 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 18 Dec 2023 17:11:24 +0100 Subject: [PATCH] Enh/advanced logging (#1247) * Minor changes in user-settings, still some errors in removing parts * Added custom setting to add custom speeds for playback and implemented these into video player * Full rewrite of the logging in the api folder * Fixed a bug in statistics.go * Changed logging in dao and tumlive * Finished rewriting logs everywhere but in the worker * Minor changes in user-settings, still some errors in removing parts * Added custom setting to add custom speeds for playback and implemented these into video player * Full rewrite of the logging in the api folder * Fixed a bug in statistics.go * Changed logging in dao and tumlive * Finished rewriting logs everywhere but in the worker * Added json logging to dao and in email.go, go upgraded to 1.21, added slogGorm package * Merged locally * Changed Dockerfile to work with multiple files in cmd/tumlive * Fixed a bug * Fixed a bug * Fixed some version things * Fixed build errors * Fixed bug in worker * Fixed another bug * Testing another change in go.work * Updated go.sum * Fixed go.work * Updated to go 1.21.5 * Removed autobuild * Added correct make targets to build * Fixed some more bugs * Changed everything to 1.21 instead of 1.21.5 * Removed toolchain directive * Added toolchain directive with new version * Last try with toolchain directive * Fixed pipeline --- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/go-test.yml | 2 +- .github/workflows/golangci-lint.yml | 2 +- .golangci.yml | 4 +- .idea/runConfigurations/all.xml | 8 -- README.md | 2 +- api/api_logger.go | 10 ++ api/chat.go | 65 +++++++------ api/courseimport.go | 17 ++-- api/courses.go | 76 +++++++-------- api/download.go | 7 +- api/download_ics.go | 5 +- api/lecture_halls.go | 19 ++-- api/live_update.go | 9 +- api/maintenance.go | 16 ++-- api/notifications.go | 7 +- api/progress.go | 9 +- api/realtime.go | 5 +- api/seek_stats.go | 7 +- api/server-notifications.go | 8 +- api/statistics.go | 45 +++++---- api/stream.go | 53 +++++------ api/token.go | 7 +- api/users.go | 66 ++++++++++--- api/voice_service_grpc.go | 9 +- api/worker.go | 5 +- api/worker_grpc.go | 121 ++++++++++++------------ api/wsHub.go | 12 +-- cmd/tumlive/tumlive.go | 54 +++++++---- dao/courses.go | 7 +- dao/dao_logger.go | 10 ++ dao/video-seek.go | 3 +- go.mod | 5 +- go.sum | 22 ++++- go.work | 2 +- model/course.go | 3 +- model/model_logger.go | 10 ++ model/user.go | 36 +++++++ tools/bot/bot.go | 5 +- tools/bot/bot_logger.go | 10 ++ tools/bot/matrix.go | 7 +- tools/branding.go | 3 +- tools/camera/camera_logger.go | 10 ++ tools/camera/panasonic.go | 15 ++- tools/config.go | 17 ++-- tools/email.go | 7 +- tools/meiliExporter.go | 17 ++-- tools/meiliSearch.go | 3 +- tools/middlewares.go | 15 ++- tools/presets.go | 23 +++-- tools/realtime/channel_store.go | 3 +- tools/realtime/realtime.go | 5 +- tools/realtime/realtime_logger.go | 10 ++ tools/session.go | 4 +- tools/template_executor.go | 5 +- tools/tools_logger.go | 10 ++ tools/tum/campus-online-base.go | 5 +- tools/tum/courses.go | 9 +- tools/tum/events.go | 11 +-- tools/tum/students.go | 7 +- tools/tum/tum_logger.go | 10 ++ vod-service/internal/internal_logger.go | 10 ++ vod-service/internal/vodService.go | 11 +-- web/admin.go | 33 ++++--- web/course.go | 16 ++-- web/index.go | 17 ++-- web/popup.go | 5 +- web/router.go | 5 +- web/saml.go | 30 +++--- web/template/user-settings.gohtml | 37 +++++++- web/template/video_only.gohtml | 2 +- web/template/watch.gohtml | 12 +-- web/ts/user-settings.ts | 16 ++++ web/user.go | 11 +-- web/watch.go | 15 ++- web/web_logger.go | 10 ++ worker/edge/go.mod | 2 +- worker/go.mod | 2 +- 78 files changed, 693 insertions(+), 502 deletions(-) delete mode 100644 .idea/runConfigurations/all.xml create mode 100644 api/api_logger.go create mode 100644 dao/dao_logger.go create mode 100644 model/model_logger.go create mode 100644 tools/bot/bot_logger.go create mode 100644 tools/camera/camera_logger.go create mode 100644 tools/realtime/realtime_logger.go create mode 100644 tools/tools_logger.go create mode 100644 tools/tum/tum_logger.go create mode 100644 vod-service/internal/internal_logger.go create mode 100644 web/web_logger.go diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c531a2e44..5e30fab8d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -55,7 +55,7 @@ jobs: # uses a compiled language #- run: | - # make bootstrap + # make all # make release - name: Perform CodeQL Analysis diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index 53e79d7ba..142575890 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -8,7 +8,7 @@ jobs: test: strategy: matrix: - go-version: [ 1.20.x ] + go-version: [ 1.21.x ] os: [ ubuntu-latest ] runs-on: ${{ matrix.os }} steps: diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index e8a5eade6..2db1a4cf4 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -15,7 +15,7 @@ jobs: steps: - uses: actions/setup-go@v4 with: - go-version: 1.19 + go-version: 1.21 - uses: actions/checkout@v3 - name: golangci-lint uses: golangci/golangci-lint-action@v3 diff --git a/.golangci.yml b/.golangci.yml index d42a24da6..ebfc5505f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -25,7 +25,7 @@ linters: fast: false run: - go: '1.19' + go: '1.21' timeout: 10m skip-dirs: - node_modules @@ -67,7 +67,7 @@ linters-settings: - name: modifies-value-receiver gofumpt: extra-rules: false - lang-version: "1.19" + lang-version: "1.21" issues: max-issues-per-linter: 0 diff --git a/.idea/runConfigurations/all.xml b/.idea/runConfigurations/all.xml deleted file mode 100644 index 38b79f9b7..000000000 --- a/.idea/runConfigurations/all.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index c32a96118..1ef96930c 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ docker run --detach \ ### Install go -- Install **go >=1.18** by following the steps [here](https://go.dev/doc/install) +- Install **go >=1.21** by following the steps [here](https://go.dev/doc/install) - Preferably use [JetBrains GoLand](https://youtu.be/vetAfxQxyJE) and open this project as it simplifies this entire process - Go to File -> Settings -> Go -> Go Modules and enable go modules integration. - Run `npm i` in the `./web` directory to install the required node modules diff --git a/api/api_logger.go b/api/api_logger.go new file mode 100644 index 000000000..d7a7b552c --- /dev/null +++ b/api/api_logger.go @@ -0,0 +1,10 @@ +package api + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "api") diff --git a/api/chat.go b/api/chat.go index bc6b575ab..f66c02dba 100644 --- a/api/chat.go +++ b/api/chat.go @@ -19,7 +19,6 @@ import ( "github.com/getsentry/sentry-go" "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" ) const ( @@ -65,7 +64,7 @@ func RegisterRealtimeChatChannel() { req, err := parseChatPayload(message) if err != nil { - log.WithError(err).Warn("could not unmarshal request") + logger.Warn("could not unmarshal request", "err", err) return } @@ -89,7 +88,7 @@ func RegisterRealtimeChatChannel() { case "react_to": routes.handleReactTo(tumLiveContext, message.Payload) default: - log.WithField("type", req.Type).Warn("unknown websocket request type") + logger.Warn("unknown websocket request type", "type", req.Type) } }, }) @@ -121,7 +120,7 @@ type chatRoutes struct { func (r chatRoutes) handleSubmitPollOptionVote(ctx tools.TUMLiveContext, msg []byte) { var req submitPollOptionVote if err := json.Unmarshal(msg, &req); err != nil { - log.WithError(err).Warn("could not unmarshal submit poll answer request") + logger.Warn("could not unmarshal submit poll answer request", "err", err) return } if ctx.User == nil { @@ -129,7 +128,7 @@ func (r chatRoutes) handleSubmitPollOptionVote(ctx tools.TUMLiveContext, msg []b } if err := r.ChatDao.AddChatPollOptionVote(req.PollOptionId, ctx.User.ID); err != nil { - log.WithError(err).Warn("could not add poll option vote") + logger.Warn("could not add poll option vote", "err", err) return } @@ -144,7 +143,7 @@ func (r chatRoutes) handleSubmitPollOptionVote(ctx tools.TUMLiveContext, msg []b if voteUpdateJson, err := json.Marshal(voteUpdateMap); err == nil { broadcastStreamToAdmins(ctx.Stream.ID, voteUpdateJson) } else { - log.WithError(err).Warn("could not marshal vote update map") + logger.Warn("could not marshal vote update map", "err", err) return } } @@ -158,7 +157,7 @@ func (r chatRoutes) handleStartPoll(ctx tools.TUMLiveContext, msg []byte) { var req startPollReq if err := json.Unmarshal(msg, &req); err != nil { - log.WithError(err).Warn("could not unmarshal start poll request") + logger.Warn("could not unmarshal start poll request", "err", err) return } if ctx.User == nil || !ctx.User.IsAdminOfCourse(*ctx.Course) { @@ -166,14 +165,14 @@ func (r chatRoutes) handleStartPoll(ctx tools.TUMLiveContext, msg []byte) { } if len(req.Question) == 0 { - log.Warn("could not create poll with empty question") + logger.Warn("could not create poll with empty question") return } var pollOptions []model.PollOption for _, answer := range req.PollAnswers { if len(answer) == 0 { - log.Warn("could not create poll with empty answer") + logger.Warn("could not create poll with empty answer") return } pollOptions = append(pollOptions, model.PollOption{ @@ -244,7 +243,7 @@ func (r chatRoutes) handleResolve(ctx tools.TUMLiveContext, msg []byte) { var req wsIdReq err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal message delete request") + logger.Warn("could not unmarshal message delete request", "err", err) return } if ctx.User == nil || !ctx.User.IsAdminOfCourse(*ctx.Course) { @@ -253,7 +252,7 @@ func (r chatRoutes) handleResolve(ctx tools.TUMLiveContext, msg []byte) { err = r.ChatDao.ResolveChat(req.Id) if err != nil { - log.WithError(err).Error("could not delete chat") + logger.Error("could not delete chat", "err", err) } broadcast := gin.H{ @@ -261,7 +260,7 @@ func (r chatRoutes) handleResolve(ctx tools.TUMLiveContext, msg []byte) { } broadcastBytes, err := json.Marshal(broadcast) if err != nil { - log.WithError(err).Error("could not marshal delete message") + logger.Error("could not marshal delete message", "err", err) return } broadcastStream(ctx.Stream.ID, broadcastBytes) @@ -271,7 +270,7 @@ func (r chatRoutes) handleDelete(ctx tools.TUMLiveContext, msg []byte) { var req wsIdReq err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal message delete request") + logger.Warn("could not unmarshal message delete request", "err", err) return } if ctx.User == nil || !ctx.User.IsAdminOfCourse(*ctx.Course) { @@ -279,14 +278,14 @@ func (r chatRoutes) handleDelete(ctx tools.TUMLiveContext, msg []byte) { } err = r.ChatDao.DeleteChat(req.Id) if err != nil { - log.WithError(err).Error("could not delete chat") + logger.Error("could not delete chat", "err", err) } broadcast := gin.H{ "delete": req.Id, } broadcastBytes, err := json.Marshal(broadcast) if err != nil { - log.WithError(err).Error("could not marshal delete message") + logger.Error("could not marshal delete message", "err", err) return } broadcastStream(ctx.Stream.ID, broadcastBytes) @@ -296,7 +295,7 @@ func (r chatRoutes) handleApprove(ctx tools.TUMLiveContext, msg []byte) { var req wsIdReq err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal message approve request") + logger.Warn("could not unmarshal message approve request", "err", err) return } if ctx.User == nil || !ctx.User.IsAdminOfCourse(*ctx.Course) { @@ -305,7 +304,7 @@ func (r chatRoutes) handleApprove(ctx tools.TUMLiveContext, msg []byte) { err = r.ChatDao.ApproveChat(req.Id) if err != nil { - log.WithError(err).Error("could not approve chat") + logger.Error("could not approve chat", "err", err) return } @@ -315,7 +314,7 @@ func (r chatRoutes) handleApprove(ctx tools.TUMLiveContext, msg []byte) { */ chat, err := r.ChatDao.GetChat(req.Id, 0) if err != nil { - log.WithError(err).Error("could not get chat") + logger.Error("could not get chat", "err", err) } broadcast := gin.H{ "approve": req.Id, @@ -323,7 +322,7 @@ func (r chatRoutes) handleApprove(ctx tools.TUMLiveContext, msg []byte) { } broadcastBytes, err := json.Marshal(broadcast) if err != nil { - log.WithError(err).Error("could not marshal approve message") + logger.Error("could not marshal approve message", "err", err) return } broadcastStream(ctx.Stream.ID, broadcastBytes) @@ -333,23 +332,23 @@ func (r chatRoutes) handleReactTo(ctx tools.TUMLiveContext, msg []byte) { var req wsReactToReq err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal reactTo request") + logger.Warn("could not unmarshal reactTo request", "err", err) return } if _, isAllowed := allowedReactions[req.Reaction]; !isAllowed { - log.Warn("user tried to add illegal reaction") + logger.Warn("user tried to add illegal reaction") return } err = r.ChatDao.ToggleReaction(ctx.User.ID, req.wsIdReq.Id, ctx.User.Name, req.Reaction) if err != nil { - log.WithError(err).Error("error reacting to message") + logger.Error("error reacting to message", "err", err) return } reactions, err := r.ChatDao.GetReactions(req.Id) if err != nil { - log.WithError(err).Error("error getting num of chat reactions") + logger.Error("error getting num of chat reactions", "err", err) return } broadcast := gin.H{ @@ -358,7 +357,7 @@ func (r chatRoutes) handleReactTo(ctx tools.TUMLiveContext, msg []byte) { } broadcastBytes, err := json.Marshal(broadcast) if err != nil { - log.WithError(err).Error("Can't marshal reactions message") + logger.Error("Can't marshal reactions message", "err", err) return } broadcastStream(ctx.Stream.ID, broadcastBytes) @@ -368,7 +367,7 @@ func (r chatRoutes) handleRetract(ctx tools.TUMLiveContext, msg []byte) { var req wsIdReq err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal message retract request") + logger.Warn("could not unmarshal message retract request", "err", err) return } if ctx.User == nil || !ctx.User.IsAdminOfCourse(*ctx.Course) { @@ -377,19 +376,19 @@ func (r chatRoutes) handleRetract(ctx tools.TUMLiveContext, msg []byte) { err = r.ChatDao.RetractChat(req.Id) if err != nil { - log.WithError(err).Error("could not retract chat") + logger.Error("could not retract chat", "err", err) return } err = r.ChatDao.RemoveReactions(req.Id) if err != nil { - log.WithError(err).Error("could not remove reactions from chat") + logger.Error("could not remove reactions from chat", "err", err) return } chat, err := r.ChatDao.GetChat(req.Id, 0) if err != nil { - log.WithError(err).Error("could not get chat") + logger.Error("could not get chat", "err", err) } broadcast := gin.H{ "retract": req.Id, @@ -397,7 +396,7 @@ func (r chatRoutes) handleRetract(ctx tools.TUMLiveContext, msg []byte) { } broadcastBytes, err := json.Marshal(broadcast) if err != nil { - log.WithError(err).Error("could not marshal retract message") + logger.Error("could not marshal retract message", "err", err) return } broadcastStream(ctx.Stream.ID, broadcastBytes) @@ -406,7 +405,7 @@ func (r chatRoutes) handleRetract(ctx tools.TUMLiveContext, msg []byte) { func (r chatRoutes) handleMessage(ctx tools.TUMLiveContext, context *realtime.Context, msg []byte) { var chat chatReq if err := json.Unmarshal(msg, &chat); err != nil { - log.WithError(err).Error("error unmarshalling chat message") + logger.Error("error unmarshalling chat message", "err", err) return } if !ctx.Course.ChatEnabled && !ctx.Stream.ChatEnabled { @@ -578,7 +577,7 @@ func (r chatRoutes) getActivePoll(c *gin.Context) { if isAdminOfCourse { voteCount, err = r.ChatDao.GetPollOptionVoteCount(option.ID) if err != nil { - log.WithError(err).Warn("could not get poll option vote count") + logger.Warn("could not get poll option vote count", "err", err) } } @@ -681,7 +680,7 @@ func CollectStats(daoWrapper dao.DaoWrapper) func() { if s.LiveNow { // store stats for livestreams only s.Stats = append(s.Stats, stat) if err := daoWrapper.AddStat(stat); err != nil { - log.WithError(err).Error("Saving stat failed") + logger.Error("Saving stat failed", "err", err) } } } @@ -734,7 +733,7 @@ func afterUnsubscribe(id string, joinTime time.Time, recording bool, daoWrapper if recording && joinTime.Before(time.Now().Add(time.Minute*-5)) { err := daoWrapper.AddVodView(id) if err != nil { - log.WithError(err).Error("Can't save vod view") + logger.Error("Can't save vod view", "err", err) } } } diff --git a/api/courseimport.go b/api/courseimport.go index bf6e7377d..18db73131 100644 --- a/api/courseimport.go +++ b/api/courseimport.go @@ -12,7 +12,6 @@ import ( "github.com/getsentry/sentry-go" "github.com/gin-gonic/gin" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "html/template" "net/http" "strconv" @@ -90,7 +89,7 @@ func (r lectureHallRoutes) postSchedule(c *gin.Context) { for _, event := range courseReq.Events { lectureHall, err := r.LectureHallsDao.GetLectureHallByPartialName(event.RoomName) if err != nil { - log.WithError(err).Error("No room found for request") + logger.Error("No room found for request", "err", err) continue } var eventID uint @@ -122,7 +121,7 @@ func (r lectureHallRoutes) postSchedule(c *gin.Context) { mail := contact.Email user, err := tum.FindUserWithEmail(mail) if err != nil || user == nil { - log.WithError(err).Errorf("can't find user %v", mail) + logger.Error("can't find user "+mail, "err", err) continue } time.Sleep(time.Millisecond * 200) // wait a bit, otherwise ldap locks us out @@ -130,14 +129,14 @@ func (r lectureHallRoutes) postSchedule(c *gin.Context) { user.Role = model.LecturerType err = r.UsersDao.UpsertUser(user) if err != nil { - log.Error(err) + logger.Error("Could not upsert user", "err", err) } else { users = append(users, user) } } for _, user := range users { if err := r.CoursesDao.AddAdminToCourse(user.ID, course.ID); err != nil { - log.WithError(err).Error("can't add admin to course") + logger.Error("can't add admin to course", "err", err) } err := r.notifyCourseCreated(MailTmpl{ Name: user.Name, @@ -146,7 +145,7 @@ func (r lectureHallRoutes) postSchedule(c *gin.Context) { OptIn: req.OptIn, }, user.Email.String, fmt.Sprintf("Vorlesungsstreams %s | Lecture streaming %s", course.Name, course.Name)) if err != nil { - log.WithFields(log.Fields{"course": course.Name, "email": user.Email.String}).WithError(err).Error("can't send email") + logger.Error("can't send email", "course", course.Name, "email", user.Email.String, "err", err) } time.Sleep(time.Millisecond * 100) // 1/10th second delay, being nice to our mailrelay } @@ -172,7 +171,7 @@ func (r lectureHallRoutes) notifyCourseCreated(d MailTmpl, mailAddr string, subj var body bytes.Buffer err = templ.ExecuteTemplate(&body, "mail-course-registered.gotemplate", d) if err != nil { - log.Error(err) + logger.Error("Could not execute mail-course-registered.gotemplate", "err", err) } return r.EmailDao.Create(context.Background(), &model.Email{ From: tools.Cfg.Mail.Sender, @@ -219,7 +218,7 @@ func (r lectureHallRoutes) getSchedule(c *gin.Context) { //todo figure out right token campus, err := campusonline.New(tools.Cfg.Campus.Tokens[0], "") if err != nil { - log.WithError(err).Error("Can't create campus client") + logger.Error("Can't create campus client", "err", err) return } var room campusonline.ICalendar @@ -245,7 +244,7 @@ func (r lectureHallRoutes) getSchedule(c *gin.Context) { room, err = campus.GetXCalOrg(from, to, depInt) } if err != nil { - log.WithError(err).Error("can not get room schedule") + logger.Error("can not get room schedule", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get room schedule", diff --git a/api/courses.go b/api/courses.go index 7502d87f5..599f2bbaa 100644 --- a/api/courses.go +++ b/api/courses.go @@ -14,7 +14,6 @@ import ( "github.com/gin-gonic/gin" "github.com/meilisearch/meilisearch-go" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "gorm.io/gorm" "io" "net/http" @@ -161,7 +160,7 @@ func (r coursesRoutes) getLive(c *gin.Context) { if stream.LectureHallID != 0 { lh, err := r.LectureHallsDao.GetLectureHallByID(stream.LectureHallID) if err != nil { - log.WithError(err).Error(err) + logger.Error("Could not get Lecture Hall ID", "err", err) } else { lectureHall = &lh } @@ -400,7 +399,7 @@ func isUserAllowedToWatchPrivateCourse(course model.Course, user *model.User) bo } func (r coursesRoutes) createVOD(c *gin.Context) { - log.Info("createVOD") + logger.Info("createVOD") var req createVODReq err := c.BindQuery(&req) if err != nil { @@ -433,7 +432,7 @@ func (r coursesRoutes) createVOD(c *gin.Context) { } func (r coursesRoutes) uploadVODMedia(c *gin.Context) { - log.Info("uploadVODMedia") + logger.Info("uploadVODMedia") var req uploadVodMediaReq if err := c.BindQuery(&req); err != nil { @@ -541,7 +540,7 @@ func (r coursesRoutes) updateSourceSettings(c *gin.Context) { Message: fmt.Sprintf("%s:'%s'", tumLiveContext.Course.Name, tumLiveContext.Course.Slug), Type: model.AuditCourseEdit, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } course.SetCameraPresetPreference(presetSettings) @@ -557,7 +556,7 @@ func (r coursesRoutes) updateSourceSettings(c *gin.Context) { course.SetSourcePreference(sourceModeSettings) if err = r.CoursesDao.UpdateCourse(c, *course); err != nil { - log.WithError(err).Error("failed to update course") + logger.Error("failed to update course", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "failed to update course", @@ -600,7 +599,7 @@ func (r coursesRoutes) activateCourseByToken(c *gin.Context) { } err = r.AuditDao.Create(&model.Audit{User: tlctx.User, Type: model.AuditCourseCreate, Message: fmt.Sprintf("opted in by token, %s:'%s'", course.Name, course.Slug)}) if err != nil { - log.WithError(err).Error("create opt in audit failed") + logger.Error("create opt in audit failed", "err", err) } } @@ -618,7 +617,7 @@ func (r coursesRoutes) removeAdminFromCourse(c *gin.Context) { admins, err := r.CoursesDao.GetCourseAdmins(tumLiveContext.Course.ID) if err != nil { - log.WithError(err).Error("could not get course admins") + logger.Error("could not get course admins", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "could not get course admins", @@ -653,12 +652,12 @@ func (r coursesRoutes) removeAdminFromCourse(c *gin.Context) { Message: fmt.Sprintf("%s:'%s' remove: %s (%d)", tumLiveContext.Course.Name, tumLiveContext.Course.Slug, user.GetPreferredName(), user.ID), // e.g. "eidi:'Einführung in die Informatik' (2020, S)" Type: model.AuditCourseEdit, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } err = r.CoursesDao.RemoveAdminFromCourse(user.ID, tumLiveContext.Course.ID) if err != nil { - log.WithError(err).Error("could not remove admin from course") + logger.Error("could not remove admin from course", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "could not remove admin from course", @@ -700,12 +699,12 @@ func (r coursesRoutes) addAdminToCourse(c *gin.Context) { Message: fmt.Sprintf("%s:'%s' add: %s (%d)", tumLiveContext.Course.Name, tumLiveContext.Course.Slug, user.GetPreferredName(), user.ID), // e.g. "eidi:'Einführung in die Informatik' (2020, S)" Type: model.AuditCourseEdit, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } err = r.CoursesDao.AddAdminToCourse(user.ID, tumLiveContext.Course.ID) if err != nil { - log.WithError(err).Error("could not add admin to course") + logger.Error("could not add admin to course", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "could not add admin to course", @@ -717,7 +716,7 @@ func (r coursesRoutes) addAdminToCourse(c *gin.Context) { user.Role = model.LecturerType err = r.UsersDao.UpdateUser(user) if err != nil { - log.WithError(err).Error("could not update user") + logger.Error("could not update user", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "could not update user", @@ -737,7 +736,7 @@ func (r coursesRoutes) getAdmins(c *gin.Context) { tumLiveContext := c.MustGet("TUMLiveContext").(tools.TUMLiveContext) admins, err := r.CoursesDao.GetCourseAdmins(tumLiveContext.Course.ID) if err != nil { - log.WithError(err).Error("error getting course admins") + logger.Error("error getting course admins", "err", err) c.AbortWithStatus(http.StatusInternalServerError) return } @@ -820,7 +819,7 @@ func (r coursesRoutes) lectureHalls(c *gin.Context, course model.Course) { for u := range lectureHallIDs { lh, err := r.LectureHallsDao.GetLectureHallByID(u) if err != nil { - log.WithError(err).Error("Can't fetch lecture hall for stream") + logger.Error("Can't fetch lecture hall for stream", "err", err) } else { // Find if sourceMode is specified for this lecture hall lectureHallData = append(lectureHallData, lhResp{ @@ -987,7 +986,7 @@ func (r coursesRoutes) updateDescription(c *gin.Context) { if msg, err := json.Marshal(wsMsg); err == nil { broadcastStream(sID, msg) } else { - log.WithError(err).Error("couldn't marshal stream rename ws msg") + logger.Error("couldn't marshal stream rename ws msg", "err", err) } } @@ -1035,7 +1034,7 @@ func (r coursesRoutes) renameLecture(c *gin.Context) { if msg, err := json.Marshal(wsMsg); err == nil { broadcastStream(sID, msg) } else { - log.WithError(err).Error("couldn't marshal stream rename ws msg") + logger.Error("couldn't marshal stream rename ws msg", "err", err) } } @@ -1062,7 +1061,7 @@ func (r coursesRoutes) updateLectureSeries(c *gin.Context) { } if err = r.StreamsDao.UpdateLectureSeries(stream); err != nil { - log.WithError(err).Error("couldn't update lecture series") + logger.Error("couldn't update lecture series", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "couldn't update lecture series", @@ -1101,10 +1100,10 @@ func (r coursesRoutes) deleteLectureSeries(c *gin.Context) { Message: fmt.Sprintf("'%s': %s (%d and series)", ctx.Course.Name, stream.Start.Format("2006 02 Jan, 15:04"), stream.ID), Type: model.AuditStreamDelete, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } if err := r.StreamsDao.DeleteLectureSeries(stream.SeriesIdentifier); err != nil { - log.WithError(err).Error("couldn't delete lecture series") + logger.Error("couldn't delete lecture series", "err", err) c.AbortWithStatusJSON(http.StatusInternalServerError, "couldn't delete lecture series") return } @@ -1143,7 +1142,7 @@ func (r coursesRoutes) deleteLectures(c *gin.Context) { Message: fmt.Sprintf("'%s': %s (%d)", tumLiveContext.Course.Name, stream.Start.Format("2006 02 Jan, 15:04"), stream.ID), Type: model.AuditStreamDelete, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } r.StreamsDao.DeleteStream(strconv.Itoa(int(stream.ID))) } @@ -1154,7 +1153,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { var req createLectureRequest if err := c.ShouldBind(&req); err != nil { - log.WithError(err).Error("invalid form") + logger.Error("invalid form", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "invalid form", @@ -1165,7 +1164,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { // Forbid setting lectureHall for vod or premiere if (req.Premiere || req.Vodup) && req.LectureHallId != "0" { - log.Error("cannot set lectureHallId on 'Premiere' or 'Vodup' Lecture.") + logger.Error("cannot set lectureHallId on 'Premiere' or 'Vodup' Lecture.") _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "cannot set lectureHallId on 'Premiere' or 'Vodup' Lecture.", @@ -1176,7 +1175,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { // try parse lectureHallId lectureHallId, err := strconv.ParseInt(req.LectureHallId, 10, 32) if err != nil { - log.WithError(err).Error("invalid LectureHallID format") + logger.Error("invalid LectureHallID format", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "invalid LectureHallId format", @@ -1197,7 +1196,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { if req.Premiere || req.Vodup { err = os.MkdirAll(premiereFolder, os.ModePerm) if err != nil { - log.WithError(err).Error("can not create folder for premiere") + logger.Error("can not create folder for premiere", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not create folder for premiere", @@ -1210,7 +1209,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { if req.Vodup { err = tools.UploadLRZ(fmt.Sprintf("%s/%s", premiereFolder, premiereFileName)) if err != nil { - log.WithError(err).Error("can not upload file for premiere") + logger.Error("can not upload file for premiere", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not upload file for premiere", @@ -1269,7 +1268,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { Message: fmt.Sprintf("Stream for '%s' Created. Time: %s", tumLiveContext.Course.Name, lecture.Start.Format("2006 02 Jan, 15:04")), Type: model.AuditStreamCreate, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit", "err", err) } tumLiveContext.Course.Streams = append(tumLiveContext.Course.Streams, lecture) @@ -1277,7 +1276,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { err = r.CoursesDao.UpdateCourse(context.Background(), *tumLiveContext.Course) if err != nil { - log.WithError(err).Warn("can not update course") + logger.Warn("can not update course", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not update course", @@ -1401,7 +1400,7 @@ func (r coursesRoutes) createCourse(c *gin.Context) { Message: fmt.Sprintf("%s:'%s' (%d, %s)", course.Slug, course.Name, course.Year, course.TeachingTerm), // e.g. "eidi:'Einführung in die Informatik' (2020, S)" Type: model.AuditCourseCreate, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } err = r.CoursesDao.CreateCourse(context.Background(), &course, true) @@ -1457,7 +1456,7 @@ func (r coursesRoutes) deleteCourseByToken(c *gin.Context) { Message: fmt.Sprintf("'%s' (%d, %s)[%d]. Token: %s", course.Name, course.Year, course.TeachingTerm, course.ID, token), Type: model.AuditCourseDelete, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } r.CoursesDao.DeleteCourse(course) @@ -1467,17 +1466,14 @@ func (r coursesRoutes) deleteCourseByToken(c *gin.Context) { func (r coursesRoutes) deleteCourse(c *gin.Context) { tumLiveContext := c.MustGet("TUMLiveContext").(tools.TUMLiveContext) - log.WithFields(log.Fields{ - "user": tumLiveContext.User.ID, - "course": tumLiveContext.Course.ID, - }).Info("Delete Course Called") + logger.Info("Delete Course Called", "user", tumLiveContext.User.ID, "course", tumLiveContext.Course.ID) if err := r.AuditDao.Create(&model.Audit{ User: tumLiveContext.User, Message: fmt.Sprintf("'%s' (%d, %s)[%d]", tumLiveContext.Course.Name, tumLiveContext.Course.Year, tumLiveContext.Course.TeachingTerm, tumLiveContext.Course.ID), Type: model.AuditCourseDelete, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit", "err", err) } r.CoursesDao.DeleteCourse(*tumLiveContext.Course) @@ -1515,7 +1511,7 @@ func (r coursesRoutes) courseInfo(c *gin.Context) { } } if err != nil { // course not found - log.WithError(err).Warn("Error getting course information") + logger.Warn("Error getting course information", "err", err) c.AbortWithStatus(http.StatusNotFound) return } @@ -1556,7 +1552,7 @@ func (r coursesRoutes) copyCourse(c *gin.Context) { admins, err := r.DaoWrapper.CoursesDao.GetCourseAdmins(course.ID) if err != nil { - log.WithError(err).Error("Error getting course admins") + logger.Error("Error getting course admins", "err", err) admins = []model.User{} } course.Model = gorm.Model{} @@ -1579,7 +1575,7 @@ func (r coursesRoutes) copyCourse(c *gin.Context) { err = r.CoursesDao.CreateCourse(c, course, true) if err != nil { - log.WithError(err).Error("Can't create course") + logger.Error("Can't create course", "err", err) _ = c.Error(tools.RequestError{Status: http.StatusInternalServerError, CustomMessage: "Can't create course", Err: err}) return } @@ -1589,14 +1585,14 @@ func (r coursesRoutes) copyCourse(c *gin.Context) { stream.Model = gorm.Model{} err := r.StreamsDao.CreateStream(&stream) if err != nil { - log.WithError(err).Error("Can't create stream") + logger.Error("Can't create stream", "err", err) numErrors++ } } for _, admin := range admins { err := r.CoursesDao.AddAdminToCourse(admin.ID, course.ID) if err != nil { - log.WithError(err).Error("Can't add admin to course") + logger.Error("Can't add admin to course", "err", err) numErrors++ } } diff --git a/api/download.go b/api/download.go index 47f2ddf51..76fc97201 100644 --- a/api/download.go +++ b/api/download.go @@ -3,12 +3,11 @@ package api import ( "errors" "fmt" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "net/http" "os" ) @@ -119,7 +118,7 @@ func sendDownloadFile(c *gin.Context, file model.File, tumLiveContext tools.TUML if tumLiveContext.User != nil { uid = tumLiveContext.User.ID } - log.Info(fmt.Sprintf("Download request, user: %d, file: %d[%s]", uid, file.ID, file.Path)) + logger.Info(fmt.Sprintf("Download request, user: %d, file: %d[%s]", uid, file.ID, file.Path)) f, err := os.Open(file.Path) if err != nil { _ = c.Error(tools.RequestError{ diff --git a/api/download_ics.go b/api/download_ics.go index 3217eb5f8..3660f658c 100644 --- a/api/download_ics.go +++ b/api/download_ics.go @@ -1,11 +1,10 @@ package api import ( - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "html/template" "net/http" "strconv" @@ -15,7 +14,7 @@ import ( func configGinDownloadICSRouter(router *gin.Engine, daoWrapper dao.DaoWrapper) { templates, err := template.ParseFS(staticFS, "template/*.gotemplate") if err != nil { - log.WithError(err).Fatal("could not parse templates") + logger.Error("could not parse templates", "err", err) return } routes := downloadICSRoutes{daoWrapper, templates} diff --git a/api/lecture_halls.go b/api/lecture_halls.go index 725669ed3..7c2f40da0 100644 --- a/api/lecture_halls.go +++ b/api/lecture_halls.go @@ -4,12 +4,11 @@ import ( "embed" "errors" "fmt" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "net/http" "strconv" "strings" @@ -91,7 +90,7 @@ func (r lectureHallRoutes) updateLectureHall(c *gin.Context) { lectureHall.PwrCtrlIp = req.PwrCtrlIp err = r.LectureHallsDao.SaveLectureHall(lectureHall) if err != nil { - log.WithError(err).Error("error while updating lecture hall") + logger.Error("error while updating lecture hall", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "error while updating lecture hall", @@ -126,7 +125,7 @@ func (r lectureHallRoutes) updateLectureHallsDefaultPreset(c *gin.Context) { preset.IsDefault = true err = r.LectureHallsDao.UnsetDefaults(c.Param("id")) if err != nil { - log.WithError(err).Error("error unsetting default presets") + logger.Error("error unsetting default presets", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "error unsetting default presets", @@ -136,7 +135,7 @@ func (r lectureHallRoutes) updateLectureHallsDefaultPreset(c *gin.Context) { } err = r.LectureHallsDao.SavePreset(preset) if err != nil { - log.WithError(err).Error("error saving preset as default") + logger.Error("error saving preset as default", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "error saving preset as default", @@ -244,7 +243,7 @@ func (r lectureHallRoutes) lectureHallIcal(c *gin.Context) { c.Header("content-type", "text/calendar") err = templ.ExecuteTemplate(c.Writer, "ical.gotemplate", icalData) if err != nil { - log.Printf("%v", err) + logger.Error("Error executing template ical.gotemplate", "err", err) } } @@ -310,7 +309,7 @@ func (r lectureHallRoutes) setLectureHall(c *gin.Context) { streams, err := r.StreamsDao.GetStreamsByIds(req.StreamIDs) if err != nil || len(streams) != len(req.StreamIDs) { - log.WithError(err).Error("can not get all streams to update lecture hall") + logger.Error("can not get all streams to update lecture hall", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get all streams to update lecture hall", @@ -322,7 +321,7 @@ func (r lectureHallRoutes) setLectureHall(c *gin.Context) { if req.LectureHallID == 0 { err = r.StreamsDao.UnsetLectureHall(req.StreamIDs) if err != nil { - log.WithError(err).Error("can not update lecture hall for streams") + logger.Error("can not update lecture hall for streams", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not update lecture hall for streams", @@ -343,7 +342,7 @@ func (r lectureHallRoutes) setLectureHall(c *gin.Context) { } err = r.StreamsDao.SetLectureHall(req.StreamIDs, req.LectureHallID) if err != nil { - log.WithError(err).Error("can not update lecture hall") + logger.Error("can not update lecture hall", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not update lecture hall", diff --git a/api/live_update.go b/api/live_update.go index 443126c3c..d728d0750 100644 --- a/api/live_update.go +++ b/api/live_update.go @@ -4,14 +4,13 @@ import ( "encoding/json" "errors" "github.com/RBG-TUM/commons" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/tools/realtime" "github.com/TUM-Dev/gocast/tools/tum" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "sync" ) @@ -85,13 +84,13 @@ func liveUpdateOnSubscribe(psc *realtime.Context) { if tumLiveContext.User != nil { userId = tumLiveContext.User.ID if userCourses, err = daoWrapper.(dao.DaoWrapper).CoursesDao.GetPublicAndLoggedInCourses(year, term); err != nil { - log.WithError(err).Error("could not fetch public and logged in courses") + logger.Error("could not fetch public and logged in courses", "err", err) return } userCourses = commons.Unique(userCourses, func(c model.Course) uint { return c.ID }) } else { if userCourses, err = daoWrapper.(dao.DaoWrapper).CoursesDao.GetPublicCourses(year, term); err != nil { - log.WithError(err).Error("could not fetch public courses") + logger.Error("could not fetch public courses", "err", err) return } } diff --git a/api/maintenance.go b/api/maintenance.go index 0a321e510..10c848ab2 100644 --- a/api/maintenance.go +++ b/api/maintenance.go @@ -1,11 +1,11 @@ package api import ( - "github.com/gin-gonic/gin" + "fmt" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "net/http" "strconv" ) @@ -50,11 +50,11 @@ func (r *maintenanceRoutes) generateThumbnails(c *gin.Context) { }) return } - log.Info("generating ", noFiles, " thumbs") + logger.Info("generating " + strconv.FormatInt(noFiles, 10) + " thumbs") go func() { courses, err := r.GetAllCourses() if err != nil { - log.WithError(err).Error("Can't get courses") + logger.Error("Can't get courses", "err", err) } processed := 0 r.thumbGenRunning = true @@ -72,14 +72,14 @@ func (r *maintenanceRoutes) generateThumbnails(c *gin.Context) { // Request thumbnail for VoD. err := RegenerateThumbs(dao.NewDaoWrapper(), file, &stream, &course) if err != nil { - log.WithError(err).Errorf( + logger.Error(fmt.Sprintf( "Can't regenerate thumbnail for stream %d with file %s", stream.ID, file.Path, - ) + )) continue } - log.Info("Processed thumbnail", processed, "of", noFiles) + logger.Info("Processed thumbnail" + string(rune(processed)) + "of" + strconv.FormatInt(noFiles, 10)) processed++ r.thumbGenProgress = float32(processed) / float32(noFiles) } @@ -110,7 +110,7 @@ func (r *maintenanceRoutes) runCronJob(c *gin.Context) { return } jobName := c.Request.FormValue("job") - log.Info("request to run ", jobName) + logger.Info("request to run " + jobName) tools.Cron.RunJob(jobName) } diff --git a/api/notifications.go b/api/notifications.go index 2d51c5802..aa11b9265 100644 --- a/api/notifications.go +++ b/api/notifications.go @@ -1,11 +1,10 @@ package api import ( - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "net/http" "strconv" ) @@ -81,7 +80,7 @@ func (r notificationRoutes) createNotification(c *gin.Context) { } notification.Body = notification.SanitizedBody // reverse json binding if err := r.NotificationsDao.AddNotification(¬ification); err != nil { - log.Error(err) + logger.Error("Error adding notification", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not add notification", @@ -104,7 +103,7 @@ func (r notificationRoutes) deleteNotification(c *gin.Context) { } err = r.NotificationsDao.DeleteNotification(uint(id)) if err != nil { - log.WithError(err).Error("error deleting notification") + logger.Error("error deleting notification", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "error deleting notification", diff --git a/api/progress.go b/api/progress.go index 5af7b4986..bcf50ab73 100644 --- a/api/progress.go +++ b/api/progress.go @@ -12,7 +12,6 @@ import ( "time" "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" ) var progressBuff *progressBuffer @@ -57,7 +56,7 @@ func (b *progressBuffer) run() { time.Sleep(b.interval) err := b.flush() if err != nil { - log.WithError(err).Error("Error flushing progress buffer") + logger.Error("Error flushing progress buffer", "err", err) } } } @@ -91,7 +90,7 @@ func (r progressRoutes) saveProgress(c *gin.Context) { err := c.BindJSON(&request) if err != nil { - log.WithError(err).Warn("Could not bind JSON.") + logger.Warn("Could not bind JSON.", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", @@ -133,7 +132,7 @@ func (r progressRoutes) markWatched(c *gin.Context) { var request watchedRequest err := c.BindJSON(&request) if err != nil { - log.WithError(err).Error("Could not bind JSON.") + logger.Error("Could not bind JSON.", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", @@ -164,7 +163,7 @@ func (r progressRoutes) markWatched(c *gin.Context) { } err = r.ProgressDao.SaveWatchedState(&prog) if err != nil { - log.WithError(err).Error("can not mark VoD as watched.") + logger.Error("can not mark VoD as watched.", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not mark VoD as watched.", diff --git a/api/realtime.go b/api/realtime.go index 0d8f5779e..302248660 100644 --- a/api/realtime.go +++ b/api/realtime.go @@ -1,11 +1,10 @@ package api import ( - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/tools/realtime" "github.com/TUM-Dev/gocast/tools/realtime/connector" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" ) type realtimeRoutes struct { @@ -25,6 +24,6 @@ func (r realtimeRoutes) handleRealtimeConnect(c *gin.Context) { properties["dao"] = r.DaoWrapper if err := RealtimeInstance.HandleRequest(c.Writer, c.Request, properties); err != nil { - log.WithError(err).Warn("Something went wrong while handling Realtime-Socket request") + logger.Warn("Something went wrong while handling Realtime-Socket request", "err", err) } } diff --git a/api/seek_stats.go b/api/seek_stats.go index 90e8b0f3f..f2e2a5510 100644 --- a/api/seek_stats.go +++ b/api/seek_stats.go @@ -1,9 +1,8 @@ package api import ( - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "net/http" ) @@ -34,7 +33,7 @@ func (r seekStatsRoutes) reportSeek(c *gin.Context) { } if err := r.VideoSeekDao.Add(c.Param("streamID"), req.Position); err != nil { - log.WithError(err).Error("Could not add seek hit") + logger.Error("Could not add seek hit", "err", err) c.AbortWithStatus(http.StatusInternalServerError) return } @@ -50,7 +49,7 @@ func (r seekStatsRoutes) getSeek(c *gin.Context) { chunks, err := r.VideoSeekDao.Get(c.Param("streamID")) if err != nil { - log.WithError(err).Error("Could not get seek hits") + logger.Error("Could not get seek hits", "err", err) c.AbortWithStatus(http.StatusInternalServerError) return } diff --git a/api/server-notifications.go b/api/server-notifications.go index 17bf6e97e..2ceb1537e 100644 --- a/api/server-notifications.go +++ b/api/server-notifications.go @@ -1,11 +1,11 @@ package api import ( - "github.com/gin-gonic/gin" + "fmt" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - "log" + "github.com/gin-gonic/gin" "net/http" "time" ) @@ -25,7 +25,7 @@ type serverNotificationRoutes struct { func (r serverNotificationRoutes) updateServerNotification(c *gin.Context) { var req notificationReq if err := c.ShouldBind(&req); err != nil { - log.Printf("%v", err) + logger.Debug(fmt.Sprintf("%v", err)) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", @@ -54,7 +54,7 @@ func (r serverNotificationRoutes) updateServerNotification(c *gin.Context) { func (r serverNotificationRoutes) createServerNotification(c *gin.Context) { var req notificationReq if err := c.ShouldBind(&req); err != nil { - log.Printf("%v", err) + logger.Debug(fmt.Sprintf("%v", err)) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", diff --git a/api/statistics.go b/api/statistics.go index ae3373d58..af063ab5e 100644 --- a/api/statistics.go +++ b/api/statistics.go @@ -2,11 +2,10 @@ package api import ( "encoding/json" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "net/http" "strconv" ) @@ -52,7 +51,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "day": res, err := r.StatisticsDao.GetCourseStatsWeekdays(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsWeekdays failed") + logger.Warn("GetCourseStatsWeekdays failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get course stats weekdays", @@ -71,7 +70,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "hour": res, err := r.StatisticsDao.GetCourseStatsHourly(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsHourly failed") + logger.Warn("GetCourseStatsHourly failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get course stats hourly", @@ -90,7 +89,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "activity-live": resLive, err := r.StatisticsDao.GetStudentActivityCourseStats(cid, true) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsLive failed") + logger.Warn("GetCourseStatsLive failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get student activity course stats", @@ -112,7 +111,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "activity-vod": resVod, err := r.StatisticsDao.GetStudentActivityCourseStats(cid, false) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsVod failed") + logger.Warn("GetCourseStatsVod failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get student activity course stats", @@ -133,7 +132,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "numStudents": res, err := r.StatisticsDao.GetCourseNumStudents(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumStudents failed") + logger.Warn("GetCourseNumStudents failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get course num students", @@ -146,7 +145,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "vodViews": res, err := r.StatisticsDao.GetCourseNumVodViews(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumVodViews failed") + logger.Warn("GetCourseNumVodViews failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not getcourse num vod views", @@ -159,7 +158,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "liveViews": res, err := r.StatisticsDao.GetCourseNumLiveViews(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumLiveViews failed") + logger.Warn("GetCourseNumLiveViews failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get course num live views", @@ -173,7 +172,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { { res, err := r.StatisticsDao.GetCourseNumVodViewsPerDay(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumLiveViews failed") + logger.Warn("GetCourseNumLiveViews failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get course num vod views per day", @@ -231,7 +230,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { } if req.Format != "json" && req.Format != "csv" { - log.WithField("courseId", cid).Warn("exportStats failed, invalid format") + logger.Warn("exportStats failed, invalid format", "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "exportStats failed, invalid format", @@ -247,7 +246,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { case "day": res, err := r.StatisticsDao.GetCourseStatsWeekdays(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsWeekdays failed") + logger.Warn("GetCourseStatsWeekdays failed", "err", err, "courseId", cid) } result = result.AddDataEntry(&tools.ExportDataEntry{ Name: interval, @@ -259,7 +258,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { case "hour": res, err := r.StatisticsDao.GetCourseStatsHourly(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsHourly failed") + logger.Warn("GetCourseStatsHourly failed", "err", err, "courseId", cid) } result = result.AddDataEntry(&tools.ExportDataEntry{ Name: interval, @@ -271,7 +270,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { case "activity-live": resLive, err := r.StatisticsDao.GetStudentActivityCourseStats(cid, true) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetStudentActivityCourseStats failed") + logger.Warn("GetStudentActivityCourseStats failed", "err", err, "courseId", cid) } result = result.AddDataEntry(&tools.ExportDataEntry{ Name: interval, @@ -283,7 +282,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { case "activity-vod": resVod, err := r.StatisticsDao.GetStudentActivityCourseStats(cid, false) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetStudentActivityCourseStats failed") + logger.Warn("GetStudentActivityCourseStats failed", "err", err, "courseId", cid) } result = result.AddDataEntry(&tools.ExportDataEntry{ Name: interval, @@ -295,7 +294,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { case "allDays": res, err := r.StatisticsDao.GetCourseNumVodViewsPerDay(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumVodViewsPerDay failed") + logger.Warn("GetCourseNumVodViewsPerDay failed", "err", err, "courseId", cid) } result = result.AddDataEntry(&tools.ExportDataEntry{ Name: interval, @@ -309,21 +308,21 @@ func (r coursesRoutes) exportStats(c *gin.Context) { numStudents, err := r.StatisticsDao.GetCourseNumStudents(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumStudents failed") + logger.Warn("GetCourseNumStudents failed", "err", err, "courseId", cid) } else { quickStats = append(quickStats, dao.Stat{X: "Enrolled Students", Y: int(numStudents)}) } vodViews, err := r.StatisticsDao.GetCourseNumVodViews(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumVodViews failed") + logger.Warn("GetCourseNumVodViews failed", "err", err, "courseId", cid) } else { quickStats = append(quickStats, dao.Stat{X: "Vod Views", Y: int(vodViews)}) } liveViews, err := r.StatisticsDao.GetCourseNumLiveViews(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumLiveViews failed") + logger.Warn("GetCourseNumLiveViews failed", "err", err, "courseId", cid) } else { quickStats = append(quickStats, dao.Stat{X: "Live Views", Y: int(liveViews)}) } @@ -335,14 +334,14 @@ func (r coursesRoutes) exportStats(c *gin.Context) { }) default: - log.WithField("courseId", cid).Warn("Invalid export interval") + logger.Warn("Invalid export interval", "courseId", cid) } } if req.Format == "json" { jsonResult, err := json.Marshal(result.ExportJson()) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("json.Marshal failed for stats export") + logger.Warn("json.Marshal failed for stats export", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "json.Marshal failed for stats export", @@ -399,7 +398,7 @@ func newChartJsOptions() chartJsOptions { } } -//chartJsDataset is a single dataset ready to be used in a Chart.js chart +// chartJsDataset is a single dataset ready to be used in a Chart.js chart type chartJsDataset struct { Label string `json:"label"` Fill bool `json:"fill"` @@ -409,7 +408,7 @@ type chartJsDataset struct { Options chartJsOptions `json:"options"` } -//New creates a chartJsDataset with some defaults +// New creates a chartJsDataset with some defaults func newChartJsDataset() chartJsDataset { return chartJsDataset{ Fill: false, diff --git a/api/stream.go b/api/stream.go index 82b83bb0a..104d5c38f 100644 --- a/api/stream.go +++ b/api/stream.go @@ -20,7 +20,6 @@ import ( "github.com/getsentry/sentry-go" "github.com/gin-gonic/gin" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "gorm.io/gorm" ) @@ -209,7 +208,7 @@ func (r streamRoutes) liveStreams(c *gin.Context) { var res []liveStreamDto streams, err := r.StreamsDao.GetCurrentLive(c) if err != nil { - log.Error(err) + logger.Error("Error getting current live", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get current live streams", @@ -220,13 +219,13 @@ func (r streamRoutes) liveStreams(c *gin.Context) { for _, s := range streams { course, err := r.CoursesDao.GetCourseById(c, s.CourseID) if err != nil { - log.Error(err) + logger.Error("Error fetching course", "err", err) } lectureHall := "Selfstream" if s.LectureHallID != 0 { l, err := r.LectureHallsDao.GetLectureHallByID(s.LectureHallID) if err != nil { - log.Error(err) + logger.Error("Error fetching lecture hall", "err", err) } else { lectureHall = l.Name } @@ -247,7 +246,7 @@ func (r streamRoutes) liveStreams(c *gin.Context) { func (r streamRoutes) endStream(c *gin.Context) { tumLiveContext := c.MustGet("TUMLiveContext").(tools.TUMLiveContext) discardVoD := c.Request.URL.Query().Get("discard") == "true" - log.Info(discardVoD) + logger.Info("End stream: " + strconv.FormatBool(discardVoD)) NotifyWorkersToStopStream(*tumLiveContext.Stream, discardVoD, r.DaoWrapper) } @@ -388,7 +387,7 @@ func (r streamRoutes) getVideoSections(c *gin.Context) { tumLiveContext := c.MustGet("TUMLiveContext").(tools.TUMLiveContext) sections, err := r.VideoSectionDao.GetByStreamId(tumLiveContext.Stream.ID) if err != nil { - log.WithError(err).Error("Can't get video sections") + logger.Error("Can't get video sections", "err", err) } c.JSON(http.StatusOK, sections) @@ -406,17 +405,17 @@ func (r streamRoutes) RegenerateThumbs(c *gin.Context) { // The thumbnails are generated automatically by the worker which then notifies the backend. err := RegenerateThumbs(r.DaoWrapper, file, stream, course) if err != nil { - log.WithError(err).Errorf("Can't regenerate thumbnail for stream %d with file %s", stream.ID, file.Path) + logger.Error(fmt.Sprintf("Can't regenerate thumbnail for stream %d with file %s", stream.ID, file.Path)) continue } sections, err := r.DaoWrapper.VideoSectionDao.GetByStreamId(stream.ID) if err != nil { - log.WithError(err).Errorf("Can't get video sections for stream %d", stream.ID) + logger.Error(fmt.Sprintf("Can't get video sections for stream %d", stream.ID)) continue } err = tools.SetSignedPlaylists(stream, nil, false) if err != nil { - log.WithError(err).Errorf("Can't set signed playlists for stream %d", stream.ID) + logger.Error(fmt.Sprintf("Can't set signed playlists for stream %d", stream.ID)) continue } // Completely redo the video section image generation. This also updates the database, if the naming scheme has changed. @@ -430,7 +429,7 @@ func (r streamRoutes) RegenerateThumbs(c *gin.Context) { } err := GenerateVideoSectionImages(r.DaoWrapper, ¶meters) if err != nil { - log.WithError(err).Error("failed to generate video section images") + logger.Error("failed to generate video section images", "err", err) } }() } @@ -442,7 +441,7 @@ func (r streamRoutes) createVideoSectionBatch(c *gin.Context) { stream := context.Stream var sections []model.VideoSection if err := c.BindJSON(§ions); err != nil { - log.WithError(err).Error("failed to bind video section JSON") + logger.Error("failed to bind video section JSON", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", @@ -453,7 +452,7 @@ func (r streamRoutes) createVideoSectionBatch(c *gin.Context) { err := r.VideoSectionDao.Create(sections) if err != nil { - log.WithError(err).Error("failed to create video sections") + logger.Error("failed to create video sections", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "failed to create video sections", @@ -464,7 +463,7 @@ func (r streamRoutes) createVideoSectionBatch(c *gin.Context) { sections, err = r.VideoSectionDao.GetByStreamId(context.Stream.ID) if err != nil { - log.WithError(err).Error("failed to get video sections") + logger.Error("failed to get video sections", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "failed to get video sections", @@ -475,7 +474,7 @@ func (r streamRoutes) createVideoSectionBatch(c *gin.Context) { err = tools.SetSignedPlaylists(stream, nil, false) if err != nil { - log.WithError(err).Error("failed to set signed playlists") + logger.Error("failed to set signed playlists", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "failed to set signed playlists", @@ -493,7 +492,7 @@ func (r streamRoutes) createVideoSectionBatch(c *gin.Context) { } err := GenerateVideoSectionImages(r.DaoWrapper, ¶meters) if err != nil { - log.WithError(err).Error("failed to generate video section images") + logger.Error("failed to generate video section images", "err", err) } }() @@ -511,7 +510,7 @@ func (r streamRoutes) updateVideoSection(c *gin.Context) { idAsString := c.Param("id") id, err := strconv.Atoi(idAsString) if err != nil { - log.WithError(err).Error("can not parse video-section id in request url") + logger.Error("can not parse video-section id in request url", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not parse video-section id in request url", @@ -523,7 +522,7 @@ func (r streamRoutes) updateVideoSection(c *gin.Context) { var update UpdateVideoSectionRequest err = c.BindJSON(&update) if err != nil { - log.WithError(err).Error("failed to bind video section JSON") + logger.Error("failed to bind video section JSON", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", @@ -539,7 +538,7 @@ func (r streamRoutes) updateVideoSection(c *gin.Context) { StartMinutes: update.StartMinutes, StartSeconds: update.StartSeconds}) if err != nil { - log.WithError(err).Error("failed to update video section") + logger.Error("failed to update video section", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not update video section", @@ -553,7 +552,7 @@ func (r streamRoutes) deleteVideoSection(c *gin.Context) { idAsString := c.Param("id") id, err := strconv.Atoi(idAsString) if err != nil { - log.WithError(err).Error("can not parse video-section id in request url") + logger.Error("can not parse video-section id in request url", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not parse video-section id in request url", @@ -564,7 +563,7 @@ func (r streamRoutes) deleteVideoSection(c *gin.Context) { old, err := r.VideoSectionDao.Get(uint(id)) if err != nil { - log.WithError(err).Error("invalid video-section id") + logger.Error("invalid video-section id", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "invalid video-section id", @@ -575,7 +574,7 @@ func (r streamRoutes) deleteVideoSection(c *gin.Context) { err = r.VideoSectionDao.Delete(uint(id)) if err != nil { - log.WithError(err).Error("can not delete video-section") + logger.Error("can not delete video-section", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not delete video-section", @@ -586,7 +585,7 @@ func (r streamRoutes) deleteVideoSection(c *gin.Context) { file, err := r.FileDao.GetFileById(fmt.Sprintf("%d", old.FileID)) if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - log.WithError(err).Error("can not get video section thumbnail file") + logger.Error("can not get video section thumbnail file", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get video section thumbnail file", @@ -597,7 +596,7 @@ func (r streamRoutes) deleteVideoSection(c *gin.Context) { go func() { err := DeleteVideoSectionImage(r.DaoWrapper.WorkerDao, file.Path) if err != nil { - log.WithError(err).Error("failed to generate video section images") + logger.Error("failed to generate video section images", "err", err) } }() } @@ -654,7 +653,7 @@ func (r streamRoutes) newAttachment(c *gin.Context) { } if err = c.SaveUploadedFile(file, path); err != nil { - log.WithError(err).Error("could not save file with path: " + path) + logger.Error("could not save file with path: "+path, "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "could not save file with path: " + path, @@ -706,7 +705,7 @@ func (r streamRoutes) deleteAttachment(c *gin.Context) { if !toDelete.IsURL() { err = os.Remove(toDelete.Path) if err != nil { - log.WithError(err).Error("can not delete file with path: " + toDelete.Path) + logger.Error("can not delete file with path: "+toDelete.Path, "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not delete file with path: " + toDelete.Path, @@ -717,7 +716,7 @@ func (r streamRoutes) deleteAttachment(c *gin.Context) { } err = r.FileDao.DeleteFile(toDelete.ID) if err != nil { - log.WithError(err).Error("can not delete file from database") + logger.Error("can not delete file from database", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not delete file from database", @@ -825,7 +824,7 @@ func (r streamRoutes) updateStreamVisibility(c *gin.Context) { Type: model.AuditStreamEdit, }) if err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit", "err", err) } err = r.DaoWrapper.StreamsDao.ToggleVisibility(ctx.Stream.ID, req.Private) diff --git a/api/token.go b/api/token.go index 41fc9a368..420ae01a2 100644 --- a/api/token.go +++ b/api/token.go @@ -2,12 +2,11 @@ package api import ( "database/sql" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" + "github.com/gin-gonic/gin" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "net/http" "time" ) @@ -28,7 +27,7 @@ func (r tokenRoutes) deleteToken(c *gin.Context) { id := c.Param("id") err := r.TokenDao.DeleteToken(id) if err != nil { - log.WithError(err).Error("can not delete token") + logger.Error("can not delete token", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not delete token", @@ -78,7 +77,7 @@ func (r tokenRoutes) createToken(c *gin.Context) { } err = r.TokenDao.AddToken(token) if err != nil { - log.WithError(err).Error("can not create token") + logger.Error("can not create token", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not create token", diff --git a/api/users.go b/api/users.go index e96921e63..f8935d8e4 100644 --- a/api/users.go +++ b/api/users.go @@ -11,12 +11,11 @@ import ( "strings" "time" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "gorm.io/gorm" ) @@ -26,6 +25,7 @@ func configGinUsersRouter(router *gin.Engine, daoWrapper dao.DaoWrapper) { router.POST("/api/users/settings/name", routes.updatePreferredName) router.POST("/api/users/settings/greeting", routes.updatePreferredGreeting) router.POST("/api/users/settings/playbackSpeeds", routes.updatePlaybackSpeeds) + router.POST("/api/users/settings/customSpeeds", routes.updateCustomSpeeds) router.POST("/api/users/resetPassword", routes.resetPassword) @@ -113,7 +113,7 @@ func (r usersRoutes) updateUser(c *gin.Context) { user.Role = req.Role err = r.UsersDao.UpdateUser(user) if err != nil { - log.WithError(err).Error("can not update user") + logger.Error("can not update user", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not update user", @@ -304,7 +304,7 @@ func (r usersRoutes) addSingleUserToCourse(name string, email string, course mod Courses: []model.Course{course}, } if err = r.UsersDao.CreateUser(context.Background(), &createdUser); err != nil { - log.Printf("%v", err) + logger.Error("Error creating User", "err", err) } else { go r.forgotPassword(email) } @@ -313,7 +313,7 @@ func (r usersRoutes) addSingleUserToCourse(name string, email string, course mod foundUser.Courses = append(foundUser.Courses, course) err := r.UsersDao.UpdateUser(foundUser) if err != nil { - log.WithError(err).Error("Can't update user") + logger.Error("Can't update user", "err", err) return } err = r.EmailDao.Create(context.Background(), &model.Email{ @@ -325,7 +325,7 @@ func (r usersRoutes) addSingleUserToCourse(name string, email string, course mod course.Name), }) if err != nil { - log.Printf("%v", err) + logger.Error("Some error", "err", err) } } } @@ -372,7 +372,7 @@ func (r usersRoutes) pinCourse(pin bool) gin.HandlerFunc { } err := c.BindJSON(&request) if err != nil { - log.WithError(err).Error("Could not bind JSON.") + logger.Error("Could not bind JSON.", "err", err) c.AbortWithStatus(http.StatusBadRequest) return } @@ -397,7 +397,7 @@ func (r usersRoutes) pinCourse(pin bool) gin.HandlerFunc { // Update user in database err = r.UsersDao.PinCourse(*tumLiveContext.User, course, pin) if err != nil { - log.WithError(err).Error("Can't update user") + logger.Error("Can't update user", "err", err) return } } @@ -508,12 +508,12 @@ func (r usersRoutes) createUserHelper(request createUserRequest, userType uint) func (r usersRoutes) forgotPassword(email string) { u, err := r.UsersDao.GetUserByEmail(context.Background(), email) if err != nil { - log.Println("couldn't get user by email") + logger.Error("couldn't get user by email") return } registerLink, err := r.UsersDao.CreateRegisterLink(context.Background(), u) if err != nil { - log.Println("couldn't create register link") + logger.Error("couldn't create register link") return } body := fmt.Sprintf("Hello!\n"+ @@ -527,7 +527,7 @@ func (r usersRoutes) forgotPassword(email string) { Body: body, }) if err != nil { - log.Println("couldn't send password mail") + logger.Error("couldn't send password mail") } } @@ -619,6 +619,42 @@ func (r usersRoutes) updatePreferredGreeting(c *gin.Context) { } } +func (r usersRoutes) updateCustomSpeeds(c *gin.Context) { + u := c.MustGet("TUMLiveContext").(tools.TUMLiveContext).User + if u == nil { + _ = c.Error(tools.RequestError{ + Status: http.StatusUnauthorized, + CustomMessage: "login required", + }) + return + } + + var req struct{ Value []float32 } + if err := c.BindJSON(&req); err != nil { + _ = c.Error(tools.RequestError{ + Status: http.StatusBadRequest, + CustomMessage: "can not bind body", + Err: err, + }) + return + } + settingsString := "[]" + if len(req.Value) != 0 { + settingBytes, _ := json.Marshal(req.Value) + settingsString = string(settingBytes) + } + err := r.DaoWrapper.AddUserSetting(&model.UserSetting{UserID: u.ID, Type: model.UserDefinedSpeeds, Value: settingsString}) + if err != nil { + _ = c.Error(tools.RequestError{ + Status: http.StatusInternalServerError, + CustomMessage: "can not add user setting", + Err: err, + }) + return + } + +} + func (r usersRoutes) updatePlaybackSpeeds(c *gin.Context) { u := c.MustGet("TUMLiveContext").(tools.TUMLiveContext).User if u == nil { @@ -736,12 +772,12 @@ func (r usersRoutes) resetPassword(c *gin.Context) { return } if err != nil { - log.WithError(err).Error("can't get user for password reset") + logger.Error("can't get user for password reset", "err", err) return } link, err := r.UsersDao.CreateRegisterLink(c, user) if err != nil { - log.WithError(err).Error("can't create register link") + logger.Error("can't create register link", "err", err) return } err = r.EmailDao.Create(c, &model.Email{ @@ -751,7 +787,7 @@ func (r usersRoutes) resetPassword(c *gin.Context) { Body: "Hi! \n\nYou can reset your TUM-Live password by clicking on the following link: \n\n" + tools.Cfg.WebUrl + "/setPassword/" + link.RegisterSecret + "\n\nIf you did not request a password reset, please ignore this email. \n\nBest regards", }) if err != nil { - log.WithError(err).Error("can't save reset password email") + logger.Error("can't save reset password email", "err", err) } } diff --git a/api/voice_service_grpc.go b/api/voice_service_grpc.go index b2da029b7..ed195728f 100644 --- a/api/voice_service_grpc.go +++ b/api/voice_service_grpc.go @@ -9,7 +9,6 @@ import ( "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/voice-service/pb" - log "github.com/sirupsen/logrus" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/keepalive" @@ -38,10 +37,10 @@ func (s subtitleReceiverServer) Receive(_ context.Context, request *pb.ReceiveRe } func init() { - log.Info("starting grpc voice-receiver") + logger.Info("starting grpc voice-receiver") lis, err := net.Listen("tcp", ":50053") if err != nil { - log.WithError(err).Error("failed to init voice-receiver server") + logger.Error("failed to init voice-receiver server", "err", err) return } grpcServer := grpc.NewServer(grpc.KeepaliveParams(keepalive.ServerParameters{ @@ -56,7 +55,7 @@ func init() { reflection.Register(grpcServer) go func() { if err := grpcServer.Serve(lis); err != nil { - log.Fatalf("failed to serve: %v", err) + logger.Error("failed to serve", "err", err) } }() } @@ -78,6 +77,6 @@ func GetSubtitleGeneratorClient() (SubtitleGeneratorClient, error) { func (s SubtitleGeneratorClient) CloseConn() { err := s.ClientConn.Close() if err != nil { - log.WithError(err).Error("could not close voice-service connection") + logger.Error("could not close voice-service connection", "err", err) } } diff --git a/api/worker.go b/api/worker.go index aac2413cd..ba2787248 100644 --- a/api/worker.go +++ b/api/worker.go @@ -1,10 +1,9 @@ package api import ( - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "net/http" ) @@ -25,7 +24,7 @@ func (r workerRoutes) deleteWorker(c *gin.Context) { id := c.Param("id") err := r.dao.DeleteWorker(id) if err != nil { - log.WithError(err).Error("can not delete worker") + logger.Error("can not delete worker", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not delete worker", diff --git a/api/worker_grpc.go b/api/worker_grpc.go index 0aa754f9e..26eb20267 100644 --- a/api/worker_grpc.go +++ b/api/worker_grpc.go @@ -19,14 +19,13 @@ import ( "time" go_anel_pwrctrl "github.com/RBG-TUM/go-anel-pwrctrl" - "github.com/getsentry/sentry-go" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/tools/camera" "github.com/TUM-Dev/gocast/worker/pb" + "github.com/getsentry/sentry-go" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" @@ -48,20 +47,20 @@ type server struct { func dialIn(targetWorker model.Worker) (*grpc.ClientConn, error) { credentials := insecure.NewCredentials() - log.Info("Connecting to:" + fmt.Sprintf("%s:50051", targetWorker.Host)) + logger.Info("Connecting to:" + fmt.Sprintf("%s:50051", targetWorker.Host)) conn, err := grpc.Dial(fmt.Sprintf("%s:50051", targetWorker.Host), grpc.WithTransportCredentials(credentials)) return conn, err } func endConnection(conn *grpc.ClientConn) { if err := conn.Close(); err != nil { - log.WithError(err).Error("Could not close connection to worker") + logger.Error("Could not close connection to worker", "err", err) } } // JoinWorkers is a request from a worker to join the pool. On success, the workerID is returned. func (s server) JoinWorkers(ctx context.Context, request *pb.JoinWorkersRequest) (*pb.JoinWorkersResponse, error) { - log.WithField("host", request.Hostname).Info("JoinWorkers called") + logger.Info("JoinWorkers called", "host", request.Hostname) if request.Token != tools.Cfg.WorkerToken { return nil, status.Error(codes.Unauthenticated, "Invalid token") } @@ -84,10 +83,10 @@ func (s server) JoinWorkers(ctx context.Context, request *pb.JoinWorkersRequest) LastSeen: time.Now(), } if err := s.DaoWrapper.WorkerDao.CreateWorker(&worker); err != nil { - log.WithError(err).Error("Could not add worker to database") + logger.Error("Could not add worker to database", "err", err) return nil, status.Errorf(codes.Internal, "Could not add worker to database") } - log.Info("Added worker to database") + logger.Info("Added worker to database") return &pb.JoinWorkersResponse{ WorkerId: worker.WorkerID, }, nil @@ -141,7 +140,7 @@ func (s server) SendSelfStreamRequest(ctx context.Context, request *pb.SelfStrea } // reject streams that are more than 30 minutes in the future or more than 30 minutes past if !(time.Now().After(stream.Start.Add(time.Minute*-30)) && time.Now().Before(stream.End.Add(time.Minute*30))) { - log.WithFields(log.Fields{"streamId": stream.ID}).Warn("Stream rejected, time out of bounds") + logger.Warn("Stream rejected, time out of bounds", "streamId", stream.ID) return nil, errors.New("stream rejected") } ingestServer, err := s.DaoWrapper.IngestServerDao.GetBestIngestServer() @@ -177,12 +176,12 @@ func (s server) NotifyStreamStart(ctx context.Context, request *pb.StreamStarted defer mutex.Unlock() _, err := s.DaoWrapper.WorkerDao.GetWorkerByID(ctx, request.GetWorkerID()) if err != nil { - log.WithField("request", request).Warn("Got stream start with invalid WorkerID") + logger.Warn("Got stream start with invalid WorkerID", "request", request) return nil, err } stream, err := s.StreamsDao.GetStreamByID(ctx, fmt.Sprintf("%d", request.StreamID)) if err != nil { - log.WithError(err).Warn("Can't get stream by ID to set live") + logger.Warn("Can't get stream by ID to set live", "err", err) return nil, err } stream.LiveNow = true @@ -197,7 +196,7 @@ func (s server) NotifyStreamStart(ctx context.Context, request *pb.StreamStarted } err = s.StreamsDao.SaveStream(&stream) if err != nil { - log.WithError(err).Error("Can't save stream when setting live") + logger.Error("Can't save stream when setting live", "err", err) return nil, err } return nil, nil @@ -210,27 +209,27 @@ func (s server) NotifyStreamFinished(ctx context.Context, request *pb.StreamFini } else { stream, err := s.StreamsDao.GetStreamByID(ctx, fmt.Sprintf("%d", request.StreamID)) if err != nil { - log.WithError(err).Error("Can't find stream to set not live") + logger.Error("Can't find stream to set not live", "err", err) } else { go func() { err := handleLightOffSwitch(stream, s.DaoWrapper) if err != nil { - log.WithError(err).Error("Can't handle light off switch") + logger.Error("Can't handle light off switch", "err", err) } err = s.StreamsDao.SaveEndedState(stream.ID, true) if err != nil { - log.WithError(err).Error("Can't set stream done") + logger.Error("Can't set stream done", "err", err) } }() } err = s.DaoWrapper.IngestServerDao.RemoveStreamFromSlot(stream.ID) if err != nil { - log.WithError(err).Error("Can't remove stream from streamName") + logger.Error("Can't remove stream from streamName", "err", err) } err = s.StreamsDao.SetStreamNotLiveById(uint(request.StreamID)) if err != nil { - log.WithError(err).Error("Can't set stream not live") + logger.Error("Can't set stream not live", "err", err) } NotifyViewersLiveState(uint(request.StreamID), false) } @@ -372,7 +371,7 @@ func (s server) NotifyTranscodingFinished(ctx context.Context, request *pb.Trans err = s.StreamsDao.RemoveTranscodingProgress(model.StreamVersion(request.SourceType), stream.ID) if err != nil { - log.WithError(err).Error("error removing transcoding progress") + logger.Error("error removing transcoding progress", "err", err) } // look for file to prevent duplication @@ -392,7 +391,7 @@ func (s server) NotifyTranscodingFinished(ctx context.Context, request *pb.Trans } err = s.DaoWrapper.StreamsDao.SaveStream(&stream) if err != nil { - log.WithError(err).Error("Can't save stream") + logger.Error("Can't save stream", "err", err) return nil, err } return &pb.Status{Ok: true}, nil @@ -414,7 +413,7 @@ func (s server) NotifyUploadFinished(ctx context.Context, req *pb.UploadFinished return nil, err } if stream.LiveNow { - log.WithField("req", req).Warn("VoD not saved, stream is live.") + logger.Warn("VoD not saved, stream is live.", "req", req) return nil, nil } stream.Recording = true @@ -479,7 +478,7 @@ func (s server) NotifyThumbnailsFinished(ctx context.Context, req *pb.Thumbnails func generateCombinedThumb(streamID uint, dao dao.DaoWrapper) { stream, err := dao.StreamsDao.GetStreamByID(context.Background(), fmt.Sprintf("%d", streamID)) if err != nil { - log.WithError(err).Warn("error getting stream") + logger.Warn("error getting stream", "err", err) return } var thumbCam, thumbPres string @@ -501,7 +500,7 @@ func generateCombinedThumb(streamID uint, dao dao.DaoWrapper) { w := workers[getWorkerWithLeastWorkload(workers)] wConn, err := dialIn(w) if err != nil { - log.WithError(err).Warn("error dialing in") + logger.Warn("error dialing in", "err", err) return } client := pb.NewToWorkerClient(wConn) @@ -511,11 +510,11 @@ func generateCombinedThumb(streamID uint, dao dao.DaoWrapper) { Path: strings.ReplaceAll(thumbPres, "PRES", "CAM_PRES"), }) if err != nil { - log.WithError(err).Warn("error combining thumbnails") + logger.Warn("error combining thumbnails", "err", err) return } if err := dao.FileDao.SetThumbnail(stream.ID, model.File{StreamID: stream.ID, Path: thumbnails.FilePath, Type: model.FILETYPE_THUMB_LG_CAM_PRES}); err != nil { - log.WithError(err).Warn("error saving thumbnail") + logger.Warn("error saving thumbnail", "err", err) } } @@ -536,7 +535,7 @@ func (s server) GetStreamInfoForUpload(ctx context.Context, request *pb.GetStrea } err = dao.NewUploadKeyDao().DeleteUploadKey(key) if err != nil { - log.WithError(err).Error("Can't delete upload key") + logger.Error("Can't delete upload key", "err", err) } return &pb.GetStreamInfoForUploadResponse{ CourseSlug: course.Slug, @@ -559,26 +558,26 @@ func (s server) NotifyStreamStarted(ctx context.Context, request *pb.StreamStart } stream, err := s.StreamsDao.GetStreamByID(ctx, fmt.Sprintf("%d", request.GetStreamID())) if err != nil { - log.WithError(err).Println("Can't find stream") + logger.Error("Can't find stream", "err", err) return nil, err } course, err := s.CoursesDao.GetCourseById(ctx, stream.CourseID) if err != nil { - log.WithError(err).Println("Can't find course") + logger.Error("Can't find course", "err", err) return nil, err } go func() { err := handleLightOnSwitch(stream, s.DaoWrapper) if err != nil { - log.WithError(err).Error("Can't handle light on switch") + logger.Error("Can't handle light on switch", "err", err) } err = handleCameraPositionSwitch(stream, s.DaoWrapper) if err != nil { - log.WithError(err).Error("Can't handle camera position switch") + logger.Error("Can't handle camera position switch", "err", err) } err = s.DaoWrapper.DeleteSilences(fmt.Sprintf("%d", stream.ID)) if err != nil { - log.WithError(err).Error("Can't delete silences") + logger.Error("Can't delete silences", "err", err) } }() go func() { @@ -587,12 +586,12 @@ func (s server) NotifyStreamStarted(ctx context.Context, request *pb.StreamStart err := s.StreamsDao.SaveStream(&stream) if err != nil { - log.WithError(err).Error("Can't save stream") + logger.Error("Can't save stream", "err", err) } err = s.StreamsDao.SetStreamLiveNowTimestampById(uint(request.StreamID), time.Now()) if err != nil { - log.WithError(err).Error("Can't set StreamLiveNowTimestamp") + logger.Error("Can't set StreamLiveNowTimestamp", "err", err) } time.Sleep(time.Second * 5) @@ -630,7 +629,7 @@ func (s server) NotifyTranscodingProgress(srv pb.FromWorker_NotifyTranscodingPro return nil } if err != nil { - log.Warnf("cannot receive %v", err) + logger.Warn("cannot receive", "err", err) return nil } err = s.DaoWrapper.StreamsDao.SaveTranscodingProgress(model.TranscodingProgress{ @@ -676,7 +675,7 @@ func CreateStreamRequest(daoWrapper dao.DaoWrapper, stream model.Stream, course } server, err := daoWrapper.IngestServerDao.GetBestIngestServer() if err != nil { - log.WithError(err).Error("Can't find ingest server") + logger.Error("Can't find ingest server", "err", err) return } var slot model.StreamName @@ -686,7 +685,7 @@ func CreateStreamRequest(daoWrapper dao.DaoWrapper, stream model.Stream, course if sourceType != "COMB" || err != nil { slot, err = daoWrapper.IngestServerDao.GetStreamSlot(server.ID) if err != nil { - log.WithError(err).Error("No free stream slot") + logger.Error("No free stream slot", "err", err) return } } @@ -710,12 +709,12 @@ func CreateStreamRequest(daoWrapper dao.DaoWrapper, stream model.Stream, course workers[workerIndex].Workload += 3 err = daoWrapper.StreamsDao.SaveWorkerForStream(stream, workers[workerIndex]) if err != nil { - log.WithError(err).Error("Could not save worker for stream") + logger.Error("Could not save worker for stream", "err", err) return } conn, err := dialIn(workers[workerIndex]) if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) workers[workerIndex].Workload -= 1 // decrease workers load only by one (backoff) return } @@ -723,7 +722,7 @@ func CreateStreamRequest(daoWrapper dao.DaoWrapper, stream model.Stream, course req.WorkerId = workers[workerIndex].WorkerID resp, err := client.RequestStream(context.Background(), &req) if err != nil || !resp.Ok { - log.WithError(err).Error("could not assign stream!") + logger.Error("could not assign stream!", "err", err) workers[workerIndex].Workload -= 1 // decrease workers load only by one (backoff) } endConnection(conn) @@ -738,25 +737,25 @@ func NotifyWorkers(daoWrapper dao.DaoWrapper) func() { streams := daoWrapper.StreamsDao.GetDueStreamsForWorkers() workers := daoWrapper.WorkerDao.GetAliveWorkers() if len(workers) == 0 && len(streams) != 0 { - log.Error("not enough workers to handle streams") + logger.Error("not enough workers to handle streams") return } for i := range streams { err := daoWrapper.StreamsDao.SaveEndedState(streams[i].ID, false) if err != nil { - log.WithError(err).Warn("Can't set stream undone") + logger.Warn("Can't set stream undone", "err", err) sentry.CaptureException(err) continue } courseForStream, err := daoWrapper.CoursesDao.GetCourseById(context.Background(), streams[i].CourseID) if err != nil { - log.WithError(err).Warn("Can't get course for stream, skipping") + logger.Warn("Can't get course for stream, skipping", "err", err) sentry.CaptureException(err) continue } lectureHallForStream, err := daoWrapper.LectureHallsDao.GetLectureHallByID(streams[i].LectureHallID) if err != nil { - log.WithError(err).Error("Can't get lecture hall for stream, skipping") + logger.Error("Can't get lecture hall for stream, skipping", "err", err) sentry.CaptureException(err) continue } @@ -786,25 +785,25 @@ func notifyWorkersPremieres(daoWrapper dao.DaoWrapper) { workers := daoWrapper.WorkerDao.GetAliveWorkers() if len(workers) == 0 && len(streams) != 0 { - log.Error("Not enough alive workers for premiere") + logger.Error("Not enough alive workers for premiere") return } for i := range streams { err := daoWrapper.StreamsDao.SaveEndedState(streams[i].ID, false) if err != nil { - log.WithError(err).Warn("Can't set stream undone") + logger.Warn("Can't set stream undone", "err", err) sentry.CaptureException(err) continue } if len(streams[i].Files) == 0 { - log.WithField("streamID", streams[i].ID).Warn("Request to self stream without file") + logger.Warn("Request to self stream without file", "streamID", streams[i].ID) continue } workerIndex := getWorkerWithLeastWorkload(workers) workers[workerIndex].Workload += 3 ingestServer, err := daoWrapper.IngestServerDao.GetBestIngestServer() if err != nil { - log.WithError(err).Error("Can't find ingest server") + logger.Error("Can't find ingest server", "err", err) continue } req := pb.PremiereRequest{ @@ -815,7 +814,7 @@ func notifyWorkersPremieres(daoWrapper dao.DaoWrapper) { } conn, err := dialIn(workers[workerIndex]) if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) endConnection(conn) workers[workerIndex].Workload -= 1 continue @@ -824,7 +823,7 @@ func notifyWorkersPremieres(daoWrapper dao.DaoWrapper) { req.WorkerID = workers[workerIndex].WorkerID resp, err := client.RequestPremiere(context.Background(), &req) if err != nil || !resp.Ok { - log.WithError(err).Error("could not assign premiere!") + logger.Error("could not assign premiere!", "err", err) workers[workerIndex].Workload -= 1 } endConnection(conn) @@ -852,7 +851,7 @@ func FetchLivePreviews(daoWrapper dao.DaoWrapper) func() { } conn, err := dialIn(workers[workerIndex]) if err != nil { - log.WithError(err).Error("Could not connect to worker") + logger.Error("Could not connect to worker", "err", err) endConnection(conn) continue } @@ -860,7 +859,7 @@ func FetchLivePreviews(daoWrapper dao.DaoWrapper) func() { workers[workerIndex].Workload += 1 if err := getLivePreviewFromWorker(&s, workers[workerIndex].WorkerID, client); err != nil { workers[workerIndex].Workload -= 1 - log.WithError(err).Error("Could not generate live preview") + logger.Error("Could not generate live preview", "err", err) endConnection(conn) continue } @@ -909,7 +908,7 @@ func RegenerateThumbs(daoWrapper dao.DaoWrapper, file model.File, stream *model. endConnection(conn) }() if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) return err } client := pb.NewToWorkerClient(conn) @@ -925,7 +924,7 @@ func RegenerateThumbs(daoWrapper dao.DaoWrapper, file model.File, stream *model. Start: timestamppb.New(stream.Start), }) if !res.Ok { - log.WithError(err).Error("did not get response from worker for thumbnail generation request") + logger.Error("did not get response from worker for thumbnail generation request", "err", err) } return nil @@ -948,7 +947,7 @@ func DeleteVideoSectionImage(workerDao dao.WorkerDao, path string) error { endConnection(conn) }() if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) return err } @@ -969,7 +968,7 @@ func GenerateVideoSectionImages(daoWrapper dao.DaoWrapper, parameters *generateV endConnection(conn) }() if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) return err } @@ -1016,12 +1015,12 @@ func GenerateVideoSectionImages(daoWrapper dao.DaoWrapper, parameters *generateV func NotifyWorkersToStopStream(stream model.Stream, discardVoD bool, daoWrapper dao.DaoWrapper) { workers, err := daoWrapper.StreamsDao.GetWorkersForStream(stream) if err != nil { - log.WithError(err).Error("Could not get workers for stream") + logger.Error("Could not get workers for stream", "err", err) return } if len(workers) == 0 { - log.Error("No workers for stream found") + logger.Error("No workers for stream found") return } @@ -1034,13 +1033,13 @@ func NotifyWorkersToStopStream(stream model.Stream, discardVoD bool, daoWrapper } conn, err := dialIn(currentWorker) if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) continue } client := pb.NewToWorkerClient(conn) resp, err := client.RequestStreamEnd(context.Background(), &req) if err != nil || !resp.Ok { - log.WithError(err).Error("Could not end stream") + logger.Error("Could not end stream", "err", err) } endConnection(conn) } @@ -1048,7 +1047,7 @@ func NotifyWorkersToStopStream(stream model.Stream, discardVoD bool, daoWrapper // All workers for stream are assumed to be done err = daoWrapper.StreamsDao.ClearWorkersForStream(stream) if err != nil { - log.WithError(err).Error("Could not delete workers for stream") + logger.Error("Could not delete workers for stream", "err", err) return } } @@ -1092,10 +1091,10 @@ func getWorkerWithLeastWorkload(workers []model.Worker) int { // ServeWorkerGRPC initializes a gRPC server on port 50052 func ServeWorkerGRPC() { - log.Info("Serving heartbeat") + logger.Info("Serving heartbeat") lis, err := net.Listen("tcp", ":50052") if err != nil { - log.WithError(err).Error("Failed to init grpc server") + logger.Error("Failed to init grpc server", "err", err) return } grpcServer := grpc.NewServer(grpc.KeepaliveParams(keepalive.ServerParameters{ @@ -1109,7 +1108,7 @@ func ServeWorkerGRPC() { reflection.Register(grpcServer) go func() { if err = grpcServer.Serve(lis); err != nil { - log.WithError(err).Errorf("Can't serve grpc") + logger.Error("Can't serve grpc", "err", err) } }() } diff --git a/api/wsHub.go b/api/wsHub.go index d2876263f..0a4265165 100644 --- a/api/wsHub.go +++ b/api/wsHub.go @@ -5,12 +5,11 @@ import ( "encoding/json" "errors" "fmt" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/tools/realtime" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "strconv" "strings" "sync" @@ -52,11 +51,12 @@ var connHandler = func(context *realtime.Context) { msg, _ := json.Marshal(gin.H{"viewers": len(sessionsMap[tumLiveContext.Stream.ID])}) err := context.Send(msg) if err != nil { - log.WithError(err).Error("can't write initial stats to session") + logger.Error("can't write initial stats to session", "err", err) } } // sendServerMessageWithBackoff sends a message to the client(if it didn't send a message to this user in the last 10 Minutes and the client is logged in) +// //lint:ignore U1000 Ignore unused function func sendServerMessageWithBackoff(session *realtime.Context, userId uint, streamId uint, msg string, t string) { if userId == 0 { @@ -71,7 +71,7 @@ func sendServerMessageWithBackoff(session *realtime.Context, userId uint, stream msgBytes, _ := json.Marshal(gin.H{"server": msg, "type": t}) err := session.Send(msgBytes) if err != nil { - log.WithError(err).Error("can't write server message to session") + logger.Error("can't write server message to session", "err", err) } // set cache item with ttl, so the user won't get a message for 10 Minutes tools.SetCacheItem(cacheKey, true, time.Minute*10) @@ -83,7 +83,7 @@ func sendServerMessage(msg string, t string, sessions ...*realtime.Context) { for _, session := range sessions { err := session.Send(msgBytes) if err != nil { - log.WithError(err).Error("can't write server message to session") + logger.Error("can't write server message to session", "err", err) } } diff --git a/cmd/tumlive/tumlive.go b/cmd/tumlive/tumlive.go index 9fa949cc0..967803c12 100755 --- a/cmd/tumlive/tumlive.go +++ b/cmd/tumlive/tumlive.go @@ -2,21 +2,22 @@ package main import ( "fmt" - "github.com/dgraph-io/ristretto" - "github.com/getsentry/sentry-go" - sentrygin "github.com/getsentry/sentry-go/gin" - "github.com/gin-contrib/gzip" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/api" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/tools/tum" "github.com/TUM-Dev/gocast/web" + "github.com/dgraph-io/ristretto" + "github.com/getsentry/sentry-go" + sentrygin "github.com/getsentry/sentry-go/gin" + "github.com/gin-contrib/gzip" + "github.com/gin-gonic/gin" + slogGorm "github.com/orandin/slog-gorm" "github.com/pkg/profile" - log "github.com/sirupsen/logrus" "gorm.io/driver/mysql" "gorm.io/gorm" + "log/slog" "net/http" _ "net/http/pprof" "os" @@ -29,6 +30,10 @@ var VersionTag = "development" type initializer func() +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "main") + var initializers = []initializer{ tools.LoadConfig, api.ServeWorkerGRPC, @@ -43,7 +48,8 @@ func initAll(initializers []initializer) { // GinServer launches the gin server func GinServer() (err error) { - router := gin.Default() + router := gin.New() + router.Use(gin.Recovery()) gin.SetMode(gin.ReleaseMode) // capture performance with sentry router.Use(sentrygin.New(sentrygin.Options{Repanic: true})) @@ -51,6 +57,16 @@ func GinServer() (err error) { tools.CookieSecure = true } + router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string { + return fmt.Sprintf("{\"service\": \"GIN\", \"time\": %s, \"status\": %d, \"client\": \"%s\", \"path\": \"%s\", \"agent\": %s}\n", + param.TimeStamp.Format(time.DateTime), + param.StatusCode, + param.ClientIP, + param.Path, + param.Request.UserAgent(), + ) + })) + router.Use(tools.InitContext(dao.NewDaoWrapper())) liveUpdates := router.Group("/api/pub-sub") @@ -67,7 +83,7 @@ func GinServer() (err error) { //err = router.RunTLS(":443", tools.Cfg.Saml.Cert, tools.Cfg.Saml.Privkey) if err != nil { sentry.CaptureException(err) - log.WithError(err).Fatal("Error starting tumlive") + logger.Error("Error starting tumlive", "err", err) } return } @@ -85,7 +101,7 @@ func main() { }() // log with time, fmt "23.09.2021 10:00:00" - log.SetFormatter(&log.TextFormatter{TimestampFormat: "02.01.2006 15:04:05", FullTimestamp: true}) + //log.SetFormatter(&log.TextFormatter{TimestampFormat: "02.01.2006 15:04:05", FullTimestamp: true}) web.VersionTag = VersionTag osSignal = make(chan os.Signal, 1) @@ -104,12 +120,15 @@ func main() { Environment: env, }) if err != nil { - log.Fatalf("sentry.Init: %s", err) + logger.Error("sentry.Init", "err", err) } // Flush buffered events before the program terminates. defer sentry.Flush(2 * time.Second) defer sentry.Recover() } + + gormJSONLogger := slogGorm.New() + db, err := gorm.Open(mysql.Open(fmt.Sprintf( "%s:%s@tcp(%s:%d)/%s?parseTime=true&loc=Local", tools.Cfg.Db.User, @@ -119,18 +138,19 @@ func main() { tools.Cfg.Db.Database), ), &gorm.Config{ PrepareStmt: true, + Logger: gormJSONLogger, }) if err != nil { sentry.CaptureException(err) sentry.Flush(time.Second * 5) - log.Fatalf("%v", err) + logger.Error("Error opening database", "err", err) } dao.DB = db err = dao.Migrator.RunBefore(db) if err != nil { - log.Error(err) + logger.Error("Error running before db", "err", err) return } @@ -172,11 +192,11 @@ func main() { if err != nil { sentry.CaptureException(err) sentry.Flush(time.Second * 5) - log.WithError(err).Fatal("can't migrate database") + logger.Error("can't migrate database", "err", err) } err = dao.Migrator.RunAfter(db) if err != nil { - log.Error(err) + logger.Error("Error running after db", "err", err) return } @@ -191,7 +211,7 @@ func main() { if err != nil { sentry.CaptureException(err) sentry.Flush(time.Second * 5) - log.Fatalf("%v", err) + logger.Error("Error risretto.NewCache", "err", err) } dao.Cache = *cache @@ -207,7 +227,7 @@ func main() { if err != nil { sentry.CaptureException(err) sentry.Flush(time.Second * 5) - log.WithError(err).Fatal("can't launch gin server") + logger.Error("can't launch gin server", "err", err) } }() keepAlive() @@ -236,5 +256,5 @@ func initCron() { func keepAlive() { signal.Notify(osSignal, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1) s := <-osSignal - log.Infof("Exiting on signal %s", s.String()) + logger.Info("Exiting on signal" + s.String()) } diff --git a/dao/courses.go b/dao/courses.go index 18294dfea..7a169f0c9 100644 --- a/dao/courses.go +++ b/dao/courses.go @@ -10,7 +10,6 @@ import ( "github.com/RBG-TUM/commons" "github.com/getsentry/sentry-go" - log "github.com/sirupsen/logrus" "gorm.io/gorm" ) @@ -305,16 +304,16 @@ func (d coursesDao) DeleteCourse(course model.Course) { for _, stream := range course.Streams { err := DB.Delete(&stream).Error if err != nil { - log.WithError(err).Error("Can't delete stream") + logger.Error("Can't delete stream", "err", err) } } err := DB.Model(&course).Updates(map[string]interface{}{"vod_enabled": false}).Error if err != nil { - log.WithError(err).Error("Can't update course settings when deleting") + logger.Error("Can't update course settings when deleting", "err", err) } err = DB.Delete(&course, course.ID).Error if err != nil { - log.WithError(err).Error("Can't delete course") + logger.Error("Can't delete course", "err", err) } } diff --git a/dao/dao_logger.go b/dao/dao_logger.go new file mode 100644 index 000000000..63eb896b4 --- /dev/null +++ b/dao/dao_logger.go @@ -0,0 +1,10 @@ +package dao + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "dao") diff --git a/dao/video-seek.go b/dao/video-seek.go index 4cc7200ed..165650cc0 100644 --- a/dao/video-seek.go +++ b/dao/video-seek.go @@ -3,7 +3,6 @@ package dao import ( "errors" "github.com/TUM-Dev/gocast/model" - log "github.com/sirupsen/logrus" "gorm.io/gorm" "gorm.io/gorm/clause" ) @@ -32,7 +31,7 @@ func (d videoSeekDao) Add(streamID string, pos float64) error { } if (pos / float64(stream.Duration.Int32)) > 1 { - log.Error("position is bigger than stream duration") + logger.Error("position is bigger than stream duration") return errors.New("position is bigger than stream duration") } diff --git a/go.mod b/go.mod index dd030c58c..1206996fa 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/TUM-Dev/gocast -go 1.18 +go 1.21 require ( github.com/RBG-TUM/CAMPUSOnline v0.0.0-20230412070523-8db58ed5c0b4 @@ -30,7 +30,7 @@ require ( google.golang.org/grpc v1.57.0 google.golang.org/protobuf v1.31.0 gorm.io/driver/mysql v1.5.1 - gorm.io/gorm v1.25.3 + gorm.io/gorm v1.25.5 mvdan.cc/xurls/v2 v2.5.0 ) @@ -50,6 +50,7 @@ require ( github.com/asticode/go-astisub v0.26.0 github.com/matthiasreumann/gomino v0.0.2 github.com/meilisearch/meilisearch-go v0.25.0 + github.com/orandin/slog-gorm v1.0.1 ) require ( diff --git a/go.sum b/go.sum index 1b9e9cfab..04b5da18a 100644 --- a/go.sum +++ b/go.sum @@ -126,6 +126,7 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= @@ -145,6 +146,7 @@ github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SU github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -155,6 +157,7 @@ github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSz github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= @@ -175,7 +178,9 @@ github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= @@ -271,13 +276,17 @@ github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= +github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= @@ -323,11 +332,13 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/meilisearch/meilisearch-go v0.25.0 h1:xIp+8YWterHuDvpdYlwQ4Qp7im3JlRHmSKiP0NvjyXs= github.com/meilisearch/meilisearch-go v0.25.0/go.mod h1:SxuSqDcPBIykjWz1PX+KzsYzArNLSCadQodWs8extS0= github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= github.com/microsoft/go-mssqldb v0.21.0 h1:p2rpHIL7TlSv1QrbXJUAcbyRKnIT0C9rRkH2E4OjLn8= +github.com/microsoft/go-mssqldb v0.21.0/go.mod h1:+4wZTUnz/SV6nffv+RRRB/ss8jPng5Sho2SmM1l2ts4= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= @@ -344,11 +355,14 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/olahol/melody v0.0.0-20180227134253-7bd65910e5ab/go.mod h1:3lo03f1jM3KFUG/rsujuLB1rBmlvIzVM3SCqbuHqsBU= +github.com/orandin/slog-gorm v1.0.1 h1:Hyhaajes1rXsgwbH59+qS2JaN31PNEBzMywiFsa2Eiw= +github.com/orandin/slog-gorm v1.0.1/go.mod h1:QLR+9XefjS+lz7Xw3ZXkDkT5U59h7/0c8TZlMZPqXpI= github.com/panjf2000/ants/v2 v2.4.2/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -367,6 +381,7 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russellhaering/goxmldsig v1.2.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= github.com/russellhaering/goxmldsig v1.4.0 h1:8UcDh/xGyQiyrW+Fq5t8f+l2DLB1+zlhYzkPUJ7Qhys= github.com/russellhaering/goxmldsig v1.4.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= @@ -803,11 +818,14 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw= gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= +gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= gorm.io/driver/sqlite v1.5.1 h1:hYyrLkAWE71bcarJDPdZNTLWtr8XrSjOWyjUYI6xdL4= +gorm.io/driver/sqlite v1.5.1/go.mod h1:7MZZ2Z8bqyfSQA1gYEV6MagQWj3cpUkJj9Z+d1HEMEQ= gorm.io/driver/sqlserver v1.5.0 h1:zol7ePfY1XiPfjEvjjBh4VatIF3kycNcPE0EMCXznHY= +gorm.io/driver/sqlserver v1.5.0/go.mod h1:tBAqioK34BHl0Iiez+BFfG5/K9nDAlhLxRkgc2qy3+4= gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -gorm.io/gorm v1.25.3 h1:zi4rHZj1anhZS2EuEODMhDisGy+Daq9jtPrNGgbQYD8= -gorm.io/gorm v1.25.3/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= +gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= diff --git a/go.work b/go.work index 61b4b2a9a..71de48fe3 100644 --- a/go.work +++ b/go.work @@ -1,4 +1,4 @@ -go 1.19 +go 1.21 use ( . diff --git a/model/course.go b/model/course.go index e902bba18..65c3524f8 100755 --- a/model/course.go +++ b/model/course.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" "gorm.io/gorm" "log" "time" @@ -148,7 +147,7 @@ func (c Course) CanUseSource(lectureHallID uint, sourceType string) bool { func (c *Course) SetSourcePreference(pref []SourcePreference) { pBytes, err := json.Marshal(pref) if err != nil { - logrus.WithError(err).Error("Could not marshal source preference") + logger.Error("Could not marshal source preference", "err", err) return } c.SourcePreferences = string(pBytes) diff --git a/model/model_logger.go b/model/model_logger.go new file mode 100644 index 000000000..2464568ee --- /dev/null +++ b/model/model_logger.go @@ -0,0 +1,10 @@ +package model + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "model") diff --git a/model/user.go b/model/user.go index 5856e127f..b16c956e9 100755 --- a/model/user.go +++ b/model/user.go @@ -9,6 +9,7 @@ import ( "encoding/json" "errors" "fmt" + "sort" "strings" "time" @@ -54,6 +55,7 @@ const ( PreferredName UserSettingType = iota + 1 Greeting CustomPlaybackSpeeds + UserDefinedSpeeds ) type UserSetting struct { @@ -79,6 +81,8 @@ type PlaybackSpeedSetting struct { Enabled bool `json:"enabled"` } +type CustomSpeeds []float32 + type PlaybackSpeedSettings []PlaybackSpeedSetting func (s PlaybackSpeedSettings) GetEnabled() (res []float32) { @@ -90,6 +94,22 @@ func (s PlaybackSpeedSettings) GetEnabled() (res []float32) { return res } +func (u *User) GetEnabledPlaybackSpeeds() (res []float32) { + if u == nil { + return []float32{1} + } + for _, setting := range u.GetPlaybackSpeeds().GetEnabled() { + res = append(res, setting) + } + for _, setting := range u.GetCustomSpeeds() { + res = append(res, setting) + } + sort.SliceStable(res, func(i, j int) bool { + return res[i] < res[j] + }) + return res +} + var defaultPlaybackSpeeds = PlaybackSpeedSettings{ {0.25, false}, {0.5, true}, @@ -120,6 +140,22 @@ func (u *User) GetPlaybackSpeeds() (speeds PlaybackSpeedSettings) { return defaultPlaybackSpeeds } +func (u *User) GetCustomSpeeds() (speeds CustomSpeeds) { + if u == nil { + return []float32{} + } + for _, setting := range u.Settings { + if setting.Type == UserDefinedSpeeds { + err := json.Unmarshal([]byte(setting.Value), &speeds) + if err != nil { + break + } + return speeds + } + } + return []float32{} +} + // GetPreferredGreeting returns the preferred greeting of the user if set, otherwise Moin func (u User) GetPreferredGreeting() string { for _, setting := range u.Settings { diff --git a/tools/bot/bot.go b/tools/bot/bot.go index 572e448e8..87272a37a 100644 --- a/tools/bot/bot.go +++ b/tools/bot/bot.go @@ -1,11 +1,10 @@ package bot import ( - "github.com/getsentry/sentry-go" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" + "github.com/getsentry/sentry-go" "github.com/microcosm-cc/bluemonday" - log "github.com/sirupsen/logrus" "strings" "time" ) @@ -147,7 +146,7 @@ func hasPrio(streamID uint, statsDao dao.StatisticsDao) bool { liveViewers, err := statsDao.GetStreamNumLiveViews(streamID) if err != nil { sentry.CaptureException(err) - log.WithError(err).Error("Failed to get current live viewers") + logger.Error("Failed to get current live viewers", "err", err) return false } diff --git a/tools/bot/bot_logger.go b/tools/bot/bot_logger.go new file mode 100644 index 000000000..8af169b64 --- /dev/null +++ b/tools/bot/bot_logger.go @@ -0,0 +1,10 @@ +package bot + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "bot") diff --git a/tools/bot/matrix.go b/tools/bot/matrix.go index 0bd8e8e2d..f1e81f7ed 100644 --- a/tools/bot/matrix.go +++ b/tools/bot/matrix.go @@ -5,9 +5,8 @@ import ( "encoding/json" "errors" "fmt" - "github.com/getsentry/sentry-go" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" "io" "math/rand" "net/http" @@ -74,14 +73,14 @@ func (m *Matrix) getClientUrl() string { func (m *Matrix) SendBotMessage(message Message) error { err := m.sendMessageToRoom(tools.Cfg.Alerts.Matrix.LogRoomID, message) if err != nil { - log.WithError(err).Error("Failed to send message to matrix log room") + logger.Error("Failed to send message to matrix log room", "err", err) sentry.CaptureException(err) return err } if message.Prio { err = m.sendMessageToRoom(tools.Cfg.Alerts.Matrix.AlertRoomID, message) if err != nil { - log.WithError(err).Error("Failed to send message to matrix alert room") + logger.Error("Failed to send message to matrix alert room", "err", err) sentry.CaptureException(err) } } diff --git a/tools/branding.go b/tools/branding.go index 644e4c349..5abd222c9 100644 --- a/tools/branding.go +++ b/tools/branding.go @@ -2,7 +2,6 @@ package tools import ( "fmt" - log "github.com/sirupsen/logrus" "github.com/spf13/viper" ) @@ -38,7 +37,7 @@ func InitBranding() { err := v.ReadInConfig() if err == nil { err = v.Unmarshal(&branding) - log.Info("Using branding.yaml.") + logger.Info("Using branding.yaml.") if err != nil { panic(fmt.Errorf("fatal error branding file: %v", err)) } diff --git a/tools/camera/camera_logger.go b/tools/camera/camera_logger.go new file mode 100644 index 000000000..ba5b22c5d --- /dev/null +++ b/tools/camera/camera_logger.go @@ -0,0 +1,10 @@ +package camera + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "camera") diff --git a/tools/camera/panasonic.go b/tools/camera/panasonic.go index 65864c6d7..27c0ab10a 100644 --- a/tools/camera/panasonic.go +++ b/tools/camera/panasonic.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/TUM-Dev/gocast/model" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" ) /** @@ -18,21 +17,21 @@ import ( const panasonicBaseUrl = "http://%s/cgi-bin" -//PanasonicCam represents Panasonic IP cameras the TUM uses +// PanasonicCam represents Panasonic IP cameras the TUM uses type PanasonicCam struct { Ip string Auth *string // currently unused as our cams have auth deactivated for PTZ operation } -//NewPanasonicCam Acts as a constructor for cameras. -//ip: the ip address of the camera -//auth: username and password of the camera (e.g. "user:password") +// NewPanasonicCam Acts as a constructor for cameras. +// ip: the ip address of the camera +// auth: username and password of the camera (e.g. "user:password") func NewPanasonicCam(ip string, auth *string) *PanasonicCam { return &PanasonicCam{Ip: ip, Auth: auth} } func (c PanasonicCam) TakeSnapshot(outDir string) (filename string, err error) { - log.Info(fmt.Sprintf("%s/view.cgi?action=snapshot", fmt.Sprintf(panasonicBaseUrl, c.Ip))) + logger.Info(fmt.Sprintf("%s/view.cgi?action=snapshot", fmt.Sprintf(panasonicBaseUrl, c.Ip))) resp, err := makeAuthenticatedRequest(c.Auth, "GET", "", fmt.Sprintf("%s/view.cgi?action=snapshot", fmt.Sprintf(panasonicBaseUrl, c.Ip))) if err != nil { return "", err @@ -45,13 +44,13 @@ func (c PanasonicCam) TakeSnapshot(outDir string) (filename string, err error) { return filename, nil } -//SetPreset tells the camera to use a preset specified by presetId +// SetPreset tells the camera to use a preset specified by presetId func (c PanasonicCam) SetPreset(presetId int) error { _, err := makeAuthenticatedRequest(c.Auth, "GET", "", fmt.Sprintf("%s/camctrl?preset=%d", fmt.Sprintf(panasonicBaseUrl, c.Ip), presetId)) return err } -//GetPresets fetches all presets stored on the camera +// GetPresets fetches all presets stored on the camera func (c PanasonicCam) GetPresets() ([]model.CameraPreset, error) { // panasonic cameras come with 100 slots for presets. These are always present but usually only a few are configured. // we therefore just return 10 stubs here. diff --git a/tools/config.go b/tools/config.go index c7639690f..145fd3cad 100644 --- a/tools/config.go +++ b/tools/config.go @@ -9,7 +9,6 @@ import ( "fmt" "github.com/meilisearch/meilisearch-go" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "github.com/spf13/viper" "os" "time" @@ -23,7 +22,7 @@ func LoadConfig() { var err error Loc, err = time.LoadLocation("Europe/Berlin") if err != nil { - log.WithError(err).Error("tools.config.LoadConfig: can't get time.location") + logger.Error("tools.config.LoadConfig: can't get time.location", "err", err) } initConfig() } @@ -39,12 +38,12 @@ func initConfig() { err := viper.ReadInConfig() if err != nil { if errors.Is(err, viper.ConfigFileNotFoundError{}) { - log.WithError(err).Warn("tools.config.LoadConfig: can't find config file") + logger.Warn("tools.config.LoadConfig: can't find config file", "err", err) } else { panic(fmt.Errorf("fatal error config file: %v", err)) } } - log.Info("Using Config file ", viper.ConfigFileUsed()) + logger.Info("Using Config file " + viper.ConfigFileUsed()) err = viper.Unmarshal(&Cfg) if err != nil { panic(fmt.Errorf("fatal error config file: %v", err)) @@ -56,14 +55,14 @@ func initConfig() { viper.Set("workerToken", Cfg.WorkerToken) err = viper.WriteConfig() if err != nil { - log.Warn("Can't write out config ", err) + logger.Warn("Can't write out config ", "err", err) } } if Cfg.JWTKey == nil { - log.Info("Generating new JWT key") + logger.Info("Generating new JWT key") JWTKey, err := rsa.GenerateKey(rand.Reader, rsaKeySize) if err != nil { - log.WithError(err).Fatal("Can't generate JWT key") + logger.Error("Can't generate JWT key", "err", err) } armoured := string(pem.EncodeToMemory( &pem.Block{ @@ -74,14 +73,14 @@ func initConfig() { viper.Set("jwtKey", armoured) err = viper.WriteConfig() if err != nil { - log.Warn("Can't write out config ", err) + logger.Warn("Can't write out config ", "err", err) } jwtKey = JWTKey } else { k, _ := pem.Decode([]byte(*Cfg.JWTKey)) key, err := x509.ParsePKCS1PrivateKey(k.Bytes) if err != nil { - log.WithError(err).Fatal("Can't parse JWT key") + logger.Error("Can't parse JWT key", "err", err) return } jwtKey = key diff --git a/tools/email.go b/tools/email.go index 02700d7e9..270f959f1 100644 --- a/tools/email.go +++ b/tools/email.go @@ -5,7 +5,6 @@ import ( "context" "fmt" "github.com/TUM-Dev/gocast/dao" - "log" "net/smtp" "os/exec" "strings" @@ -33,7 +32,7 @@ func (m *Mailer) Run() { lastRun = time.Now() emails, err := m.Dao.EmailDao.GetDue(context.Background(), m.MaxMailsPerMinute) if err != nil { - log.Printf("error getting due emails: %v", err) + logger.Error("error getting due emails", "err", err) continue } for _, email := range emails { @@ -47,7 +46,7 @@ func (m *Mailer) Run() { } err = m.Dao.EmailDao.Save(context.Background(), &email) if err != nil { - log.Printf("error saving email: %v", err) + logger.Error("error saving email", "err", err) } sleepDur := time.Duration(1000 * (60 / m.MaxMailsPerMinute)) @@ -57,7 +56,7 @@ func (m *Mailer) Run() { } func (m *Mailer) sendMail(addr, from, subject, body string, to []string) error { - log.Printf("sending mail to %v, subject: %s body:\n%s", to, subject, body) + logger.Info("sending mail", "to", to, "subject", subject, "body", body) r := strings.NewReplacer("\r\n", "", "\r", "", "\n", "", "%0a", "", "%0d", "") signed, err := openssl([]byte(body), "smime", "-text", "-sign", "-signer", Cfg.Mail.SMIMECert, "-inkey", Cfg.Mail.SMIMEKey) diff --git a/tools/meiliExporter.go b/tools/meiliExporter.go index 2fbd595e6..d72da9833 100644 --- a/tools/meiliExporter.go +++ b/tools/meiliExporter.go @@ -3,10 +3,9 @@ package tools import ( "errors" "fmt" - "github.com/asticode/go-astisub" "github.com/TUM-Dev/gocast/dao" + "github.com/asticode/go-astisub" "github.com/meilisearch/meilisearch-go" - log "github.com/sirupsen/logrus" "strings" ) @@ -39,7 +38,7 @@ func NewMeiliExporter(d dao.DaoWrapper) *MeiliExporter { if err != nil && errors.Is(err, ErrMeiliNotConfigured) { return nil } else if err != nil { - log.WithError(err).Error("could not get meili client") + logger.Error("could not get meili client", "err", err) return nil } @@ -53,7 +52,7 @@ func (m *MeiliExporter) Export() { index := m.c.Index("STREAMS") _, err := m.c.Index("SUBTITLES").DeleteAllDocuments() if err != nil { - log.WithError(err).Warn("could not delete all old subtitles") + logger.Warn("could not delete all old subtitles", "err", err) } m.d.StreamsDao.ExecAllStreamsWithCoursesAndSubtitles(func(streams []dao.StreamWithCourseAndSubtitles) { @@ -75,7 +74,7 @@ func (m *MeiliExporter) Export() { vtt, err := astisub.ReadFromWebVTT(strings.NewReader(stream.Subtitles)) if err != nil { - log.WithError(err).Warn("could not parse subtitles") + logger.Warn("could not parse subtitles", "err", err) continue } for i, _ := range vtt.Items { @@ -96,14 +95,14 @@ func (m *MeiliExporter) Export() { if len(meiliSubtitles) > 0 { _, err := m.c.Index("SUBTITLES").AddDocuments(&meiliSubtitles, "ID") if err != nil { - log.WithError(err).Error("issue adding subtitles to meili") + logger.Error("issue adding subtitles to meili", "err", err) } } } } _, err := index.AddDocuments(&meilistreams, "ID") if err != nil { - log.WithError(err).Error("issue adding documents to meili") + logger.Error("issue adding documents to meili", "err", err) } }) @@ -120,7 +119,7 @@ func (m *MeiliExporter) SetIndexSettings() { } _, err := index.UpdateSynonyms(&synonyms) if err != nil { - log.WithError(err).Error("could not set synonyms for meili index STREAMS") + logger.Error("could not set synonyms for meili index STREAMS", "err", err) } _, err = m.c.Index("SUBTITLES").UpdateSettings(&meilisearch.Settings{ @@ -129,6 +128,6 @@ func (m *MeiliExporter) SetIndexSettings() { SortableAttributes: []string{"timestamp"}, }) if err != nil { - log.WithError(err).Warn("could not set settings for meili index SUBTITLES") + logger.Warn("could not set settings for meili index SUBTITLES", "err", err) } } diff --git a/tools/meiliSearch.go b/tools/meiliSearch.go index 9b3b8a035..4770dfae1 100644 --- a/tools/meiliSearch.go +++ b/tools/meiliSearch.go @@ -3,7 +3,6 @@ package tools import ( "fmt" "github.com/meilisearch/meilisearch-go" - log "github.com/sirupsen/logrus" ) func SearchSubtitles(q string, streamID uint) *meilisearch.SearchResponse { @@ -16,7 +15,7 @@ func SearchSubtitles(q string, streamID uint) *meilisearch.SearchResponse { Limit: 10, }) if err != nil { - log.WithError(err).Error("could not search meili") + logger.Error("could not search meili", "err", err) return nil } return response diff --git a/tools/middlewares.go b/tools/middlewares.go index b523ba213..dee069940 100644 --- a/tools/middlewares.go +++ b/tools/middlewares.go @@ -2,13 +2,12 @@ package tools import ( "errors" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" - "github.com/golang-jwt/jwt/v4" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools/realtime" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" + "github.com/golang-jwt/jwt/v4" "net/http" "net/url" "strconv" @@ -50,13 +49,13 @@ func InitContext(daoWrapper dao.DaoWrapper) gin.HandlerFunc { return key, nil }) if err != nil { - log.Info("JWT parsing error: ", err) + logger.Info("JWT parsing error: ", "err", err) c.Set("TUMLiveContext", TUMLiveContext{}) c.SetCookie("jwt", "", -1, "/", "", false, true) return } if !token.Valid { - log.Info("JWT token is not valid") + logger.Info("JWT token is not valid") c.Set("TUMLiveContext", TUMLiveContext{}) c.SetCookie("jwt", "", -1, "/", "", false, true) return @@ -90,7 +89,7 @@ func RenderErrorPage(c *gin.Context, status int, message string) { Branding: BrandingCfg, }) if err != nil { - log.Error(err) + logger.Error("Error on executing template error.gohtml", "err", err) } c.Abort() } @@ -371,7 +370,7 @@ func AdminToken(daoWrapper dao.DaoWrapper) gin.HandlerFunc { } err = daoWrapper.TokenDao.TokenUsed(t) if err != nil { - log.WithError(err).Warn("error marking token as used") + logger.Warn("error marking token as used", "err", err) return } } diff --git a/tools/presets.go b/tools/presets.go index 317725ec0..b0d3f8647 100644 --- a/tools/presets.go +++ b/tools/presets.go @@ -3,11 +3,10 @@ package tools import ( "context" "errors" - "github.com/getsentry/sentry-go" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools/camera" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" "time" ) @@ -39,7 +38,7 @@ func (p presetUtility) ProvideCamera(ctype model.CameraType, ip string) (camera. return nil, errors.New("invalid camera type") } -//FetchCameraPresets Queries all cameras of lecture halls for their camera presets and saves them to the database +// FetchCameraPresets Queries all cameras of lecture halls for their camera presets and saves them to the database func (p presetUtility) FetchCameraPresets(ctx context.Context) { span := sentry.StartSpan(ctx, "FetchCameraPresets") defer span.Finish() @@ -53,12 +52,12 @@ func (p presetUtility) FetchLHPresets(lectureHall model.LectureHall) { if lectureHall.CameraIP != "" { cam, err := p.ProvideCamera(lectureHall.CameraType, lectureHall.CameraIP) if err != nil { - log.WithError(err) + logger.Error("Error providing camera", "err", err) return } presets, err := cam.GetPresets() if err != nil { - log.WithError(err).WithField("AxisCam", lectureHall.CameraIP).Warn("FetchCameraPresets: failed to get Presets") + logger.Warn("FetchCameraPresets: failed to get Presets", "err", err, "AxisCam", lectureHall.CameraIP) return } /*for i := range presets { @@ -78,17 +77,17 @@ func (p presetUtility) UsePreset(preset model.CameraPreset) { } cam, err := p.ProvideCamera(lectureHall.CameraType, lectureHall.CameraIP) if err != nil { - log.WithError(err) + logger.Error("Error providing camera", "err", err) return } err = cam.SetPreset(preset.PresetID) if err != nil { - log.WithError(err).Error("UsePreset: unable to set preset for camera") + logger.Error("UsePreset: unable to set preset for camera", "err", err) } } -//TakeSnapshot Creates an image for a preset. Saves it to the disk and database. -//Function is blocking and needs ~20 Seconds to complete! Only call in goroutine. +// TakeSnapshot Creates an image for a preset. Saves it to the disk and database. +// Function is blocking and needs ~20 Seconds to complete! Only call in goroutine. func (p presetUtility) TakeSnapshot(preset model.CameraPreset) { p.UsePreset(preset) time.Sleep(time.Second * 10) @@ -99,18 +98,18 @@ func (p presetUtility) TakeSnapshot(preset model.CameraPreset) { } cam, err := p.ProvideCamera(lectureHall.CameraType, lectureHall.CameraIP) if err != nil { - log.WithError(err) + logger.Error("Error providing camera", "err", err) return } fileName, err := cam.TakeSnapshot(Cfg.Paths.Static) if err != nil { - log.WithField("cam", lectureHall.CameraIP).WithError(err).Error("TakeSnapshot: failed to get camera snapshot") + logger.Error("TakeSnapshot: failed to get camera snapshot", "err", err, "cam", lectureHall.CameraIP) return } preset.Image = fileName err = p.LectureHallDao.SavePreset(preset) if err != nil { - log.WithField("cam", lectureHall.CameraIP).WithError(err).Error("TakeSnapshot: failed to save snapshot file") + logger.Error("TakeSnapshot: failed to save snapshot file", "err", err, "cam", lectureHall.CameraIP) return } } diff --git a/tools/realtime/channel_store.go b/tools/realtime/channel_store.go index 9ed1abf71..eebc67c62 100644 --- a/tools/realtime/channel_store.go +++ b/tools/realtime/channel_store.go @@ -1,7 +1,6 @@ package realtime import ( - log "github.com/sirupsen/logrus" "strings" ) @@ -45,7 +44,7 @@ func (s *ChannelStore) OnMessage(client *Client, message *Message) { return } - log.WithField("channel", message.Channel).Warn("unknown channel on websocket message") + logger.Warn("unknown channel on websocket message", "channel", message.Channel) } func (s *ChannelStore) Subscribe(client *Client, channelPath string) bool { diff --git a/tools/realtime/realtime.go b/tools/realtime/realtime.go index 4b44e3da7..da4372e46 100644 --- a/tools/realtime/realtime.go +++ b/tools/realtime/realtime.go @@ -3,7 +3,6 @@ package realtime import ( "encoding/json" "errors" - log "github.com/sirupsen/logrus" "net/http" ) @@ -86,7 +85,7 @@ func (r *Realtime) messageHandler(c *Client, msg []byte) { var req Message err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal request") + logger.Warn("could not unmarshal request", "err", err) return } @@ -98,6 +97,6 @@ func (r *Realtime) messageHandler(c *Client, msg []byte) { case MessageTypeChannelMessage: r.channels.OnMessage(c, &req) default: - log.WithField("type", req.Type).Warn("unknown pubsub websocket request type") + logger.Warn("unknown pubsub websocket request type", "type", req.Type) } } diff --git a/tools/realtime/realtime_logger.go b/tools/realtime/realtime_logger.go new file mode 100644 index 000000000..229f391e2 --- /dev/null +++ b/tools/realtime/realtime_logger.go @@ -0,0 +1,10 @@ +package realtime + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "realtime") diff --git a/tools/session.go b/tools/session.go index 9231cc794..2d8112010 100644 --- a/tools/session.go +++ b/tools/session.go @@ -3,8 +3,6 @@ package tools import ( "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v4" - log "github.com/sirupsen/logrus" - "time" ) @@ -16,7 +14,7 @@ type SessionData struct { func StartSession(c *gin.Context, data *SessionData) { token, err := createToken(data.Userid, data.SamlSubjectID) if err != nil { - log.WithError(err).Error("Could not create token") + logger.Error("Could not create token", "err", err) return } c.SetCookie("jwt", token, 60*60*24*7, "/", "", CookieSecure, true) diff --git a/tools/template_executor.go b/tools/template_executor.go index f0aa4e6ad..cfc62c5f4 100644 --- a/tools/template_executor.go +++ b/tools/template_executor.go @@ -2,7 +2,6 @@ package tools import ( "github.com/Masterminds/sprig/v3" - log "github.com/sirupsen/logrus" "html/template" "io" ) @@ -22,14 +21,14 @@ func (e DebugTemplateExecutor) ExecuteTemplate(w io.Writer, name string, data in var t, err = template.New("base").Funcs(sprig.FuncMap()).ParseGlob(e.Patterns[0]) if err != nil { - log.Print("Failed to load pattern: '" + e.Patterns[0] + "'. Error: " + err.Error()) + logger.Error("Failed to load pattern: '"+e.Patterns[0], "err", err.Error()) } for i := 1; i < len(e.Patterns); i++ { pattern := e.Patterns[i] _, err := t.ParseGlob(pattern) if err != nil { - log.Print("Failed to load pattern: '" + pattern + "'. Error: " + err.Error()) + logger.Error("Failed to load pattern: '"+pattern+"'.", "err", err.Error()) } } diff --git a/tools/tools_logger.go b/tools/tools_logger.go new file mode 100644 index 000000000..d5f0d766d --- /dev/null +++ b/tools/tools_logger.go @@ -0,0 +1,10 @@ +package tools + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "tools") diff --git a/tools/tum/campus-online-base.go b/tools/tum/campus-online-base.go index b990327e0..7cb8c63b4 100644 --- a/tools/tum/campus-online-base.go +++ b/tools/tum/campus-online-base.go @@ -4,10 +4,9 @@ import ( "context" "errors" "fmt" - "github.com/antchfx/xmlquery" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/antchfx/xmlquery" ) func GetCourseInformation(courseID string, token string) (CourseInfo, error) { @@ -34,7 +33,7 @@ func FetchCourses(daoWrapper dao.DaoWrapper) func() { y, t := GetCurrentSemester() courses, err := daoWrapper.CoursesDao.GetAllCoursesWithTUMIDFromSemester(context.Background(), y, t) if err != nil { - log.WithError(err).Error("Could not get courses with TUM online identifier:", err) + logger.Error("Could not get courses with TUM online identifier:", "err", err) return } FindStudentsForCourses(courses, daoWrapper.UsersDao) diff --git a/tools/tum/courses.go b/tools/tum/courses.go index 9d0b731e5..93ecc870b 100644 --- a/tools/tum/courses.go +++ b/tools/tum/courses.go @@ -7,7 +7,6 @@ import ( "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model/search" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" "strconv" "strings" ) @@ -17,7 +16,7 @@ func PrefetchCourses(dao dao.DaoWrapper) func() { return func() { client, err := tools.Cfg.GetMeiliClient() if err != nil { - log.Info("Skipping course prefetching, reason: ", err) + logger.Info("Skipping course prefetching, reason: ", "err", err) return } @@ -28,16 +27,16 @@ func PrefetchCourses(dao dao.DaoWrapper) func() { for _, org := range *tools.Cfg.Campus.RelevantOrgs { r, err := getCoursesForOrg(org) if err != nil { - log.Error(err) + logger.Error("Error getting courses for organisation "+org, "err", err) } else { res = append(res, r...) } } index := client.Index("PREFETCHED_COURSES") _, err = index.AddDocuments(&res, "courseID") - log.Info(len(res)) + logger.Info(string(rune(len(res)))) if err != nil { - log.WithError(err).Error("issue adding documents to meili") + logger.Error("issue adding documents to meili", "err", err) } } } diff --git a/tools/tum/events.go b/tools/tum/events.go index f56b83f3b..e61eaab2b 100644 --- a/tools/tum/events.go +++ b/tools/tum/events.go @@ -4,12 +4,11 @@ import ( "context" "errors" "fmt" - "github.com/antchfx/xmlquery" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" + "github.com/antchfx/xmlquery" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "strconv" "strings" "time" @@ -32,12 +31,12 @@ func getEventsForCourse(courseID string, token string) (events map[time.Time]Eve start, timeErr1 := time.ParseInLocation("20060102T150405", xmlquery.FindOne(event, "//cor:attribute[@cor:attrID='dtstart']").InnerText(), tools.Loc) end, timeErr2 := time.ParseInLocation("20060102T150405", xmlquery.FindOne(event, "//cor:attribute[@cor:attrID='dtend']").InnerText(), tools.Loc) if timeErr1 != nil || timeErr2 != nil { - log.WithFields(log.Fields{"timeErr1": timeErr1, "timeErr2": timeErr2}).Warn("getEventsForCourse: couldn't parse time") + logger.Warn("getEventsForCourse: couldn't parse time", "timeErr1", timeErr1, "timeErr2", timeErr2) break } eventID64, err := strconv.Atoi(xmlquery.FindOne(event, "//cor:attribute[@cor:attrID='singleEventID']").InnerText()) if err != nil { - log.WithField("TUMOnlineCourseID", courseID).WithError(err).Error("getEventsForCourse: EventID not an int") + logger.Error("getEventsForCourse: EventID not an int", "err", err, "TUMOnlineCourseID", courseID) break } var eventTypeName, status, roomCode, roomName string @@ -91,7 +90,7 @@ func GetEventsForCourses(courses []model.Course, daoWrapper dao.DaoWrapper) { for _, event := range events { stream, err := daoWrapper.StreamsDao.GetStreamByTumOnlineID(context.Background(), event.SingleEventID) if err != nil { // Lecture does not exist yet - log.Info("Adding course") + logger.Info("Adding course") course.Streams = append(course.Streams, model.Stream{ CourseID: course.ID, Start: event.Start, @@ -114,7 +113,7 @@ func GetEventsForCourses(courses []model.Course, daoWrapper dao.DaoWrapper) { } err = daoWrapper.CoursesDao.UpdateCourse(context.Background(), course) if err != nil { - log.WithError(err).WithField("CourseID", course.ID).Warn("Can't update course") + logger.Warn("Can't update course", "err", err, "CourseID", course.ID) } } } diff --git a/tools/tum/students.go b/tools/tum/students.go index 127cb3bf9..f8def6ff8 100644 --- a/tools/tum/students.go +++ b/tools/tum/students.go @@ -3,11 +3,10 @@ package tum import ( "errors" "fmt" - "github.com/antchfx/xmlquery" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/antchfx/xmlquery" ) func FindStudentsForCourses(courses []model.Course, usersDao dao.UsersDao) { @@ -21,12 +20,12 @@ func FindStudentsForCourses(courses []model.Course, usersDao dao.UsersDao) { } } if err != nil { - log.WithError(err).WithField("TUMOnlineIdentifier", courses[i].TUMOnlineIdentifier).Error("FindStudentsForCourses: Can't get Students for course with id") + logger.Error("FindStudentsForCourses: Can't get Students for course with id", "err", err, "TUMOnlineIdentifier", courses[i].TUMOnlineIdentifier) continue } err = usersDao.AddUsersToCourseByTUMIDs(studentIDs, courses[i].ID) if err != nil { - log.WithError(err).Error("FindStudentsForCourses: Can't add users to course") + logger.Error("FindStudentsForCourses: Can't add users to course", "err", err) } } } diff --git a/tools/tum/tum_logger.go b/tools/tum/tum_logger.go new file mode 100644 index 000000000..a7a83d01d --- /dev/null +++ b/tools/tum/tum_logger.go @@ -0,0 +1,10 @@ +package tum + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "tum") diff --git a/vod-service/internal/internal_logger.go b/vod-service/internal/internal_logger.go new file mode 100644 index 000000000..15ff05489 --- /dev/null +++ b/vod-service/internal/internal_logger.go @@ -0,0 +1,10 @@ +package internal + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "internal_vod_service") diff --git a/vod-service/internal/vodService.go b/vod-service/internal/vodService.go index 176a36a76..fdad7827e 100644 --- a/vod-service/internal/vodService.go +++ b/vod-service/internal/vodService.go @@ -3,7 +3,6 @@ package internal import ( "fmt" "io" - "log" "net/http" "os" "os/exec" @@ -22,7 +21,7 @@ type App struct { func NewApp() *App { outputDir := os.Getenv("OUTPUT_DIR") if outputDir == "" { - log.Fatal("OUTPUT_DIR environment variable not set.") + logger.Error("OUTPUT_DIR environment variable not set.") } if !strings.HasSuffix(outputDir, "/") { outputDir += "/" @@ -67,7 +66,7 @@ func (a *App) uploadHandler(w http.ResponseWriter, r *http.Request) { _, err = io.Copy(tempFile, file) if err != nil { - log.Println(err) + logger.Error("Error on io copy", "err", err) return } // write this byte array to our temporary file @@ -82,19 +81,19 @@ func (a *App) packageFile(file, name string) { defer func() { err := os.Remove(file) if err != nil { - log.Printf("Error cleaning up file: %v", err) + logger.Error("Error cleaning up file", "err", err) } }() name = fileNameIllegal.ReplaceAllString(name, "_") // override eventually existing files err := os.RemoveAll(a.config.outputDir + name) if err != nil { - log.Println(err) + logger.Error("Error on removing files", "err", err) // try to continue anyway } err = os.MkdirAll(a.config.outputDir+name, os.ModePerm) if err != nil { - log.Println(err) + logger.Error("Error on creating directories", "err", err) return } c := exec.Command("ffmpeg", diff --git a/web/admin.go b/web/admin.go index 9a7b992f7..63e9fc1dc 100755 --- a/web/admin.go +++ b/web/admin.go @@ -5,13 +5,12 @@ import ( "encoding/json" "errors" "fmt" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/tools/tum" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "gorm.io/gorm" "net/http" "regexp" @@ -34,7 +33,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { _ = r.UsersDao.GetAllAdminsAndLecturers(&users) courses, err := r.CoursesDao.GetAdministeredCoursesByUserId(context.Background(), tumLiveContext.User.ID, "", 0) if err != nil { - log.WithError(err).Error("couldn't query courses for user.") + logger.Error("couldn't query courses for user.", "err", err) courses = []model.Course{} } workers, err := r.WorkerDao.GetAllWorkers() @@ -74,7 +73,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { page = "notifications" found, err := r.NotificationsDao.GetAllNotifications() if err != nil { - log.WithError(err).Error("couldn't query notifications") + logger.Error("couldn't query notifications", "err", err) } else { notifications = found } @@ -84,7 +83,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { page = "token" tokens, err = r.TokenDao.GetAllTokens() if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - log.WithError(err).Error("couldn't query tokens") + logger.Error("couldn't query tokens", "err", err) c.AbortWithStatus(http.StatusInternalServerError) } } @@ -93,7 +92,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { page = "info-pages" infopages, err = r.InfoPageDao.GetAll() if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - log.WithError(err).Error("couldn't query texts") + logger.Error("couldn't query texts", "err", err) c.AbortWithStatus(http.StatusInternalServerError) } } @@ -101,7 +100,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { page = "serverStats" streams, err := r.StreamsDao.GetAllStreams() if err != nil { - log.WithError(err).Error("Can't get all streams") + logger.Error("Can't get all streams", "err", err) sentry.CaptureException(err) streams = []model.Stream{} } @@ -116,7 +115,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { if res, err := r.ServerNotificationDao.GetAllServerNotifications(); err == nil { serverNotifications = res } else { - log.WithError(err).Warn("could not get all server notifications") + logger.Warn("could not get all server notifications", "err", err) } } semesters := r.CoursesDao.GetAvailableSemesters(c) @@ -137,7 +136,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { Notifications: notifications, }) if err != nil { - log.Printf("%v", err) + logger.Error("Error executing template admin.gohtml", "err", err) } } @@ -155,7 +154,7 @@ func (r mainRoutes) LectureCutPage(c *gin.Context) { } tumLiveContext := foundContext.(tools.TUMLiveContext) if err := templateExecutor.ExecuteTemplate(c.Writer, "lecture-cut.gohtml", tumLiveContext); err != nil { - log.Fatalln(err) + logger.Error("Error executing template lecture-cut.gohtml", "err", err) } } @@ -190,7 +189,7 @@ func (r mainRoutes) CourseStatsPage(c *gin.Context) { indexData.TUMLiveContext = tumLiveContext courses, err := r.CoursesDao.GetAdministeredCoursesByUserId(context.Background(), tumLiveContext.User.ID, "", 0) if err != nil { - log.Printf("couldn't query courses for user. %v\n", err) + logger.Error("couldn't query courses for user.", "err", err) courses = []model.Course{} } semesters := r.CoursesDao.GetAvailableSemesters(c) @@ -203,7 +202,7 @@ func (r mainRoutes) CourseStatsPage(c *gin.Context) { CurT: tumLiveContext.Course.TeachingTerm, }) if err != nil { - log.Printf("%v\n", err) + logger.Error("Error getting available semesters", "err", err) } } @@ -218,20 +217,20 @@ func (r mainRoutes) EditCoursePage(c *gin.Context) { lectureHalls := r.LectureHallsDao.GetAllLectureHalls() err := r.CoursesDao.GetInvitedUsersForCourse(tumLiveContext.Course) if err != nil { - log.Printf("%v", err) + logger.Error("Error getting invited users for course", "err", err) } indexData := NewIndexData() indexData.TUMLiveContext = tumLiveContext courses, err := r.CoursesDao.GetAdministeredCoursesByUserId(context.Background(), tumLiveContext.User.ID, "", 0) if err != nil { - log.Printf("couldn't query courses for user. %v\n", err) + logger.Error("couldn't query courses for user.", "err", err) courses = []model.Course{} } semesters := r.CoursesDao.GetAvailableSemesters(c) for i := range tumLiveContext.Course.Streams { err := tools.SetSignedPlaylists(&tumLiveContext.Course.Streams[i], tumLiveContext.User, true) if err != nil { - log.WithError(err).Error("could not set signed playlist for admin page") + logger.Error("could not set signed playlist for admin page", "err", err) } } err = templateExecutor.ExecuteTemplate(c.Writer, "admin.gohtml", AdminPageData{ @@ -244,7 +243,7 @@ func (r mainRoutes) EditCoursePage(c *gin.Context) { EditCourseData: EditCourseData{IndexData: indexData, IngestBase: tools.Cfg.IngestBase, LectureHalls: lectureHalls}, }) if err != nil { - log.Printf("%v\n", err) + logger.Error("Error executing template admin.gohtml", "err", err) } } diff --git a/web/course.go b/web/course.go index d6c076790..f9fde23ec 100644 --- a/web/course.go +++ b/web/course.go @@ -8,8 +8,6 @@ import ( "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" - "github.com/getsentry/sentry-go" sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" @@ -52,7 +50,7 @@ func (r mainRoutes) editCourseByTokenPage(c *gin.Context) { err = templateExecutor.ExecuteTemplate(c.Writer, "edit-course-by-token.gohtml", d) if err != nil { - log.Println(err) + logger.Error("Error executing template edit-course-by-token.gohtml", "err", err) } } @@ -90,7 +88,7 @@ func (r mainRoutes) optOutPage(c *gin.Context) { } err = templateExecutor.ExecuteTemplate(c.Writer, "opt-out.gohtml", d) if err != nil { - log.WithError(err).Error("can't render template") + logger.Error("can't render template", "err", err) } } @@ -119,7 +117,7 @@ func (r mainRoutes) HighlightPage(c *gin.Context) { return } else { sentry.CaptureException(err) - log.Printf("%v", err) + logger.Error("Error getting current or next lecture for course", "err", err) } description := "" if indexData.TUMLiveContext.Stream != nil { @@ -133,7 +131,7 @@ func (r mainRoutes) HighlightPage(c *gin.Context) { IsHighlightPage: true, } if err = templateExecutor.ExecuteTemplate(c.Writer, "watch.gohtml", d2); err != nil { - log.Printf("%v", err) + logger.Error("Error executing template watch.gohtml", "err", err) return } } @@ -164,7 +162,7 @@ func (r mainRoutes) CoursePage(c *gin.Context) { streamsWithWatchState, err := r.StreamsDao.GetStreamsWithWatchState((*tumLiveContext.Course).ID, (*tumLiveContext.User).ID) if err != nil { sentry.CaptureException(err) - log.WithError(err).Error("loading streamsWithWatchState and progresses for a given course and user failed") + logger.Error("loading streamsWithWatchState and progresses for a given course and user failed", "err", err) } tumLiveContext.Course.Streams = streamsWithWatchState // Update the course streams to contain the watch state. @@ -172,7 +170,7 @@ func (r mainRoutes) CoursePage(c *gin.Context) { for i := range tumLiveContext.Course.Streams { err = tools.SetSignedPlaylists(&tumLiveContext.Course.Streams[i], tumLiveContext.User, false) if err != nil { - log.WithError(err).Warn("Can't sign playlists") + logger.Warn("Can't sign playlists", "err", err) } } @@ -197,7 +195,7 @@ func (r mainRoutes) CoursePage(c *gin.Context) { encoded, err := json.Marshal(clientWatchState) if err != nil { sentry.CaptureException(err) - log.WithError(err).Error("marshalling watched infos for client failed") + logger.Error("marshalling watched infos for client failed", "err", err) } err = templateExecutor.ExecuteTemplate(c.Writer, "course-overview.gohtml", CoursePageData{IndexData: indexData, Course: *tumLiveContext.Course, WatchedData: string(encoded)}) diff --git a/web/index.go b/web/index.go index fbb2f692e..8179ae34a 100644 --- a/web/index.go +++ b/web/index.go @@ -4,13 +4,12 @@ import ( "context" "errors" "github.com/RBG-TUM/commons" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/tools/tum" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "gorm.io/gorm" "html/template" "net/http" @@ -45,7 +44,7 @@ func (r mainRoutes) MainPage(c *gin.Context) { indexData.LoadPinnedCourses() if err := templateExecutor.ExecuteTemplate(c.Writer, "index.gohtml", indexData); err != nil { - log.WithError(err).Errorf("Could not execute template: 'index.gohtml'") + logger.Error("Could not execute template: 'index.gohtml'", "err", err) } } @@ -66,7 +65,7 @@ func (r mainRoutes) InfoPage(id uint, name string) gin.HandlerFunc { text, err := r.InfoPageDao.GetById(id) if err != nil { - log.WithError(err).Error("Could not get text with id") + logger.Error("Could not get text with id", "err", err) c.AbortWithStatus(http.StatusInternalServerError) return } @@ -114,7 +113,7 @@ func NewIndexDataWithContext(c *gin.Context) IndexData { tumLiveContext = tumLiveContextQueried.(tools.TUMLiveContext) indexData.TUMLiveContext = tumLiveContext } else { - log.Warn("could not get TUMLiveContext") + logger.Warn("could not get TUMLiveContext") c.AbortWithStatus(http.StatusInternalServerError) } @@ -139,7 +138,7 @@ func (d *IndexData) LoadCurrentNotifications(serverNoticationDao dao.ServerNotif if notifications, err := serverNoticationDao.GetCurrentServerNotifications(); err == nil { d.ServerNotifications = notifications } else if err != gorm.ErrRecordNotFound { - log.WithError(err).Warn("could not get server notifications") + logger.Warn("could not get server notifications", "err", err) } } @@ -174,7 +173,7 @@ func (d *IndexData) LoadSemesters(spanMain *sentry.Span, coursesDao dao.CoursesD func (d *IndexData) LoadLivestreams(c *gin.Context, daoWrapper dao.DaoWrapper) { streams, err := daoWrapper.GetCurrentLive(context.Background()) if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - log.WithError(err).Error("could not get current live streams") + logger.Error("could not get current live streams", "err", err) c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"message": "Could not load current livestream from database."}) } @@ -203,7 +202,7 @@ func (d *IndexData) LoadLivestreams(c *gin.Context, daoWrapper dao.DaoWrapper) { if tumLiveContext.User != nil && tumLiveContext.User.Role == model.AdminType && stream.LectureHallID != 0 { lh, err := daoWrapper.LectureHallsDao.GetLectureHallByID(stream.LectureHallID) if err != nil { - log.WithError(err).Error(err) + logger.Error("Error getting lecture hall by id", "err", err) } else { lectureHall = &lh } diff --git a/web/popup.go b/web/popup.go index d4c1a8eac..f39f6eb0a 100644 --- a/web/popup.go +++ b/web/popup.go @@ -2,10 +2,9 @@ package web import ( "errors" + "github.com/TUM-Dev/gocast/tools" "github.com/getsentry/sentry-go" "github.com/gin-gonic/gin" - "github.com/TUM-Dev/gocast/tools" - "log" "net/http" ) @@ -26,6 +25,6 @@ func (r mainRoutes) PopOutChat(c *gin.Context) { err := templateExecutor.ExecuteTemplate(c.Writer, "popup-chat.gohtml", data) if err != nil { - log.Printf("couldn't render template: %v\n", err) + logger.Error("couldn't render template popup-chat.gohtml", "err", err) } } diff --git a/web/router.go b/web/router.go index 90d2faea0..89a6943e8 100755 --- a/web/router.go +++ b/web/router.go @@ -4,16 +4,15 @@ import ( "embed" "fmt" "github.com/getsentry/sentry-go" - log "github.com/sirupsen/logrus" "html/template" "net/http" "os" "path" "github.com/Masterminds/sprig/v3" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/tools" + "github.com/gin-gonic/gin" ) var templateExecutor tools.TemplateExecutor @@ -199,7 +198,7 @@ func (r mainRoutes) home(c *gin.Context) { indexData := NewIndexDataWithContext(c) if err := templateExecutor.ExecuteTemplate(c.Writer, "home.gohtml", indexData); err != nil { - log.WithError(err).Errorf("Could not execute template: 'home.gohtml'") + logger.Error("Could not execute template: 'home.gohtml'", "err", err) } } diff --git a/web/saml.go b/web/saml.go index b38426f05..338894aff 100644 --- a/web/saml.go +++ b/web/saml.go @@ -9,13 +9,12 @@ import ( "net/url" "strings" - "github.com/crewjam/saml" - "github.com/crewjam/saml/samlsp" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/crewjam/saml" + "github.com/crewjam/saml/samlsp" + "github.com/gin-gonic/gin" ) func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { @@ -27,27 +26,27 @@ func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { // create saml.ServiceProvider keyPair, err := tls.LoadX509KeyPair(tools.Cfg.Saml.Cert, tools.Cfg.Saml.Privkey) if err != nil { - log.WithError(err).Fatal("Could not load SAML keypair") + logger.Error("Could not load SAML keypair", "err", err) } keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0]) if err != nil { - log.WithError(err).Fatal("Could not parse SAML keypair") + logger.Error("Could not parse SAML keypair", "err", err) } idpMetadataURL, err := url.Parse(tools.Cfg.Saml.IdpMetadataURL) if err != nil { - log.WithError(err).Fatal("Could not parse Identity Provider metadata URL") + logger.Error("Could not parse Identity Provider metadata URL", "err", err) } idpMetadata, err := samlsp.FetchMetadata(context.Background(), http.DefaultClient, *idpMetadataURL) if err != nil { - log.WithError(err).Error("Could not load Identity Provider metadata") + logger.Error("Could not load Identity Provider metadata", "err", err) } var samlSPs []*samlsp.Middleware for _, l := range tools.Cfg.Saml.RootURLs { u, err := url.Parse(l) if err != nil { - log.WithError(err).Error("Could not parse Root URL") + logger.Error("Could not parse Root URL", "err", err) continue } samlSP, err := samlsp.New(samlsp.Options{ @@ -59,7 +58,7 @@ func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { AllowIDPInitiated: true, }) if err != nil { - log.WithError(err).Fatal("Could not create SAML Service Provider") + logger.Error("Could not create SAML Service Provider", "err", err) } samlSP.ServiceProvider.AcsURL = *u samlSPs = append(samlSPs, samlSP) @@ -101,7 +100,7 @@ func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { if err != nil { return } - log.Info("Logout request: ", request) + logger.Info("Logout request: " + request.String()) c.Redirect(http.StatusFound, request.String()) } }) @@ -131,12 +130,7 @@ func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { matrNr = extractSamlField(response, "eduPersonPrincipalName") // MWN id if no matrNr s := strings.Split(matrNr, "@") if len(s) == 0 || s[0] == "" { - log.WithFields(log.Fields{ - "LRZ-ID": lrzID, - "firstName": firstName, - "lastName": lastName, - "mwnID": matrNr, - }).Error("Can't extract mwn id") + logger.Error("Can't extract mwn id", "LRZ-ID", lrzID, "firstName", firstName, "lastName", lastName, "mwnID", matrNr) c.AbortWithStatus(http.StatusInternalServerError) } matrNr = s[0] @@ -149,7 +143,7 @@ func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { } err = daoWrapper.UsersDao.UpsertUser(&user) if err != nil { - log.WithError(err).Error("Could not upsert user") + logger.Error("Could not upsert user", "err", err) c.AbortWithStatus(http.StatusInternalServerError) } HandleValidLogin(c, &tools.SessionData{Userid: user.ID, SamlSubjectID: &subjectID}) diff --git a/web/template/user-settings.gohtml b/web/template/user-settings.gohtml index 135495f1f..7a528301e 100644 --- a/web/template/user-settings.gohtml +++ b/web/template/user-settings.gohtml @@ -34,7 +34,7 @@ -
+
@@ -75,9 +75,10 @@ @change="global.updatePreference(global.UserSetting.Greeting, currentGreeting).then((r) => {err=r;})"> -
+

Playback Speeds

- +
+ +
+

Custom Speeds

+
+ + + + +

Privacy & Data Protection

diff --git a/web/template/video_only.gohtml b/web/template/video_only.gohtml index aeb73f0ea..372d9382f 100644 --- a/web/template/video_only.gohtml +++ b/web/template/video_only.gohtml @@ -75,7 +75,7 @@