Apex GoでSNSからメッセージを受け取りSlackへ投げてみる

Apex Go を使用した[こちらの記事](http://qiita.com/tfutada/items/d5f000828c7335d9ba5b)の続編です。

今回はローカルでのApex Lambdaの開発方法を紹介しつつ説明します。

まず一度だけ、SNSイベントのJSONデータをダンプするための簡単なLambdaを作成し、AWSにデプロイして実行します。

```go:main.go
package main

import (
	"log"
	"encoding/json"

	apex "github.com/apex/go-apex"
	apexSns "github.com/apex/go-apex/sns"
)

func main() {
	apexSns.HandleFunc(func(event *apexSns.Event, ctx *apex.Context) error {
		b, _ := json.MarshalIndent(event, "", "    ")
		log.Printf("%s\n", b) // SNSイベントダンプ
		return nil
	})
}
```

ApexコマンドでLambdaをAWSにデプロイします。

```bash
$ apex deploy
$ apex logs -f # CloudWatchのログを出力します。
```

次にAWSコンソールからSNSトピックを作成します。
サブスクリプションでデプロイしたLambdaをトピックに割り当てます。

![3AWS_SNS_🔊.png](https://qiita-image-store.s3.amazonaws.com/0/75231/95eb84cd-d5c8-5d9b-c659-3f9b2045d637.png)

SNSコンソールからメッセージをテスト送信します。
Lambdaがイベントを受け取り、`apex logs`の出力に受け取ったSNSイベントがダンプされます。

![1__apex_logs_slack_-f__apex_.png](https://qiita-image-store.s3.amazonaws.com/0/75231/31d63902-aee7-317a-c0b9-6f4e9fef6288.png)

JSONの部分をコピペしてファイルに保存します。`event.json`

```json:event.json
{
  "event": { // この部分は出力されませんので追加します。
    "Records": [
         {
             "EventSource": "aws:sns",
             "EventVersion": "1.0",
             "Sns": {
                 "Type": "Notification",
             ...
```

これでめでたくローカルで作業できます。 :smiley: 

```bash
$ go run main.go < event.json
```

次にSlackの`incoming webhooks`を使用してメッセージを送信する部分を実装します。

SlackのWebコンソールからWebHook URLを発行してください。

![App_Directory___Internal_Nor__Project_Slack_🔊.png](https://qiita-image-store.s3.amazonaws.com/0/75231/feb0eaa6-f1bd-7e5a-8b4f-c87368e33378.png)

GoのSlack APIは`Ashwanth Kumar`のライブラリを使ってみました。

```bash
$ go get github.com/ashwanthkumar/slack-go-webhook
```

アタッチメント付きのメッセージを送るコードの例です。

```go:main.go
package main

import (
	"encoding/json"
	"fmt"
	"log"

	apex "github.com/apex/go-apex"
	apexSns "github.com/apex/go-apex/sns"

	"github.com/ashwanthkumar/slack-go-webhook"
)

const (
	webhookUrl = "https://hooks.slack.com/services/xxx" // WebHook URL
	channelName = "#systemalerts" // Slackチャネル
)

func main() {
	apexSns.HandleFunc(func(event *apexSns.Event, ctx *apex.Context) error {
        // Slackアタッチメント
		footer := []string{"Test", "https://platform.slack-edge.com/img/default_application_icon.png"}
		attachment1 := slack.Attachment{}
		attachment1.Footer = &footer[0]
		attachment1.FooterIcon = &footer[1]
		attachment1.AddField(slack.Field{Title: "Author", Value: "Ashwanth Kumar" }).AddField(slack.Field { Title: "Status", Value: "Completed" })
        // Payload作成
		payload := slack.Payload{
			Text: "Hello from <https://github.com/ashwanthkumar/slack-go-webhook|slack-go-webhook>, a Go-Lang library to send slack webhook messages.\n<https://golangschool.com/wp-content/uploads/golang-teach.jpg|golang-img>",
			Username: "robot",
			Channel: channelName,
			IconEmoji: ":monkey_face:",
			Attachments: []slack.Attachment{attachment1},
		}
        // Slackへ送信
		err := slack.Send(webhookUrl, "", payload)
		if len(err) > 0 {
			fmt.Printf("error: %s\n", err)
		}
		return nil
	})
}
```

ローカルで実行します。
こんな感じに送られてきます。

![2Slack.png](https://qiita-image-store.s3.amazonaws.com/0/75231/d2d498df-34f3-eb42-438f-1f25e4cee8da.png)

SNSから受け取ったメッセージは、
`event.Records[i].SNS.Message`で取得できるので、`Payload.Text`にセットするなり、好きなようにしてください。

AWSのSNSは、CloudWatch, CodeDeployなどがパブリッシャーとして使えますので、Lambdaを経由してSlackに流すことができます。

また、LogstashからWebアプリのエラーログを吸い上げてSNSに送り、Slackに流すこともできますので、アラート系をSlackに寄せることができ便利かと思います。