Use logrus to handle logs
All checks were successful
continuous-integration/drone/push Build is passing

This commit adds the logrus module, and improves logs handling for the
entire program. Error logs are better displayed, and the log level can
be set from the configuration file.
This commit is contained in:
Melora Hugues 2023-02-04 18:14:23 +01:00
parent 93e8bc0f52
commit 51bc7cb3a0
7 changed files with 87 additions and 11 deletions

View file

@ -41,7 +41,10 @@ For now, the program is configured through a JSON configuration file. Here is a
"token": "<your_bot_token>", "token": "<your_bot_token>",
"channel_id": 9999999 "channel_id": 9999999
}, },
"polling_frequency": 5 "polling_frequency": 5,
"log": {
"level": "info"
}
} }
``` ```

View file

@ -8,9 +8,11 @@ import (
"git.faercol.me/faercol/public-ip-tracker/tracker/config" "git.faercol.me/faercol/public-ip-tracker/tracker/config"
"git.faercol.me/faercol/public-ip-tracker/tracker/ip" "git.faercol.me/faercol/public-ip-tracker/tracker/ip"
"git.faercol.me/faercol/public-ip-tracker/tracker/logger"
"github.com/ahugues/go-telegram-api/bot" "github.com/ahugues/go-telegram-api/bot"
"github.com/ahugues/go-telegram-api/notifier" "github.com/ahugues/go-telegram-api/notifier"
"github.com/ahugues/go-telegram-api/structs" "github.com/ahugues/go-telegram-api/structs"
"github.com/sirupsen/logrus"
) )
type Notifier struct { type Notifier struct {
@ -26,21 +28,26 @@ type Notifier struct {
errChan chan error errChan chan error
changesChan chan net.IP changesChan chan net.IP
exitChan chan struct{} exitChan chan struct{}
logger logrus.Logger
} }
func (n *Notifier) SendInitMessage() error { func (n *Notifier) SendInitMessage() error {
n.logger.Debug("Getting current public IP")
publicIP, err := n.ipGetter.GetCurrentPublicIP(n.ctx) publicIP, err := n.ipGetter.GetCurrentPublicIP(n.ctx)
if err != nil { if err != nil {
return fmt.Errorf("failed to get current public IP: %w", err) return fmt.Errorf("failed to get current public IP: %w", err)
} }
n.logger.Debugf("Current public IP is %s", publicIP.String())
n.currentIP = publicIP n.currentIP = publicIP
currentTime := n.timeGetter() currentTime := n.timeGetter()
n.logger.Debug("Sending init message to Telegram")
initMsg := fmt.Sprintf("Public IP tracker initialized at %v, public IP is %s", currentTime, publicIP) initMsg := fmt.Sprintf("Public IP tracker initialized at %v, public IP is %s", currentTime, publicIP)
if err := n.tgBot.SendMessage(n.ctx, n.tgChatID, initMsg); err != nil { if err := n.tgBot.SendMessage(n.ctx, n.tgChatID, initMsg); err != nil {
return fmt.Errorf("failed to send initialization message: %w", err) return fmt.Errorf("failed to send initialization message: %w", err)
} }
n.logger.Debug("Message sent")
return nil return nil
} }
@ -61,6 +68,7 @@ func (n *Notifier) sendCurrentIP() error {
} }
func (n *Notifier) watchTG() { func (n *Notifier) watchTG() {
n.logger.Debug("Subscribing to messages notificator")
id, updateChan := n.tgWatcher.Subscribe([]structs.UpdateType{structs.UpdateMessage}) id, updateChan := n.tgWatcher.Subscribe([]structs.UpdateType{structs.UpdateMessage})
go n.tgWatcher.Run(n.ctx) go n.tgWatcher.Run(n.ctx)
@ -81,21 +89,29 @@ func (n *Notifier) watchTG() {
func (n *Notifier) Run() { func (n *Notifier) Run() {
go n.watchTG() go n.watchTG()
n.logger.Infof("Start watching for public IP changes, polling frequency is %v", n.frequency)
for { for {
select { select {
case <-time.After(n.frequency): case <-time.After(n.frequency):
n.logger.Debug("Checking if current IP has changed")
newIP, err := n.ipGetter.GetCurrentPublicIP(n.ctx) newIP, err := n.ipGetter.GetCurrentPublicIP(n.ctx)
if err != nil { if err != nil {
n.errChan <- fmt.Errorf("failed to update public IP: %w", err) n.errChan <- fmt.Errorf("failed to update public IP: %w", err)
continue continue
} }
n.logger.Debugf("Got new public IP %s", newIP.String())
if !newIP.Equal(n.currentIP) { if !newIP.Equal(n.currentIP) {
n.logger.Debug("New public IP is different from previous IP")
n.logger.Warnf("Public IP has changed from %s to %s", n.currentIP.String(), newIP.String())
n.currentIP = newIP n.currentIP = newIP
if err := n.sendUpdatedIPMsg(); err != nil { if err := n.sendUpdatedIPMsg(); err != nil {
n.errChan <- err n.errChan <- err
} }
} else {
n.logger.Debug("Public IP has not changed")
} }
case <-n.ctx.Done(): case <-n.ctx.Done():
n.logger.Info("Stopping notification daemon")
n.exitChan <- struct{}{} n.exitChan <- struct{}{}
return return
} }
@ -125,5 +141,6 @@ func New(ctx context.Context, config *config.Config) *Notifier {
exitChan: make(chan struct{}, 1), exitChan: make(chan struct{}, 1),
frequency: config.PollingFrequency, frequency: config.PollingFrequency,
tgWatcher: notifier.New(config.Telegram.Token), tgWatcher: notifier.New(config.Telegram.Token),
logger: logger.L,
} }
} }

View file

@ -5,6 +5,8 @@ import (
"fmt" "fmt"
"os" "os"
"time" "time"
"github.com/sirupsen/logrus"
) )
type TelegramConfig struct { type TelegramConfig struct {
@ -12,14 +14,33 @@ type TelegramConfig struct {
Token string `json:"token"` Token string `json:"token"`
} }
type LogConfig struct {
Level logrus.Level
}
type jsonLogConfig struct {
Level string `json:"level"`
}
type Config struct { type Config struct {
Telegram *TelegramConfig Telegram *TelegramConfig
PollingFrequency time.Duration PollingFrequency time.Duration
Log *LogConfig
} }
type jsonConfig struct { type jsonConfig struct {
Telegram *TelegramConfig `json:"telegram"` Telegram *TelegramConfig `json:"telegram"`
PollingFrequency int64 `json:"polling_frequency"` PollingFrequency int64 `json:"polling_frequency"`
Log *jsonLogConfig `json:"log"`
}
func parseLevel(lvlStr string) logrus.Level {
for _, lvl := range logrus.AllLevels {
if lvl.String() == lvlStr {
return lvl
}
}
return logrus.InfoLevel
} }
func New(filepath string) (*Config, error) { func New(filepath string) (*Config, error) {
@ -34,5 +55,8 @@ func New(filepath string) (*Config, error) {
return &Config{ return &Config{
Telegram: jsonConf.Telegram, Telegram: jsonConf.Telegram,
PollingFrequency: time.Duration(jsonConf.PollingFrequency) * time.Second, PollingFrequency: time.Duration(jsonConf.PollingFrequency) * time.Second,
Log: &LogConfig{
Level: parseLevel(jsonConf.Log.Level),
},
}, nil }, nil
} }

View file

@ -5,4 +5,5 @@ go 1.16
require ( require (
github.com/ahugues/go-telegram-api v0.1.0 github.com/ahugues/go-telegram-api v0.1.0
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
github.com/sirupsen/logrus v1.9.0
) )

View file

@ -1,7 +1,17 @@
github.com/ahugues/go-telegram-api v0.1.0 h1:CGJG0WR282O0hAO9JH2RutPj+Vn+Q+zbjdSHjuvN5yY= github.com/ahugues/go-telegram-api v0.1.0 h1:CGJG0WR282O0hAO9JH2RutPj+Vn+Q+zbjdSHjuvN5yY=
github.com/ahugues/go-telegram-api v0.1.0/go.mod h1:8I/JWxd9GYM7dHOgGmkRI3Ei1u+nGvzeR2knIMmFw7E= github.com/ahugues/go-telegram-api v0.1.0/go.mod h1:8I/JWxd9GYM7dHOgGmkRI3Ei1u+nGvzeR2knIMmFw7E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -16,6 +26,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@ -26,3 +38,6 @@ golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

10
tracker/logger/logger.go Normal file
View file

@ -0,0 +1,10 @@
package logger
import "github.com/sirupsen/logrus"
var L logrus.Logger
func Init(level logrus.Level) {
L = *logrus.New()
L.SetLevel(level)
}

View file

@ -3,12 +3,12 @@ package main
import ( import (
"context" "context"
"flag" "flag"
"fmt"
"os" "os"
"os/signal" "os/signal"
"git.faercol.me/faercol/public-ip-tracker/tracker/bot" "git.faercol.me/faercol/public-ip-tracker/tracker/bot"
"git.faercol.me/faercol/public-ip-tracker/tracker/config" "git.faercol.me/faercol/public-ip-tracker/tracker/config"
"git.faercol.me/faercol/public-ip-tracker/tracker/logger"
) )
type cliArgs struct { type cliArgs struct {
@ -26,45 +26,51 @@ func parseArgs() *cliArgs {
} }
func main() { func main() {
fmt.Println("Parsing arguments")
args := parseArgs() args := parseArgs()
mainCtx, cancel := context.WithCancel(context.Background()) mainCtx, cancel := context.WithCancel(context.Background())
fmt.Println("Parsing config")
conf, err := config.New(args.configPath) conf, err := config.New(args.configPath)
if err != nil { if err != nil {
panic(err) panic(err)
} }
fmt.Println("Initializing bot") logger.Init(conf.Log.Level)
logger.L.Infof("Intialized logger with level %v", conf.Log.Level)
logger.L.Debug("Initializing notification bot")
notifBot := bot.New(mainCtx, conf) notifBot := bot.New(mainCtx, conf)
logger.L.Debug("Sending initialization message to Telegram")
if err := notifBot.SendInitMessage(); err != nil { if err := notifBot.SendInitMessage(); err != nil {
panic(err) logger.L.Fatalf("Failed to send an initialization message: %s", err.Error())
} }
fmt.Println("Starting monitoring") logger.L.Debug("Starting IP monitoring")
go notifBot.Run() go notifBot.Run()
c := make(chan os.Signal, 1) c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt) signal.Notify(c, os.Interrupt)
logger.L.Info("Public IP monitoring service is operational")
outerloop: outerloop:
for { for {
select { select {
case <-c: case <-c:
fmt.Println("received cancel") logger.L.Info("Stopping IP monitoring service")
cancel() cancel()
break outerloop break outerloop
case err := <-notifBot.ErrChan(): case err := <-notifBot.ErrChan():
fmt.Printf("Unexpected error %s", err.Error()) logger.L.Error(err.Error())
case <-notifBot.Exit(): case <-notifBot.Exit():
fmt.Println("Unexpected exit") logger.L.Fatal("Unexpected exit from the monitoring bot")
} }
} }
logger.L.Debug("Waiting for all services to shut down")
<-notifBot.Exit() <-notifBot.Exit()
fmt.Println("OK") logger.L.Info("Public IP monitoring service successfully stopped")
os.Exit(0) os.Exit(0)
} }