Hiro Asari Senior Software Engineer Red Hat Failure is not an option or: How I learned to read the logs and love the stack trace RubyConf Brasil 2012 Friday, August 31, 12
Hiro AsariSenior Software EngineerRed Hat
Failure is not an optionor: How I learned to read the logs and love the stack trace
RubyConf Brasil 2012
Friday, August 31, 12
Failure is not an optionor: How I learned to read the logs and love the stack trace
Hiro AsariJRuby Support Engineer
RubyConf Brasil 2012
Friday, August 31, 12
If debugging is the process of removing bugs, then programming must be the process of putting them in.
Edsger Dijkstra©2002 Hamilton Richards
Friday, August 31, 12
All code appearing in this talk are fictitious. Any resemblance
to real code fragments, in production or otherwise, is
purely coincidental.
Friday, August 31, 12
Know where your logs are
http://www.flickr.com/photos/41449558@N06/6690612703Friday, August 31, 12
Gather the logs
http://www.flickr.com/photos/30505480@N00/6820686281Friday, August 31, 12
Know your architecture
http://en.wikipedia.org/wiki/File:Ponte_estaiada_Octavio_Frias_-_Sao_Paulo.jpg
Friday, August 31, 12
HAProxy
nginx
unicorn
nginx nginx nginx nginx
unicorn unicorn unicorn
request
Web Server
Friday, August 31, 12
http://www.flickr.com/photos/usnavy/6871499850/
What if there are no logs?
Friday, August 31, 12
⋮gems/bundler-1.0.9/lib/bundler/ui.rb:56: uninitialized constant Gem::SilentUI (NameError)⋮
$ bundle install$
Friday, August 31, 12
Read th
e stac
k trac
e
http://www.flickr.com/photos/26699508@N04/2529389660
Friday, August 31, 12
NoMethodError: undefined method `[]' for nil:NilClass! !initialize at c:/jruby/lib/ruby/gems/1.8/gems/metric_fu-2.1.1/lib/generators/saikuro.rb:232! !get_elements at c:/jruby/lib/ruby/gems/1.8/gems/metric_fu-2.1.1/lib/generators/saikuro.rb:169! !initialize at c:/jruby/lib/ruby/gems/1.8/gems/metric_fu-2.1.1/lib/generators/saikuro.rb:130! !assemble_files at c:/jruby/lib/ruby/gems/1.8/gems/metric_fu-2.1.1/lib/generators/saikuro.rb:111
Example
Friday, August 31, 12
def initialize(line)!!@line = line!!@element_type = line.match(TYPE_REGEX)[1].strip!!@name = line.match(NAME_REGEX)[1].strip!!@complexity = line.match(COMPLEXITY_REGEX)[1].strip!!@lines = line.match(LINES_REGEX)[1].strip!!@defs = []end
Example
line 232
Friday, August 31, 12
rake assets:precompile failure
Example
JRuby 1.6.6Rails 3.1.1
can't convert Encoding into String
Friday, August 31, 12
rake aborted!can't convert Encoding into String (in /opt/jruby/lib/ruby/gems/shared/gems/haml_coffee_assets-0.6.0/vendor/assets/javascripts/hamlcoffee.js.coffee.erb)org/jruby/RubyIO.java:3722:in `popen'/opt/jruby/lib/ruby/gems/shared/gems/execjs-1.2.9/lib/execjs/external_runtime.rb:165:in `sh'/opt/jruby/lib/ruby/gems/shared/gems/execjs-1.2.9/lib/execjs/external_runtime.rb:125:in `exec_runtime'org/jruby/RubyBasicObject.java:1700:in `__send__'org/jruby/RubyKernel.java:2099:in `send'⋮
Example
Friday, August 31, 12
def sh(command) output, options = nil, {} options[:external_encoding] = @encoding if @encoding options[:internal_encoding] =
Encoding.default_internal || 'UTF-8' IO.popen(command, options) { |f| output = f.read } output end
line 165
jruby -e 'output = nil; IO.popen("ls",{:internal_encoding => Encoding::EucJP}) { |f| output = f.read }; p output'
Minimal Failure
Friday, August 31, 12
$ jruby -v --1.9 -e 'output = nil; IO.popen("ls",{:internal_encoding => Encoding::EucJP}) { |f| output = f.read }; p output'jruby 1.6.6 (ruby-1.9.2-p312) (2012-01-30 5673572) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_04) [darwin-x86_64-java]TypeError: can't convert Encoding into String popen at org/jruby/RubyIO.java:3722 (root) at -e:1
Example
Friday, August 31, 12
rake aborted!can't convert Encoding into String (in /opt/jrubylib/ruby/gems/shared/gems/haml_coffee_assets-0.6.0/vendor/assets/javascripts/hamlcoffee.js.coffee.erb)org/jruby/RubyIO.java:3722:in `popen'/opt/jrubylib/ruby/gems/shared/gems/execjs-1.2.9/lib/execjs/external_runtime.rb:165:in `sh'/opt/jrubylib/ruby/gems/shared/gems/execjs-1.2.9/lib/execjs/external_runtime.rb:125:in `exec_runtime'org/jruby/RubyBasicObject.java:1700:in `__send__'org/jruby/RubyKernel.java:2099:in `send'⋮
Example
Friday, August 31, 12
Set up continuous integration
• Travis http://travis-ci.org
• Jenkins http://jenkins-ci.org
Friday, August 31, 12
Code Coverage
• Shows what you did not test
• Does not show your tests are complete
Friday, August 31, 12
def foo(arg) begin if arg.nil? raise ArgumentError else raise RegexpError end rescue Exception raise "Play it again, Sam" endend
Rescue exceptions judiciously
Friday, August 31, 12
def foo(arg) begin if arg.nil? raise ArgumentError else raise RegexpError end rescue Exception => e raise e endend
Rescue exceptions judiciously
Friday, August 31, 12
unless arg.is_a? Array arg = [arg] end # do stuff with arg arg.each do … endend
Let it faildef foo(arg)
Friday, August 31, 12
# do stuff with arg arg.each do … endend
Let it fail
unless arg.is_a? Array arg = [arg] end
def foo(arg)
Friday, August 31, 12
Prefer hard-coded* error messages
Ugh!
$ ack -c 'Expected.*but got' .15
$ ruby -S awesome_appExpected 1, but got 2.
Friday, August 31, 12
irb(main):007:0> obj.foo.foo.foo.foo.fooNoMethodError: undefined method `foo' for nil:NilClass!!!! from (irb):7!!!! from /usr/local/bin/irb2.0:12:in `<main>'
Method chaining
Friday, August 31, 12
…if you're as clever as you can be when you write [a program], how will you ever debug it?
Brian KernighanFriday, August 31, 12
http://yqg06172.img.jugem.jp/20110824_2225189.jpg
Friday, August 31, 12
Thank you!
http://www.flickr.com/photos/74084024@N00/40222490
Hiro Asari
@hiro_asari
Uncredited photos: http://t.co/a2H1SU4
Brought to you byGill Sans and Inconsolata
Friday, August 31, 12