-
Notifications
You must be signed in to change notification settings - Fork 2
/
debugging_rails_applications.html
840 lines (767 loc) · 49.1 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
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-CN" lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>调试 Rails 程序 — Ruby on Rails 指南</title>
<link rel="stylesheet" type="text/css" href="stylesheets/style.css" />
<link rel="stylesheet" type="text/css" href="stylesheets/print.css" media="print" />
<link rel="stylesheet" type="text/css" href="stylesheets/syntaxhighlighter/shCore.css" />
<link rel="stylesheet" type="text/css" href="stylesheets/syntaxhighlighter/shThemeRailsGuides.css" />
<link rel="stylesheet" type="text/css" href="stylesheets/fixes.css" />
<link href="images/favicon.ico" rel="shortcut icon" type="image/x-icon" />
</head>
<body class="guide">
<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>模型</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>视图</dt>
<dd><a href="layouts_and_rendering.html">Rails 布局和视图渲染</a></dd>
<dd><a href="form_helpers.html">Action View 表单帮助方法</a></dd>
<dt>控制器</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">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>
</dl>
</div>
</li>
<!-- <li><a class="nav-item" href="//github.com/docrails-tw/wiki">参与翻译</a></li> -->
<li><a class="nav-item" href="https://github.com/ruby-china/guides/blob/master/CONTRIBUTING.md">贡献</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="模型">
<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="视图">
<option value="layouts_and_rendering.html">Rails 布局和视图渲染</option>
<option value="form_helpers.html">Action View 表单帮助方法</option>
</optgroup>
<optgroup label="控制器">
<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">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>
</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>如何分析调用堆栈;</li>
</ul>
<div id="subCol">
<h3 class="chapter"><img src="images/chapters_icon.gif" alt="" />Chapters</h3>
<ol class="chapters">
<li>
<a href="#%E8%B0%83%E8%AF%95%E7%9B%B8%E5%85%B3%E7%9A%84%E8%A7%86%E5%9B%BE%E5%B8%AE%E5%8A%A9%E6%96%B9%E6%B3%95">调试相关的视图帮助方法</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="#logger-%E6%98%AF%E4%BB%80%E4%B9%88">Logger 是什么</a></li>
<li><a href="#%E6%97%A5%E5%BF%97%E7%AD%89%E7%BA%A7">日志等级</a></li>
<li><a href="#%E5%86%99%E6%97%A5%E5%BF%97">写日志</a></li>
<li><a href="#%E6%97%A5%E5%BF%97%E6%A0%87%E7%AD%BE">日志标签</a></li>
<li><a href="#%E6%97%A5%E5%BF%97%E5%AF%B9%E6%80%A7%E8%83%BD%E7%9A%84%E5%BD%B1%E5%93%8D">日志对性能的影响</a></li>
</ul>
</li>
<li>
<a href="#%E4%BD%BF%E7%94%A8-debugger-gem-%E8%B0%83%E8%AF%95">使用 <code>debugger</code> gem 调试</a>
<ul>
<li><a href="#%E5%AE%89%E8%A3%85">安装</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%BA%BF%E7%A8%8B">线程</a></li>
<li><a href="#%E5%AE%A1%E6%9F%A5%E5%8F%98%E9%87%8F">审查变量</a></li>
<li><a href="#%E9%80%90%E6%AD%A5%E6%89%A7%E8%A1%8C">逐步执行</a></li>
<li><a href="#%E6%96%AD%E7%82%B9">断点</a></li>
<li><a href="#%E6%8D%95%E8%8E%B7%E5%BC%82%E5%B8%B8">捕获异常</a></li>
<li><a href="#%E6%81%A2%E5%A4%8D%E6%89%A7%E8%A1%8C">恢复执行</a></li>
<li><a href="#%E7%BC%96%E8%BE%91">编辑</a></li>
<li><a href="#%E9%80%80%E5%87%BA">退出</a></li>
<li><a href="#%E8%AE%BE%E7%BD%AE">设置</a></li>
</ul>
</li>
<li>
<a href="#%E8%B0%83%E8%AF%95%E5%86%85%E5%AD%98%E6%B3%84%E9%9C%B2">调试内存泄露</a>
<ul>
<li><a href="#valgrind">Valgrind</a></li>
</ul>
</li>
<li><a href="#%E7%94%A8%E4%BA%8E%E8%B0%83%E8%AF%95%E7%9A%84%E6%8F%92%E4%BB%B6">用于调试的插件</a></li>
<li><a href="#%E5%8F%82%E8%80%83%E8%B5%84%E6%BA%90">参考资源</a></li>
</ol>
</div>
</div>
</div>
<div id="container">
<div class="wrapper">
<div id="mainCol">
<h3 id="调试相关的视图帮助方法">1 调试相关的视图帮助方法</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> 标签中,可以把任何对象转换成人类可读的数据格式。例如,在视图中有以下代码:</p><div class="code_container">
<pre class="brush: ruby; html-script: true; gutter: false; toolbar: false">
<%= debug @post %>
<p>
<b>Title:</b>
<%= @post.title %>
</p>
</pre>
</div>
<p>渲染后会看到如下结果:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
--- !ruby/object:Post
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: ruby; html-script: true; gutter: false; toolbar: false">
<%= simple_format @post.to_yaml %>
<p>
<b>Title:</b>
<%= @post.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:Post
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 时使用这个方法特别方便。<code>inspect</code> 方法以字符串的形式显示对象的值。例如:</p><div class="code_container">
<pre class="brush: ruby; html-script: true; gutter: false; toolbar: false">
<%= [1, 2, 3, 4, 5].inspect %>
<p>
<b>Title:</b>
<%= @post.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> 类把信息写入日志。当然也可换用其他代码库,比如 <code>Log4r</code>。</p><p>替换日志代码库可以在 <code>environment.rb</code> 或其他环境文件中设置:</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>
<div class="info"><p>默认情况下,日志文件都保存在 <code>Rails.root/log/</code> 文件夹中,日志文件名为 <code>environment_name.log</code>。</p></div><h4 id="日志等级">2.2 日志等级</h4><p>如果消息的日志等级等于或高于设定的等级,就会写入对应的日志文件中。如果想知道当前的日志等级,可以调用 <code>Rails.logger.level</code> 方法。</p><p>可用的日志等级包括:<code>:debug</code>,<code>:info</code>,<code>:warn</code>,<code>:error</code>,<code>:fatal</code> 和 <code>:unknown</code>,分别对应数字 0-5。修改默认日志等级的方式如下:</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>这么设置在开发环境和交付准备环境中很有用,在生产环境中则不会写入大量不必要的信息。</p><div class="info"><p>Rails 所有环境的默认日志等级是 <code>debug</code>。</p></div><h4 id="写日志">2.3 写日志</h4><p>把消息写入日志文件可以在控制器、模型或邮件发送程序中调用 <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 PostsController < ApplicationController
# ...
def create
@post = Post.new(params[:post])
logger.debug "New post: #{@post.attributes.inspect}"
logger.debug "Post should be valid: #{@post.valid?}"
if @post.save
flash[:notice] = 'Post was successfully created.'
logger.debug "The post was saved and now the user is going to be redirected..."
redirect_to(@post)
else
render action: "new"
end
end
# ...
end
</pre>
</div>
<p>执行上述动作后得到的日志如下:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
Processing PostsController#create (for 127.0.0.1 at 2008-09-08 11:52:54) [POST]
Session ID: BAh7BzoMY3NyZl9pZCIlMDY5MWU1M2I1ZDRjODBlMzkyMWI1OTg2NWQyNzViZjYiCmZsYXNoSUM6J0FjdGl
vbkNvbnRyb2xsZXI6OkZsYXNoOjpGbGFzaEhhc2h7AAY6CkB1c2VkewA=--b18cd92fba90eacf8137e5f6b3b06c4d724596a4
Parameters: {"commit"=>"Create", "post"=>{"title"=>"Debugging Rails",
"body"=>"I'm learning how to print in logs!!!", "published"=>"0"},
"authenticity_token"=>"2059c1286e93402e389127b1153204e0d1e275dd", "action"=>"create", "controller"=>"posts"}
New post: {"updated_at"=>nil, "title"=>"Debugging Rails", "body"=>"I'm learning how to print in logs!!!",
"published"=>false, "created_at"=>nil}
Post should be valid: true
Post Create (0.000443) INSERT INTO "posts" ("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 post was saved and now the user is going to be redirected...
Redirected to #<Post:0x20af760>
Completed in 0.01224 (81 reqs/sec) | DB: 0.00044 (3%) | 302 Found [http://localhost/posts]
</pre>
</div>
<p>加入这种日志信息有助于发现异常现象。如果添加了额外的日志消息,记得要合理设定日志等级,免得把大量无用的消息写入生产环境的日志文件。</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>如果把日志写入硬盘,肯定会对程序有点小的性能影响。不过可以做些小调整:<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>在上述代码中,即使日志等级不包含 <code>:debug</code> 也会对性能产生影响。因为 Ruby 要初始化字符串,再花时间做插值。因此推荐把代码块传给 <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>代码块中的内容,即字符串插值,仅当允许 <code>:debug</code> 日志等级时才会执行。这种降低性能的方式只有在日志量比较大时才能体现出来,但却是个好的编程习惯。</p><h3 id="使用-debugger-gem-调试">3 使用 <code>debugger</code> gem 调试</h3><p>如果代码表现异常,可以在日志文件或者控制台查找原因。但有时使用这种方法效率不高,无法找到导致问题的根源。如果需要检查源码,<code>debugger</code> gem 可以助你一臂之力。</p><p>如果想学习 Rails 源码但却无从下手,也可使用 <code>debugger</code> gem。随便找个请求,然后按照这里介绍的方法,从你编写的代码一直研究到 Rails 框架的代码。</p><h4 id="安装">3.1 安装</h4><p><code>debugger</code> gem 可以设置断点,实时查看执行的 Rails 代码。安装方法如下:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
$ gem install debugger
</pre>
</div>
<p>从 2.0 版本开始,Rails 内置了调试功能。在任何 Rails 程序中都可以使用 <code>debugger</code> 方法调出调试器。</p><p>下面举个例子:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class PeopleController < ApplicationController
def new
debugger
@person = Person.new
end
end
</pre>
</div>
<p>然后就能在控制台或者日志中看到如下信息:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
***** Debugger requested, but was not available: Start server with --debugger to enable *****
</pre>
</div>
<p>记得启动服务器时要加上 <code>--debugger</code> 选项:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
$ rails server --debugger
=> Booting WEBrick
=> Rails 4.2.0 application starting on http://0.0.0.0:3000
=> Debugger enabled
...
</pre>
</div>
<div class="info"><p>在开发环境中,如果启动服务器时没有指定 <code>--debugger</code> 选项,不用重启服务器,加入 <code>require "debugger"</code> 即可。</p></div><h4 id="shell">3.2 Shell</h4><p>在程序中调用 <code>debugger</code> 方法后,会在启动程序所在的终端窗口中启用调试器 shell,并进入调试器的终端 <code>(rdb:n)</code> 中。其中 <code>n</code> 是线程编号。在调试器的终端中会显示接下来要执行哪行代码。</p><p>如果在浏览器中执行的请求触发了调试器,当前浏览器选项卡会处于停顿状态,等待调试器启动,跟踪完整个请求。</p><p>例如:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
@posts = Post.all
(rdb:7)
</pre>
</div>
<p>现在可以深入分析程序的代码了。首先我们来查看一下调试器的帮助信息,输入 <code>help</code>:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(rdb:7) help
ruby-debug help v0.10.2
Type 'help <command-name>' for help on a specific command
Available commands:
backtrace delete enable help next quit show trace
break disable eval info p reload source undisplay
catch display exit irb pp restart step up
condition down finish list ps save thread var
continue edit frame method putl set tmate where
</pre>
</div>
<div class="info"><p>要想查看某个命令的帮助信息,可以在终端里输入 <code>help <command-name></code>,例如 <code>help var</code>。</p></div><p>接下来要学习最有用的命令之一:<code>list</code>。调试器中的命令可以使用简写形式,只要输入的字母数量足够和其他命令区分即可。因此,可使用 <code>l</code> 代替 <code>list</code>。</p><p><code>list</code> 命令输出当前执行代码的前后 5 行代码。下面的例子中,当前行是第 6 行,前面用 <code>=></code> 符号标记。</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(rdb:7) list
[1, 10] in /PathTo/project/app/controllers/posts_controller.rb
1 class PostsController < ApplicationController
2 # GET /posts
3 # GET /posts.json
4 def index
5 debugger
=> 6 @posts = Post.all
7
8 respond_to do |format|
9 format.html # index.html.erb
10 format.json { render json: @posts }
</pre>
</div>
<p>如果再次执行 <code>list</code> 命令,请用 <code>l</code> 试试。接下来要执行的 10 行代码会显示出来:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(rdb:7) l
[11, 20] in /PathTo/project/app/controllers/posts_controller.rb
11 end
12 end
13
14 # GET /posts/1
15 # GET /posts/1.json
16 def show
17 @post = Post.find(params[:id])
18
19 respond_to do |format|
20 format.html # show.html.erb
</pre>
</div>
<p>可以一直这么执行下去,直到文件的末尾。如果到文件末尾了,<code>list</code> 命令会回到该文件的开头,再次从头开始执行一遍,把文件视为一个环形缓冲。</p><p>如果想查看前面 10 行代码,可以输入 <code>list-</code>(或者 <code>l-</code>):</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(rdb:7) l-
[1, 10] in /PathTo/project/app/controllers/posts_controller.rb
1 class PostsController < ApplicationController
2 # GET /posts
3 # GET /posts.json
4 def index
5 debugger
6 @posts = Post.all
7
8 respond_to do |format|
9 format.html # index.html.erb
10 format.json { render json: @posts }
</pre>
</div>
<p>使用 <code>list</code> 命令可以在文件中来回移动,查看 <code>debugger</code> 方法所在位置前后的代码。如果想知道 <code>debugger</code> 方法在文件的什么位置,可以输入 <code>list=</code>:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(rdb:7) list=
[1, 10] in /PathTo/project/app/controllers/posts_controller.rb
1 class PostsController < ApplicationController
2 # GET /posts
3 # GET /posts.json
4 def index
5 debugger
=> 6 @posts = Post.all
7
8 respond_to do |format|
9 format.html # index.html.erb
10 format.json { render json: @posts }
</pre>
</div>
<h4 id="上下文">3.3 上下文</h4><p>开始调试程序时,会进入堆栈中不同部分对应的不同上下文。</p><p>到达一个停止点或者触发某个事件时,调试器就会创建一个上下文。上下文中包含被终止程序的信息,调试器用这些信息审查调用帧,计算变量的值,以及调试器在程序的什么地方终止执行。</p><p>任何时候都可执行 <code>backtrace</code> 命令(简写形式为 <code>where</code>)显示程序的调用堆栈。这有助于理解如何执行到当前位置。只要你想知道程序是怎么执行到当前代码的,就可以通过 <code>backtrace</code> 命令获得答案。</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(rdb:5) where
#0 PostsController.index
at line /PathTo/project/app/controllers/posts_controller.rb:6
#1 Kernel.send
at line /PathTo/project/vendor/rails/actionpack/lib/action_controller/base.rb:1175
#2 ActionController::Base.perform_action_without_filters
at line /PathTo/project/vendor/rails/actionpack/lib/action_controller/base.rb:1175
#3 ActionController::Filters::InstanceMethods.call_filters(chain#ActionController::Fil...,...)
at line /PathTo/project/vendor/rails/actionpack/lib/action_controller/filters.rb:617
...
</pre>
</div>
<p>执行 <code>frame n</code> 命令可以进入指定的调用帧,其中 <code>n</code> 为帧序号。</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(rdb:5) frame 2
#2 ActionController::Base.perform_action_without_filters
at line /PathTo/project/vendor/rails/actionpack/lib/action_controller/base.rb:1175
</pre>
</div>
<p>可用的变量和逐行执行代码时一样。毕竟,这就是调试的目的。</p><p>向前或向后移动调用帧可以执行 <code>up [n]</code>(简写形式为 <code>u</code>)和 <code>down [n]</code> 命令,分别向前或向后移动 n 帧。n 的默认值为 1。向前移动是指向更高的帧数移动,向下移动是指向更低的帧数移动。</p><h4 id="线程">3.4 线程</h4><p><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><code>thread</code> 命令有很多作用。调试并发线程时,如果想确认代码中没有条件竞争,使用这个命令十分方便。</p><h4 id="审查变量">3.5 审查变量</h4><p>任何表达式都可在当前上下文中运行。如果想计算表达式的值,直接输入表达式即可。</p><p>下面这个例子说明如何查看在当前上下文中 <code>instance_variables</code> 的值:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
@posts = Post.all
(rdb:11) instance_variables
["@_response", "@action_name", "@url", "@_session", "@_cookies", "@performed_render", "@_flash", "@template", "@_params", "@before_filter_chain_aborted", "@request_origin", "@_headers", "@performed_redirect", "@_request"]
</pre>
</div>
<p>你可能已经看出来了,在控制器中可使用的所有实例变量都显示出来了。这个列表随着代码的执行会动态更新。例如,使用 <code>next</code> 命令执行下一行代码:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(rdb:11) next
Processing PostsController#index (for 127.0.0.1 at 2008-09-04 19:51:34) [GET]
Session ID: BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA==--b16e91b992453a8cc201694d660147bba8b0fd0e
Parameters: {"action"=>"index", "controller"=>"posts"}
/PathToProject/posts_controller.rb:8
respond_to do |format|
</pre>
</div>
<p>然后再查看 <code>instance_variables</code> 的值:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(rdb:11) instance_variables.include? "@posts"
true
</pre>
</div>
<p>实例变量中出现了 <code>@posts</code>,因为执行了定义这个变量的代码。</p><div class="info"><p>执行 <code>irb</code> 命令可进入 <strong>irb</strong> 模式,irb 会话使用当前上下文。警告:这是实验性功能。</p></div><p><code>var</code> 命令是显示变量值最便捷的方式:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
var
(rdb:1) v[ar] const <object> show constants of object
(rdb:1) v[ar] g[lobal] show global variables
(rdb:1) v[ar] i[nstance] <object> show instance variables of object
(rdb:1) v[ar] l[ocal] show local variables
</pre>
</div>
<p>上述方法可以很轻易的查看当前上下文中的变量值。例如:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(rdb:9) var local
__dbg_verbose_save => false
</pre>
</div>
<p>审查对象的方法可以使用下述方式:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(rdb:9) var instance Post.new
@attributes = {"updated_at"=>nil, "body"=>nil, "title"=>nil, "published"=>nil, "created_at"...
@attributes_cache = {}
@new_record = true
</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">
(rdb:1) display @recent_comments
1: @recent_comments =
</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><div class="info"><p><code>step+ n</code> 和 <code>step- n</code> 可以相应的向前或向后 <code>n</code> 步。</p></div><p><code>next</code> 命令的作用和 <code>step</code> 命令类似,但执行的方法不会停止。和 <code>step</code> 命令一样,也可使用加号前进 <code>n</code> 步。</p><p><code>next</code> 命令和 <code>step</code> 命令的区别是,<code>step</code> 命令会在执行下一行代码之前停止,一次只执行一步;<code>next</code> 命令会执行下一行代码,但不跳出方法。</p><p>例如,下面这段代码调用了 <code>debugger</code> 方法:</p><div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">
class Author < ActiveRecord::Base
has_one :editorial
has_many :comments
def find_recent_comments(limit = 10)
debugger
@recent_comments ||= comments.where("created_at > ?", 1.week.ago).limit(limit)
end
end
</pre>
</div>
<div class="info"><p>在控制台中也可启用调试器,但要记得在调用 <code>debugger</code> 方法之前先 <code>require "debugger"</code>。</p></div><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
$ rails console
Loading development environment (Rails 4.2.0)
>> require "debugger"
=> []
>> author = Author.first
=> #<Author id: 1, first_name: "Bob", last_name: "Smith", created_at: "2008-07-31 12:46:10", updated_at: "2008-07-31 12:46:10">
>> author.find_recent_comments
/PathTo/project/app/models/author.rb:11
)
</pre>
</div>
<p>停止执行代码时,看一下输出:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(rdb:1) list
[2, 9] in /PathTo/project/app/models/author.rb
2 has_one :editorial
3 has_many :comments
4
5 def find_recent_comments(limit = 10)
6 debugger
=> 7 @recent_comments ||= comments.where("created_at > ?", 1.week.ago).limit(limit)
8 end
9 end
</pre>
</div>
<p>在方法内的最后一行停止了。但是这行代码执行了吗?你可以审查一下实例变量。</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(rdb:1) var instance
@attributes = {"updated_at"=>"2008-07-31 12:46:10", "id"=>"1", "first_name"=>"Bob", "las...
@attributes_cache = {}
</pre>
</div>
<p><code>@recent_comments</code> 还未定义,所以这行代码还没执行。执行 <code>next</code> 命令执行这行代码:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(rdb:1) next
/PathTo/project/app/models/author.rb:12
@recent_comments
(rdb:1) var instance
@attributes = {"updated_at"=>"2008-07-31 12:46:10", "id"=>"1", "first_name"=>"Bob", "las...
@attributes_cache = {}
@comments = []
@recent_comments = []
</pre>
</div>
<p>现在看以看到,因为执行了这行代码,所以加载了 <code>@comments</code> 关联,也定义了 <code>@recent_comments</code>。</p><p>如果想深入方法和 Rails 代码执行堆栈,可以使用 <code>step</code> 命令,一步一步执行。这是发现代码问题(或者 Rails 框架问题)最好的方式。</p><h4 id="断点">3.7 断点</h4><p>断点设置在何处终止执行代码。调试器会在断点设定行调用。</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>expression</code>,其返回结果必须为 <code>true</code> 才会启动调试器;</li>
<li>
<code>break class(.|\#)method [if expression]</code>:在 <code>class</code> 类的 <code>method</code> 方法中设置断点,<code>.</code> 和 <code>\#</code> 分别表示类和实例方法。表达式 <code>expression</code> 的作用和上个命令一样;</li>
</ul>
<div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(rdb:5) break 10
Breakpoint 1 file /PathTo/project/vendor/rails/actionpack/lib/action_controller/filters.rb, line 10
</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">
(rdb:5) info breakpoints
Num Enb What
1 y at filters.rb:10
</pre>
</div>
<p>如果想删除断点,可以执行 <code>delete n</code> 命令,删除编号为 <code>n</code> 的断点。如果不指定数字 <code>n</code>,则删除所有在用的断点。</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
(rdb:5) delete 1
(rdb:5) info breakpoints
No breakpoints.
</pre>
</div>
<p>启用和禁用断点的方法如下:</p>
<ul>
<li>
<code>enable breakpoints</code>:允许使用指定的断点列表或者所有断点终止执行程序。这是创建断点后的默认状态。</li>
<li>
<code>disable breakpoints</code>:指定的断点 <code>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>):一直执行程序,直到指定的堆栈帧结束为止。如果没有指定 <code>frame-number</code> 参数,程序会一直执行,直到当前堆栈帧结束为止。当前堆栈帧就是最近刚使用过的帧,如果之前没有移动帧的位置(执行 <code>up</code>,<code>down</code> 或 <code>frame</code> 命令),就是第 0 帧。如果指定了帧数,则运行到指定的帧结束为止。</li>
</ul>
<h4 id="编辑">3.10 编辑</h4><p>下面两种方法可以从调试器中使用编辑器打开源码:</p>
<ul>
<li>
<code>edit [file:line]</code>:使用环境变量 <code>EDITOR</code> 指定的编辑器打开文件 <code>file</code>。还可指定文件的行数(<code>line</code>)。</li>
<li>
<code>tmate n</code>(简写形式为 <code>tm</code>):在 TextMate 中打开当前文件。如果指定了参数 <code>n</code>,则使用第 n 帧。</li>
</ul>
<h4 id="退出">3.11 退出</h4><p>要想退出调试器,请执行 <code>quit</code> 命令(缩写形式为 <code>q</code>),或者别名 <code>exit</code>。</p><p>退出后会终止所有线程,所以服务器也会被停止,因此需要重启。</p><h4 id="设置">3.12 设置</h4><p><code>debugger</code> gem 能自动显示你正在分析的代码,在编辑器中修改代码后,还会重新加载源码。下面是可用的选项:</p>
<ul>
<li>
<code>set reload</code>:修改代码后重新加载;</li>
<li>
<code>set autolist</code>:在每个断点处执行 <code>list</code> 命令;</li>
<li>
<code>set listsize n</code>:设置显示 <code>n</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> 可以查看 <code>subcommand</code> 的帮助信息。</p><div class="info"><p>设置可以保存到家目录中的 <code>.rdebugrc</code> 文件中。启动调试器时会读取这个文件中的全局设置。</p></div><p>下面是 <code>.rdebugrc</code> 文件示例:</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">
set autolist
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 提供了很多工具,可用来侦察内存管理和线程问题,也能详细分析程序。例如,如果 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>有很多 Rails 插件可以帮助你查找问题和调试程序。下面列出一些常用的调试插件:</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>:提供了一个邮件发送程序和一组默认的邮件模板,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> 文件的内容,显示的内容包括:数据库查询时间,渲染时间,总时间,参数列表,渲染的视图等。</li>
</ul>
<h3 id="参考资源">6 参考资源</h3>
<ul>
<li><a href="http://bashdb.sourceforge.net/ruby-debug/home-page.html">ruby-debug 首页</a></li>
<li><a href="https://github.com/cldwalker/debugger">debugger 首页</a></li>
<li><a href="http://www.sitepoint.com/debug-rails-app-ruby-debug/">文章:使用 ruby-debug 调试 Rails 程序</a></li>
<li><a href="http://railscasts.com/episodes/54-debugging-ruby-revised">Ryan Bates 制作的视频“Debugging Ruby (revised)”</a></li>
<li><a href="http://railscasts.com/episodes/24-the-stack-trace">Ryan Bates 制作的视频“The Stack Trace”</a></li>
<li><a href="http://railscasts.com/episodes/56-the-logger">Ryan Bates 制作的视频“The Logger”</a></li>
<li><a href="http://bashdb.sourceforge.net/ruby-debug.html">使用 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/ruby-china/guides/fork">Fork</a> 修正,或至此处<a href="https://github.com/ruby-china/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/">创用 CC 姓名标示-相同方式分享 4.0 国际授权条款</a>授权。</p>
<p>“Rails”、“Ruby on Rails”,以及 Rails logo 为 David Heinemeier Hansson 的商标。版权所有。</p>
</div>
</div>
<script type="text/javascript" src="javascripts/jquery.min.js"></script>
<script type="text/javascript" src="javascripts/responsive-tables.js"></script>
<script type="text/javascript" src="javascripts/guides.js"></script>
<script type="text/javascript" src="javascripts/syntaxhighlighter/shCore.js"></script>
<script type="text/javascript" src="javascripts/syntaxhighlighter/shBrushRuby.js"></script>
<script type="text/javascript" src="javascripts/syntaxhighlighter/shBrushXml.js"></script>
<script type="text/javascript" src="javascripts/syntaxhighlighter/shBrushSql.js"></script>
<script type="text/javascript" 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', '', 'ruby-china.github.io');
ga('require', 'displayfeatures');
ga('send', 'pageview');
</script>
</body>
</html>