diff --git a/docs/how-tos/receive-notification.md b/docs/how-tos/receive-notification.md index 45a0d07..86efd85 100644 --- a/docs/how-tos/receive-notification.md +++ b/docs/how-tos/receive-notification.md @@ -4,10 +4,10 @@ layout: default parent: How Tos nav_order: 12 --- -Send Email or Telegram notifications on success or failed backup. +Send Email or Telegram notifications on successfully or failed backup. ### Email -To send out email notifications on failed backup runs, provide SMTP credentials, a sender and a recipient: +To send out email notifications on failed or successfully backup runs, provide SMTP credentials, a sender and a recipient: ```yaml services: @@ -30,6 +30,10 @@ services: - MAIL_FROM= - MAIL_TO=me@example.com,team@example.com,manager@example.com - MAIL_SKIP_TLS=false + ## Time format for notification + - TIME_FORMAT=2006-01-02 at 15:04:05 + ## Backup reference, in case you want to identify every backup instance + - BACKUP_REFERENCE=database/Paris cluster networks: - web networks: @@ -54,6 +58,10 @@ services: - DB_PASSWORD=password - TG_TOKEN=[BOT ID]:[BOT TOKEN] - TG_CHAT_ID= + ## Time format for notification + - TIME_FORMAT=2006-01-02 at 15:04:05 + ## Backup reference, in case you want to identify every backup instance + - BACKUP_REFERENCE=database/Paris cluster networks: - web networks: @@ -67,7 +75,8 @@ Template sources must be mounted inside the container in /config/templates: - email.template: Email notification template - telegram.template: Telegram notification template -- error.template: Error notification template +- email-error.template: Error notification template +- telegram-error.template: Error notification template ### Data @@ -78,6 +87,7 @@ Here is a list of all data passed to the template: - `Storage`: Backup storage - `BackupLocation`: Backup location - `BackupSize`: Backup size +- `BackupReference`: Backup reference(eg: database/cluster name or server name) > email.template: @@ -87,19 +97,20 @@ Here is a list of all data passed to the template: - [✅ Database Backup Notification – {{.Database}} + ✅ Database Backup Notification – {{.Database}}

Hi,

Backup of the {{.Database}} database has been successfully completed on {{.EndTime}}.

Backup Details:

Best regards,

@@ -109,7 +120,7 @@ Here is a list of all data passed to the template: > telegram.template ```html -[✅ Database Backup Notification – {{.Database}} +✅ Database Backup Notification – {{.Database}} Hi, Backup of the {{.Database}} database has been successfully completed on {{.EndTime}}. @@ -120,9 +131,32 @@ Backup Details: - Backup Storage: {{.Storage}} - Backup Location: {{.BackupLocation}} - Backup Size: {{.BackupSize}} bytes +- Backup Reference: {{.BackupReference}} ``` -> error.template +> email-error.template + +```html + + + + + 🔴 Urgent: Database Backup Failure Notification + + +

Hi,

+

An error occurred during database backup.

+

Failure Details:

+ + + +``` + +> telegram-error.template ```html diff --git a/pkg/backup.go b/pkg/backup.go index 21aed44..3bdc6d0 100644 --- a/pkg/backup.go +++ b/pkg/backup.go @@ -224,7 +224,7 @@ func BackupDatabase(db *dbConfig, backupFileName string, disableCompression bool } func localBackup(db *dbConfig, config *BackupConfig) { utils.Info("Backup database to local storage") - startTime = time.Now().Format("2006-01-02 15:04:05") + startTime = time.Now().Format(utils.TimeFormat()) BackupDatabase(db, config.backupFileName, disableCompression) finalFileName := config.backupFileName if config.encryption { @@ -247,7 +247,7 @@ func localBackup(db *dbConfig, config *BackupConfig) { Storage: config.storage, BackupLocation: filepath.Join(config.remotePath, finalFileName), StartTime: startTime, - EndTime: time.Now().Format("2006-01-02 15:04:05"), + EndTime: time.Now().Format(utils.TimeFormat()), }) //Delete old backup if config.prune { @@ -262,7 +262,7 @@ func s3Backup(db *dbConfig, config *BackupConfig) { bucket := utils.GetEnvVariable("AWS_S3_BUCKET_NAME", "BUCKET_NAME") s3Path := utils.GetEnvVariable("AWS_S3_PATH", "S3_PATH") utils.Info("Backup database to s3 storage") - startTime = time.Now().Format("2006-01-02 15:04:05") + startTime = time.Now().Format(utils.TimeFormat()) //Backup database BackupDatabase(db, config.backupFileName, disableCompression) finalFileName := config.backupFileName @@ -307,7 +307,7 @@ func s3Backup(db *dbConfig, config *BackupConfig) { Storage: config.storage, BackupLocation: filepath.Join(config.remotePath, finalFileName), StartTime: startTime, - EndTime: time.Now().Format("2006-01-02 15:04:05"), + EndTime: time.Now().Format(utils.TimeFormat()), }) //Delete temp deleteTemp() @@ -316,7 +316,7 @@ func s3Backup(db *dbConfig, config *BackupConfig) { } func sshBackup(db *dbConfig, config *BackupConfig) { utils.Info("Backup database to Remote server") - startTime = time.Now().Format("2006-01-02 15:04:05") + startTime = time.Now().Format(utils.TimeFormat()) //Backup database BackupDatabase(db, config.backupFileName, disableCompression) finalFileName := config.backupFileName @@ -359,7 +359,7 @@ func sshBackup(db *dbConfig, config *BackupConfig) { Storage: config.storage, BackupLocation: filepath.Join(config.remotePath, finalFileName), StartTime: startTime, - EndTime: time.Now().Format("2006-01-02 15:04:05"), + EndTime: time.Now().Format(utils.TimeFormat()), }) //Delete temp deleteTemp() @@ -368,7 +368,7 @@ func sshBackup(db *dbConfig, config *BackupConfig) { } func ftpBackup(db *dbConfig, config *BackupConfig) { utils.Info("Backup database to the remote FTP server") - startTime = time.Now().Format("2006-01-02 15:04:05") + startTime = time.Now().Format(utils.TimeFormat()) //Backup database BackupDatabase(db, config.backupFileName, disableCompression) @@ -412,7 +412,7 @@ func ftpBackup(db *dbConfig, config *BackupConfig) { Storage: config.storage, BackupLocation: filepath.Join(config.remotePath, finalFileName), StartTime: startTime, - EndTime: time.Now().Format("2006-01-02 15:04:05"), + EndTime: time.Now().Format(utils.TimeFormat()), }) //Delete temp deleteTemp() diff --git a/templates/email-error.template b/templates/email-error.template index 02b3997..0d00484 100644 --- a/templates/email-error.template +++ b/templates/email-error.template @@ -11,6 +11,7 @@

©2024 pg-bkup

diff --git a/templates/email.template b/templates/email.template index c3b5c77..1e49620 100644 --- a/templates/email.template +++ b/templates/email.template @@ -15,6 +15,7 @@
  • Backup Storage: {{.Storage}}
  • Backup Location: {{.BackupLocation}}
  • Backup Size: {{.BackupSize}} bytes
  • +
  • Backup Reference: {{.BackupReference}}
  • Best regards,

    ©2024 pg-bkup

    diff --git a/templates/telegram-error.template b/templates/telegram-error.template index d6b465e..fc5336c 100644 --- a/templates/telegram-error.template +++ b/templates/telegram-error.template @@ -2,6 +2,7 @@ Hi, An error occurred during database backup. Failure Details: -Date: {{.EndTime}} -Error Message: {{.Error}} +- Date: {{.EndTime}} +- Backup Reference: {{.BackupReference}} +- Error Message: {{.Error}} diff --git a/templates/telegram.template b/templates/telegram.template index 825b031..c25e73d 100644 --- a/templates/telegram.template +++ b/templates/telegram.template @@ -8,4 +8,5 @@ Backup Details: - Backup EndTime: {{.EndTime}} - Backup Storage: {{.Storage}} - Backup Location: {{.BackupLocation}} -- Backup Size: {{.BackupSize}} bytes \ No newline at end of file +- Backup Size: {{.BackupSize}} bytes +- Backup Reference: {{.BackupReference}} diff --git a/utils/config.go b/utils/config.go index 6fcbe13..c498f03 100644 --- a/utils/config.go +++ b/utils/config.go @@ -12,20 +12,23 @@ type MailConfig struct { SkipTls bool } type NotificationData struct { - File string - BackupSize int64 - Database string - StartTime string - EndTime string - Storage string - BackupLocation string + File string + BackupSize int64 + Database string + StartTime string + EndTime string + Storage string + BackupLocation string + BackupReference string } type ErrorMessage struct { - Database string - EndTime string - Error string + Database string + EndTime string + Error string + BackupReference string } +// loadMailConfig gets mail environment variables and returns MailConfig func loadMailConfig() *MailConfig { return &MailConfig{ MailHost: os.Getenv("MAIL_HOST"), @@ -39,4 +42,18 @@ func loadMailConfig() *MailConfig { } +// TimeFormat returns the format of the time +func TimeFormat() string { + format := os.Getenv("TIME_FORMAT") + if format == "" { + return "2006-01-02 at 15:04:05" + + } + return format +} + +func backupReference() string { + return os.Getenv("BACKUP_REFERENCE") +} + const templatePath = "/config/templates" diff --git a/utils/notification.go b/utils/notification.go index 9482fec..0b8f13a 100644 --- a/utils/notification.go +++ b/utils/notification.go @@ -31,8 +31,8 @@ func parseTemplate[T any](data T, fileName string) (string, error) { return buf.String(), nil } -func SendEmail(subject, body string) { - Info("Start sending email....") +func SendEmail(subject, body string) error { + Info("Start sending email notification....") config := loadMailConfig() emails := strings.Split(config.MailTo, ",") m := mail.NewMessage() @@ -44,14 +44,16 @@ func SendEmail(subject, body string) { d.TLSConfig = &tls.Config{InsecureSkipVerify: config.SkipTls} if err := d.DialAndSend(m); err != nil { - Fatal("Error could not send email : %v", err) + Error("Error could not send email : %v", err) + return err } - Info("Email has been sent") + Info("Email notification has been sent") + return nil } -func sendMessage(msg string) { +func sendMessage(msg string) error { - Info("Sending notification... ") + Info("Sending Telegram notification... ") chatId := os.Getenv("TG_CHAT_ID") body, _ := json.Marshal(map[string]string{ "chat_id": chatId, @@ -67,18 +69,21 @@ func sendMessage(msg string) { client := &http.Client{} response, err := client.Do(request) if err != nil { - panic(err) + return err } code := response.StatusCode if code == 200 { - Info("Notification has been sent") + Info("Telegram notification has been sent") + return nil } else { body, _ := ioutil.ReadAll(response.Body) - Fatal("Error could not send message, error: %s", string(body)) + Error("Error could not send message, error: %s", string(body)) + return fmt.Errorf("error could not send message %s", string(body)) } } func NotifySuccess(notificationData *NotificationData) { + notificationData.BackupReference = backupReference() var vars = []string{ "TG_TOKEN", "TG_CHAT_ID", @@ -99,17 +104,23 @@ func NotifySuccess(notificationData *NotificationData) { if err != nil { Error("Could not parse email template: %v", err) } - SendEmail(fmt.Sprintf("✅ Database Backup Notification – %s", notificationData.Database), body) + err = SendEmail(fmt.Sprintf("✅ Database Backup Notification – %s", notificationData.Database), body) + if err != nil { + Error("Could not send email: %v", err) + } } //Telegram notification err = CheckEnvVars(vars) if err == nil { message, err := parseTemplate(*notificationData, "telegram.template") if err != nil { - Error("Could not parse email template: %v", err) + Error("Could not parse telegram template: %v", err) } - sendMessage(message) + err = sendMessage(message) + if err != nil { + Error("Could not send Telegram message: %v", err) + } } } func NotifyError(error string) { @@ -130,26 +141,35 @@ func NotifyError(error string) { err := CheckEnvVars(mailVars) if err == nil { body, err := parseTemplate(ErrorMessage{ - Error: error, - EndTime: time.Now().Format("2006-01-02 15:04:05"), + Error: error, + EndTime: time.Now().Format(TimeFormat()), + BackupReference: os.Getenv("BACKUP_REFERENCE"), }, "email-error.template") if err != nil { - Error("Could not parse email template: %v", err) + Error("Could not parse error template: %v", err) + } + err = SendEmail(fmt.Sprintf("🔴 Urgent: Database Backup Failure Notification"), body) + if err != nil { + Error("Could not send email: %v", err) } - SendEmail(fmt.Sprintf("🔴 Urgent: Database Backup Failure Notification"), body) } //Telegram notification err = CheckEnvVars(vars) if err == nil { message, err := parseTemplate(ErrorMessage{ - Error: error, - EndTime: time.Now().Format("2006-01-02 15:04:05"), + Error: error, + EndTime: time.Now().Format(TimeFormat()), + BackupReference: os.Getenv("BACKUP_REFERENCE"), }, "telegram-error.template") if err != nil { - Error("Could not parse email template: %v", err) + Error("Could not parse error template: %v", err) + } - sendMessage(message) + err = sendMessage(message) + if err != nil { + Error("Could not send telegram message: %v", err) + } } }