Capturing Logger Output Inside a Method

Capturing logger output inside a method

I've done this in several different ways, and the most convenient I've found is to build a delegation object that routes messages to two or more loggers:

require 'stringio'
require 'logger'

class LoggerTee

def initialize *loggers
@loggers = loggers
end

def method_missing meth, *args, &block
@loggers.each { |logger| logger.send(meth, *args, &block) }
end

end

capture_stringio = StringIO.new
console_log = Logger.new(STDOUT)
string_log = Logger.new(capture_stringio)
log = LoggerTee.new(console_log, string_log)

log.debug 'Hello world'
puts capture_stringio.string

Output:

D, [2013-04-30T18:59:18.026285 #14533] DEBUG -- : Hello world
D, [2013-04-30T18:59:18.026344 #14533] DEBUG -- : Hello world

In this example, the LoggerTee class is instantiated with two separate loggers, one that goes to the console, the other to a StringIO instance. The resulting LoggerTee instance is a drop-in replacement for any standard logger object.

How to overrider Logger class with method to select log level and output line of the log

If you would like to stick with your helper function approach, the logging methods accept kwarg stacklevel that specifies the corresponding number of stack frames to skip when computing the line number and function name ref. The default is 1, so setting it to 2 should look to the frame above you helper function. For example:

import logging

logging.basicConfig(format="%(lineno)d")
logger = logging.getLogger(__name__)

def log():
logger.error("message", stacklevel=2)

log()

Capture logging output using subprocess.check_output in Python

I'm guessing is that logging does not write on the same stdout that subprocess.check_output is expecting?

logging doesn't write to stdout at all (by default); it writes to stderr.

You will need to either redirect your stderr to stdout by adding the stderr argument thus: subprocess.check_output(..., stderr=subprocess.STDOUT) or you will need to use one of the other subprocess functions such as run that gives access to stderr.

The docs do say:

The recommended approach to invoking subprocesses is to use the run() function for all use cases it can handle

Capture output from non-python third-party library with python logger

You can temporarily redirect stdout from your 3rd party function go to a logger.

Using the StreamToLogger class from the answer you linked: Redirect Python 'print' output to Logger

def wrap_third_party_function():
stdout = sys.stdout # save for restoring afterwards
# redirect stdout to use a logger, with INFO level
sys.stdout = StreamToLogger(logging.getLogger("mylogger.thirdparty"), logging.INFO)
print("start third_party_function; stdout to log")
third_party_function()
sys.stdout = stdout # restore stdout
print("done third_party_function; stdout restored")

def my_helper():
logger.debug("Inside of 'my_helper', before third party call.")
wrap_third_party_function()
logger.warning("Finished with third party call.")

On the console, you'll get this:

done third_party_function; stdout restored
Finished with third party call.

And progress.out will have:

Inside of 'my_helper', before third party call.
start third_party_function; stdout to log
Inside of 'third_party_function'.
Finished with third party call.

Adding a formatter makes it easier to see:

formatter = logging.Formatter("%(name)s %(levelname)-8s %(message)s")
stream_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)

With this configuration, progress.out shows:

mylogger DEBUG    Inside of 'my_helper', before third party call.
mylogger.thirdparty INFO start third_party_function; stdout to log
mylogger.thirdparty INFO Inside of 'third_party_function'.
mylogger WARNING Finished with third party call.

Redirect Python 'print' output to Logger

You have two options:

  1. Open a logfile and replace sys.stdout with it, not a function:

    log = open("myprog.log", "a")
    sys.stdout = log

    >>> print("Hello")
    >>> # nothing is printed because it goes to the log file instead.
  2. Replace print with your log function:

    # If you're using python 2.x, uncomment the next line
    #from __future__ import print_function
    print = log.info

    >>> print("Hello!")
    >>> # nothing is printed because log.info is called instead of print


Related Topics



Leave a reply



Submit