0

I am using the Apartment gem for a multi tenant Rails 5.2 app. I'm not sure that this even matters for my question but just giving some context.

Is there a way to override the Rails logger and redirect every single log entry to a file based on the tenant (database) that is being used?

Thinking... is there a method I can monkeypatch in Logger that will change the file written to dynamically?

Example: I want every error message directed to a file for that day. So at the end of a week there will be 7 dynamically generated files for errors that occurred on each specific day.

Another example: Before you write any server log message check if it is before 1pm. If it is before 1pm write it to /log/before_1.log ... if it is after 1pm write it to /log/after_1.log

Silly examples... but I want that kind of dynamic control before any line of log is written.

Thank you!

slindsey3000
  • 4,053
  • 5
  • 36
  • 56
  • https://guides.rubyonrails.org/debugging_rails_applications.html#tagged-logging – max Oct 12 '18 at 17:33
  • That link talks about tagging lines of a log. I want to direct every line of log that is written to a specific file. I was hoping I would be able to override a method like 'filename=' with code that would direct log output to the file I want. – slindsey3000 Oct 12 '18 at 17:36

1 Answers1

1

Usually the logger is usually configured per server (or per environment really) while apartment sets tenants per request - which means that in practice its not really going to work that well.

You can set the logger at any point by assigning Rails.logger to a logger instance.

Rails.logger = Logger.new(Rails.root.join('log/foo.log'), File::APPEND)

# or for multiple loggers
Rails.logger.extend(Logger.new(Rails.root.join('log/foo.log'), File::APPEND))

However its not that simple - you can't just throw that into ApplicationController and think that everything is hunky-dory - it will be called way to late and most of the entries with important stuff like the request or any errors that pop up before the controller will end up in the default log.

What you could do is write a custom piece of middleware that switches out the log:

# app/middleware/tenant_logger.rb
class TenantLogger
  def initialize app
    @app = app
  end

  def call(env)
    file_name = "#{Appartment::Tenant.current}.log"
    Rails.logger = Logger.new(Rails.root.join('log', file_name), File::APPEND)
    @app.call(env)
  end
end

And mount it after the "elevator" in the middleware stack:

Rails.application.config.middleware.insert_after Apartment::Elevators::Subdomain, TenantLogger

However as this is pretty far down in the middleware stack you will still miss quite a lot of important info logged by the middleware such as Rails::Rack::Logger.

Using the tagged logger as suggested by the Rails guides with a single file is a much better solution.

max
  • 96,212
  • 14
  • 104
  • 165
  • 1
    I would look into logging tools like new relic which make it easier to analyse/filter the logs instead. – max Oct 12 '18 at 18:27