chore: fix infinity calling Fatal, add backup reference
This commit is contained in:
@@ -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:
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>[✅ Database Backup Notification – {{.Database}}</title>
|
||||
<title>✅ Database Backup Notification – {{.Database}}</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Hi,</h2>
|
||||
<p>Backup of the {{.Database}} database has been successfully completed on {{.EndTime}}.</p>
|
||||
<h3>Backup Details:</h3>
|
||||
<ul>
|
||||
<li>Database Name: {{.Database}}</li>
|
||||
<li>Backup Start Time: {{.StartTime}}</li>
|
||||
<li>Backup End Time: {{.EndTime}}</li>
|
||||
<li>Backup Storage: {{.Storage}}</li>
|
||||
<li>Backup Location: {{.BackupLocation}}</li>
|
||||
<li>Backup Size: {{.BackupSize}} bytes</li>
|
||||
<li>Database Name: {{.Database}}</li>
|
||||
<li>Backup Start Time: {{.StartTime}}</li>
|
||||
<li>Backup End Time: {{.EndTime}}</li>
|
||||
<li>Backup Storage: {{.Storage}}</li>
|
||||
<li>Backup Location: {{.BackupLocation}}</li>
|
||||
<li>Backup Size: {{.BackupSize}} bytes</li>
|
||||
<li>Backup Reference: {{.BackupReference}} </li>
|
||||
</ul>
|
||||
<p>Best regards,</p>
|
||||
</body>
|
||||
@@ -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
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>🔴 Urgent: Database Backup Failure Notification</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Hi,</h2>
|
||||
<p>An error occurred during database backup.</p>
|
||||
<h3>Failure Details:</h3>
|
||||
<ul>
|
||||
<li>Error Message: {{.Error}}</li>
|
||||
<li>Date: {{.EndTime}}</li>
|
||||
<li>Backup Reference: {{.BackupReference}} </li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
> telegram-error.template
|
||||
|
||||
|
||||
```html
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<ul>
|
||||
<li>Error Message: {{.Error}}</li>
|
||||
<li>Date: {{.EndTime}}</li>
|
||||
<li>Backup Reference: {{.BackupReference}} </li>
|
||||
</ul>
|
||||
<p>©2024 <a href="github.com/jkaninda/pg-bkup">pg-bkup</a></p>
|
||||
</body>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<li>Backup Storage: {{.Storage}}</li>
|
||||
<li>Backup Location: {{.BackupLocation}}</li>
|
||||
<li>Backup Size: {{.BackupSize}} bytes</li>
|
||||
<li>Backup Reference: {{.BackupReference}} </li>
|
||||
</ul>
|
||||
<p>Best regards,</p>
|
||||
<p>©2024 <a href="github.com/jkaninda/pg-bkup">pg-bkup</a></p>
|
||||
|
||||
@@ -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}}
|
||||
|
||||
|
||||
@@ -8,4 +8,5 @@ Backup Details:
|
||||
- Backup EndTime: {{.EndTime}}
|
||||
- Backup Storage: {{.Storage}}
|
||||
- Backup Location: {{.BackupLocation}}
|
||||
- Backup Size: {{.BackupSize}} bytes
|
||||
- Backup Size: {{.BackupSize}} bytes
|
||||
- Backup Reference: {{.BackupReference}}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user