# Streams of Data Part I ## Logging Basics # We don't need anything complex here. # We will use the logger in the stdlib. # Rails.logger works fine here as well. # Using Rails.logger is prefered as you won't muck up # the screen when running tests. require 'logger' module Log extend self def puts(msg) # Forget about log FILES that are on spinning disks # Think of this logger as an outlet for streams of data. @@logger ||= Logger.new(STDOUT) # There are different kinds of levels. We will use info. @@logger.info(msg) end end # Ask the operating system to not buffer our output # and to flush immediately $stdout.sync = true # Here is some business logic. class Invoice # log line ratio 1/4 def initialize(user) log("begin init params=#{user}") @id = rand(42) @user = user @status = "processing" end # log line ratio 3/8 # Our logs tell a story about how are method is behaving. def status # Anchor this message for quick searches. # The "#" char is arbitrary but important. # Think of this as a "real-time" code comment. log("#invoice_check_status") # Quickly dump important peices of state. # This will help us debug invocations long after # they were invoked. log("invoice=#{@id} status=#{@status}") if @status == "processing" # We are about to do something interesting. Let's log it :) # Again, notice that our anchored message tells a story. log("invoice=#{@id} #invoice_finalize") @status = "finalize" else @status end end def log(msg) # Don't be afraid to provide a mechanism # to disable logging. if ENV["VERBOSE"] Log.puts("user=#{@user} #{msg}") end end end MongoDb = {} # More or less.... run Proc.new {|env| # Define a log method wherever you want # to customize the context. Often different # modules of code will want to have a definition of logging. # In our invoice model, we inserted the user=id into all messages. def log(msg) Log.puts(msg) end user_id = env["REMOTE_ADDR"] if invoice = MongoDb[user_id] # Now we are telling a story about how # we interact with our robust document store. log("user=#{user_id} #database_hit") else # Whoops! log("user=#{user_id} #database_miss") invoice = MongoDb[user_id] = Invoice.new(user_id) end [ 200, {'Content-Type' => 'text/plain'}, [invoice.status] ] } # Streams of data on Heorku + Papertrail