diff --git a/api.go b/api.go index cb14396..a701e88 100644 --- a/api.go +++ b/api.go @@ -8,7 +8,7 @@ import ( "strings" "time" - log "github.com/sirupsen/logrus" + log "github.com/rs/zerolog/log" ) var ( @@ -17,7 +17,7 @@ var ( func init() { sessionID = RandomString(5) + Nonce() - log.WithField("sessionId", sessionID).Debug("Session ID Generated") + log.Debug().Str("sessionId", sessionID).Msg("Session ID Generated") } type Term struct { @@ -262,7 +262,7 @@ func GetCourseMeetingTime(term int, crn int) (*MeetingTimeResponse, error) { // Assert that the response is JSON if !ContainsContentType(res.Header.Get("Content-Type"), "application/json") { - log.Fatalf("Response was not JSON: %s", res.Header.Get("Content-Type")) + log.Fatal().Msgf("Response was not JSON: %s", res.Header.Get("Content-Type")) } // Read the response body into JSON diff --git a/go.mod b/go.mod index 90a4c15..780f48a 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,12 @@ require github.com/bwmarrin/discordgo v0.27.1 require github.com/joho/godotenv v1.5.1 -require github.com/sirupsen/logrus v1.9.3 // indirect +require ( + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/rs/zerolog v1.31.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect +) require ( github.com/gorilla/websocket v1.5.1 // fndirect diff --git a/go.sum b/go.sum index 182f012..cfadd33 100644 --- a/go.sum +++ b/go.sum @@ -2,9 +2,11 @@ github.com/bwmarrin/discordgo v0.27.0 h1:4ZK9KN+rGIxZ0fdGTmgdCcliQeW8Zhu6MnlFI92 github.com/bwmarrin/discordgo v0.27.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= github.com/bwmarrin/discordgo v0.27.1 h1:ib9AIc/dom1E/fSIulrBwnez0CToJE113ZGt4HoliGY= github.com/bwmarrin/discordgo v0.27.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -19,8 +21,17 @@ github.com/juju/persistent-cookiejar v1.0.0/go.mod h1:zrbmo4nBKaiP/Ez3F67ewkMbzG github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +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/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/clock v0.0.0-20190514195947-2896927a307a/go.mod h1:4r5QyqhjIWCcK8DO4KMclc5Iknq5qVBAlbYYzAbUScQ= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= +github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -36,6 +47,9 @@ golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/helpers.go b/helpers.go index 3eb6d47..6098705 100644 --- a/helpers.go +++ b/helpers.go @@ -9,7 +9,7 @@ import ( "strings" "time" - log "github.com/sirupsen/logrus" + log "github.com/rs/zerolog/log" ) func BuildRequestWithBody(method string, path string, params map[string]string, body io.Reader) *http.Request { diff --git a/main.go b/main.go index 1071c79..a5d9c50 100644 --- a/main.go +++ b/main.go @@ -2,16 +2,15 @@ package main import ( "flag" - "io" "net/http" "net/http/cookiejar" "os" "os/signal" - "time" "github.com/bwmarrin/discordgo" "github.com/joho/godotenv" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" ) var ( @@ -24,94 +23,44 @@ var ( integerOptionMinValue = 0.0 ) -type MeetingTimeFaculty struct { - bannerId int - category string - displayName string - email string - primary bool +// logOut implements zerolog.LevelWriter +type logOut struct{} + +// Write should not be called +func (l logOut) Write(p []byte) (n int, err error) { + return os.Stdout.Write(p) } -type MeetingTimeResponse struct { - faculty []MeetingTimeFaculty - weekdays map[time.Weekday]bool - campus string - campusDescription string - creditHours int - building string - buildingDescription string - room string - timeStart NaiveTime - timeEnd NaiveTime - dateStart time.Time - dateEnd time.Time - hoursPerWeek float32 - meetingScheduleType string - meetingType string - meetingTypeDescription string -} +const timeFormat = "2006-01-02 15:04:05" -// WriterHook is a hook that writes logs of specified LogLevels to specified Writer -type WriterHook struct { - Writer io.Writer - LogLevels []log.Level -} +var ( + standardOut = zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: timeFormat} + errorOut = zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: timeFormat} +) -// Fire will be called when some logging function is called with current hook -// It will format log entry to string and write it to appropriate writer -func (hook *WriterHook) Fire(entry *log.Entry) error { - line, err := entry.String() - if err != nil { - return err +// WriteLevel write to the appropriate output +func (l logOut) WriteLevel(level zerolog.Level, p []byte) (n int, err error) { + if level <= zerolog.WarnLevel { + return standardOut.Write(p) + } else { + return errorOut.Write(p) } - _, err = hook.Writer.Write([]byte(line)) - return err } -// Levels define on which log levels this hook would trigger -func (hook *WriterHook) Levels() []log.Level { - return hook.LogLevels +func init() { + log.Logger = zerolog.New(logOut{}).With().Timestamp().Logger() } func main() { - log.SetOutput(io.Discard) // Send all logs to nowhere by default - - // Send logs with level warning and higher to stderr - log.AddHook(&WriterHook{ - Writer: os.Stderr, - LogLevels: []log.Level{ - log.PanicLevel, - log.FatalLevel, - log.ErrorLevel, - log.WarnLevel, - }, - }) - - // Send info and debug logs to stdout - log.AddHook(&WriterHook{ - Writer: os.Stdout, - LogLevels: []log.Level{ - log.InfoLevel, - log.DebugLevel, - }, - }) - - log.SetFormatter(&log.TextFormatter{ - TimestampFormat: "2006-01-02 15:04:05", - FullTimestamp: true, - }) - // Load environment variables if err := godotenv.Load(); err != nil { - log.WithFields(log.Fields{ - "error": err, - }).Warn("Error loading .env file") + log.Debug().Err(err).Msg("Error loading .env file") } baseURL = os.Getenv("BANNER_BASE_URL") cookies, err := cookiejar.New(nil) if err != nil { - log.WithField("error", err).Fatal(err) + log.Err(err).Msg("Cannot create cookie jar") } client = http.Client{Jar: cookies} @@ -119,20 +68,21 @@ func main() { session, err = discordgo.New("Bot " + os.Getenv("BOT_TOKEN")) if err != nil { - log.WithField("error", err).Fatal("Invalid bot parameters") + log.Err(err).Msg("Invalid bot parameters") } session.AddHandler(func(s *discordgo.Session, r *discordgo.Ready) { - log.WithFields(log.Fields{ - "username": r.User.Username, - "discriminator": r.User.Discriminator, - "id": r.User.ID, - "session": s.State.SessionID, - }).Info("Bot is logged in") + // log.WithFields(log.Fields{ + // "username": r.User.Username, + // "discriminator": r.User.Discriminator, + // "id": r.User.ID, + // "session": s.State.SessionID, + // }).Info("Bot is logged in") + // log. }) err = session.Open() if err != nil { - log.Fatalf("Cannot open the session: %v", err) + log.Fatal().Msgf("Cannot open the session: %v", err) } session.AddHandler(func(internalSession *discordgo.Session, interaction *discordgo.InteractionCreate) { @@ -146,7 +96,7 @@ func main() { for i, v := range commandDefinitions { cmd, err := session.ApplicationCommandCreate(session.State.User.ID, os.Getenv("BOT_TARGET_GUILD"), v) if err != nil { - log.Panicf("Cannot create '%v' command: %v", v.Name, err) + log.Panic().Msgf("Cannot create '%v' command: %v", v.Name, err) } registeredCommands[i] = cmd } @@ -155,7 +105,7 @@ func main() { stop := make(chan os.Signal, 1) signal.Notify(stop, os.Interrupt) - log.Println("Press Ctrl+C to exit") + log.Info().Msgf("Press Ctrl+C to exit") <-stop if *RemoveCommands { @@ -164,11 +114,11 @@ func main() { for _, v := range registeredCommands { err := session.ApplicationCommandDelete(session.State.User.ID, os.Getenv("BOT_TARGET_GUILD"), v.ID) if err != nil { - log.Panicf("Cannot delete '%v' command: %v", v.Name, err) + log.Error().Msgf("Cannot delete '%v' command: %v", v.Name, err) } } } - log.Println("Gracefully shutting down.") + log.Info().Msg("Gracefully shutting down.") } diff --git a/session.go b/session.go index f5b8995..2324c68 100644 --- a/session.go +++ b/session.go @@ -4,12 +4,12 @@ import ( "net/http/cookiejar" "net/url" - log "github.com/sirupsen/logrus" + log "github.com/rs/zerolog/log" ) func setup(cookies *cookiejar.Jar) { // Makes the initial requests that sets up the session cookies for the rest of the application - log.Println("Setting up session...") + log.Info().Msg("Setting up session...") request_queue := []string{ "/registration/registration", @@ -26,7 +26,7 @@ func setup(cookies *cookiejar.Jar) { // Validate that cookies were set baseURL_parsed, err := url.Parse(baseURL) if err != nil { - log.Fatalf("Failed to parse baseURL: %s", baseURL) + log.Fatal().Msgf("Failed to parse baseURL: %s", baseURL) } current_cookies := cookies.Cookies(baseURL_parsed) @@ -46,10 +46,10 @@ func setup(cookies *cookiejar.Jar) { // Check if all required cookies were set for cookie_name, cookie_set := range required_cookies { if !cookie_set { - log.Fatalf("Required cookie %s was not set", cookie_name) + log.Error().Msgf("Required cookie %s was not set", cookie_name) } } - log.Println("All cookies acquired. Session setup complete.") + log.Info().Msg("All cookies acquired. Session setup complete.") // TODO: Validate that the session allows access to termSelection } diff --git a/types.go b/types.go new file mode 100644 index 0000000..1d421a9 --- /dev/null +++ b/types.go @@ -0,0 +1,30 @@ +package main + +import "time" + +type MeetingTimeFaculty struct { + bannerId int + category string + displayName string + email string + primary bool +} + +type MeetingTimeResponse struct { + faculty []MeetingTimeFaculty + weekdays map[time.Weekday]bool + campus string + campusDescription string + creditHours int + building string + buildingDescription string + room string + timeStart NaiveTime + timeEnd NaiveTime + dateStart time.Time + dateEnd time.Time + hoursPerWeek float32 + meetingScheduleType string + meetingType string + meetingTypeDescription string +}