Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add alert action to check ethstorage state #330

Merged
merged 15 commits into from
Nov 1, 2024
36 changes: 36 additions & 0 deletions .github/workflows/alerting.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Alerting
on:
schedule:
- cron: '1 */1 * * *'
workflow_dispatch:

jobs:
alert:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.21'

- name: check
run: |
cd ./cmd/alert
go build
./alert --htmlbody ./body.html

- name: Send notification email
if: failure()
uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
username: ${{ secrets.SMTP_USERNAME }}
password: ${{ secrets.SMTP_PASSWORD }}
subject: EthStorage Alert!
to: [email protected],[email protected],[email protected],[email protected],[email protected]
from: ${{ secrets.SMTP_USERNAME }}
html_body: file://./cmd/alert/body.html
89 changes: 89 additions & 0 deletions cmd/alert/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package main

import (
"context"
"flag"
"fmt"
"os"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/ethstorage/go-ethstorage/ethstorage/eth"
"github.com/ethstorage/go-ethstorage/ethstorage/miner"
)

const (
emailFormat = "<html><body><div><h3>Ethstorage Alert!</h3>%s</div></body></html>"
noMinedBlockAlertContent = "<p>No blocks mined in last 24 hours. Last mined block: %d; last mined time: %v; l1 source: %s.</p>"
errorContent = "<p>Check alert fail with error: %s</p>"
)

var (
rpcURLFlag = flag.String("rpcurl", "http://88.99.30.186:8545", "L1 RPC URL")
l1ContractFlag = flag.String("l1contract", "0x804C520d3c084C805E37A35E90057Ac32831F96f", "Storage contract address on l1")
bodyFileFlag = flag.String("htmlbody", "body.html", "Alert email html body file")
)

func main() {
flag.Parse()
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(3), log.StreamHandler(os.Stderr, log.TerminalFormat(true))))

var (
contract = common.HexToAddress(*l1ContractFlag)
logger = log.New("app", "alert")
)

client, err := eth.Dial(*rpcURLFlag, contract, 12, logger)
if err != nil {
log.Crit("Failed to create L1 source", "err", err)
}

needAlert, content := checkLastMinedBlock(client, contract, logger)
if needAlert {
writeHtmlFile(fmt.Sprintf(emailFormat, content))
os.Exit(1)
}
}

func checkLastMinedBlock(client *eth.PollingClient, contract common.Address, logger log.Logger) (bool, string) {
var (
ctx = context.Background()
api = miner.NewL1MiningAPI(client, nil, logger)
err error
)

for i := 0; i < 3; i++ {
info, e := api.GetMiningInfo(ctx, contract, 0)
if e != nil {
time.Sleep(time.Minute)
log.Error("Get mining info fail", "error", e)
err = e
continue
}

lastMinedTime := time.Unix(int64(info.LastMineTime), 0)
logger.Info("", "last mined time", lastMinedTime, "mined block", info.BlockMined)
targetTime := time.Now().Add(-24 * time.Hour)
if targetTime.After(lastMinedTime) {
content := fmt.Sprintf(noMinedBlockAlertContent, info.BlockMined, lastMinedTime, *rpcURLFlag)
return true, content
}
return false, ""
}

return true, fmt.Sprintf(errorContent, err.Error())
}

func writeHtmlFile(content string) {
file, err := os.Create(*bodyFileFlag)
if err != nil {
log.Crit("Create html file fail", "error", err.Error())
}
defer file.Close()

_, err = file.WriteString(content)
if err != nil {
log.Crit("Write html file fail", "error", err.Error())
}
}
Loading