The stdout. log file is a console logging file that has poor log management which causes the file to grow too large. PROBLEM DESCRIPTION. From PingFederate 9.0 onwards: 1) If an OS service start up script is being used or <pfinstall>/sbin/pingfederate-run.sh, output can be sent to stdout.
logging - Making Python loggers output all messages to stdout in addition to log file - Stack Overflow. Stack Overflow for Teams – Start collaborating and sharing organizational knowledge.
I had this same issue before and found this snippet very useful:
class Tee(object):
def __init__(self, name, mode):
self.file = open(name, mode)
self.stdout = sys.stdout
sys.stdout = self
def __del__(self):
sys.stdout = self.stdout
self.file.close()
def write(self, data):
self.file.write(data)
self.stdout.write(data)
def flush(self):
self.file.flush()
from: http://mail.python.org/pipermail/python-list/2007-May/438106.html
The print
statement will call the write()
method of any object you assign to sys.stdout.
I would spin up a small class to write to two places at once...
import sys
class Logger(object):
def __init__(self):
self.terminal = sys.stdout
self.log = open("log.dat", "a")
def write(self, message):
self.terminal.write(message)
self.log.write(message)
sys.stdout = Logger()
Now the print
statement will both echo to the screen and append to your log file:
# prints "1 2" to <stdout> AND log.dat
print "%d %d" % (1,2)
This is obviously quick-and-dirty. Some notes:
<stdout>
if you
won't be logging for the duration of the program.These are all straightforward enough that I'm comfortable leaving them as exercises for the reader. The key insight here is that print
just calls a "file-like object" that's assigned to sys.stdout
.
What you really want is logging
module from standard library. Create a logger and attach two handlers, one would be writing to a file and the other to stdout or stderr.
See Logging to multiple destinations for details
Since you're comfortable spawning external processes from your code, you could use tee
itself. I don't know of any Unix system calls that do exactly what tee
does.
# Note this version was written circa Python 2.6, see below for
# an updated 3.3+-compatible version.
import subprocess, os, sys
# Unbuffer output (this ensures the output is in the correct order)
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
tee = subprocess.Popen(["tee", "log.txt"], stdin=subprocess.PIPE)
os.dup2(tee.stdin.fileno(), sys.stdout.fileno())
os.dup2(tee.stdin.fileno(), sys.stderr.fileno())
print "\nstdout"
print >>sys.stderr, "stderr"
os.spawnve("P_WAIT", "/bin/ls", ["/bin/ls"], {})
os.execve("/bin/ls", ["/bin/ls"], os.environ)
You could also emulate tee
using the multiprocessing package (or use processing if you're using Python 2.5 or earlier).
Update
Here is a Python 3.3+-compatible version:
import subprocess, os, sys
tee = subprocess.Popen(["tee", "log.txt"], stdin=subprocess.PIPE)
# Cause tee's stdin to get a copy of our stdin/stdout (as well as that
# of any child processes we spawn)
os.dup2(tee.stdin.fileno(), sys.stdout.fileno())
os.dup2(tee.stdin.fileno(), sys.stderr.fileno())
# The flush flag is needed to guarantee these lines are written before
# the two spawned /bin/ls processes emit any output
print("\nstdout", flush=True)
print("stderr", file=sys.stderr, flush=True)
# These child processes' stdin/stdout are
os.spawnve("P_WAIT", "/bin/ls", ["/bin/ls"], {})
os.execve("/bin/ls", ["/bin/ls"], os.environ)
Here is another solution, which is more general than the others -- it supports splitting output (written to sys.stdout
) to any number of file-like objects. There's no requirement that __stdout__
itself is included.
import sys
class multifile(object):
def __init__(self, files):
self._files = files
def __getattr__(self, attr, *args):
return self._wrap(attr, *args)
def _wrap(self, attr, *args):
def g(*a, **kw):
for f in self._files:
res = getattr(f, attr, *args)(*a, **kw)
return res
return g
# for a tee-like behavior, use like this:
sys.stdout = multifile([ sys.stdout, open('myfile.txt', 'w') ])
# all these forms work:
print 'abc'
print >>sys.stdout, 'line2'
sys.stdout.write('line3\n')
NOTE: This is a proof-of-concept. The implementation here is not complete, as it only wraps methods of the file-like objects (e.g. write
), leaving out members/properties/setattr, etc. However, it is probably good enough for most people as it currently stands.
What I like about it, other than its generality, is that it is clean in the sense it doesn't make any direct calls to write
, flush
, os.dup2
, etc.
As described elsewhere, perhaps the best solution is to use the logging module directly:
import logging
logging.basicConfig(level=logging.DEBUG, filename='mylog.log')
logging.info('this should to write to the log file')
However, there are some (rare) occasions where you really want to redirect stdout. I had this situation when I was extending django's runserver command which uses print: I didn't want to hack the django source but needed the print statements to go to a file.
This is a way of redirecting stdout and stderr away from the shell using the logging module:
import logging, sys
class LogFile(object):
"""File-like object to log text using the `logging` module."""
def __init__(self, name=None):
self.logger = logging.getLogger(name)
def write(self, msg, level=logging.INFO):
self.logger.log(level, msg)
def flush(self):
for handler in self.logger.handlers:
handler.flush()
logging.basicConfig(level=logging.DEBUG, filename='mylog.log')
# Redirect stdout and stderr
sys.stdout = LogFile('stdout')
sys.stderr = LogFile('stderr')
print 'this should to write to the log file'
You should only use this LogFile implementation if you really cannot use the logging module directly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With