From f1c1986aecd50fa24779933db1579f99b9a560dd Mon Sep 17 00:00:00 2001 From: tetsuya28 Date: Mon, 1 Jan 2024 21:15:43 +0900 Subject: [PATCH 1/2] Seperate config package --- config/config.go | 16 ++++++++++++++++ main.go | 18 +++++++----------- 2 files changed, 23 insertions(+), 11 deletions(-) create mode 100644 config/config.go diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..86c9183 --- /dev/null +++ b/config/config.go @@ -0,0 +1,16 @@ +package config + +import "github.com/kelseyhightower/envconfig" + +type Config struct { + SlackToken string `required:"true" envconfig:"SLACK_TOKEN"` + SlackChannel string `required:"true" envconfig:"SLACK_CHANNEL"` +} + +func New() (*Config, error) { + config := Config{} + if err := envconfig.Process("", &config); err != nil { + return nil, err + } + return &Config{}, nil +} diff --git a/main.go b/main.go index bfa6d49..0c0ce89 100644 --- a/main.go +++ b/main.go @@ -9,17 +9,12 @@ import ( "github.com/aws/aws-lambda-go/lambda" "github.com/aws/aws-sdk-go/service/costexplorer" - "github.com/kelseyhightower/envconfig" "github.com/slack-go/slack" + "github.com/tetsuya28/aws-cost-report/config" "github.com/tetsuya28/aws-cost-report/external" "github.com/ucpr/mongo-streamer/pkg/log" ) -type Config struct { - SlackToken string `required:"true" envconfig:"SLACK_TOKEN"` - SlackChannel string `required:"true" envconfig:"SLACK_CHANNEL"` -} - type DailyCost struct { Total float64 Services map[string]ServiceDetail @@ -37,11 +32,12 @@ func main() { } func handler() error { - config := Config{} - if err := envconfig.Process("", &config); err != nil { - panic(err) + cfg, err := config.New() + if err != nil { + return err } - slk := external.NewSlack(config.SlackToken) + + slk := external.NewSlack(cfg.SlackToken) result, err := external.GetCost() if err != nil { @@ -92,7 +88,7 @@ func handler() error { option := slack.MsgOptionText(text, false) attachments := toAttachment(cost) - err = slk.PostMessage(config.SlackChannel, option, slack.MsgOptionAttachments(attachments...)) + err = slk.PostMessage(cfg.SlackChannel, option, slack.MsgOptionAttachments(attachments...)) if err != nil { return err } From deb29a6b99d948d80d695633c0245fa3e230161d Mon Sep 17 00:00:00 2001 From: tetsuya28 Date: Tue, 2 Jan 2024 01:53:11 +0900 Subject: [PATCH 2/2] Add i18y --- README.md | 20 +++++++++++- config/config.go | 7 ++-- docs/notification.jpg | Bin 0 -> 55826 bytes go.mod | 4 +-- i18y/i18y.go | 72 +++++++++++++++++++++++++++++++++++++++++ i18y/i18y_test.go | 38 ++++++++++++++++++++++ i18y/languages/en.yaml | 3 ++ i18y/languages/ja.yaml | 3 ++ main.go | 44 +++++++++++++++++-------- 9 files changed, 171 insertions(+), 20 deletions(-) create mode 100644 docs/notification.jpg create mode 100644 i18y/i18y.go create mode 100644 i18y/i18y_test.go create mode 100644 i18y/languages/en.yaml create mode 100644 i18y/languages/ja.yaml diff --git a/README.md b/README.md index a96e32a..96410ae 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,12 @@ ## What is aws_cost_usage Notify daily cost usage of an AWS account to slack channel. +![](./docs/notification.jpg) + ## How to use this -You can deploy with Terraform resources on your AWS account. +### Execution +#### Lambda +You can deploy with Terraform resources on your AWS account with AWS Lambda. ```hcl terraform { @@ -28,6 +32,15 @@ module "cost" { } ``` +#### Others +You can download binary from GitHub Release. + +### Support multi languages +- English + - Set `LANGUAGE=en` +- Japanese + - Set `LANGUAGE=ja` + ## Development - Init ``` @@ -38,3 +51,8 @@ cp .env{.sample,} ``` make run ``` + +## Known issues +### Got daily cost as $0.000 +If you set CloudWatch Events Schedule near AM 0:00 in UTC, AWS has not reflect daily cost yet. +So, you need to set the schedule for more later. diff --git a/config/config.go b/config/config.go index 86c9183..e7d1ecc 100644 --- a/config/config.go +++ b/config/config.go @@ -5,12 +5,13 @@ import "github.com/kelseyhightower/envconfig" type Config struct { SlackToken string `required:"true" envconfig:"SLACK_TOKEN"` SlackChannel string `required:"true" envconfig:"SLACK_CHANNEL"` + Language string `required:"true" envconfig:"LANGUAGE" default:"ja"` } -func New() (*Config, error) { +func New() (Config, error) { config := Config{} if err := envconfig.Process("", &config); err != nil { - return nil, err + return Config{}, err } - return &Config{}, nil + return config, nil } diff --git a/docs/notification.jpg b/docs/notification.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9058d22618f11f24d201452dab2d755e57e39e51 GIT binary patch literal 55826 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 literal 0 HcmV?d00001 diff --git a/go.mod b/go.mod index fda7cf6..76b6742 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,8 @@ require ( github.com/slack-go/slack v0.9.3 github.com/stretchr/testify v1.8.4 github.com/ucpr/mongo-streamer v0.0.4 + golang.org/x/text v0.14.0 + gopkg.in/yaml.v3 v3.0.1 ) require ( @@ -48,7 +50,6 @@ require ( golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/sync v0.5.0 // indirect golang.org/x/sys v0.15.0 // indirect - golang.org/x/text v0.14.0 // indirect google.golang.org/api v0.128.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect @@ -56,5 +57,4 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect google.golang.org/grpc v1.56.3 // indirect google.golang.org/protobuf v1.31.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/i18y/i18y.go b/i18y/i18y.go new file mode 100644 index 0000000..fc5d0e5 --- /dev/null +++ b/i18y/i18y.go @@ -0,0 +1,72 @@ +package i18y + +import ( + "embed" + _ "embed" + "fmt" + "io/fs" + "path/filepath" + "strings" + + "golang.org/x/text/language" + "golang.org/x/text/message" + "gopkg.in/yaml.v3" +) + +const ( + LanguagesDir = "languages" +) + +var ( + languages = []language.Tag{ + language.Japanese, + language.English, + } + //go:embed languages/*.yaml + configByte embed.FS +) + +type Messages map[string]map[string]string + +func Init() error { + files, err := configByte.ReadDir(LanguagesDir) + if err != nil { + return err + } + + for _, file := range files { + data, err := fs.ReadFile(configByte, fmt.Sprintf("%s/%s", LanguagesDir, file.Name())) + if err != nil { + return err + } + + var m map[string]string + err = yaml.Unmarshal(data, &m) + if err != nil { + return err + } + + // Make language tag from file name + l := language.Make(strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))) + for k, v := range m { + err = message.SetString(l, k, v) + if err != nil { + return err + } + } + } + + return nil +} + +func Translate(acceptLanguage string, msg string, args ...interface{}) string { + t, _, err := language.ParseAcceptLanguage(acceptLanguage) + if err != nil { + return msg + } + + matcher := language.NewMatcher(languages) + tag, _, _ := matcher.Match(t...) + p := message.NewPrinter(tag) + return p.Sprintf(msg, args...) +} diff --git a/i18y/i18y_test.go b/i18y/i18y_test.go new file mode 100644 index 0000000..1f69768 --- /dev/null +++ b/i18y/i18y_test.go @@ -0,0 +1,38 @@ +package i18y + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "golang.org/x/text/language" +) + +func TestTranslate(t *testing.T) { + err := Init() + assert.NoError(t, err) + + tests := []struct { + name string + acceptLanguage string + key string + out string + }{ + { + name: "japanese", + acceptLanguage: language.Japanese.String(), + key: "cost", + out: "料金", + }, + { + name: "english", + acceptLanguage: language.English.String(), + key: "cost", + out: "Cost", + }, + } + + for _, tt := range tests { + out := Translate(tt.acceptLanguage, tt.key) + assert.Equal(t, tt.out, out) + } +} diff --git a/i18y/languages/en.yaml b/i18y/languages/en.yaml new file mode 100644 index 0000000..f15cd28 --- /dev/null +++ b/i18y/languages/en.yaml @@ -0,0 +1,3 @@ +title: "%s cost of %s is `$%.3f`" +cost: Cost +usage: Usage diff --git a/i18y/languages/ja.yaml b/i18y/languages/ja.yaml new file mode 100644 index 0000000..75dc47e --- /dev/null +++ b/i18y/languages/ja.yaml @@ -0,0 +1,3 @@ +title: "%s : %s のコスト : `$%.3f`" +cost: 料金 +usage: 利用量 diff --git a/main.go b/main.go index 0c0ce89..888c9de 100644 --- a/main.go +++ b/main.go @@ -12,9 +12,14 @@ import ( "github.com/slack-go/slack" "github.com/tetsuya28/aws-cost-report/config" "github.com/tetsuya28/aws-cost-report/external" + "github.com/tetsuya28/aws-cost-report/i18y" "github.com/ucpr/mongo-streamer/pkg/log" ) +var ( + Language string +) + type DailyCost struct { Total float64 Services map[string]ServiceDetail @@ -34,6 +39,15 @@ func main() { func handler() error { cfg, err := config.New() if err != nil { + log.Warn("failed to new config, err=%w", err) + return err + } + + Language = cfg.Language + + err = i18y.Init() + if err != nil { + log.Warn("failed to init i18y, err=%w", err) return err } @@ -41,6 +55,7 @@ func handler() error { result, err := external.GetCost() if err != nil { + log.Warn("failed to get cost, err=%w", err) return err } @@ -70,7 +85,7 @@ func handler() error { dailyCost.Services[serviceName] = c - // 日次合計を計算する + // Sum total daily cost dailyCost.Total += c.CostAmount } @@ -79,17 +94,19 @@ func handler() error { fullName, err := external.GetAccountFullName(context.Background()) if err != nil { + log.Warn("failed to get account info, err=%w", err) return err } now := time.Now() yesterday := now.AddDate(0, 0, -1) - text := fmt.Sprintf("%s の %s コスト\n合計金額: $%.3f", fullName, yesterday.Format("2006-01-02"), cost[0].Total) + text := i18y.Translate(Language, "title", fullName, yesterday.Format("2006-01-02"), cost[1].Total) option := slack.MsgOptionText(text, false) attachments := toAttachment(cost) err = slk.PostMessage(cfg.SlackChannel, option, slack.MsgOptionAttachments(attachments...)) if err != nil { + log.Warn("failed to post message to Slack, err=%w", err) return err } @@ -142,9 +159,9 @@ func toCost(result *costexplorer.Group) (ServiceDetail, error) { } func toAttachment(cost []DailyCost) []slack.Attachment { - // 一昨日、昨日のコスト比較なので 2 つのみ - // [0] : 一昨日、 [1] : 昨日 + // Just day before yesterday and yesterday if len(cost) != 2 { + log.Warn("cost length is not 2") return nil } @@ -158,22 +175,21 @@ func toAttachment(cost []DailyCost) []slack.Attachment { diff := (detail.CostAmount / before.CostAmount) * 100 if !math.IsNaN(diff) { - priceDiffStatement += " ( 前日比 : " - - // 前日よりも高くなってたら赤色にする + diffMark := "" + // Set red color if diff is over 100% if diff == 100 { color = "#ffffff" - priceDiffStatement += "" } else if diff > 100 { color = "#ff0000" - priceDiffStatement += "📈 " + diffMark = "📈" } else { color = "#0000ff" - priceDiffStatement += "📉 " + diffMark = "📉" } - priceDiffStatement += fmt.Sprintf( - "%.1f%% )", + priceDiffStatement = fmt.Sprintf( + " ( %s %.1f%% )", + diffMark, diff, ) } @@ -181,7 +197,7 @@ func toAttachment(cost []DailyCost) []slack.Attachment { fields := []slack.AttachmentField{ { - Title: "料金", + Title: i18y.Translate(Language, "cost"), Value: fmt.Sprintf( "%.3f%s%s", detail.CostAmount, @@ -191,7 +207,7 @@ func toAttachment(cost []DailyCost) []slack.Attachment { Short: true, }, { - Title: "使用量", + Title: i18y.Translate(Language, "usage"), Value: fmt.Sprintf("%.3f%s", detail.UsageAmount, detail.UsageUnit), Short: true, },