-
Notifications
You must be signed in to change notification settings - Fork 0
/
debugging_rails_applications.html
915 lines (824 loc) · 49.3 KB
/
debugging_rails_applications.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>除錯 Rails 應用程式 — Ruby on Rails 指南</title>
<meta name="description" content="Ruby on Rails 指南:系統學習 Rails(Rails 4.2 版本)" >
<meta name="keywords" content="Ruby on Rails Guides 指南 中文 學習 免費 網路 Web 開發" >
<meta name="author" content="http://git.io/G_R1sA">
<meta property="fb:admins" content="1340181291">
<meta property="og:title" content="除錯 Rails 應用程式 — Ruby on Rails 指南" >
<meta property="og:site_name" content="Ruby on Rails 指南">
<meta property="og:image" content="http://rails.ruby.tw/images/rails_guides_cover.jpg">
<meta property="og:url" content="http://rails.ruby.tw/">
<meta property="og:type" content="article">
<meta property="og:description" content="Ruby on Rails 指南:系統學習 Rails(Rails 4.2 版本)">
<link rel="stylesheet" href="stylesheets/application.css">
<link href="http://fonts.googleapis.com/css?family=Noto+Sans:400,700|Noto+Serif:700|Source+Code+Pro" rel="stylesheet">
<link href="images/favicon.ico" rel="shortcut icon" type="image/x-icon">
</head>
<body class="guide">
<div id="fb-root"></div>
<script>(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/zh-TW/sdk.js#xfbml=1&appId=837401439623727&version=v2.0";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
<script type="text/javascript">
window.twttr=(function(d,s,id){var t,js,fjs=d.getElementsByTagName(s)[0];if(d.getElementById(id)){return}js=d.createElement(s);js.id=id;js.src="https://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);return window.twttr||(t={_e:[],ready:function(f){t._e.push(f)}})}(document,"script","twitter-wjs"));
</script>
<div id="topNav">
<div class="wrapper">
<strong class="more-info-label">更多內容 <a href="http://rubyonrails.org/">rubyonrails.org:</a></strong>
<span class="red-button more-info-button">
更多內容
</span>
<ul class="more-info-links s-hidden">
<li class="more-info"><a href="http://rubyonrails.org/">綜覽</a></li>
<li class="more-info"><a href="http://rubyonrails.org/download">下載</a></li>
<li class="more-info"><a href="http://rubyonrails.org/deploy">部署</a></li>
<li class="more-info"><a href="https://github.com/rails/rails">原始碼</a></li>
<li class="more-info"><a href="http://rubyonrails.org/screencasts">影片</a></li>
<li class="more-info"><a href="http://rubyonrails.org/documentation">文件</a></li>
<li class="more-info"><a href="http://rubyonrails.org/community">社群</a></li>
<li class="more-info"><a href="http://weblog.rubyonrails.org/">Blog</a></li>
</ul>
</div>
</div>
<div id="header">
<div class="wrapper clearfix">
<h1><a href="index.html" title="回首頁">Guides.rubyonrails.org</a></h1>
<ul class="nav">
<li><a class="nav-item" href="index.html">首頁</a></li>
<li class="guides-index guides-index-large">
<a href="index.html" id="guidesMenu" class="guides-index-item nav-item">指南目錄</a>
<div id="guides" class="clearfix" style="display: none;">
<hr>
<dl class="L">
<dt>起步走</dt>
<dd><a href="getting_started.html">Rails 起步走</a></dd>
<dt>Models</dt>
<dd><a href="active_record_basics.html">Active Record 基礎</a></dd>
<dd><a href="active_record_migrations.html">Active Record 遷移</a></dd>
<dd><a href="active_record_validations.html">Active Record 驗證</a></dd>
<dd><a href="active_record_callbacks.html">Active Record 回呼</a></dd>
<dd><a href="association_basics.html">Active Record 關聯</a></dd>
<dd><a href="active_record_querying.html">Active Record 查詢</a></dd>
<dt>Views</dt>
<dd><a href="layouts_and_rendering.html">Rails 算繪與版型</a></dd>
<dd><a href="form_helpers.html">Action View 表單輔助方法</a></dd>
<dt>Controllers</dt>
<dd><a href="action_controller_overview.html">Action Controller 綜覽</a></dd>
<dd><a href="routing.html">Rails 路由:深入淺出</a></dd>
</dl>
<dl class="R">
<dt>深入了解</dt>
<dd><a href="active_support_core_extensions.html">Active Support 核心擴展</a></dd>
<dd><a href="i18n.html">Rails 國際化 API</a></dd>
<dd><a href="action_mailer_basics.html">Action Mailer 基礎</a></dd>
<dd><a href="active_job_basics.html">Active Job 基礎</a></dd>
<dd><a href="security.html">Rails 安全指南</a></dd>
<dd><a href="debugging_rails_applications.html">除錯 Rails 應用程式</a></dd>
<dd><a href="configuring.html">Rails 應用程式設定</a></dd>
<dd><a href="command_line.html">Rake 任務與 Rails 命令列工具</a></dd>
<dd><a href="asset_pipeline.html">Asset Pipeline</a></dd>
<dd><a href="working_with_javascript_in_rails.html">在 Rails 使用 JavaScript</a></dd>
<dd><a href="constant_autoloading_and_reloading.html">Constant Autoloading and Reloading</a></dd>
<dt>擴充 Rails</dt>
<dd><a href="rails_on_rack.html">Rails on Rack</a></dd>
<dd><a href="generators.html">客製與新建 Rails 產生器</a></dd>
<dd><a href="rails_application_templates.html">Rails 應用程式模版</a></dd>
<dt>貢獻 Ruby on Rails</dt>
<dd><a href="contributing_to_ruby_on_rails.html">貢獻 Ruby on Rails</a></dd>
<dd><a href="api_documentation_guidelines.html">API 文件準則</a></dd>
<dd><a href="ruby_on_rails_guides_guidelines.html">Ruby on Rails 指南準則</a></dd>
<dt>維護方針</dt>
<dd><a href="maintenance_policy.html">維護方針</a></dd>
<dt>發佈記</dt>
<dd><a href="upgrading_ruby_on_rails.html">升級 Ruby on Rails</a></dd>
<dd><a href="4_2_release_notes.html">Ruby on Rails 4.2 發佈記</a></dd>
<dd><a href="4_1_release_notes.html">Ruby on Rails 4.1 發佈記</a></dd>
<dd><a href="4_0_release_notes.html">Ruby on Rails 4.0 發佈記</a></dd>
<dd><a href="3_2_release_notes.html">Ruby on Rails 3.2 發佈記</a></dd>
<dd><a href="3_1_release_notes.html">Ruby on Rails 3.1 發佈記</a></dd>
<dd><a href="3_0_release_notes.html">Ruby on Rails 3.0 發佈記</a></dd>
<dd><a href="2_3_release_notes.html">Ruby on Rails 2.3 發佈記</a></dd>
<dd><a href="2_2_release_notes.html">Ruby on Rails 2.2 發佈記</a></dd>
<dt>Rails 指南翻譯術語</dt>
<dd><a href="translation_terms.html">翻譯術語</a></dd>
</dl>
</div>
</li>
<li><a class="nav-item" href="//github.com/docrails-tw/guides">貢獻翻譯</a></li>
<li><a class="nav-item" href="contributing_to_ruby_on_rails.html">貢獻</a></li>
<li><a class="nav-item" href="credits.html">致謝</a></li>
<li class="guides-index guides-index-small">
<select class="guides-index-item nav-item">
<option value="index.html">指南目錄</option>
<optgroup label="起步走">
<option value="getting_started.html">Rails 起步走</option>
</optgroup>
<optgroup label="Models">
<option value="active_record_basics.html">Active Record 基礎</option>
<option value="active_record_migrations.html">Active Record 遷移</option>
<option value="active_record_validations.html">Active Record 驗證</option>
<option value="active_record_callbacks.html">Active Record 回呼</option>
<option value="association_basics.html">Active Record 關聯</option>
<option value="active_record_querying.html">Active Record 查詢</option>
</optgroup>
<optgroup label="Views">
<option value="layouts_and_rendering.html">Rails 算繪與版型</option>
<option value="form_helpers.html">Action View 表單輔助方法</option>
</optgroup>
<optgroup label="Controllers">
<option value="action_controller_overview.html">Action Controller 綜覽</option>
<option value="routing.html">Rails 路由:深入淺出</option>
</optgroup>
<optgroup label="深入了解">
<option value="active_support_core_extensions.html">Active Support 核心擴展</option>
<option value="i18n.html">Rails 國際化 API</option>
<option value="action_mailer_basics.html">Action Mailer 基礎</option>
<option value="active_job_basics.html">Active Job 基礎</option>
<option value="security.html">Rails 安全指南</option>
<option value="debugging_rails_applications.html">除錯 Rails 應用程式</option>
<option value="configuring.html">Rails 應用程式設定</option>
<option value="command_line.html">Rake 任務與 Rails 命令列工具</option>
<option value="asset_pipeline.html">Asset Pipeline</option>
<option value="working_with_javascript_in_rails.html">在 Rails 使用 JavaScript</option>
<option value="constant_autoloading_and_reloading.html">Constant Autoloading and Reloading</option>
</optgroup>
<optgroup label="擴充 Rails">
<option value="rails_on_rack.html">Rails on Rack</option>
<option value="generators.html">客製與新建 Rails 產生器</option>
<option value="rails_application_templates.html">Rails 應用程式模版</option>
</optgroup>
<optgroup label="貢獻 Ruby on Rails">
<option value="contributing_to_ruby_on_rails.html">貢獻 Ruby on Rails</option>
<option value="api_documentation_guidelines.html">API 文件準則</option>
<option value="ruby_on_rails_guides_guidelines.html">Ruby on Rails 指南準則</option>
</optgroup>
<optgroup label="維護方針">
<option value="maintenance_policy.html">維護方針</option>
</optgroup>
<optgroup label="發佈記">
<option value="upgrading_ruby_on_rails.html">升級 Ruby on Rails</option>
<option value="4_2_release_notes.html">Ruby on Rails 4.2 發佈記</option>
<option value="4_1_release_notes.html">Ruby on Rails 4.1 發佈記</option>
<option value="4_0_release_notes.html">Ruby on Rails 4.0 發佈記</option>
<option value="3_2_release_notes.html">Ruby on Rails 3.2 發佈記</option>
<option value="3_1_release_notes.html">Ruby on Rails 3.1 發佈記</option>
<option value="3_0_release_notes.html">Ruby on Rails 3.0 發佈記</option>
<option value="2_3_release_notes.html">Ruby on Rails 2.3 發佈記</option>
<option value="2_2_release_notes.html">Ruby on Rails 2.2 發佈記</option>
</optgroup>
<optgroup label="Rails 指南翻譯術語">
<option value="translation_terms.html">翻譯術語</option>
</optgroup>
</select>
</li>
</ul>
</div>
</div>
</div>
<hr class="hide">
<div id="feature">
<div class="wrapper">
<h2>除錯 Rails 應用程式</h2><p>本篇介紹 Rails 應用程式除錯技巧。</p><p>讀完本篇,您將了解:</p>
<ul>
<li>除錯的目的。</li>
<li>如何追蹤測試沒有找出的問題。</li>
<li>各種除錯方法。</li>
<li>如何分析 Stack Trace。</li>
</ul>
<div id="subCol">
<h3 class="chapter"><img src="images/chapters_icon.gif" alt="" />Chapters</h3>
<ol class="chapters">
<li>
<a href="#%E9%99%A4%E9%8C%AF%E7%94%A8%E7%9A%84-view-%E8%BC%94%E5%8A%A9%E6%96%B9%E6%B3%95">除錯用的 View 輔助方法</a>
<ul>
<li><a href="#debug"><code>debug</code></a></li>
<li><a href="#to-yaml"><code>to_yaml</code></a></li>
<li><a href="#inspect"><code>inspect</code></a></li>
</ul>
</li>
<li>
<a href="#logger">Logger</a>
<ul>
<li><a href="#%E4%BB%80%E9%BA%BC%E6%98%AF-logger%EF%BC%9F">什麼是 Logger?</a></li>
<li><a href="#log-%E5%B1%A4%E7%B4%9A">Log 層級</a></li>
<li><a href="#%E5%AF%AB%E5%85%A5%E8%A8%8A%E6%81%AF">寫入訊息</a></li>
<li><a href="#%E7%B5%A6%E8%A8%98%E9%8C%84%E6%89%93%E6%A8%99%E7%B1%A4">給記錄打標籤</a></li>
<li><a href="#%E8%A8%98%E9%8C%84%E5%B0%8D%E6%95%88%E8%83%BD%E7%9A%84%E5%BD%B1%E9%9F%BF">記錄對效能的影響</a></li>
</ul>
</li>
<li>
<a href="#%E4%BD%BF%E7%94%A8-byebug-gem-%E4%BE%86%E9%99%A4%E9%8C%AF">使用 <code>byebug</code> Gem 來除錯</a>
<ul>
<li><a href="#%E4%BD%BF%E7%94%A8-byebug-gem-%E4%BE%86%E9%99%A4%E9%8C%AF-%E8%A8%AD%E5%AE%9A">設定</a></li>
<li><a href="#shell">Shell</a></li>
<li><a href="#%E4%B8%8A%E4%B8%8B%E6%96%87">上下文</a></li>
<li><a href="#%E7%B7%9A%E7%A8%8B">線程</a></li>
<li><a href="#%E6%9F%A5%E7%9C%8B%E8%AE%8A%E6%95%B8">查看變數</a></li>
<li><a href="#%E9%80%90%E6%AD%A5%E5%9F%B7%E8%A1%8C">逐步執行</a></li>
<li><a href="#%E6%96%B7%E9%BB%9E">斷點</a></li>
<li><a href="#%E8%A3%9C%E6%8D%89%E7%95%B0%E5%B8%B8">補捉異常</a></li>
<li><a href="#%E7%B9%BC%E7%BA%8C%E5%9F%B7%E8%A1%8C">繼續執行</a></li>
<li><a href="#%E7%B7%A8%E8%BC%AF">編輯</a></li>
<li><a href="#%E9%9B%A2%E9%96%8B">離開</a></li>
<li><a href="#%E4%BD%BF%E7%94%A8-byebug-gem-%E4%BE%86%E9%99%A4%E9%8C%AF-%E8%A8%AD%E5%AE%9A">設定</a></li>
</ul>
</li>
<li>
<a href="#%E6%89%BE%E5%87%BA%E8%A8%98%E6%86%B6%E9%AB%94%E6%B4%A9%E6%BC%8F">找出記憶體洩漏</a>
<ul>
<li><a href="#valgrind">Valgrind</a></li>
</ul>
</li>
<li><a href="#%E9%99%A4%E9%8C%AF%E5%A5%97%E4%BB%B6">除錯套件</a></li>
<li><a href="#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99">參考資料</a></li>
</ol>
</div>
</div>
</div>
<div id="container">
<div class="wrapper">
<div id="mainCol">
<h3 id="除錯用的-view-輔助方法">1 除錯用的 View 輔助方法</h3><p>除錯常見任務之一是查看變數的內容。在 Rails 可以用三種方法:</p>
<ul>
<li><code>debug</code></li>
<li><code>to_yaml</code></li>
<li><code>inspect</code></li>
</ul>
<h4 id="debug">1.1 <code>debug</code>
</h4><p><code>debug</code> 輔助方法會對物件以 YAML 格式算繪,把結果包在 <code><pre></code> 標籤內回傳。譬如,View 有如下程式:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
<%= debug @article %>
<p>
<b>Title:</b>
<%= @article.title %>
</p>
</pre>
</div>
<p>輸出則像是:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
--- !ruby/object Article
attributes:
updated_at: 2008-09-05 22:55:47
body: It's a very helpful guide for debugging your Rails app.
title: Rails debugging guide
published: t
id: "1"
created_at: 2008-09-05 22:55:47
attributes_cache: {}
Title: Rails debugging guide
</pre>
</div>
<h4 id="to-yaml">1.2 <code>to_yaml</code>
</h4><p>以 YAML 格式顯示實體變數、物件、方法。用法:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
<%= simple_format @article.to_yaml %>
<p>
<b>Title:</b>
<%= @article.title %>
</p>
</pre>
</div>
<p><code>to_yaml</code> 方法把物件轉成可讀性比較高的 YAML 格式,接著 <code>simple_format</code> 會使用和終端同樣的方法來算繪物件。<code>debug</code> 方法其實就是結合了這兩者:</p><p>上例輸出結果:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
--- !ruby/object Article
attributes:
updated_at: 2008-09-05 22:55:47
body: It's a very helpful guide for debugging your Rails app.
title: Rails debugging guide
published: t
id: "1"
created_at: 2008-09-05 22:55:47
attributes_cache: {}
Title: Rails debugging guide
</pre>
</div>
<h4 id="inspect">1.3 <code>inspect</code>
</h4><p>另一個顯示物件數值的有用方法是 <code>inspect</code>,對陣列或 Hash 尤其有用。會把物件的數值以字串形式印出,譬如:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
<%= [1, 2, 3, 4, 5].inspect %>
<p>
<b>Title:</b>
<%= @article.title %>
</p>
</pre>
</div>
<p>算繪出來為:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
[1, 2, 3, 4, 5]
Title: Rails debugging guide
</pre>
</div>
<h3 id="logger">2 Logger</h3><p>程式執行時,寫入資訊到記錄檔很有用。而 Rails 替每個環境都準備了一個記錄檔。</p><h4 id="什麼是-logger?">2.1 什麼是 Logger?</h4><p>Rails 使用 <code>ActiveSupport::Logger</code> 來寫入記錄資訊。也可以換用別的 Logger,譬如 <code>Log4r</code>。</p><p>可以在 <code>environment.rb</code> 指定其它的 Logger,或在其它環境檔案內指定也可以。</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
Rails.logger = Logger.new(STDOUT)
Rails.logger = Log4r::Logger.new("Application Log")
</pre>
</div>
<p>或在 <code>Initializer</code> 加入下面任一行:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
config.logger = Logger.new(STDOUT)
config.logger = Log4r::Logger.new("Application Log")
</pre>
</div>
<div class="info"><p>記錄檔預設存在 <code>Rails.root/log/</code> 目錄下,記錄檔以應用程式正執行的環境命名。</p></div><h4 id="log-層級">2.2 Log 層級</h4><p>當產生的 Log 訊息層級高過設定的 Log 層級時,就會把 Log 記錄到對應的記錄檔裡。若想知道當前的 Log 層級,可以呼叫 <code>Rails.logger.level</code> 方法。</p><p>可用 Log 層級有:<code>:debug</code>、<code>:info</code>、<code>:warn</code>、<code>:error</code>、<code>:fatal</code> 以及 <code>:unknown</code>,分別對應到數字 <code>0</code> 到 <code>5</code>。修改預設 Log 層級:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
config.log_level = :warn # In any environment initializer, or
Rails.logger.level = 0 # at any time
</pre>
</div>
<p>這在開發和準上線環境(Staging)下很有用,也能避免上線環境寫入大量不必要的資訊。</p><div class="info"><p>Rails 所有環境預設的 Log 層級是 <code>debug</code>。</p></div><h4 id="寫入訊息">2.3 寫入訊息</h4><p>要寫入訊息到目前的記錄檔裡,在 Controller、Model 或 Mailer 裡使用 <code>logger.(debug|info|warn|error|fatal)</code>:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
logger.debug "Person attributes hash: #{@person.attributes.inspect}"
logger.info "Processing the request..."
logger.fatal "Terminating application, raised unrecoverable error!!!"
</pre>
</div>
<p>以下是有額外記錄資訊的方法:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class ArticlesController < ApplicationController
# ...
def create
@article = Article.new(params[:article])
logger.debug "New article: #{@article.attributes.inspect}"
logger.debug "Article should be valid: #{@article.valid?}"
if @article.save
flash[:notice] = 'Article was successfully created.'
logger.debug "The article was saved and now the user is going to be redirected..."
redirect_to(@article)
else
render action: "new"
end
end
# ...
end
</pre>
</div>
<p>動作執行的紀錄檔:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
Processing ArticlesController#create (for 127.0.0.1 at 2008-09-08 11:52:54) [POST]
Session ID: BAh7BzoMY3NyZl9pZCIlMDY5MWU1M2I1ZDRjODBlMzkyMWI1OTg2NWQyNzViZjYiCmZsYXNoSUM6J0FjdGl
vbkNvbnRyb2xsZXI6OkZsYXNoOjpGbGFzaEhhc2h7AAY6CkB1c2VkewA=--b18cd92fba90eacf8137e5f6b3b06c4d724596a4
Parameters: {"commit"=>"Create", "article"=>{"title"=>"Debugging Rails",
"body"=>"I'm learning how to print in logs!!!", "published"=>"0"},
"authenticity_token"=>"2059c1286e93402e389127b1153204e0d1e275dd", "action"=>"create", "controller"=>"articles"}
New article: {"updated_at"=>nil, "title"=>"Debugging Rails", "body"=>"I'm learning how to print in logs!!!",
"published"=>false, "created_at"=>nil}
Article should be valid: true
Article Create (0.000443) INSERT INTO "articles" ("updated_at", "title", "body", "published",
"created_at") VALUES('2008-09-08 14:52:54', 'Debugging Rails',
'I''m learning how to print in logs!!!', 'f', '2008-09-08 14:52:54')
The article was saved and now the user is going to be redirected...
Redirected to # Article:0x20af760>
Completed in 0.01224 (81 reqs/sec) | DB: 0.00044 (3%) | 302 Found [http://localhost/articles]
</pre>
</div>
<p>增加額外的記錄可以更容易在記錄檔裡找到異常行為。若需要記錄更多資訊,記得設定合理的 Log 等級,避免在上線環境的紀錄檔裡寫入不必要的訊息。</p><h4 id="給記錄打標籤">2.4 給記錄打標籤</h4><p>執行多使用者、多帳號的應用程式時,可以使用自訂規則來過濾記錄檔很有用。Active Support 的 <code>TaggedLogging</code> 便為此而生。可以在記錄裡加入像是子域名、請求 ID 等,其它有助於除錯的訊息。</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
logger.tagged("BCX") { logger.info "Stuff" } # Logs "[BCX] Stuff"
logger.tagged("BCX", "Jason") { logger.info "Stuff" } # Logs "[BCX] [Jason] Stuff"
logger.tagged("BCX") { logger.tagged("Jason") { logger.info "Stuff" } } # Logs "[BCX] [Jason] Stuff"
</pre>
</div>
<h4 id="記錄對效能的影響">2.5 記錄對效能的影響</h4><p>記錄肯定會對效能產生影響,特別是將記錄存到硬碟裡。有幾個潛在的問題:</p><p>使用 <code>:debug</code> 層級對效能的影響最大(與 <code>:fatal</code> 相比)。因為 <code>:debug</code> 與 <code>:fatal</code> 相比起來,需要處理的字串多很多,還得再寫入到磁碟。</p><p>另一個潛在的陷阱是,若是這樣使用 <code>Logger</code>:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
logger.debug "Person attributes hash: #{@person.attributes.inspect}"
</pre>
</div>
<p>在上例裡,即便 Logger 層級不包含 <code>:debug</code> 也會影響效能。因為 Ruby 需要對這些字串做求值,求值便需要實體化這些字串,再處理字串插值,這些都需要時間。</p><p>因此使用 <code>logger</code> 方法時,傳入區塊會比較好。區塊只在 Logger 層級相符時才會求值(即惰性加載)。上例可改寫為:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
logger.debug {"Person attributes hash: #{@person.attributes.inspect}"}
</pre>
</div>
<p>區塊的內容只在 <code>:debug</code> 層級的紀錄啟用時才會求值。省下的效能只在記錄大量資料時會體現出來,但這是可以遵循的良好實踐。</p><h3 id="使用-byebug-gem-來除錯">3 使用 <code>byebug</code> Gem 來除錯</h3><p>當程式不按預期執行時,可以試著印出 Log 或在終端裡查看來找出問題。不幸的是,有時這些方法無法有效的找出問題所在。當需要逐步追蹤程式碼如何執行,除錯器是你的最佳夥伴。</p><p>除錯器也可以幫助你了解 Rails 的原始碼。若不知道從何下手,從任何一個請求切入,再運用下面教你的方法,一步一步深入 Rails 原始碼。</p><h4 id="使用-byebug-gem-來除錯-設定">3.1 設定</h4><p>使用 <code>byebug</code> gem 來下斷點,即可在正在執行的程式裡逐步執行。首先要安裝 <code>byebug</code>:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
$ gem install byebug
</pre>
</div>
<p>在 Rails 應用程式裡的任何地方,可以使用 <code>byebug</code> 方法來呼叫除錯器。</p><p>範例:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class PeopleController < ApplicationController
def new
byebug
@person = Person.new
end
end
</pre>
</div>
<h4 id="shell">3.2 Shell</h4><p>只要呼叫了 <code>byebug</code> 方法,除錯器便會啟動。啟動伺服器時,會在終端機裡開一個 Shell 起來,會停在呼叫 <code>byebug</code> 的地方。即將執行的程式碼左邊會有 <code>=></code> 提示符號:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
[1, 10] in /PathTo/project/app/controllers/articles_controller.rb
3:
4: # GET /articles
5: # GET /articles.json
6: def index
7: byebug
=> 8: @articles = Article.find_recent
9:
10: respond_to do |format|
11: format.html # index.html.erb
12: format.json { render json: @articles }
(byebug)
</pre>
</div>
<p>若是從瀏覽器觸發,瀏覽器分頁會停住,直到除錯器與請求結束。</p><p>比如說:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
=> Booting WEBrick
=> Rails 4.2.0 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
=> Notice: server is listening on all interfaces (0.0.0.0). Consider using 127.0.0.1 (--binding option)
=> Ctrl-C to shutdown server
[2014-04-11 13:11:47] INFO WEBrick 1.3.1
[2014-04-11 13:11:47] INFO ruby 2.1.1 (2014-02-24) [i686-linux]
[2014-04-11 13:11:47] INFO WEBrick::HTTPServer#start: pid=6370 port=3000
Started GET "/" for 127.0.0.1 at 2014-04-11 13:11:48 +0200
ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations".* FROM "schema_migrations"
Processing by ArticlesController#index as HTML
[3, 12] in /PathTo/project/app/controllers/articles_controller.rb
3:
4: # GET /articles
5: # GET /articles.json
6: def index
7: byebug
=> 8: @articles = Article.find_recent
9:
10: respond_to do |format|
11: format.html # index.html.erb
12: format.json { render json: @articles }
(byebug)
</pre>
</div>
<p>現在是時候深入程式一探究竟了。先看看有什麼命令可以用,輸入 <code>help</code>:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(byebug) help
byebug 2.7.0
Type 'help <command-name>' for help on a specific command
Available commands:
backtrace delete enable help list pry next restart source up
break disable eval info method ps save step var
catch display exit interrupt next putl set thread
condition down finish irb p quit show trace
continue edit frame kill pp reload skip undisplay
</pre>
</div>
<div class="info"><p>要查看任何命令的說明文件,請使用 <code>help <command-name></code>,譬如 <code>help list</code>。也可以使用縮寫(輸入足夠與其他命令區別的字元即可),比如 <code>list</code> 可用 <code>l</code> 即可,例如:</p></div><p>要列出前十行程式,可以使用 <code>list-</code> 或 <code>l-</code>:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(byebug) l-
[1, 10] in /PathTo/project/app/controllers/articles_controller.rb
1 class ArticlesController < ApplicationController
2 before_action :set_article, only: [:show, :edit, :update, :destroy]
3
4 # GET /articles
5 # GET /articles.json
6 def index
7 byebug
8 @articles = Article.find_recent
9
10 respond_to do |format|
</pre>
</div>
<p>這樣便可看 <code>byebug</code> 上面與下面的程式碼。最後,要回到 <code>byebug</code> 停下來的地方,輸入 <code>list=</code>:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(byebug) list=
[3, 12] in /PathTo/project/app/controllers/articles_controller.rb
3:
4: # GET /articles
5: # GET /articles.json
6: def index
7: byebug
=> 8: @articles = Article.find_recent
9:
10: respond_to do |format|
11: format.html # index.html.erb
12: format.json { render json: @articles }
(byebug)
</pre>
</div>
<h4 id="上下文">3.3 上下文</h4><p>開始除錯應用程式時,會在不同的上下文裡跳轉。</p><p>除錯器停在某個地方(或觸發事件時),會建立一個上下文,上下文有當下暫停程式的資訊,讓除錯器可以檢查 Frame Stack、以當下程式的角度對變數求值,並擁有程式暫停的位置資訊。</p><p>任何時候都可以使用 <code>backtrace</code>(別名 <code>where</code>)來印出應用程式的 Backtrace。這可以知道程式是怎麼跑到這裡來。若困惑程式是如何執行到這裡,執行 <code>backtrace</code> 便可找到答案。</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(byebug) where
--> #0 ArticlesController.index
at /PathTo/project/test_app/app/controllers/articles_controller.rb:8
#1 ActionController::ImplicitRender.send_action(method#String, *args#Array)
at /PathToGems/actionpack-4.2.0/lib/action_controller/metal/implicit_render.rb:4
#2 AbstractController::Base.process_action(action#NilClass, *args#Array)
at /PathToGems/actionpack-4.2.0/lib/abstract_controller/base.rb:189
#3 ActionController::Rendering.process_action(action#NilClass, *args#NilClass)
at /PathToGems/actionpack-4.2.0/lib/action_controller/metal/rendering.rb:10
...
</pre>
</div>
<p>當下的 Frame 會以 <code>--></code> 註記。可以使用 <code>frame n</code> 命令移動到 Frame 的任何地方,<code>n</code> 是 Frame 的編號。移動時,<code>byebug</code> 會同時顯示新的上下文。</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(byebug) frame 2
[184, 193] in /PathToGems/actionpack-4.2.0/lib/abstract_controller/base.rb
184: # is the intended way to override action dispatching.
185: #
186: # Notice that the first argument is the method to be dispatched
187: # which is *not* necessarily the same as the action name.
188: def process_action(method_name, *args)
=> 189: send_action(method_name, *args)
190: end
191:
192: # Actually call the method associated with the action. Override
193: # this method if you wish to change how action methods are called,
(byebug)
</pre>
</div>
<p>也可以使用 <code>up [n]</code> 或 <code>down [n]</code> 來往上或下幾個 Frame。<code>n</code> 預設是 <code>1</code>。往上會往編號較高的 Frame 走;而下是往編號較低的 Frame 去。</p><h4 id="線程">3.4 線程</h4><p>除錯器可以列出線程(Thread)、停止線程、繼續線程、切換線程:<code>thread</code> 命令(或縮寫 <code>th</code>)。有以下選項可用:</p>
<ul>
<li>
<code>thread</code>:顯示當前的線程。</li>
<li>
<code>thread list</code>:用來列出所有線程及線程的狀態。線程數字前有 <code>+</code> 號表示為當前的線程。</li>
<li>
<code>thread stop n</code>:停止線程 <code>n</code>。</li>
<li>
<code>thread resume n</code>:繼續線程 <code>n</code>。</li>
<li>
<code>thread switch n</code>:切換當前的線程到線程 <code>n</code>。</li>
</ul>
<p>這條命令在需要除錯當前線程時很有用,比如可以檢查線程是否有競態條件。</p><h4 id="查看變數">3.5 查看變數</h4><p>當前的上下文裡可以執行任何表達式。要對表達式做求值,輸入表達式即可!</p><p>下例示範如何在當下的上下文裡印出實體變數:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
[3, 12] in /PathTo/project/app/controllers/articles_controller.rb
3:
4: # GET /articles
5: # GET /articles.json
6: def index
7: byebug
=> 8: @articles = Article.find_recent
9:
10: respond_to do |format|
11: format.html # index.html.erb
12: format.json { render json: @articles }
(byebug) instance_variables
[:@_action_has_layout, :@_routes, :@_headers, :@_status, :@_request,
:@_response, :@_env, :@_prefixes, :@_lookup_context, :@_action_name,
:@_response_body, :@marked_for_same_origin_verification, :@_config]
</pre>
</div>
<p>你可能看出來了,所有 Controller 可以存取的變數都印出來了。這個變數清單會隨程式執行而變。譬如使用 <code>next</code> 可跳到下一行:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(byebug) next
[5, 14] in /PathTo/project/app/controllers/articles_controller.rb
5 # GET /articles.json
6 def index
7 byebug
8 @articles = Article.find_recent
9
=> 10 respond_to do |format|
11 format.html # index.html.erb
12 format.json { render json: @articles }
13 end
14 end
15
(byebug)
</pre>
</div>
<p>接著再使用 <code>instance_variables</code>:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(byebug) instance_variables.include? "@articles"
true
</pre>
</div>
<p>現在 <code>@articles</code> 被加到實體變數清單裡了,因為定義 <code>@articles</code> 的那一行已經被執行了。</p><div class="info"><p>也可以切換到 <code>irb</code> 模式,使用 <code>irb</code> 命令即可。會在當下的上下文裡,起一個新的 irb 起來,但這個功能還在實驗階段。</p></div><p><code>var</code> 是用來顯示變數的方法,說明文件如下:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(byebug) help var
v[ar] cl[ass] show class variables of self
v[ar] const <object> show constants of object
v[ar] g[lobal] show global variables
v[ar] i[nstance] <object> show instance variables of object
v[ar] l[ocal] show local variables
</pre>
</div>
<p>這是用來檢視當前上下文變數的好方法。舉個例子,看有沒有定義任何區域變數:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(byebug) var local
(byebug)
</pre>
</div>
<p>檢視物件的實體變數:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(byebug) var instance Article.new
@_start_transaction_state = {}
@aggregation_cache = {}
@association_cache = {}
@attributes = {"id"=>nil, "created_at"=>nil, "updated_at"=>nil}
@attributes_cache = {}
@changed_attributes = nil
...
</pre>
</div>
<div class="info"><p><code>p</code>(print)和 <code>pp</code>(pretty print)可以用來對 Ruby 表達式求值、顯示變數的值到終端。</p></div><p>也可用 <code>display</code> 來“關注”變數。這是程式執行時,用來追蹤變數值的好方法。</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(byebug) display @articles
1: @articles = nil
</pre>
</div>
<p>在 <code>display</code> 關注清單的變數,會在上下文切換時印出來。要停止關注變數,<code>undisplay n</code>,<code>n</code> 是變數前的編號(上例 <code>1</code>)。</p><h4 id="逐步執行">3.6 逐步執行</h4><p>現在應該了解如何知道自己在執行程式的位置,並能印出變數。接著看程式如何執行。</p><p>使用 <code>step</code>(縮寫 <code>s</code>)來繼續執行程式直到下個斷點,控制權會轉移回除錯器。</p><p>也可以使用 <code>next</code>,跟 <code>step</code> 類似,但會略過行內的程式執行。</p><div class="info"><p>可以用 <code>step n</code> 或 <code>next n</code> 來一次往前 <code>n</code> 步。</p></div><p><code>next</code> 與 <code>step</code> 的差別是 <code>step</code> 會跳到下一行程式碼“裡”;而 <code>next</code> 則會移到“下一行”程式,不會執行行內的程式碼。</p><p>看看下面這個例子:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
Started GET "/" for 127.0.0.1 at 2014-04-11 13:39:23 +0200
Processing by ArticlesController#index as HTML
[1, 8] in /home/davidr/Proyectos/test_app/app/models/article.rb
1: class Article < ActiveRecord::Base
2:
3: def self.find_recent(limit = 10)
4: byebug
=> 5: where('created_at > ?', 1.week.ago).limit(limit)
6: end
7:
8: end
(byebug)
</pre>
</div>
<p>若使用 <code>next</code>,<code>next</code> 不會深入 <code>where(...)</code>,而是跳到下一行。上例剛好到了 <code>end</code>,則會跳到下一個 Frame。</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(byebug) next
Next went up a frame because previous frame finished
[4, 13] in /PathTo/project/test_app/app/controllers/articles_controller.rb
4: # GET /articles
5: # GET /articles.json
6: def index
7: @articles = Article.find_recent
8:
=> 9: respond_to do |format|
10: format.html # index.html.erb
11: format.json { render json: @articles }
12: end
13: end
(byebug)
</pre>
</div>
<p>反之若使用的是 <code>step</code>,則會到“下一行”,這個例子會跳到 Active Support 的 <code>week</code> 方法。</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(byebug) step
[50, 59] in /PathToGems/activesupport-4.2.0/lib/active_support/core_ext/numeric/time.rb
50: ActiveSupport::Duration.new(self * 24.hours, [[:days, self]])
51: end
52: alias :day :days
53:
54: def weeks
=> 55: ActiveSupport::Duration.new(self * 7.days, [[:days, self * 7]])
56: end
57: alias :week :weeks
58:
59: def fortnights
(byebug)
</pre>
</div>
<p>這是找出 Bug 最好的方法之一,或者說這是在 Ruby on Rails 框架裡最好的除錯方法。</p><h4 id="斷點">3.7 斷點</h4><p>斷點可使程式在執行到某處時停下來,會在該處起一個 Shell。</p><p>可以動態加斷點,使用 <code>break</code> (或 <code>b</code> 就好)。有三種方式可以手動加斷點:</p>
<ul>
<li>
<code>break line</code>:在目前的檔案裡對 <code>line</code> 行下斷點。</li>
<li>
<code>break file:line [if expression]</code>: 在 <code>file</code> 的 <code>line</code> 行下斷點。<code>if</code> 表達式求值為真時會啟動除錯器。</li>
<li>
<code>break class(.|\#)method [if expression]</code>: 在 <em><code>class</code></em> 的類別方法或實體方法裡下斷點。同樣在 <code>if</code> 表達式求值為真時會啟動除錯器。</li>
</ul>
<p>譬如在前例下斷點:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
[4, 13] in /PathTo/project/app/controllers/articles_controller.rb
4: # GET /articles
5: # GET /articles.json
6: def index
7: @articles = Article.find_recent
8:
=> 9: respond_to do |format|
10: format.html # index.html.erb
11: format.json { render json: @articles }
12: end
13: end
(byebug) break 11
Created breakpoint 1 at /PathTo/project/app/controllers/articles_controller.rb:11
</pre>
</div>
<p>使用 <code>info breakpoints n</code> 或 <code>info break n</code> 來列出斷點。若有給 <code>n</code> 號碼,會只列出對應號碼的斷點,否則列出所有的斷點。</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(byebug) info breakpoints
Num Enb What
1 y at /PathTo/project/app/controllers/articles_controller.rb:11
</pre>
</div>
<p>要刪除斷點,使用 <code>delete n</code>,來移除 <code>n</code> 號斷點。若沒指定則會刪除所有使用中的斷點。</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(byebug) delete 1
(byebug) info breakpoints
No breakpoints.
</pre>
</div>
<p>也可以啟用或停用某個斷點:</p>
<ul>
<li>
<code>enable breakpoints</code>:接受一個斷點清單。沒給清單會啟用所有的斷點(預設)。</li>
<li>
<code>disable breakpoints</code>:指定的斷點不會對程式造成影響。</li>
</ul>
<h4 id="補捉異常">3.8 補捉異常</h4><p><code>catch exception-name</code>(或 <code>cat exception-name</code>)命令可用來攔截沒有預設處理程序的異常(異常的類型為 <code>exception-name</code>)。</p><p>列出所有的攔截點請用 <code>catch</code>。</p><h4 id="繼續執行">3.9 繼續執行</h4><p>除錯器暫停程式,有兩種恢復程式執行的方法:</p>
<ul>
<li>
<code>continue [line-specification]</code>(或 <code>c</code>):在上次停下來的地方繼續執行程式,該行的任何斷點會被忽略。接受一個選擇性參數 <code>line-specification</code>,允許指定行號。可以消掉指定行號的斷點。</li>
<li>
<code>finish [frame-number]</code>(或 <code>fin</code>):執行 Frame 裡的所有程式。沒指定要執行那個 Frame 時,程式會執行到當下的 Frame 結束為止。若有指定 Frame,則會執行到該 Frame 結束為止。</li>
</ul>
<h4 id="編輯">3.10 編輯</h4><p>兩個命令可以從除錯器裡開啟編輯器來編輯:</p>
<ul>
<li>
<code>edit [file:line]</code>: 使用環境變數 <code>EDITOR</code> 指定的編輯器來編輯 <em><code>file</code></em>,可以選擇性指定要編輯的行號 <code>line</code>。</li>
</ul>
<h4 id="離開">3.11 離開</h4><p>要離開除錯器,使用 <code>quit</code> 命令(縮寫 <code>q</code>),別名:<code>exit</code>。</p><p>離開實際上會終止所有的線程。因此伺服器會被停止,需要自己重新啟動。</p><h4 id="使用-byebug-gem-來除錯-設定">3.12 設定</h4><p><code>byebug</code> 有幾個可用的選項:</p>
<ul>
<li>
<code>set autoreload</code>: 原始碼改變時自動重載(預設 <code>true</code>)。</li>
<li>
<code>set autolist</code>:每個斷點自動執行 <code>list</code> 命令(預設 <code>true</code>)。</li>
<li>
<code>set listsize _n_</code>: 設定要列出的行數(預設 <code>10</code>)。</li>
<li>
<code>set forcestep</code>:確保 <code>next</code> 和 <code>step</code> 命令總是移到下一行。</li>
</ul>
<p>可以使用 <code>help set</code> 看完整的設定選項。使用 <code>help set subcommand</code> 來學習特定子命令的知識。</p><div class="info"><p>可以將這些設定直存在家目錄下的 <code>.byebugrc</code> 檔案裡。除錯器在啟動時會讀取這些全域設定。譬如:</p></div><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
set forcestep
set listsize 25
</pre>
</div>
<h3 id="找出記憶體洩漏">4 找出記憶體洩漏</h3><p>Ruby 應用(不管是不是 Rails)都有可能會洩漏記憶體,可能是 Ruby 或是 C 程式洩漏記憶體。</p><p>本節介紹 Valgrind 工具,可以用來找出並修正記憶體洩漏的問題。</p><h4 id="valgrind">4.1 Valgrind</h4><p><a href="http://valgrind.org/">Valgrind</a> 只能在 Linux 上使用,用來找出 C 語言的記憶體洩漏或是競態條件。</p><p>有一些 Valgrind 工具可以自動偵測出記憶體洩漏、線程 Bugs 並可以對程式做詳細的分析。舉個例子,若有個用 C 寫的擴充程式,在直譯器呼叫了 <code>malloc()</code>,但沒有 <code>free()</code>,這些記憶體在應用程式結束時才會被釋放。</p><p>關於安裝 Valgrind 以及如何跟 Ruby 使用,請參考 Evan Weaver 所寫的文章:<a href="http://blog.evanweaver.com/articles/2008/02/05/valgrind-and-ruby/">Valgrind and Ruby</a>。</p><h3 id="除錯套件">5 除錯套件</h3><p>以下是幫助你找出錯誤與除錯程式的套件清單。</p>
<ul>
<li>
<a href="https://github.com/josevalim/rails-footnotes">Footnotes</a> 在每頁的頁腳印出請求的資訊、並連結到對應的程式碼(TextMate)。</li>
<li>
<a href="https://github.com/ntalbott/query_trace/tree/master">Query Trace</a> 增加查詢記錄的源頭。</li>
<li>
<a href="https://github.com/nesquena/query_reviewer">Query Reviewer</a> 這個 Rails 插件只會在開發模式的 <code>SELECT</code> 查詢前執行 <code>EXPLAIN</code>,並將分析過後的結果放在 <code>div</code> 裡,附在每一頁裡。</li>
<li>
<a href="https://github.com/smartinez87/exception_notification/tree/master">Exception Notifier</a> 提供一個 Mailer 物件以及一組模版。當 Rails 程式出錯時,寄送一封郵件通知。</li>
<li>
<a href="https://github.com/charliesome/better_errors">Better Errors</a> 替換 Rails 標準的錯誤頁面,用有更多上下文資訊的頁面(像是出錯的程式、變量等)來取代。</li>
<li>
<a href="https://github.com/dejan/rails_panel">RailsPanel</a> Chrome 套件,在瀏覽器的開發工具顯示 <code>development.log</code> 的內容。提供像是資料庫查詢時間、算繪時間、總時間、參數列表、算繪的 View 等資訊。</li>
</ul>
<h3 id="參考資料">6 參考資料</h3>
<ul>
<li><a href="http://bashdb.sourceforge.net/ruby-debug/home-page.html">ruby-debug Homepage</a></li>
<li><a href="https://github.com/cldwalker/debugger">debugger Homepage</a></li>
<li><a href="https://github.com/deivid-rodriguez/byebug">byebug Homepage</a></li>
<li><a href="http://www.sitepoint.com/debug-rails-app-ruby-debug/">Article: Debugging a Rails application with ruby-debug</a></li>
<li><a href="http://railscasts.com/episodes/54-debugging-ruby-revised">Ryan Bates' debugging ruby (revised) screencast</a></li>
<li><a href="http://railscasts.com/episodes/24-the-stack-trace">Ryan Bates' stack trace screencast</a></li>
<li><a href="http://railscasts.com/episodes/56-the-logger">Ryan Bates' logger screencast</a></li>
<li><a href="http://bashdb.sourceforge.net/ruby-debug.html">Debugging with ruby-debug</a></li>
</ul>
<h3>反饋</h3>
<p>
歡迎幫忙改善指南的品質。
</p>
<p>
如發現任何錯誤之處,歡迎修正。開始貢獻前,可以先閱讀<a href="http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#contributing-to-the-rails-documentation">貢獻指南:文件</a>。
</p>
<p>翻譯如有錯誤,深感抱歉,歡迎 <a href="https://github.com/docrails-tw/guides/fork">Fork</a> 修正,或至此處<a href="https://github.com/docsrails-tw/guides/issues/new">回報</a>。</p>
<p>
文章可能有未完成或過時的內容。請先檢查 <a href="http://edgeguides.rubyonrails.org">Edge Guides</a> 來確定問題在 master 是否已經修掉了。再上 master 補上缺少的文件。內容參考 <a href="ruby_on_rails_guides_guidelines.html">Ruby on Rails 指南準則</a>來了解行文風格。
</p>
<p>最後,任何關於 Ruby on Rails 文件的討論,歡迎至 <a href="http://groups.google.com/group/rubyonrails-docs">rubyonrails-docs 郵件論壇</a>。
</p>
</div>
</div>
</div>
<hr class="hide">
<div id="footer">
<div class="wrapper">
<p>本著作係採用<a href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh_TW">創用 CC 姓名標示-相同方式分享 4.0 國際授權條款</a>授權。</p>
<p>“Rails”、“Ruby on Rails”,以及 Rails logo 為 David Heinemeier Hansson 的商標。版權所有。</p>
</div>
</div>
<script src="javascripts/jquery.min.js"></script>
<script src="javascripts/responsive-tables.js"></script>
<script src="javascripts/guides.js"></script>
<script src="javascripts/syntaxhighlighter/shCore.js"></script>
<script src="javascripts/syntaxhighlighter/shBrushRuby.js"></script>
<script src="javascripts/syntaxhighlighter/shBrushXml.js"></script>
<script src="javascripts/syntaxhighlighter/shBrushSql.js"></script>
<script src="javascripts/syntaxhighlighter/shBrushPlain.js"></script>
<script type="text/javascript">
SyntaxHighlighter.all();
$(guidesIndex.bind);
</script>
<script>
(function(i,s,o,g,r,a,m){i["GoogleAnalyticsObject"]=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,"script","//www.google-analytics.com/analytics.js","ga");
ga("create", "UA-49903900-1", "auto");
ga("require", "displayfeatures");
ga("send", "pageview");
</script>
</body>
</html>