- 投稿日:2020-02-24T23:27:55+09:00
PyPortal で TinyGo プログラミングを始めよう
この記事では、以下の環境で Windows 10 環境で TinyGo + Pyportal を試した時のメモをまとめます。
- Windows 10 Home / Pro 64bit
TinyGo 0.12→ docker の tinygo/tinygo-dev を使う事- PyPortal
個別に記載しない限りは Windows 10 を対象としたメモであることに注意。
また、基本的には PyPortal でしか確認していませんが、他のボードも大差ないと思います。2020/02/25 追記)
以下の Windows 版 tinygo 0.12 だと PyPortal で float 演算をしようとするとフリーズする。
現時点では docker の tinygo/tinygo-dev を使用する事で回避できる。
以下の本文中の記載は、随時 tinygo/tinygo-dev での確認結果をベースとしたものに書き換えていきます。
- tinygo version 0.12.0 windows/amd64 (using go version go1.13.1)
最初に
メモを書くきっかけ
TinyGo でマイコンプ遊びをしようと思ったがまとまった情報が少なかった。
基本的には TinyGo 専用ボードというのはないので、書き込み方法含め不明点が多かった。
同僚が Windows 10 + Adafruit Trinket M0 で TinyGo デビューしようとして躓いていた。
ボード毎に異なる部分もあり L チカまですんなり進むようにサポートしたいという思いがあった。TinyGo とは
マイコンや WASM などの Small Places 向けの Go Compiler です。
ここでは Go の文法でマイコン開発ができるもの、という程度の認識でよいです。PyPortal とは
Adafruit 社の 3.2 インチカラー液晶タッチディスプレイ (320x240) な IoT ディスプレイマイコンボード。
基本的には Arduino や CircuitPython での開発が想定されているが、 TinyGo でも 0.12 でサポートされた。
ESP-WROOM-32 が搭載されていて Wi-Fi 経由で何かをしたり、等も可能。マイコンは Microchip 社の ATSAMD51J20 (Arm Cortex-M4 120MHz) が搭載されている。
2020/02/24 時点で、スイッチサイエンスの値段は 8,767 円で、在庫は残り 8 個となっている。
- Adafruit PyPortal - CircuitPython IoTディスプレイ - スイッチサイエンス
- Adafruit PyPortal - CircuitPython Powered Internet Display - オフィシャル
- Overview | Adafruit PyPortal - IoT for CircuitPython - オフィシャル Overview
TinyGo 対応ボード
オフィシャルで対応が謳われているものについては以下に列挙されている。
AVR / RISC-V / Xtensa / ARM Cortex-M などがサポートされている。
現時点では ARM 系が開発の中心となっているので、新しく買うなら ARM 系のボードで試すのが良いはず。なぜ Pyportal を選んだのか
PIC16F あたり?からデビューした世代なので、楽ができるオールインワンなボードが欲しかったから。
- 本体だけでそれなりに遊べそう
- ブレッドボードを使わなくてもいい
- ネットワークにそのままつながる
- TinyGo 0.12 で新規サポートされた
- FOSDEM 2020 (2020/02) のデモ でも使われていた
- 画面描画部分の TinyGo のソースが手に入る
- CPU (ATSAMD51J20) が Adafruit Feather M4 等の他の TinyGo ターゲットでも使われている
とはいえ、好きなのを買うのが良いと思います。
引っかからずに進むためには、ドキュメントが多いボードを使うのが安全です。
引っかかるのも経験だし勉強になるのも、そういう考え方も OK です。サンプルコード
最初にどういうコードをビルドして試せばよいか悩むと思います。
自分も悩みました。とりあえず以下を書き込むことで、基板上の LED を点滅させることができます。
動作確認が出来たら、反転周期を切り替えてみる等をしてみると良いです。以下のソースコードは、 TinyGo のオフィシャルにあるサンプルになります。
PyPortal 環境では、液晶の裏側の赤 LED が machine.LED として設定されています。
他のボードでも動く (ように machine.LED とかがボード毎に設定され続ける) と思います。ビルド方法と書き込み方法は後述。
package main import ( "machine" "time" ) func main() { led := machine.LED led.Configure(machine.PinConfig{Mode: machine.PinOutput}) for { led.Low() time.Sleep(time.Millisecond * 1000) led.High() time.Sleep(time.Millisecond * 1000) } }TinyGo の始め方
TinyGo のインストール
2020/02/21 時点の最新版である
tinygo0.12.0.windows-amd64.zip
をダウンロード&解凍しC:\tinygo
以下に配置します。その後、環境変数 PATH に
C:\tinygo\bin
を追加します。$ set PATH=C:\tinygo\bin;%PATH%%実際にはファイルの場所はどこでも良いので適宜好きな場所に読み替えても OK です。
とにかくtinygo
の実行体 (Windows だとtinygo.exe
) に PATH が通ってればよいです。なお、上記では Windows Native 版を紹介しましたが Docker ベースでも開発可能です。
2020/02/25 追記)
ビルドした実行体に何か問題がある場合は Docker の tinygo/tinygo や、より新しい開発版である tinygo/tinygo-dev を使う事。ビルドの前準備
ビルドに必要な依存ライブラリ等は事前に vendoring しておきます。
この時の Go は Go1.13 ではなく、また Go1.12 の最新版ではなく少し古めのものである必要があります。ここでは、 Go の 1.12.14 をインストールします。
注意) 以下を実施する前に Go 1.13 等をインストールしておく必要があります)go get golang.org/dl/go1.12.14 go1.12.14 downloadその後、開発ディレクトリにて
go mod vendor
を実行します。set GO111MODULE=on go1.12.14 mod init go1.12.14 mod vendor正しく実行できると、 import している依存ライブラリが
./vendor
以下に配置されます。
例えばあるプロジェクトだと以下のようになります。
vendor 以下にtinygo.org/x/drivers
以下のファイルが追加されているのが分かります。./go.mod ./go.sum ./touch.go ./vendor/modules.txt ./vendor/tinygo.org/x/drivers/ili9341/ili9341.go ./vendor/tinygo.org/x/drivers/ili9341/parallel_atsamd51.go ./vendor/tinygo.org/x/drivers/ili9341/README.md ./vendor/tinygo.org/x/drivers/ili9341/registers.go ./vendor/tinygo.org/x/drivers/LICENSE ./vendor/tinygo.org/x/drivers/touch/point.go ./vendor/tinygo.org/x/drivers/touch/resistive/fourwire.goビルド方法
Windows Native 版の TinyGo を使っても良いですし、 docker 版を使っても良いです。
それぞれの実行方法は以下の通り。ビルド方法 (Windows Native 版 TinyGo)
tinygo build -o app.uf2 -target pyportal [PATH TO YOUR PROGRAM]ビルド方法 (docker 版 tinygo/tinygo)
TinyGo Tutorial - GolangRdyJp に色々記載があるので参照すると良いです。
簡単に書くと以下でビルドします。
Windows 10 Home 等で Docker Toolbox on Windows を使っていて、 Docker Quickstart Terminal (bash) で実行する分には以下が実行可能です。docker run -it --rm -v $PWD:/go/src/github.com/user/repo \ -w /go/src/github.com/user/repo \ -e GOPATH=/go \ tinygo/tinygo tinygo build -o app.hex -target pyportal .ただし、 Windows 10 Pro + Docker Desktop + cmd.exe だったりすると以下のようになります。
※カレントディレクトリが %GOAPTH%/src/github/com/user/repo である場合docker run -it --rm -v %GOPATH%/src/github.com/user/repo:/go/src/github.com/user/repo \ -w /go/src/github.com/user/repo \ -e GOPATH=/go \ tinygo/tinygo tinygo build -o app.hex -target pyportal .更には、 Docker Toolbox on Windows を使っているけど cmd.exe で実行したい場合は上記だとうまく動かず下記のように実行する必要があります。
試した感じでは Docker Toolbox on Windows の docker の場合は/c/Users
のように/
始まりかつ小文字のドライブレターにする必要があります。docker run -it --rm -v /c/Users/USER/go/src/github.com/user/repo:/go/src/github.com/user/repo \ -w /go/src/github.com/user/repo \ -e GOPATH=/go \ tinygo/tinygo tinygo build -o app.hex -target pyportal .正直覚えにくいし面倒だと思いましたので、
tinygo-docker
というヘルパーコマンドを作りました。
良かったら使ってみてください。
Windows Native 版 TinyGo と限りなく同じやり方でtinygo
をtinygo-docker
に変更すればビルドできます。
ただし docker 経由なので flash は出来ません。tinygo-docker build -o app.uf2 -target pyportal .2020/02/25 追記)
上記では、tinygo/tinygo
を使いましたが、tinygo/tinygo-dev
を指定することで最新の開発版を使うことができます。
手元の環境において Windows TinyGo 0.12 + PyPortal だと float 演算でマイコンがフリーズしてしまいますが、 tinygo/tinygo-dev だと動きました。
以下のようしてビルドを実行します。docker run -it --rm -v $PWD:/go/src/github.com/user/repo \ -w /go/src/github.com/user/repo \ -e GOPATH=/go \ tinygo/tinygo-dev tinygo build -o app.hex -target pyportal .tinygo-docker では以下のように設定できます。
引数--docker-image
の位置は tinygo-docker の直後に指定する事。tinygo-docker --docker-image tinygo/tinygo-dev build -o app.uf2 -target pyportal .マイコンへの書き込み方
Windows の場合のみ、 PyPortal に書き込む前に都度
書き込み可能モード
に切り替える必要があります。
液晶裏側のリセットをダブルタップすることで書き込み可能モード
に入ります。
(Windows 以外の場合は、 オフィシャルドキュメント を読む限り何もしなくてもよさそう)その後、
- Windows Native 版 TinyGo を使って書き込む
- マウントされたドライブ (PORTALBOOT) に作成した
*.uf2
ファイルをコピーのいずれかの方法で書き込みます。
【備考】
自分は最初に UF2 をアップデートしたのですが、おそらく出荷時バージョンで問題ないかと思います (未確認)。
上記を試してみても書き込み出来ない場合は、 UF2 を update してみてください。Windows Native 版 TinyGo を使って書き込む
上記のマイコンボード毎のドキュメントの記載にないですが、実際には
-port
の指定が必須です。
-port
で指定するポートは、デバイスマネージャー (Win-R > devmgmt.msc
) から確認できます。
後述の画像の例だとCOM4
を指定する必要があります。以下の例では、再ビルドしてマイコンへの書き込みまで実施します。
tinygo flash -port COM4 -target=pyportal [PATH TO YOUR PROGRAM]マウントされたドライブに
*.uf2
ファイルをコピーして書き込むマウントされたドライブに作成した
*.uf2
ファイルをコピーすることで書き込みができます。
書き込み後は自動的にリセットして、書き込んだファイルの動作を行います。
例えば以下のようなコマンドで書き込みすることができます。$ copy app.uf2 D:参照資料等
マイコンボード毎の TinyGo のドキュメント
以下にあります。
PyPortal については以下にあります。
周辺デバイスのドライバ
TinyGo 全般用として、様々な周辺デバイス用のドライバが以下あります。
例えば PyPortal の液晶は ILI9341 TFT Display なので以下を使うと簡単に画面描画できます。
PyPortal 用のものについてのまとめは以下。
- ATSAMD51J20 : Arm Cortex-M4
- https://www.microchip.com/wwwproducts/en/ATSAMD51J20A
- One Full-Speed (12 Mbps) Universal Serial Bus (USB) 2.0 interface
- ILI9341 : Display 3.2" 320 x 240 color TFT
- 画面描画周り
- https://github.com/tinygo-org/drivers/tree/master/ili9341
- https://github.com/tinygo-org/drivers/tree/master/examples/ili9341/pyportal_boing
- タッチパネル周り
- https://github.com/tinygo-org/drivers/tree/master/touch
- https://github.com/tinygo-org/drivers/tree/master/examples/touch/resistive/pyportal_touchpaint
- ライブラリ類
- https://github.com/tinygo-org/tinydraw
- https://github.com/tinygo-org/tinyfont
- ESP-WROOM-32 : WiFi / Bluetooth v4.2
- speaker
- ALS-PT19 : light sensor
- Data Sheet
- https://www.adafruit.com/product/2748
- ADT7410 : 温度センサー
- Data Sheet
- https://www.analog.com/jp/products/adt7410.html
- https://github.com/tinygo-org/drivers/tree/master/adt7410
- https://github.com/tinygo-org/drivers/tree/master/examples/adt7410
- A1 / A0 が GND につながっているので I2C アドレスは 0x48
- NeoPixel : 本体裏のフルカラー LED
- machine.NEOPIXELS ではなく machine.NEOPIXEL ピンで接続されていることに注意
- https://github.com/tinygo-org/drivers/tree/master/ws2812
- https://github.com/tinygo-org/drivers/tree/master/examples/ws2812
- microSD
- 8MB flash
- plug-in ports for I2C
- 2 x analog/digital pins
日本語情報リンク
- TinyGoで始める組み込みプログラミング - 144Labグループ開発者ブログ
- TinyGo Tutorial - GolangRdyJp
- TinyGoで組み込み開発を始めよう!!
- Arduino Unoでtinygoをやってみた - Qiita
雑多なメモ/困りごと/制限事項など
- math.Abs() 関数を使うとフリーズする
- 2020/02/25 加筆) Windows Native 0.12 および docker の tinygo/tinygo だとフリーズする
- 2020/02/25 加筆) tinygo/tinygo-dev であればフリーズしない
- float64 を返す関数を使うとフリーズする
- 2020/02/25 加筆) docker の tinygo/tinygo-dev であればフリーズしない
- goroutine は LLVM coroutine を使ってエミュレートしている
- goroutine は GOMAXPROX = 1 時の動きに近い
- time.Sleep() や chan 操作時などに異なる goroutine に切り替わる
- Windows 10 だと USB-CDC が動いてなさそう
- 本来は
print()
とかprintln()
とかからシリアルポートに書き込める感じ- デバイスマネージャーで COM ポートとして認識しない
- ここが解決したら
ResetProcessor()
が動くようになってリセットボタンのダブルタップが不要になりそう- tinygo flash する時、 taget に従ったファイルが読み込まれる (target/pyportal.json) が、 flash-method が msd なので本当は flash-1200-bsp-reset は false が正しいはず
- この部分が (少なくとも windows 環境に対しては) 間違っているので公式ドキュメント通りに書き込めず -port 指定が必要となっている
- 投稿日:2020-02-24T21:00:37+09:00
今日からGO言語 入門 〜Part2 Import 〜
Go言語 Importについて
Importは、Goが標準で提供するライブラリ(またはパッケージ)をインポートするためのもの
例)
- fmt
- os
- timeなどなど。
パッケージの一覧はこちらImportの書き方
main.goimport "fmt"複数インポートする場合は、
main.goimport ( "fmt" "time" "os/user" )と書くことができる
go docを使用して、コンソールからライブラリ情報を閲覧する方法
[形式]
$ go doc ライブラリー名[例]
$ go doc fmt
- 投稿日:2020-02-24T20:43:40+09:00
今日からGO言語 入門 〜Part1 Hello World 〜
Go言語(Golang)とは
Go言語は、「Go」や「golang」とも呼ばれています。
2009年にGoogleが開発したオープンソースの静的型付プログラミング言語であり、Google社内におけるソフトウェア開発の生産性や拡張性のために開発されました。
Go言語の特徴として、
- 実行速度が速い
- 並列処理に強い
- 拡張性が高い
- 消費リソースが少ない
- シンプルな言語構造
などなど、日本ではまだまだ少ないですが、今後伸びてくる言語だと私は思っています。
Go言語についての詳細はこちらGo言語の学習のため、投稿してアプトプットして行こうかなと思っています。
Go言語をインストールする
Go言語のインストール方法については、下記のリンクの公式サイトからファイルをダウンロードし、インストールしてください。
公式サイトインストールが完了したら、Windowsならコマンドライン、Macならターミナルを起動し、以下のコマンドを入力してください。
Goのバージョンが表示されていれば、インストールが完了しています。$ go version go version go1.13.4 darwin/amd64実際にプログラミングして動かしてみる
とりあえず、最初なのでHello Worldをコンソールに表示させたいと思います。
下記のソースをコピーしてファイルに貼り付けます。
そして、ファイルの名前をmain.goという名前で保存します。
main.gopackage main import "fmt" func main(){ fmt.Prilnt("Hello World") }下記のコマンドを実行すれば、Hello Worldがコンソールに表示されます。
少しだけ、説明すると、fmtというのは、Go言語が提供する標準のライブラリのようなもので、
今回の場合、コンソールに表示するために使用しています。
またGo言語は、C言語とかと同じように、func mainを書かないとエラーに
なってしまいます。
$ go run main.go Hello World
- 投稿日:2020-02-24T17:01:28+09:00
GoでValidationを実装してみる①
GoでValidationを実装してみる①
こんにちは、株式会社アクシス福岡オフィスのueharaです。
この記事は福岡支部にて定期的に行っている開発合宿での内容を記事にした物です。
開催された日時は「2020/01/25」と約1ヶ月前に行われたものとなり、大分投稿が遅くなってしまいましたが、色々と一旦落ち着いたのでやっとのことで投稿するに至りました。私がこの開発合宿で記事を上げるのは2回目となり、基本的には共同開発しているSNSアプリのバックエンド回りの実装を記事にしています。
興味のある方は、前回の記事も読んで頂けると嬉しいです。では、早速始めます!
今回はGoを使ってEmailのValidationを実装したいと思います。要件
ユーザによる新規登録実施前にEmailの重複、及びリクエストされたEmailの文字列が正しい形となっているかをチェックする機能。
利用シーン(ユーザーストーリー)
- SNSアプリに初めてアクセスする
- 登録制のサイトなので「新規登録」ボタンをクリックする
- 新規登録画面に遷移する
- メールアドレスを入力して次へ
上記「手順4」にてユーザーが「次へ」ボタンをクリック後にフロントエンド 側でリクエストデータを詰めてバックエンド側で処理します。この時Emailのバリデーションを実施します。
設計
エンドポイント、インタフェース(リクエストデータやレスポンスデータ)を定義していきたいと思います。
Endpoint
POST /users/check_email
インタフェース
リクエストデータ
{ "email": "xxx@xxx.com" }レスポンスデータ
{ "status": HTTP STATUS "message": Successful Message or Failed Message }
- 成功
- status: 200
- message: successful!
- リクエストメソッドがPOST以外
- status: 400
- message: request method type is need post
- Content-Typeが”application/json”以外
- status: 400
- message: Content-Type entity header is need “application/json”
- emailキーの値がvalidationに通らない
- status: 400
- message: validation target value format is wrong
- Emailに重複がある
- status: 422
- message: already registered
実装方針
「go-playground/validator」を利用していきます。
そのため、「emailキーの値がvalidationに通らない」はこのパッケージに全て任せちゃいます。また、DB操作は jinzhu/gorm を利用します。
実装
今回は「go-playground/validator」を利用した実装とgormを利用したDatabase参照を必要とするvalidationは実装できていません。
そのため、今回の対象となるのは以下です。
- POSTメソッドでない場合
- statusが400
- messageが「request method type is need post」であること
- Content-Typeが”application/json”以外である場合
- statusが400
- messageが「Content-Type entity header is need “application/json”」であること
本来はJSONで返ってくる値のアサーションまでを行いたかったのですが、できませんでした。
なので、「意図した真偽値を返すこと」をテストするところまで実装してみました。
JSONをアサーションするにはエラーハンドリングとか考慮しないといけず、お恥ずかしい話勉強不足で上手く実装できませんでした。。。main.gopackage main import ( "package/validator" "log" "net/http" ) func main() { http.HandleFunc("/users/check_email", validator.CheckEmail) err := http.ListenAndServe(":9000", nil) //監視するポートを設定する。 if err != nil { log.Fatal("ListenAndServe: ", err) } }※上記
main.go
について一つ注意事項がございます。コードを載せていますが、main.go
で読み込んでいる”package/validator”
は自身のリポジトリでパッケージ化しているものとなるため、コードをそのまま載せても動作しません。その点のみご理解ください。user.gopackage validator import ( "encoding/json" "net/http" ) type HttpResult struct { Status int `json:"status"` Message string `json:"message"` } func newDefaultHttpResult() *HttpResult { result := new(HttpResult) result.Status = http.StatusOK result.Message = "successful" return result } func CheckEmail(w http.ResponseWriter, r *http.Request) { result := newDefaultHttpResult() if isPost := isPostMethod(r); !isPost { result.Status = http.StatusBadRequest result.Message = "request method type is need post" } if isJson := isApplicationJson(r); !isJson { result.Status = http.StatusBadRequest result.Message = "Content-Type entity header is need application/json" } if err := json.NewEncoder(w).Encode(result); err != nil { panic(err) } } func isApplicationJson(r *http.Request) bool { if r.Header.Get("Content-Type") != "application/json" { return false } return true } func isPostMethod(r *http.Request) bool { if r.Method != "POST" { return false } return true }TEST
上記でチェックしている「POSTメソッドでない場合」と「Content-Typeが”application/json”以外である場合」のテストを書きたいと思います。対象の関数は「isApplicationJson」と「isPostMethod」ですね。
user_test.gopackage validator import ( "net/http" "testing" ) // リクエストメソッドがPOSTであるためtrueが返ってくることを期待するテストです。 func TestIsPostMethodOK(t *testing.T) { request, _ := http.NewRequest("POST", "", nil) if result := isPostMethod(request); !result { t.Fatal("failed test") } } // リクエストメソッドがGETであるためfalseが返ってくることを期待するテストです。 func TestIsPostMethodNG(t *testing.T) { request, _ := http.NewRequest("GET", "", nil) if result := isPostMethod(request); result { t.Fatal("failed test") } } // Content-Typeがapplication/jsonであるためtrueが返ってくることを期待するテストです。 func TestIsApplicationJsonOK(t *testing.T) { request, _ := http.NewRequest("", "", nil) request.Header.Set("Content-Type", "application/json") if result := isApplicationJson(request); !result { t.Fatal("failed test") } } // Content-Typeがfailedであるためfalseが返ってくることを期待するテストです。 func TestIsApplicationJsonNG(t *testing.T) { request, _ := http.NewRequest("", "", nil) request.Header.Set("Content-Type", "failed") if result := isApplicationJson(request); result { t.Fatal("failed test") } }まとめ
実際に書いてみましたが、勉強不足で思うように実装できなかったです。
本腰入れてGoの勉強をすることにします。
忘れるといけないので現時点で「課題」だと思うものを列挙しとこうと思います。
- そもそもJSONが返ってくるはずなのにそれに対するテストができていない
- エラーハンドリングされていないのでresultが上書きされる
- 真偽値のテストをしているが、最終的なデータをアサーションできないと意味ない
今回実装できなかったところ+上で挙げた課題を②で対応できたらなぁと考えています。
それでは〜
- 投稿日:2020-02-24T16:33:03+09:00
Golang: ピーターからの問題を解いてみた
問題
下記の記事で紹介されているパズルを、Goで解いてみた。
これをjsで解けと会社の上司に言われたんですが全然わからん。
— ケイセイ@JavaScriptと仲良くなりたい (@keisei_otsuka) February 2, 2020
誰かわかります?笑 pic.twitter.com/ZM6VmigaVQRuby: Array#permutationでクイズを解いてみた
https://techracho.bpsinc.jp/hachi8833/2020_02_20/88192Haskell: ピーターからの問題を解いてみた
https://techracho.bpsinc.jp/jhonda/2020_02_21/89044回答
Go (go 1.12.1)
https://ideone.com/3AB5t2package main import "fmt" func main() { n := 9 ans := make([]int, n) for i := range ans { ans[i] = i + 1 } evaluate := func(a []int) bool { div0 := a[1]*10 + a[2] div1 := a[4]*10 + a[5] div2 := a[7]*10 + a[8] return a[0]*div1*div2+a[3]*div0*div2+a[6]*div0*div1 == div0*div1*div2 } // (開発用)生成したpermutationの総数を確認 cnt := 0 _ = cnt var permutate func(int) permutate = func(s int) { if s+2 < n { permutate(s + 1) } else { if evaluate(ans) { fmt.Println(ans) } cnt++ } for i := s + 1; i < n; i++ { ans[s], ans[i] = ans[i], ans[s] permutate(s + 1) ans[s], ans[i] = ans[i], ans[s] } } permutate(0) // fmt.Println(cnt) // must be n! }
- 投稿日:2020-02-24T15:01:54+09:00
aws sdk goでAPIスロットリングした時のリトライ回数を指定する
aws-sdk-go を利用してAPIから
ThrottlingException: Rate exceeded
が発生した際のデバッグ方法とリトライ試行回数の指定方法package main import ( "context" "fmt" "log" "sync" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/cloudwatchlogs" "github.com/aws/aws-sdk-go/service/ec2" ) func main() { mySession := session.Must(session.NewSession()) loop := 10 var wg sync.WaitGroup wg.Add(loop) // 意図的にスロットリングを発生させるために並列実行している for i := 0; i < loop; i++ { go func() { getLogs(mySession) wg.Done() }() } wg.Wait() } func getLogs(sess *session.Session) { svc := cloudwatchlogs.New(sess, aws.NewConfig().WithMaxRetries(10)) // リトライ試行回数を指定 t := time.Now().Add(-time.Hour).Unix() * 1000 ctx := context.Background() for i := 0; i < 100; i++ { res, err := svc.FilterLogEventsWithContext(ctx, &cloudwatchlogs.FilterLogEventsInput{ FilterPattern: aws.String(""), LogGroupName: aws.String("/aws/apigateway/welcome"), StartTime: aws.Int64(t), }, request.WithLogLevel(aws.LogDebugWithRequestErrors), // リクエストエラーのデバッグ表示(リトライの度に表示される) ) if err != nil { e, ok := err.(awserr.Error) if ok { log.Printf("i=%d FilterLogEvents code:%s message:%s", i, e.Code(), e.Message()) return } log.Printf("i=%d FilterLogEvents err:%s", i, err) return } if len(res.Events) > 0 { log.Printf("len(events)=%d", len(res.Events)) } } }
- 投稿日:2020-02-24T12:21:12+09:00
COTOHA アクセストークンの取得 (Golang)
COTOHA API Portal の使用例です。
次と同じことを Golang で行いました。
ライブラリーのインストール
go get github.com/joho/godotenvaccess_token.go// --------------------------------------------------------------- // // access_token.go // // Feb/24/2020 // --------------------------------------------------------------- package main import ( "fmt" "os" "strings" "io/ioutil" "net/http" "encoding/json" "github.com/joho/godotenv" ) // --------------------------------------------------------------- func main() { fmt.Fprintf (os.Stderr,"*** 開始 ***\n") err := godotenv.Load() if err != nil { fmt.Println("Error loading .env file") } unit_aa := make (map[string]interface{}) unit_aa["grantType"] = "client_credentials" unit_aa["clientId"] = os.Getenv("CLIENT_ID") unit_aa["clientSecret"] = os.Getenv("CLIENT_SECRET") str_json, _ := json.Marshal(unit_aa) url_target := os.Getenv("ACCESS_TOKEN_PUBLISH_URL") response, error := http.Post(url_target,"application/json", strings.NewReader(string(str_json))) if error != nil { fmt.Println("Request error:", error) } bb, err := ioutil.ReadAll(response.Body) if err == nil { fmt.Println(string(bb)) } fmt.Fprintf (os.Stderr,"*** 終了 ***\n") } // ---------------------------------------------------------------実行コマンド
go run access_token.go
- 投稿日:2020-02-24T10:46:14+09:00
Golang の http クライアントの使い方 (Post)
http_post.go// --------------------------------------------------------------- // // http_post.go // // Feb/24/2020 // --------------------------------------------------------------- package main import ( "fmt" "io/ioutil" "net/http" "net/url" ) // --------------------------------------------------------------- func main() { fmt.Printf ("*** 開始 ***\n") url_target := "https://httpbin.org/post" args := url.Values{} args.Add("user","jiro") args.Add("password","123456") res, err := http.PostForm(url_target,args) if err != nil { fmt.Println("Request error:", err) return } defer res.Body.Close() body, err := ioutil.ReadAll(res.Body) if err != nil { fmt.Println("Request error:", err) return } str_json := string(body) fmt.Println(str_json) fmt.Printf ("*** 終了 ***\n") } // ---------------------------------------------------------------実行結果
$ go run http_post.go *** 開始 *** { "args": {}, "data": "", "files": {}, "form": { "password": "123456", "user": "jiro" }, "headers": { "Accept-Encoding": "gzip", "Content-Length": "25", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "User-Agent": "Go-http-client/2.0", "X-Amzn-Trace-Id": "Root=1-5e532ac5-3fd72da01bd57240d7b094c8" }, "json": null, "origin": "163.49.213.57", "url": "https://httpbin.org/post" } *** 終了 ***
- 投稿日:2020-02-24T10:43:43+09:00
Golang の http クライアントの使い方 (Get)
http_get.go// --------------------------------------------------------------- // // http_get.go // // Feb/24/2020 // --------------------------------------------------------------- package main import ( "fmt" "io/ioutil" "net/http" ) // --------------------------------------------------------------- func main() { fmt.Printf ("*** 開始 ***\n") url_target := "https://httpbin.org/get" res, err := http.Get(url_target) if err != nil { fmt.Println("Request error:", err) return } defer res.Body.Close() body, err := ioutil.ReadAll(res.Body) if err != nil { fmt.Println("Request error:", err) return } str_json := string(body) fmt.Println(str_json) fmt.Printf ("*** 終了 ***\n") } // ---------------------------------------------------------------実行結果
$ go run http_get.go *** 開始 *** { "args": {}, "headers": { "Accept-Encoding": "gzip", "Host": "httpbin.org", "User-Agent": "Go-http-client/2.0", "X-Amzn-Trace-Id": "Root=1-5e532a2d-03367851ed2afcb58a0a452d" }, "origin": "163.49.213.57", "url": "https://httpbin.org/get" } *** 終了 ***