Implemented proper logging and added more log messages

This commit is contained in:
ChaoticByte 2023-10-14 10:41:22 +02:00
parent 5a90f9736b
commit 9534dc3492
7 changed files with 89 additions and 23 deletions

View file

@ -31,11 +31,12 @@ Example:
```json
{
"api_fetch_interval": 600,
"datafile": "data",
"enabled_api_endpoints": [
"bay",
"bund"
],
"datafile": "data",
"loglevel": 2,
"recipients": [
{
"address": "guenther@example.org",
@ -59,6 +60,8 @@ Example:
}
```
To show debug messages, set the `loglevel` to `3`.
## Filters
You define filters for notices to be sent per recipient. Multiple filters can be set per recipient and multiple criteria can be used per filter. The configuration field for those filters is `include`. See [Configuration](#configuration) for an example.

View file

@ -5,7 +5,6 @@ package main
import (
"encoding/json"
"errors"
"fmt"
"io/fs"
"os"
"time"
@ -15,6 +14,7 @@ type Config struct {
ApiFetchInterval int `json:"api_fetch_interval"` // in seconds
EnabledApiEndpoints []string `json:"enabled_api_endpoints"`
PersistentDataFilePath string `json:"datafile"`
LogLevel int `json:"loglevel"`
Recipients []Recipient `json:"recipients"`
SmtpConfiguration SmtpSettings `json:"smtp"`
Template MailTemplateConfig `json:"template"`
@ -26,6 +26,7 @@ func NewConfig() Config {
ApiFetchInterval: 60 * 10, // every 10 minutes,
EnabledApiEndpoints: []string{"bay", "bund"},
PersistentDataFilePath: "data",
LogLevel: 2,
Recipients: []Recipient{},
SmtpConfiguration: SmtpSettings{
From: "from@example.org",
@ -43,21 +44,21 @@ func NewConfig() Config {
func checkConfig(config Config) {
if len(config.Recipients) < 1 {
fmt.Println("ERROR\tConfiguration is incomplete.")
logger.error("Configuration is incomplete")
panic(errors.New("no recipients are configured"))
}
for _, r := range config.Recipients {
if !mailAddressIsValid(r.Address) {
fmt.Println("ERROR\tConfiguration includes invalid data.")
logger.error("Configuration includes invalid data")
panic(errors.New("'" + r.Address + "' is not a valid e-mail address"))
}
if len(r.Filters) < 1 {
fmt.Println("ERROR\tConfiguration is incomplete.")
logger.error("Configuration is incomplete")
panic(errors.New("recipient " + r.Address + " has no filter defined - at least {'any': true/false} should be configured"))
}
}
if !mailAddressIsValid(config.SmtpConfiguration.From) {
fmt.Println("ERROR\tConfiguration includes invalid data.")
logger.error("Configuration includes invalid data")
panic(errors.New("'" + config.SmtpConfiguration.From + "' is not a valid e-mail address"))
}
}

48
logging.go Normal file
View file

@ -0,0 +1,48 @@
// Copyright (c) 2023 Julian Müller (ChaoticByte)
package main
import (
"log"
"os"
)
type Logger struct {
LogLevel int
ErrorLogger *log.Logger // 0
WarningLogger *log.Logger // 1
InfoLogger *log.Logger // 2
DebugLogger *log.Logger // 3
}
func (l *Logger) error(msg any) {
l.ErrorLogger.Println(msg)
}
func (l *Logger) warn(msg any) {
if l.LogLevel >= 1 {
l.WarningLogger.Println(msg)
}
}
func (l *Logger) info(msg any) {
if l.LogLevel >= 2 {
l.InfoLogger.Println(msg)
}
}
func (l *Logger) debug(msg any) {
if l.LogLevel >= 3 {
l.DebugLogger.Println(msg)
}
}
func NewLogger(loglevel int) Logger {
l := Logger{}
l.LogLevel = loglevel
l.ErrorLogger = log.New(os.Stderr, "ERROR ", log.Ldate|log.Ltime|log.Lmicroseconds|log.Lshortfile)
l.WarningLogger = log.New(os.Stderr, "WARN ", log.Ldate|log.Ltime|log.Lmicroseconds|log.Lshortfile)
l.InfoLogger = log.New(os.Stderr, "INFO ", log.Ldate|log.Ltime|log.Lmicroseconds)
l.DebugLogger = log.New(os.Stderr, "DEBUG ", log.Ldate|log.Ltime|log.Lmicroseconds)
return l
}

View file

@ -64,11 +64,13 @@ func (r Recipient) filterAndSendNotices(notices []WidNotice, template MailTempla
}
}
slices.Reverse(filteredNotices)
logger.debug(fmt.Sprintf("Including %v of %v notices for recipient %v", len(filteredNotices), len(notices), r.Address))
logger.debug("Templating and sending mails for recipient " + r.Address + " ...")
for _, n := range filteredNotices {
mailContent, err := template.generate(n)
if err != nil {
fmt.Println("ERROR\tCould not create mail from template.")
fmt.Println(err)
logger.error("Could not create mail from template")
logger.error(err)
}
// serialize & send mail
data := mailContent.serializeValidMail(smtpConfig.From, r.Address)
@ -82,8 +84,8 @@ func (r Recipient) filterAndSendNotices(notices []WidNotice, template MailTempla
if err != nil {
return err
}
// fmt.Printf("%v", strings.ReplaceAll(string(data), "\r", "\\r"))
}
logger.debug("Sent all mails for recipient " + r.Address)
return nil
}

31
main.go
View file

@ -9,6 +9,8 @@ import (
"time"
)
var logger Logger
func main() {
// get cli arguments
args := os.Args
@ -17,8 +19,11 @@ func main() {
os.Exit(1)
}
configFilePath := os.Args[1]
// create logger
logger = NewLogger(2)
// init
println("INFO\tInitializing ...")
logger.info("Initializing ...")
defer logger.info("Exiting ...")
config := NewDataStore(
configFilePath,
NewConfig(),
@ -30,15 +35,17 @@ func main() {
NewPersistentData(config),
false,
0640)
// exit handler
defer println("INFO\tExiting ...")
// check config
logger.LogLevel = config.LogLevel
logger.debug("Checking configuration file ...")
checkConfig(config)
// create mail template from mail template config
logger.debug("Parsing mail template ...")
if config.Template.SubjectTemplate == "" {
logger.debug("Using default template for mail subject")
config.Template.SubjectTemplate = DEFAULT_SUBJECT_TEMPLATE
}
if config.Template.BodyTemplate == "" {
logger.debug("Using default template for mail body")
config.Template.BodyTemplate = DEFAULT_BODY_TEMPLATE
}
mailTemplate := NewTemplateFromTemplateConfig(config.Template)
@ -54,42 +61,48 @@ func main() {
for _, a := range apiEndpoints {
for _, b := range config.EnabledApiEndpoints {
if a.Id == b {
logger.debug("Endpoint '" + b + "' is enabled")
enabledApiEndpoints = append(enabledApiEndpoints, a)
}
}
}
// main loop
logger.debug("Entering main loop ...")
for {
t1 := time.Now().UnixMilli()
newNotices := []WidNotice{}
for _, a := range enabledApiEndpoints {
fmt.Printf("INFO\t%v Querying endpoint '%v' for new notices ...\n", time.Now().Format(time.RFC3339Nano), a.Id)
logger.info("Querying endpoint '" + a.Id + "' for new notices ...")
n, t, err := a.getNotices(persistent.data.(PersistentData).LastPublished[a.Id])
if err != nil {
// retry
logger.warn("Couldn't query notices from API endpoint '" + a.Id + "'. Retrying ...")
logger.warn(err)
n, t, err = a.getNotices(persistent.data.(PersistentData).LastPublished[a.Id])
}
if err != nil {
// ok then...
fmt.Print("ERROR\t", err)
logger.error("Couldn't query notices from API endpoint '" + a.Id + "'")
logger.error(err)
} else {
newNotices = append(newNotices, n...)
persistent.data.(PersistentData).LastPublished[a.Id] = t
persistent.save()
}
}
logger.debug(fmt.Sprintf("Got %v new notices", len(newNotices)))
if len(newNotices) > 0 {
fmt.Printf("INFO\t%v Sending email notifications ...\n", time.Now().Format(time.RFC3339Nano))
logger.info("Sending email notifications ...")
recipientsNotified := 0
for _, r := range config.Recipients {
err := r.filterAndSendNotices(newNotices, mailTemplate, mailAuth, config.SmtpConfiguration)
if err != nil {
fmt.Printf("ERROR\t%v\n", err)
logger.error(err)
} else {
recipientsNotified++
}
}
fmt.Printf("INFO\t%v Email notifications sent to %v of %v recipients.\n", time.Now().Format(time.RFC3339Nano), recipientsNotified, len(config.Recipients))
logger.info(fmt.Sprintf("Email notifications sent to %v of %v recipients", recipientsNotified, len(config.Recipients)))
}
t2 := time.Now().UnixMilli()
dt := int(t2 - t1)

View file

@ -4,7 +4,6 @@ package main
import (
"bytes"
"fmt"
"text/template"
)
@ -58,12 +57,12 @@ func (t MailTemplate) generate(notice WidNotice) (MailContent, error) {
func NewTemplateFromTemplateConfig(tc MailTemplateConfig) MailTemplate {
subjectTemplate, err := template.New("subject").Parse(tc.SubjectTemplate)
if err != nil {
fmt.Println("ERROR\tCould not parse template.")
logger.error("Could not parse template")
panic(err)
}
bodyTemplate, err := template.New("body").Parse(tc.BodyTemplate)
if err != nil {
fmt.Println("ERROR\tCould not parse template.")
logger.error("Could not parse template")
panic(err)
}
return MailTemplate{

View file

@ -66,7 +66,7 @@ func (e ApiEndpoint) getNotices(since time.Time) ([]WidNotice, time.Time, error)
}
notices = parseApiResponse(decodedData, e)
} else {
fmt.Printf("ERROR\tGet \"%v\": %v\n", url, res.Status)
logger.error(fmt.Sprintf("Get \"%v\": %v\n", url, res.Status))
return nil, time.Time{}, err
}
} else {
@ -104,7 +104,7 @@ func parseApiResponse(data map[string]interface{}, apiEndpoint ApiEndpoint) []Wi
}
published, err := time.Parse(PUBLISHED_TIME_FORMAT, d["published"].(string))
if err != nil {
fmt.Println("ERROR\t", err)
logger.error(err)
}
notice.Published = published
// optional fields