0

My app has some additional logging, it works fine on a local machine and even on Heroku local. When I push it to Heroku, it raises a FileNotFoundError. Here is my code:

class Logger:
    def __init__(self, name, file_handler, formatter, stream_handler):
        if not os.path.exists('Logs'):
            os.makedirs('Logs')

        self.logger = logging.getLogger(name)
        self.logger.setLevel(logging.DEBUG)

        file_handler.setFormatter(formatter)
        self.logger.addHandler(file_handler)

        if stream_handler:
            stream_handler = logging.StreamHandler()
            stream_handler.setFormatter(formatter)
            self.logger.addHandler(stream_handler)


logger_dev = Logger('dev',
                    handlers.TimedRotatingFileHandler(f'Logs/dev.log', when='midnight', backupCount=2),
                    logging.Formatter('%(asctime)s : %(levelname)s : %(filename)s : %(funcName)s : %(message)s'),
                    True)

logger_usr = Logger('usr',
                    handlers.RotatingFileHandler(f'Logs/usr.log', maxBytes=7 * 1024 * 1024, backupCount=2),
                    logging.Formatter('%(asctime)s : %(message)s'),
                    False)

I've also tried explicitly creating .log files by adding this to the Logger class:

if not os.path.exists(f'Logs/{name}.log'):
    open(f'Logs/{name}.log', 'w+').close()

Here are Heroku logs:

2020-06-15T20:59:43.441969+00:00 app[worker.1]: Traceback (most recent call last):
2020-06-15T20:59:43.441997+00:00 app[worker.1]: File "bot.py", line 8, in <module>
2020-06-15T20:59:43.442110+00:00 app[worker.1]: import settings as s
2020-06-15T20:59:43.442114+00:00 app[worker.1]: File "/app/settings.py", line 60, in <module>
2020-06-15T20:59:43.442251+00:00 app[worker.1]: handlers.TimedRotatingFileHandler(f'Logs/dev.log', when='midnight', backupCount=2),
2020-06-15T20:59:43.442254+00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.8/logging/handlers.py", line 200, in __init__
2020-06-15T20:59:43.442437+00:00 app[worker.1]: BaseRotatingHandler.__init__(self, filename, 'a', encoding, delay)
2020-06-15T20:59:43.442439+00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.8/logging/handlers.py", line 55, in __init__
2020-06-15T20:59:43.442606+00:00 app[worker.1]: logging.FileHandler.__init__(self, filename, mode, encoding, delay)
2020-06-15T20:59:43.442622+00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.8/logging/__init__.py", line 1143, in __init__
2020-06-15T20:59:43.443050+00:00 app[worker.1]: StreamHandler.__init__(self, self._open())
2020-06-15T20:59:43.443054+00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.8/logging/__init__.py", line 1172, in _open
2020-06-15T20:59:43.443475+00:00 app[worker.1]: return open(self.baseFilename, self.mode, encoding=self.encoding)
2020-06-15T20:59:43.443501+00:00 app[worker.1]: FileNotFoundError: [Errno 2] No such file or directory: '/app/Logs/dev.log'
ChrisGPT was on strike
  • 127,765
  • 105
  • 273
  • 257
Lev Slinsen
  • 369
  • 1
  • 4
  • 21

1 Answers1

1

Don't log to files on Heroku. Its ephemeral filesystem means that anything you write could be lost at any time, and will be lost at least daily.

Instead, log to stderr or stdout. Then Heroku can incorporate your logs into its log stream:

A Heroku app’s logs are aggregated from the output streams of all of its running processes, system components, and backing services

Logs are mostly transient on Heroku, so you might want to set up a logging addon or log drain:

The logs command retrieves 100 log lines by default. You can specify the number of log lines to retrieve (up to a maximum of 1,500 lines) by using the --num (or -n) option.

ChrisGPT was on strike
  • 127,765
  • 105
  • 273
  • 257
  • The idea here is to be able to download these log files. This is a bot, and there is a function to download user activity history, that's why I've set it up like that in the first place. – Lev Slinsen Jun 15 '20 at 22:55
  • That's irrelevant. You can literally lose them _at any moment_. Log to the output streams. This is [part of Heroku's fundamental design](https://12factor.net/logs). – ChrisGPT was on strike Jun 15 '20 at 23:00
  • I get that, but how do I produce logs that can be stored and retrieved then? – Lev Slinsen Jun 15 '20 at 23:32
  • Don't think of logs as files. As described in the link I provided in my previous comment, think of them as streams. If you want to do something with them, set up a logging addon or log drain as I suggested and get them from there. – ChrisGPT was on strike Jun 15 '20 at 23:35