egalite 1.4.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -123,6 +123,18 @@ egaliteには自動でCSRF対策のチェック値を埋め込む機能が付い
123
123
  class Pages < Egalite::CSRFController
124
124
  end
125
125
 
126
+ ## エラー処理
127
+
128
+ 例外が発生した場合、:error_templateに設定されたHTMLテンプレートを表示します。
129
+
130
+ このテンプレートには:exception_log_tableが指定されている場合は、記録されたエラーログ番号がlogidとして埋め込まれます。これによりシステムエラー時のユーザからの問い合わせに迅速に対応することができるようになります。
131
+
132
+ Egalite::UserErrorまたはEgalite::SystemErrorという例外が送出された場合には、その中のmessageがテンプレートにmessageとして埋め込まれます。これにより簡易的にユーザーにエラーメッセージを表示することができます。
133
+
134
+ UserError例外はエラーログに記録されません。
135
+
136
+ UserError例外発生時には、テンプレートにusererror => trueが引き渡されます。
137
+
126
138
  ## モジュール
127
139
 
128
140
  ### キャッシュモジュール
@@ -167,3 +179,14 @@ RDBMSでのテーブル定義は以下の通り。
167
179
 
168
180
  HTMLテンプレートに記載された文章や画像はm17n.txtに記述するだけで、コントローラーには一切手を加えることなく多言語化が可能です。
169
181
 
182
+ ## リリースノート
183
+
184
+ ### 1.5
185
+
186
+ UserErrorとSystemError例外が追加されました。これによりユーザにエラーメッセージを容易に表示できます。
187
+
188
+ :error_template_fileが追加されました。ファイル名を指定するだけでエラーテンプレートが読み込まれるようになります。
189
+
190
+ ### 1.5.1
191
+
192
+ Egalite::ErrorLogger.catch_exception(sendmail) {}が追加されました。これを使うと、任意のブロックで発生した例外をキャッチして、管理者へのメール送信やログの出力を行います。重要なエラーが発生する可能性がある場所への利用に適しています。
@@ -1,3 +1,3 @@
1
1
  module Egalite
2
- VERSION = "1.4.0"
2
+ VERSION = "1.5.1"
3
3
  end
data/lib/egalite.rb CHANGED
@@ -29,6 +29,12 @@ class CriticalError < RuntimeError
29
29
  end
30
30
 
31
31
  module Egalite
32
+ class UserError < RuntimeError
33
+ # ユーザーの手順によるエラーを記録する。ログに残らない。
34
+ end
35
+ class SystemError < RuntimeError
36
+ # システムのエラーを記録する。ログに残る。
37
+ end
32
38
 
33
39
  module AccessLogger
34
40
  @@io = nil
@@ -85,34 +91,59 @@ module Egalite
85
91
  module ErrorLogger
86
92
  @@table = nil
87
93
  @@admin_emails = nil
94
+ @@email_from = nil
88
95
  class <<self
96
+ def create_table(db, opts = {})
97
+ table = opts[:table_name] || :logs
98
+
99
+ db.create_table(table) {
100
+ primary_key :id, :integer, :auto_increment => true
101
+ column :severity, :varchar
102
+ column :ipaddress, :varchar
103
+ column :text, :varchar
104
+ column :url, :varchar
105
+ column :md5, :varchar
106
+ column :created_at, :timestamp
107
+ column :checked_at, :timestamp
108
+ }
109
+ end
89
110
  def table=(t)
90
111
  @@table=t
91
112
  end
92
113
  def admin_emails=(t)
93
114
  @@admin_emails=t
94
115
  end
95
- def write(hash)
116
+ def email_from=(t)
117
+ @@email_from=t
118
+ end
119
+ def write(hash, sendmail = false)
96
120
  hash[:md5] = Digest::MD5.hexdigest(hash[:text]) unless hash[:md5]
97
- if hash[:severity] == 'critical' and @@admin_emails
121
+ if (hash[:severity] == 'critical' or sendmail) and @@admin_emails
98
122
  Sendmail.send(hash[:text],{
99
- :from => 'info@xcream.net',
123
+ :from => @@email_from || "egalite@example.com",
100
124
  :to => @@admin_emails,
101
- :subject => 'Critical error at xcream.net'
125
+ :subject => "Exception report from Egalite framework."
102
126
  })
103
127
  end
104
128
  if @@table
105
129
  @@table.insert(hash) rescue nil
106
130
  end
107
131
  end
108
- def write_exception(e, hash)
132
+ def write_exception(e, hash, sendmail = false)
109
133
  severity = 'exception'
110
134
  severity = 'security' if e.is_a?(SecurityError)
111
135
  severity = 'critical' if e.is_a?(CriticalError)
112
136
 
113
137
  text = "#{e.to_s}\n#{e.backtrace.join("\n")}"
114
138
 
115
- ErrorLogger.write({:severity => severity, :text => text}.merge(hash))
139
+ ErrorLogger.write({:severity => severity, :text => text}.merge(hash),sendmail)
140
+ end
141
+ def catch_exception(sendmail = false, hash = {})
142
+ begin
143
+ yield
144
+ rescue Exception => e
145
+ ErrorLogger.write_exception(e, hash, sendmail)
146
+ end
116
147
  end
117
148
  end
118
149
  end
@@ -389,12 +420,18 @@ class Handler
389
420
 
390
421
  @profile_logger = opts[:profile_logger]
391
422
  @notfound_template = opts[:notfound_template]
392
- @error_template = opts[:error_template]
423
+ if opts[:error_template_file]
424
+ @error_template = File.open(opts[:error_template_file]).read
425
+ else
426
+ @error_template = opts[:error_template]
427
+ end
393
428
  @admin_emails = opts[:admin_emails]
429
+ @email_from = opts[:email_from]
394
430
  @exception_log_table = opts[:exception_log_table]
395
431
  if @exception_log_table
396
432
  Egalite::ErrorLogger.table = db[@exception_log_table]
397
433
  Egalite::ErrorLogger.admin_emails = @admin_emails
434
+ Egalite::ErrorLogger.email_from = @email_from
398
435
  end
399
436
  end
400
437
 
@@ -704,7 +741,7 @@ class Handler
704
741
  begin
705
742
  # write error log
706
743
  logid = nil
707
- if @exception_log_table
744
+ if @exception_log_table and not e.is_a?(UserError)
708
745
  logid = ErrorLogger.write_exception(e,{:ipaddress => req.ip, :url => req.url})
709
746
  end
710
747
 
@@ -715,6 +752,8 @@ class Handler
715
752
  values[:logid] = logid if logid
716
753
  values[:exception] = e.to_s
717
754
  values[:backtrace] = e.backtrace
755
+ values[:message] = e.message if e.is_a?(UserError) or e.is_a?(SystemError)
756
+ values[:usererror] = true if e.is_a?(UserError)
718
757
  html = @template_engine.new.handleTemplate(@error_template.dup,values)
719
758
  res = [500, {"Content-type"=>"text/html; charset=utf-8"}, [html]]
720
759
  else
@@ -0,0 +1,16 @@
1
+ <html>
2
+ <body>
3
+ <p>
4
+ logid: &=logid;
5
+ </p>
6
+ <p>
7
+ message: &=message;
8
+ </p>
9
+ <p>
10
+ <if name='usererror'>
11
+ this is usererror
12
+ </if>
13
+ </p>
14
+ </body>
15
+ </html>
16
+
@@ -0,0 +1,46 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '..')
3
+
4
+ require 'rubygems'
5
+ require 'test/unit'
6
+ require 'lib/egalite'
7
+
8
+ require 'rack'
9
+ require 'rack/multipart'
10
+ require 'rack/test'
11
+
12
+ require 'setup'
13
+
14
+ class ErrorLoggerController < Egalite::Controller
15
+ def foo
16
+ Egalite::ErrorLogger.catch_exception(true) {
17
+ raise "piyolog"
18
+ }
19
+ "hoge"
20
+ end
21
+ end
22
+
23
+ class T_ErrorLogger < Test::Unit::TestCase
24
+ include Rack::Test::Methods
25
+
26
+ def app
27
+ db = Sequel.sqlite
28
+ @db = db
29
+ Egalite::ErrorLogger.create_table(db)
30
+ Egalite::Handler.new({
31
+ :admin_emails => "to@example.com",
32
+ :email_from => "from@example.com",
33
+ :exception_log_table => :logs,
34
+ :db => db,
35
+ })
36
+ end
37
+ def test_errortemplate
38
+ Sendmail.mock = true
39
+ get "/error/logger/foo"
40
+ assert last_response.ok?
41
+ assert_equal "hoge", last_response.body
42
+ assert_equal "from@example.com", Sendmail.lastmail[1]
43
+ assert_match /piyolog/, Sendmail.lastmail[0]
44
+ assert_match /piyolog/, @db[:logs].first[:text]
45
+ end
46
+ end
@@ -0,0 +1,35 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '..')
3
+
4
+ require 'rubygems'
5
+ require 'test/unit'
6
+ require 'lib/egalite'
7
+
8
+ require 'rack'
9
+ require 'rack/multipart'
10
+ require 'rack/test'
11
+
12
+ require 'setup'
13
+
14
+ class ErrorTemplateController < Egalite::Controller
15
+ def foo
16
+ raise Egalite::UserError.new("UserError")
17
+ end
18
+ end
19
+
20
+ class T_ErrorTemplate < Test::Unit::TestCase
21
+ include Rack::Test::Methods
22
+
23
+ def app
24
+ Egalite::Handler.new(
25
+ :error_template_file => "test/error_template.html"
26
+ )
27
+ end
28
+ def test_errortemplate
29
+ $raise_exception = false
30
+ get "/error/template/foo"
31
+ assert_match /message: UserError/, last_response.body
32
+ assert_match /this is usererror/, last_response.body
33
+ $raise_exception = true
34
+ end
35
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: egalite
3
3
  version: !ruby/object:Gem::Version
4
- hash: 7
4
+ hash: 1
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
- - 4
9
- - 0
10
- version: 1.4.0
8
+ - 5
9
+ - 1
10
+ version: 1.5.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Shunichi Arai
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2014-09-24 00:00:00 Z
18
+ date: 2015-01-15 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: bundler
@@ -117,6 +117,7 @@ files:
117
117
  - test/cache.html
118
118
  - test/cache_cache.html
119
119
  - test/cache_nocache.html
120
+ - test/error_template.html
120
121
  - test/french.html
121
122
  - test/french_msg.html
122
123
  - test/m17n.txt
@@ -131,6 +132,8 @@ files:
131
132
  - test/test_cache.rb
132
133
  - test/test_csrf.rb
133
134
  - test/test_errorconsole.rb
135
+ - test/test_errorlogger.rb
136
+ - test/test_errortemplate.rb
134
137
  - test/test_handler.rb
135
138
  - test/test_helper.rb
136
139
  - test/test_keitai.rb
@@ -177,6 +180,7 @@ test_files:
177
180
  - test/cache.html
178
181
  - test/cache_cache.html
179
182
  - test/cache_nocache.html
183
+ - test/error_template.html
180
184
  - test/french.html
181
185
  - test/french_msg.html
182
186
  - test/m17n.txt
@@ -191,6 +195,8 @@ test_files:
191
195
  - test/test_cache.rb
192
196
  - test/test_csrf.rb
193
197
  - test/test_errorconsole.rb
198
+ - test/test_errorlogger.rb
199
+ - test/test_errortemplate.rb
194
200
  - test/test_handler.rb
195
201
  - test/test_helper.rb
196
202
  - test/test_keitai.rb