Rails Have a custom Logger in Heroku - ruby-on-rails

I need to have a custom Logger that logs specific actions that occur in my deployed application in Heroku. This log is for the user to view (that's why the default logger is no good here).
While testing on development on local everything is fine. I have
logger = Logger.new(PATH)
logger.info("...")
PATH is set on environment variables.
Now I want to deploy to Heroku but I find myself with a problem: how can the user view this log? Where would I need to save it?

On heroku filesystem is read-only, you should log to stdout. Default log can be directed there by rails_12factor gem (or configure by youself, but the former is easier)
But for custom log, that is going to be viewed by the user it's better to write to db, because probability of future access control being needed is high

Heroku has an ephemeral filesystem meaning whatever file you upload would be deleted shortly afterwards.
If you need a custom logger on Heroku, I'd say you should probably use something that is more persistent. You may use something like Redis.
Look at this answer for more info.

Related

What is the correct way to use config/credentials in Rails 6? And how do I stop my app from using /tmp/development_secret?

I'm working on a Rails application and I am attempting to organize my secret_key_base and related important secrets (Think API keys, database credentials, etc.)
I am trying to find a way to setup something like the following, under /config
/config
credentials.yml.enc
master.key
/config/credentials
development.yml.enc
development.key
production.yml.enc
production.key
test.yml.enc
test.key
First Question:
Is it that secret_key_base exists in /config/credentials.yml.enc, which is loaded (first?) and then the credentials are loaded for the environment rails is running in? Or should I create a different secret_key_base for each environment?
Second Question:
No matter what I do, when I run in development or test, tmp/development_secret loads first. In addition, whenever I try to access my secrets in development, (Rails.application.secret_key_base) as referenced here: What's the correct way of defining secret_key_base on Rails 6, I run into an issue where I only ever receive nil when looking for secrets I've defined in my development.yml.enc, which I assume is because it's not loading anything in that file, it's going to tmp/development_secret and not finding anything else (Maybe I'm wrong.)
Goals:
Stop tmp/development_secret from being created, and instead access
secrets using the specific .yml.enc file depending on the
environment.
Understand why /config/credentials.yml.enc exists if it doesn't
load in all the environments. If it doesn't, then it isn't clear when it loads.
Why?
Using config/database.yml as an example, I want to store different creds for each environment, but none of them in version control. (I want nobody but a few to have production.) However, I want to access them the exact same way in all of my environments. Not having creds load in production because of an issue with a .yml file will crash my app, so I don't want to load them differently in test/development.
Put together a blog post about this because searching for documentation on this feature is painful. It's a really easy thing because then only the master.key, and production.key would need loaded as ENV variables which is great. (Or possibility just one of them.)
This really should be a simple, out-of-the-box thing, but it's hard to find real documentation on best practices.
I've found the answer, at least the one I'm looking for. You can have your initializer load whatever file you want by overriding the defaults.
config.credentials.content_path = 'config/credentials/development.yml.enc'
config.credentials.key_path = 'config/credentials/development.key'
https://edgeapi.rubyonrails.org/classes/Rails/Application.html

Rails adding translations to a running rails environment

Is there a way to manually inject a translation through the Rails console ?
Suppose I am working on a dev environment, and I want to test some code in a production console (eg to test some statistics on real data).Problem is, the code I want to test relies on new translations that didn't exist (or were changed) in the production environment.
So my code returns a lot of translation_missing
Can I inject the missing translations ? Via a hash or a YML file ?
I18n.load_translations(hash_or_file)
Usually Application instances that serve http requests (for example running under Unicorn/Puma) are not available via Rails console. When someone login to production server and type $RAILS_ENV=production rails c it starts another application process. Translations dictionary is a kind of in-memory cache and usually it is not possible to change that cache for/from another process (in general). You can reload translations only for application instance that started by Rails console, but not for running server.
Only one way to hot reload translations is adding kind of a hook into source code of application to re-read YAML file, but it seems better just restart application server.
UPDATE: For testing purposes I18n cache could be modified like:
I18n.backend.send(:translations)[:en][:date][:formats][:default] = "%Y-%Z"

Passenger logging and STDOUT

When developing rails applications I usually use thin for my development environment. I like thin because the logs are not outputed directly on STDOUT but instead written in log/{development,production}.log.
Sometimes I just insert a p <some object> inside a controller's action just to have a quick look at some object and debug my code. I know that I could use the rails loggin api but I don't want to do that when for every request you get 1000+ loggin lines.
On my production servers I used thin in the past (I configured apache to work as a proxy for my thin instances). In the log directory thin created a file called thin.log where you can see thin's STDOUT-output.
But in new production server I started using Passenger for my production environment. log/production.log is created and I can see the logs the whole time. But what I really would want to do is to see somewhere Passaneger's STDOUT-output, to get something like log/passenger.log (like thins does).
I've already searched in google about this but I couldn't find anything useful there. Is there a way I could archive that?
As it seems that nobody knows if this is possible I found here something that works for me fine.

Development workflow for Heroku?

I have used Heroku to push up my already coded Rails applications.
But now I wonder how the workflow would look like if I start coding a new Rails application from scratch.
For example if I use their addons (MongoHQ, Redis, Websolr, Sendgrid etc) in my application code, then I guess I shouldn't install MongoDB, Redis, Solr, Mail server etc in my local environment since they won't work with my code, correct?
So that means I have to push my app up to the Heroku platform to be able to run it in the web browser. That means, after a change of lines I have to commit and push it up.
If I'm correct, isn't this time-consuming since before I just changed the code and I could see the results in the browser immediately. Now I have to push for every change I want to see in browser.
You can install all of these locally - you should only need to specify different configurations when you are running in production rather than development.
For example, with Websolr, adding the following line in your initializer:
Sunspot.config.solr.url = ENV['WEBSOLR_URL'] if ENV['WEBSOLR_URL']
Will allow it to work both locally and on Heroku. See the docs for more information.
I can't tell for all addons, but the ones I used have very good fall-back mechanism for local deployment in development mode.
For example, Sendgrid will detect when you're using ActionMailer and send emails for you. You don't have to configure or call anything in your code. Locally you send emails as before (through sendmail or smtp server)
Same with exceptional (although you can invoke its API directly).
MongoHQ... Isn't it supposed to be replacement for PostgreSQL? Then, you should not care in most cases, just like you don't care about PostgreSQL running and not MySQL.

Disabling Rails logging from script/runner

Is there some way to disable all logging (whether from ActiveRecord, other parts of Rails, plugins, etc.) from a script running via script/runner? I've got a long data-loading script running, and it's generating an absurd amount of useless logging information. I'm not trying to change script/runner's environment (e.g., production, development, etc.)- the script currently needs to run in the "development" environment, and it's doing so without issue at the moment.
All I want to do is suppress all logging for the duration of the script's lifetime. From reading the docs, it looks like if I can get a handle to its Rails::Configuration I should be either able to set log_level to something other than :debug or set its logger to nil. Am I on the right track? If so, how do I get access to its Rails::Configuration object?
There are a couple of ways I can think of.
1) Set the log level so high that nothing will get logged:
ActiveRecord::Base.logger.level = Logger::Severity::UNKNOWN
See Logger::Severity for more about that. UNKNOWN is the highest.
"level" is just a number, so it can be set to Logger::Severity::UNKNOWN + 1 if you feel paranoid. :)
2) Send the output to /dev/null.
ActiveRecord::Base.logger = Logger.new('/dev/null')
(I'm assuming that there is just one instance of Logger that is used by Rails, and that it's the one you get via ActiveRecord::Base.logger. If there are more of them you'd have to find them and fiddle with them also.)
If you don't like these you might find something else by reading the Logger docs.
The settings are in your config/environments/*.rb files, which override the default for environment.rb. When it does "Rails::Initializer.run do |config|" it's running with the config object. I'm fairly sure you can change either to suite your needs, but I'm not sure how you'd pass it a flag saying it was a script/runner script currently executing.
(I know you said your not interested in changing the environment, but I thought I'd throw out there that you could create a new env for a dataload script that has most of the same settings but no logging fairly easily)

Resources