Dave
Dave

Reputation: 19150

With Rails 4.2 and lograge, how do I enable date/times before each logged line?

I use the gem “Lograge” 0.3.6, and Rails 4.2. I have this configured in my config/environments/development.rb file

  config.lograge.enabled = true
  config.lograge.formatter = CustomLogstash.new

However, I notice the output in my log/development.log file doesn’t contain date/times in front of each line. How do I configure lograge (or maybe just my Rails logger?) to prefix each line in that file with a date and time?

Upvotes: 0

Views: 1659

Answers (4)

Nitin Srivastava
Nitin Srivastava

Reputation: 1424

As per the document, the lograge gem provides below log formatters.

Lograge::Formatters::Lines.new  # need to install "lines" gem
Lograge::Formatters::Cee.new
Lograge::Formatters::Graylog2.new
Lograge::Formatters::KeyValue.new  # default lograge format
Lograge::Formatters::Json.new
Lograge::Formatters::Logstash.new  # need to install "logstash-event" gem 
Lograge::Formatters::LTSV.new
Lograge::Formatters::Raw.new       # Returns a ruby hash object

By default the lograge gem uses Lograge::Formatters::KeyValue.new format for log.

You can customize this and make it universal by using your CustomLogStash class with some changes.

class CustomLogStash < Lograge::Formatters::KeyValue
  def call(data)
    # I'm using timestamp key here, you can choose whatever you want.
    data_hash = { timestamp: Time.now.utc.strftime("%Y-%m-%dT%H:%M:%S.%3N")}.merge!(data)
    super(data_hash)
  end
end

Same way you can use any Lograge::Formatters class and apply the custom format to the log.

Now add below code to your config/initializers/lograge.rb file.

Rails.application.configure do
  config.lograge.enabled = true
  config.lograge.formatter = CustomLogStash.new
end

Now restart your server and load a page in your browser. You will see the logs something like below:

timestamp=2021-11-21T17:14:10.726 method=GET path=/categories format=html controller=categories action=index status=200 duration=259.11 view=244.91 db=2.60

EDITED

If you are looking for logs something like enter image description here

then you don't need any gem for this. You can achieve this by adding below lines to your preferred environment development/production/test

config.log_level = :debug
config.log_formatter = ::Logger::Formatter.new

If you want to apply this across all environments then add above lines to the config/application.rb file.

Upvotes: 1

Archana David
Archana David

Reputation: 1374

As per official documentation for lograge, you can make use of custom_options

EDIT 1 : custom_options using time: Time.now or time:event.time


Rails.application.configure do
  config.lograge.enabled = true
  config.lograge.formatter = Lograge::Formatters::Logstash.new

  # add time to lograge
  config.lograge.custom_options = lambda do |event|
    { time: Time.now } #or use time:event.time 
  end
end

Note: When using the logstash output, you need to add the additional gem logstash-event. You can simply add it to your Gemfile like this

      gem "logstash-event"

EDIT 2: Update based on comments custom_options using :time => event.time


#config/environments/production.rb
MyApp::Application.configure do
  config.lograge.enabled = true

  # add time to lograge
  config.lograge.custom_options = lambda do |event|
    {:time => event.time}
  end
end

OR the below custom options which was a fix in lograge issue to ensure both date and time logged using time: event.time.to_s(:db)


config.lograge.custom_options = lambda do |event|
      unwanted_keys = %w[format action controller utf8]
      params = event.payload[:params].reject { |key,_| unwanted_keys.include? key }
      {time: event.time.to_s(:db), user: event.payload[:user], params: params}
    end

ALTERNATIVELY you can use this Custom logger


# Define a setter to pass in a custom log formatter

class ActiveSupport::BufferedLogger

  def formatter=(formatter)

    @log.formatter = formatter

  end

end



# Defines a custom log format (time, severity, message, PID, backtrace)... all with color!

class Formatter

  SEVERITY_TO_TAG   = {'DEBUG'=>'meh', 'INFO'=>'fyi', 'WARN'=>'hmm', 'ERROR'=>'wtf', 'FATAL'=>'omg', 'UNKNOWN'=>'???'}

  SEVERITY_TO_COLOR = {'DEBUG'=>'37',  'INFO'=>'32',  'WARN'=>'33',  'ERROR'=>'31',  'FATAL'=>'31',  'UNKNOWN'=>'37'}

  HUMOR_FOR_ENV     = {development: true, test: true, production: false}

  DEPTH_FOR_ENV     = {development: 3,    test: 3,    production: 1}

  EXCLUSION_REGEX   = /log|active_support|active_record/



  def humorous?

    return @is_humorous if defined? @is_humorous

    @is_humorous = HUMOR_FOR_ENV[ Rails.env.to_sym ]

  end



  def depth

    @depth ||= DEPTH_FOR_ENV[ Rails.env.to_sym ]

  end



  def call(severity, time, progname, msg)

    t     = time.strftime("%Y-%m-%d %H:%M:%S.") << time.usec.to_s[0..2].rjust(3)

    color = SEVERITY_TO_COLOR[severity]

    sev   = humorous? ? "%-3s" % SEVERITY_TO_TAG[severity] # pad to at least 3 characters

                      : "%-5s" % severity                  # pad to at least 5 characters



    # 2013-05-01 19:16:00.785 [omg] oh noes! (pid:30976) (admin/user.rb:45:in `block (4 levels) in <top (required)>') <- `call' <- `content_for' <- `block (2 levels) in row' <- `block in build_tag'

    "\033[0;37m#{t}\033[0m [\033[#{color}m#{sev}\033[0m] #{msg.strip} (pid:#{$$}) #{whodunit}\033[0m\n"

  end



  def whodunit

    latest, *others = caller.select{ |a| a !~ EXCLUSION_REGEX }[0, depth]

    latest = latest[/(lib|app)\/(.*)/,-1] || latest

    string = ""

    string << "\033[36m(#{latest})"

    string << "\033[35m <- " + others.map{ |s| s[/`.*/] }.join(' <- ') if others.any?

    string

  end



end



Rails.logger.formatter = Formatter.new



For Rails 4.2 don’t forget to add ActiveSupport::TaggedLogging to be able to call custom logger like a default rails logger

ActiveSupport::TaggedLogging is used to wrap any standard logger instance to add "tags" to a log statement. A "tag" in this case usually describes a subdomain, and is used by the default Rails.logger to allow you to tag log statements with subdomains, request ids, etc. in your multi-user, multi-instance production applications.


include 
ActiveSupport::TaggedLogging::Formatter


to the Formatter class.

Upvotes: 0

olhor
olhor

Reputation: 978

Can you paste contents of CustomLogstash class? From docs, this class should respond to call method and return Hash.

This works for me:

class CustomLogstash
  def call(data)
    { time: Time.now, controller: data[:controller] } # this can be anything as long it is Hash, eg. data.merge(time: Time.now)

  end
end

Sample output from above:

{:time=>"2021-11-18T20:31:41.486+01:00", :controller=>"calendar_events"}

Upvotes: 0

Farhad Ajaz
Farhad Ajaz

Reputation: 274

Can you add the following in config if it helps.

config.lograge.formatter = ->(data) { data.reverse_merge({time: Time.now}) }# data is a ruby hash.

It will give you output like following

{:time=>2021-11-16 12:26:24.65362 +0000, :method=>"GET", :path=>"/", :format=>:html, :controller=>"Controller", :action=>"index", :status=>200, :duration=>393.41, :view=>85.55, :db=>1.38}

Upvotes: 0

Related Questions