is ruby logger thread(process)-safe? at rubyconf 2013

22
Is Ruby Logger Thread(Process)- safe? RubyConf 2013 @Miami SEO Naotoshi (@sonots) 2013/11/09

Upload: naotoshi-seo

Post on 09-May-2015

4.077 views

Category:

Technology


9 download

TRANSCRIPT

Page 1: Is ruby logger thread(process)-safe? at RubyConf 2013

Is Ruby LoggerThread(Process)-

safe?

RubyConf 2013 @MiamiSEO Naotoshi (@sonots)

2013/11/09

Page 2: Is ruby logger thread(process)-safe? at RubyConf 2013

Naotoshi SEOlike Now-toshi Say-oh

@sonots (twitter, github)Dev Engineer for OperationsBecame as a commiter of Fluentd

Page 3: Is ruby logger thread(process)-safe? at RubyConf 2013

•realtime pipelining of log streams

•plugins written in ruby

Page 4: Is ruby logger thread(process)-safe? at RubyConf 2013

Log Management Tool•syslog-ng / rsyslog•splunk•scribed•flumeNG

•logstash

Only collection

No Plugin

Java Plugin

Ruby Plugin (Not Gem)

Not Free

•fluentd Ruby Plugin (Gem Support)

Page 5: Is ruby logger thread(process)-safe? at RubyConf 2013

Try thefluentd!It’s very nice tool, check it out!

http://fluentd.org/

Page 6: Is ruby logger thread(process)-safe? at RubyConf 2013

Today’sTalk

Page 7: Is ruby logger thread(process)-safe? at RubyConf 2013

Logger

Page 8: Is ruby logger thread(process)-safe? at RubyConf 2013

We needed aLogger whichworks safely

in multiprocessfor Fluentd

Page 9: Is ruby logger thread(process)-safe? at RubyConf 2013

Examined Ruby Logger

• 1) Will logs not be mixtured in multi-threads?

• 2) Will logs not be mixtured in multi-processes?

• 3) Does log rotation work safely in multi-threads?

• 4) Does log rotation work safely in multi-processes?

Page 10: Is ruby logger thread(process)-safe? at RubyConf 2013

1) Will logs not be mixtured in multi-threads?

require 'logger'require 'parallel'

logger = Logger.new("/tmp/test.log")Parallel.map(['a', 'b'], :in_threads => 2) do |letter| 10000.times do logger.info letter * 5000 endend

Code

Result

$ egrep -e 'ab' -e 'ba' /tmp/test.log[empty]

OK

Page 11: Is ruby logger thread(process)-safe? at RubyConf 2013

WHY?

def write(message) begin @mutex.synchronize do ... @dev.write(message) ... end

logger.rb#L559

Ruby’s Logger is taking mutex to be thread-safe.

Page 12: Is ruby logger thread(process)-safe? at RubyConf 2013

2) Will logs not be mixtured in multi-processes?

require 'logger'require 'parallel'

logger = Logger.new("/tmp/test.log")Parallel.map(['a', 'b'], :in_processes => 2) do |letter| 10000.times do logger.info letter * 5000 endend

Code

Result

$ egrep -e 'ab' -e 'ba' /tmp/test.log[empty]

OK

Page 13: Is ruby logger thread(process)-safe? at RubyConf 2013

Really? Why?

But, Linux system call write(2) itself is atomic as long as writing to a local file.

Atomic/non-atomic: A write is atomic if the whole amount written in oneoperation is not interleaved with data from any other process. This isuseful when there are multiple writers sending data to a single reader. Applications need to know how large a write request can be expected tobe performed atomically. This maximum is called {PIPE_BUF}. This volumeof IEEE Std 1003.1-2001 does not say whether write requests for morethan {PIPE_BUF} bytes are atomic, but requires that writes of {PIPE_BUF} orfewer bytes shall be atomic.

Mutex does not work to exclusively lock in multi-processes environment.

OK

Page 14: Is ruby logger thread(process)-safe? at RubyConf 2013

3) Does log rotation work safely multi-threads?

require 'logger'require 'parallel'

logger = Logger.new("/tmp/test.log", 3, 1024 * 10)Parallel.map(['a', 'b'], :in_threads => 2) do |letter| 10000.times do logger.info letter * 5000 endend

Code

Result

$ ls -l /tmp/test*-rw-r--r-- 1 sonots sonots 10806 9月 29 23:03 /tmp/test.log-rw-r--r-- 1 sonots sonots 10806 9月 29 23:03 /tmp/test.log.0-rw-r--r-- 1 sonots sonots 10806 9月 29 23:03 /tmp/test.log.1

No Error, OK

Page 15: Is ruby logger thread(process)-safe? at RubyConf 2013

4) Does log rotation work safely in multi-processes?

require 'logger'require 'parallel'

logger = Logger.new("/tmp/test.log", 3, 1024 * 10)Parallel.map(['a', 'b'], :in_processes => 2) do |letter| 10000.times do logger.info letter * 5000 endend

Code

Result

log writing failed. closed streamlog shifting failed. closed streamlog writing failed. closed streamlog shifting failed. closed stream...

Oops, Bad!

Page 16: Is ruby logger thread(process)-safe? at RubyConf 2013

WHY?

def write(message) begin @mutex.synchronize do ... check_shift_log ... end

logger.rb#L559

Ruby’s Logger is taking mutex to be thread-safe, but was not treating anything for multi-processes.

Page 17: Is ruby logger thread(process)-safe? at RubyConf 2013

We(@frsyuki and me) Fixed

• The approach is to use flock(2) without creating another *.lock file

Page 18: Is ruby logger thread(process)-safe? at RubyConf 2013

Pull requested to ruby

My first contribution to ruby

Page 19: Is ruby logger thread(process)-safe? at RubyConf 2013

Merged!!

Thanks to @naruse for his review and advice!!

Page 20: Is ruby logger thread(process)-safe? at RubyConf 2013

Will be releasedwith 2.1.0!!

on 12/25

Page 21: Is ruby logger thread(process)-safe? at RubyConf 2013

•Ruby Logger was not safe in multi-processes, but it is safe now!!!

•Try ruby-trunk orhttps://github.com/sonots/

process_safe_logger

CONCLUSION

Page 22: Is ruby logger thread(process)-safe? at RubyConf 2013

Try thefluentd!It’s very nice tool, check it out!

http://fluentd.org/