ウェブサービスのログ設計についてメモ
ログの設計について、ググっても断片的にしか見つからなかったのでメモ。
ログの目的
- 不具合の原因を特定するため
- 不正利用の検出
- 利用統計の取得
ログレベル
- fatal
サービス全体の提供が不可能な状態になる状態。DBに接続できないとか、syntaxエラーがある場合など。このレベルのログが出るとインフラ担当の人達にメールが飛んだりする。
- error
全体が止まるほどではないが、ユーザーの一部の処理が完了しないような場合が該当する。エラーページが表示されるような場合はこのレベル。
- warn
言語自体のwarningや処理フロー上来ることがない値がかえって来た場合などはこのレベル。(例えばユーザーが不正にAPIを叩いてブロックされた時とか) 状況によってはerror相当なので場合によりけり。
- info
このレベルから下は開発者の胃を傷めないログレベル。アクセスログなど。hadoopでコネコネしたりして企画担当が利用したりする。
- debug
これ以下は開発時に欲しい情報。本番環境では出力しない。
- trace
println("ここまで処理が来た")
何をログとして残すか
例えばユーザーの行動についてなら
- [いつ]アクセス日時
- [誰が]ユーザ情報(ID)/ホスト/ポート/ユーザーエージェント
- [何をした] ログファイルを切り替えてファイル名で表現する(例)login_failure.log
異なるファイルにログを出力するのは重要。特定のログに素早くアクセスでき、かつログの種類によって保存期間や閲覧権限を変えたりできる。機能とユーザー数が増えるほどその恩恵にあずかれる。
ログをどれだけの期間保存するか。
ログの重要度と書き込み頻度によって決める。
(容量肥大対策の一例)
ログを一日ごとのログローテーションで記録し、30日間保存する場合、前日のログはすぐアクセスできるようにファイル圧縮して同じディレクトリにおき、それ以前はバックアップサーバーに送って30日前まで保存するようにするなど。
ログのドキュメントに何を書くか。
ドキュメントを整備・保守しつづけないと、「どこで使用されているかわからないので消せないログ出力」が生まれてコードのエントロピーが増大する。
ログに何を書いてはいけないか
メールアドレスなどの特に重要な個人情報をログに残さないようにする。
ログに書くこと
- 作成者
- 出力条件
(例)認証キー発行APIを実行した時
- 利用目的
(例)不正利用がないか記録を残します
- フォーマット
- ログの例
ログ設計について何かよい資料があったら誰か教えてください。
play-slickを試した
play framework + Java + ebeanで色々やったので、今度はscalaでDB操作をしたかった。
調べるとSquerylとslickとで人気を二分しているらしい。今回はscalaの勉強であることとtypesafe stackに入っていることも考えてslickを試してみた。
play frameworkとslickを使うサンプルがすでにgithub上にあるが、どうもうまく統合できていないように感じたので調べたところplay-slickというプラグインがあるらしいので動かすところまでメモ。
環境
- play framework 2.1.1
- slick 2.10.0-RC5
- play-slick 0.3.2
howto
いつもどおりplay new
play new mySlickSample
project/Build.scalaに追加
val appDependencies = Seq( //...他の依存ライブラリ "com.typesafe" % "slick_2.10.0-RC5" % "0.11.2", "com.typesafe.play" %% "play-slick" % "0.3.2" )
application.confにDBの設定
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
play-slickを有効にする設定をapplication.confに追加。
このへんはebeanと同じですね。
# slick # ~~~~~ # It is possible to specify individual objects like: # slick.default="models.Users,models.Settings" slick.default="models.*"
modelを作成
package models import play.api.db.slick.Config.driver.simple._ case class User( id: Option[Long],//privary keyの場合はOption name: String) object Users extends Table[User]("USERS") { def id = column[Long]("ID", O.PrimaryKey, O AutoInc) // This is the primary key column def name = column[String]("COF_NAME") def * = id.? ~ name <> (User.apply _, User.unapply _) //とりあえずfindAllだけ def findAll(filter: String = "%") = { //scalaのコレクションっぽく扱えるのが素敵 for { u <- Users if (u.name like ("%" + filter)) } yield u } }
controllerも
package controllers import models.Users import play.api._ import play.api.Play.current import play.api.db.slick.Config.driver.simple._ import play.api.mvc._ object Application extends Controller { def index = Action { //controllerでwithSessionを使うのが気持ち悪い気がするのだが、これでいいのだろうか? play.api.db.slick.DB.withSession { implicit session => val users = Users.findAll().list Ok(views.html.index(users)) } } }
view
@(users: List[User]) @main("slick test") { <ul> @for(u <- users){ <li>@u.toString()</li> } </ul> }
あとappのdefault packageにGlobal.scalaとか作っておいて、
import play.api.Application import play.api.GlobalSettings import play.api.Play.current import play.api.db.slick.Config.driver.simple._ import models.Users import models.User object Global extends GlobalSettings { override def onStart(app: Application) { play.api.db.slick.DB withSession {implicit session => Users.insertAll( User(None, "jhon"), User(None, "bob")) } } }
とやればテスト用データを入れておける。
localhost:9000にアクセスすれば表示できる。
次はtodoアプリを作ろう。
参考
Slick ガイド - tototoshiの日記
Slick
追記(2013/6/25)
今後play frameworkではAnormからslickに移行していくようだ。
play-slickがplay framework本体にプルリクされているようで
https://github.com/playframework/Play20/pull/1230
wktkが止まらないですね。
MS932で指定した方がよかったメモ
charset=Shift_JIS
なのに
Source.fromURL(vipSubjectsUrl, "Shift_JIS")
で「たまに」失敗することがあって困った。他言語でよく指定する"CP932"がないので30分くらい詰まった。 正解として "CP932"ではなく"MS932"を指定するらしい。
参考: http://blue-red.ddo.jp/~ao/wiki/wiki.cgi?page=Java+%A4%CE+MS932%2C+Cp943C%2C+SJIS+%A4%CE%B0%E3%A4%A4
play framework + Java + Ebean + eclipseでJUnitテストが起動に失敗するときの対処法
現象: play.db.ebean.Modelを継承したModelをテストする際に以下のメッセージがコンソールに出てエラーになる。
環境:
- play framework 2.1.1
- eclipse juno(4.2 RC2)
対処法: VM引数にjavaagentを設定する.
- ebeanを公式(http://www.avaje.org/download.html)から適当な場所にダウンロード&&解凍
- テストのVM引数に-javaagent:/path/to/ebean-2.7.0-agent.jarを設定
3.実行すれば問題が解消されるはず。
参考: http://blog.matthieuguillermin.fr/2012/03/unit-testing-tricks-for-play-2-0-and-ebean/
残る疑問