sampleをつかわずに、自力でやるのは大変そうだけど気になる。。
goaの構造
ロギングを見るうちに理解について課題があるなと感じた。
serverのmain.goのserviceはどういう意味か。
serviceにロギングの設定を与えればコントローラーにも伝えられる。
(実行順には注意)
mainの実装コメントの間にだけ実装するという縛り
サンプルをみてもコメントの外に記述してたりする。
gormaのためにコントローラーへの引数を追加して、dbを渡す。
contextを使うにしてもmainは変更せざるを得なさそうな。。
どうするのがいいのかしら。とりあえず保留。
たぶん、goage main --regen
は諦めるしかないんだろうな。
DBの引き回し
どうやら、サンプルのcontrollerへの渡し方は公式サンプルのシンプルな例と同様なもの。
理由があってcontrollerに引数を増やす方式なのかもしれないが、
可能ならregenを使う方向に持っていきたいのでcontext経由にしてみよう。
goa の controller を実装する - 押してダメならふて寝しろ
http://ikawaha.hateblo.jp/entry/2016/10/11/234941
goadesign/goa-cellar: goa winecellar example service
https://github.com/goadesign/goa-cellar
if *db_run {
db_con, err := gorm.Open("postgres", os.Getenv("DB_ENV"))
if err != nil {
log.Fatalf("database initialization failed: %s", err)
}
service.Use(mymiddleware.Database(db_con))
}
db := ctx.Value("DB").(*gorm.DB)
bdb := models.NewUserDB(db)
わーい、うまくいったぜい。Valueで受け取ってからキャスト(?)するところが詰まったけど。
これでいいのかどうか。。
contextの使い方 - Qiita
http://qiita.com/taizo/items/69d3de8622eabe8da6a2
ミドルウェアの概要
使って見つつも、まだよくわかってない。
reduxをやったときのやつと似てる。。
リクエストミドルウエア · goa :: Design-first API Generation
https://goa.design/ja/implement/middleware/
ミドルウエアを書くことは、すなわち、ハンドラを受け取ってハンドラを返す関数を書くことからなります:
...
設定情報をパラメータとして受け付け、クロージャを使用してミドルウェアを構築するコンストラクタ・メソッドを提供することで簡単に達成できます
おー、すごい。
goaでお手軽google loginを行うミドルウェアを作ってみました。 - Qiita
http://qiita.com/m0a/items/af1ed672e6d4db53ed76
goaで手軽にwebAPIをつくれるのはいいのですが、ユーザ認証が意外と面倒です。
かと言って個人開発でauth0とか使ってられないし。
googleアカウントで認証を行いtokenを発行して以降、それを使って
通信を行いたいです。できるだけ手軽に。
そういうのが簡単に実現できるミドルウェアを作ってみました。
またセキュリテイ上の懸念があるようでしたらご指摘いただければ幸いです。
実際に動かして見た。
いくらか説明には記載がないところは自力で動かしつつやってみたり、
exampleのサンプルコードを確認していったら動いた。
公式のセキュリティのページも見た。
あとは、モデルがgormaなのでマニュアルカスタマイズのディレクトリを追加してみたが、、今後整理かもな。
なるほどー。今後、ブラウザ側と連携するときに使うかもなあ。。
gogen js
で作られるjsとの親和性があればいいなー。
Google アカウントの認証を OpenID から OpenID Connect に移行する方法 - WebOS Goodies
http://webos-goodies.jp/archives/how_to_migrate_from_openid_to_openid_connect.html
セキュリティ · goa :: Design-first API Generation
https://goa.design/ja/design/security/
JSON Web Token の効用 - Qiita
http://qiita.com/kaiinui/items/21ec7cc8a1130a1a103a
goaのロギング
まだわかってなかった。
いろいろ詰まった。
結局はコントローラーの処理の実行の後にログアダプターの設定をしていたことが原因だった。。ひどい。
おかげさまで、logAdapterについて、いろいろメソッドがあるけど理解していない不安感がある。
ロギングとバッファー
コマンドでデバッグするときにはエラーが見えつつ、ファイルにも出力するロギングとか。
バッファーをつかって標準出力を扱う必要がわからないけどひとまずメモ。
bytes.Buffer
bufio
io/ioutil
golangのファイルへの読み書きのまとめ | Hackers Log
https://hackerslog.net/post/labs/golang-io-summary/
今の標準パッケージには、同様以上の機能が実装されています。 そこで、簡単にですが、そのパッケージの紹介をします。
golangでlogを標準出力とテキストファイルの2箇所の出力する - Qiita
http://qiita.com/74th/items/441ffcab80a6a28f7ee3
2箇所に出力したい場合、io.MultiWriterが便利。
あ、でも、ファイル出力有効にしてたままbuildした場合にどうなっちゃうんだろう。。
いろんな例
// Create logger
logger := log.New("module", "app/server")
// Configure it
logger.SetHandler(log.StreamHandler(os.Stderr, log.LogfmtFormat()))
// Inject it
service.WithLogger(goalog15.New(logger))
公式の例
公式で用意されている
いろんなログのための実装を利用する場合には
これがスタンダードな記述ってことかしら
これをどこに記述すればいいか不安な気持ちでmainに書いてみてうまく動かなくってドツボに。。
まだよくわからん。
logBuf := bytes.Buffer
logger := log.New(&logBuf, "", log.Ltime)
service.WithLogger(goa.NewLogger(logger))
Talks - The Go Programming Language
https://talks.goa.design/slides/gophercon2016/demos
https://talks.goa.design/slides/gophercon2016/demos/3-document/app/test/bottle_testing.go
第2引数では、ログの文頭の文字列を設定
log.Ltime
とある第3引数はlog.LstdFlags
だと日付(Ldate)もつくのね
二回newしているのがややこしい気もしたけど、最初はロガーをインスタンス化(?)、
次でゴアのロガーとしてのオブジェクト(?)を生成、
WithLoggerでDIって、公式に書いてる。
サービスのインスタンス直後にミドルウェアの読み込みより先にロガーを設定してる。。
そのほうがいいのかな。
logger := goa.NewLogger(log.New(os.Stderr, "", log.LstdFlags))
ctx := goa.WithLogger(context.Background(), logger)
生成された/tool/cli/commands.goにあるログ処理。
公式のcontextパッケージをつかってる。
Go1.7のcontextパッケージ | SOTA
http://deeeet.com/writing/2016/07/22/context/
golangでcontextパッケージを使う - write ahead log
http://twinbird-htn.hatenablog.com/entry/2017/04/07/214420
ふーむ、並列処理とかのときにコンテキストという単位で管理するためのパッケージ?
サーバープロセスとプロセスマネージャーみたいな関係の時?
import "github.com/goadesign/goa/logging"
// Setup logger adapter
logger := log15.New()
// Create service
service := goa.New("my service")
service.WithLogger(goalog15.New(logger))
こっちも公式だな。
ContextLoggerってなんだろう
goa - GoDoc
https://godoc.org/github.com/goadesign/goa
ContextLoggerは、指定されたコンテキストからロガーを抽出します。
コンテキストごとにロガーが違う場合とか、、例えば、何かの外部ライブラリのロガーをつかって書き込むとかそういうこと??
保留。
改めてどのロガーを使うか
goaで用意しているやつから選ぶか。。
直感ではgo-kitが良さそうなんだけど、、記事とか少ないしひとまずいいかな。。
6年間におけるGoのベストプラクティス | プログラミング | POSTD
http://postd.cc/go-best-practices-2016/#logging-and-instrumentation
構造化ログを使う。偏見ながら、go-kit/logが良い。
Go Logging | LibHunt
https://go.libhunt.com/categories/504-logging
一旦、log15でターミナル向けのフォーマットを指定して、
慣れてきたら構造化ログにしていくとかかしら。。
逐次パッケージの選定に時間を食いそうだけど。。
log15でのロギングの準備
公式にあるように、mainに下記を定義したらコントローラーから呼び出せる。
ミドルウェアでコンテキストから使う方法はまだよくわかってない。(WithLogContextとか)
// define logInfo, logWarn, and logError globally:
func LogDebug(ctx context.Context, msg string, keyvals...interface{}) {
goalog15.Logger(ctx).Debug(msg, keyvals...)
}
func LogInfo(ctx context.Context, msg string, keyvals...interface{}) {
goalog15.Logger(ctx).Info(msg, keyvals...)
}
func LogWarn(ctx context.Context, msg string, keyvals...interface{}) {
goalog15.Logger(ctx).Warn(msg, keyvals...)
}
func LogError(ctx context.Context, msg string, keyvals...interface{}) {
goalog15.Logger(ctx).Error(msg, keyvals...)
}
func LogCrit(ctx context.Context, msg string, keyvals...interface{}) {
goalog15.Logger(ctx).Crit(msg, keyvals...)
}
複数のロガーを設定しても動くことは動いた
後からやったやつが利用される。でも、前者も読み込まれていてコンテキストから取得できた。。
特に意味ない。
logger := log15.New()
logger.SetHandler(log15.StreamHandler(io.MultiWriter(logfile, os.Stdout), log15.TerminalFormat()))
service.WithLogger(goalog15.New(logger))
std_logger := log.New(io.MultiWriter(logfile, os.Stdout), "", log.LstdFlags)
logger2 := goa.NewLogger(std_logger)
service.WithLogger(logger2)
ポインタ渡し、参照渡し
いまいち使いどころがわかってない。
値渡し、ポインタ渡し、参照渡しの違い - Qiita
http://qiita.com/Rompei/items/e70e3b453cb485858062
そのうち読んだ方が良さそう
6年間におけるGoのベストプラクティス | プログラミング | POSTD
http://postd.cc/go-best-practices-2016/#logging-and-instrumentation