Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I'm having a problem with python 3, I'm trying to log the stdout and the stderr to a log file. I was able to figure it out using http://www.electricmonk.nl/log/2011/08/14/redirect-stdout-and-stderr-to-a-logger-in-python/

The point of it was to have both the log file and the console output as normal, while using only the print statement. (I know that's not how you're supposed to do it, I'm trying to log someone else's code)

I came up with this:

import logging
import sys
import traceback

class StreamToLogger(object):

    def __init__(self, logger, log_level, std):
        self.logger = logger
        self.log_level = log_level
        self.linebuf = ''
        self.std = std

    def write(self, buf):
        for line in buf.rstrip().splitlines():
            self.logger.log(self.log_level, line.rstrip())
            self.std.write(line+"\n")
            self.std.flush()

    def flush(self):
        return

logging.basicConfig(
   level=logging.DEBUG,
   format='%(asctime)s:%(levelname)s:%(name)s:%(message)s',
   filename="history.log",
   filemode='a'
)

stdout_logger = logging.getLogger('STDOUT')
sl = StreamToLogger(stdout_logger, logging.INFO, sys.__stdout__)
sys.stdout = sl

stderr_logger = logging.getLogger('STDERR')
sl = StreamToLogger(stderr_logger, logging.ERROR, sys.__stderr__)
sys.stderr = sl

try:
    import bot
    #program that I am logging
except Exception as e:
    traceback.print_exc()
    sys.exit(1)

This worked great, until the log file got to huge to handle.

So my idea is to use the rotating log file thing. Unfortunately my implementation of the rotating log file what I came up with causes a stack overflow immediately after the first time the program prints anything.

This is the new code:

import logging
import sys
import traceback
import logging.handlers

class StreamToLogger(object):

    def __init__(self, logger, log_level, std, handler):
        self.handler = handler
        self.logger = logger
        self.log_level = log_level
        self.linebuf = ''
        self.std = std

    def write(self, buf):
        for line in buf.rstrip().splitlines():
            self.handler.emit(line)
            #^^STACK OVERFLOW^^
            self.logger.log(self.log_level, line.rstrip())
            self.std.write(line+"\n")
            self.std.flush()

    def flush(self):
        return


hand = logging.handlers.TimedRotatingFileHandler("bot.log", when="S", interval=20)
#my attempt at handling


stdout_logger = logging.getLogger('STDOUT')
sl = StreamToLogger(stdout_logger, logging.INFO, sys.__stdout__, hand)
sys.stdout = sl

stderr_logger = logging.getLogger('STDERR')
sl = StreamToLogger(stderr_logger, logging.ERROR, sys.__stderr__, hand)
sys.stderr = sl

try:
    import bot
except Exception as e:
    traceback.print_exc()
    sys.exit(1)

Anyone have any ideas that could help?

share|improve this question
1  
maybe if u can use RotatingLoggingHandler instead of timed one and set the roll over at 8-9 Gb before the stackover flow occurs. Could that help? –  GIRISH RAMNANI Mar 7 at 20:45
    
The stack overflow happens immediately when the program I'm debugging the has a print(), I'm pretty sure I accidentally made something recursive accidentally.... The stack overflow didn't happen when it got to 10 GB, it happened after i made the change. I changed the original post to remove that ambiguity. –  Mike111177 Mar 7 at 23:18
    
i removed the sys.stdout = sl the piping that u did and then tried so the log file was created but a new error showed up something related to message format. –  GIRISH RAMNANI Mar 8 at 5:20
    
the emit method requires a LogRecord but you are passing a string –  GIRISH RAMNANI Mar 8 at 5:41

1 Answer 1

up vote 0 down vote accepted

I found the error, actually the emit is called by the logger so you just need to add the handler using streamlogger.addHandler.

The updated code

__author__ = 'Girish'

import logging
import sys
import traceback
import logging.handlers


class StreamToLogger(object):
    def __init__(self, logger, log_level, std):

        self.logger = logger
        self.log_level = log_level
        self.linebuf = ''
        self.std = std

    def write(self, buf):
        for line in buf.rstrip().splitlines():
            # ^^STACK OVERFLOW^^
            self.logger.log(self.log_level, line.rstrip())
            self.std.write(line + "\n")
    def flush(self):
        self.std.flush()


logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s:%(levelname)s:%(name)s:%(message)s',
    filename="history.log",
    filemode='a'
)
hand = logging.handlers.TimedRotatingFileHandler("bot.log", when="S", interval=20)
# my attempt at handling


stdout_logger = logging.getLogger('STDOUT')

sl = StreamToLogger(stdout_logger, logging.INFO, sys.__stdout__)

stderr_logger = logging.getLogger('STDERR')
stderr_logger.addHandler(hand) #here

sl = StreamToLogger(stderr_logger, logging.ERROR, sys.__stderr__)
sys.stdout = sl
for i in range(2):
    sl.write("is this working")
share|improve this answer
    
IT WORKS! Thank you very much for the help :) –  Mike111177 Mar 8 at 9:09

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.