views:

120

answers:

7

I want to create a function that works like the build-in print function in Python:

print 'test', i, 'started'

So a call like this should work:

log('test', i, 'started)

The log function should call the logging.info() function (from the Python logging module). How can I create such a function?

This is my first try:

import logging
def log(*args):
    logging.info(args)

log('test', i, 'started)

But the output is not what I want:

('test', 2, 'started')

While it should be:

test 2 started
+2  A: 

You can do this kind of thing:

def log(*args):
  logging.info(' '.join(args))
sje397
I'm looking for a solution that calls logging.info().
compie
beware that if args contains non-strings (as it does in the question), this will cause an exception. compie's answer, or `logging.info(' '.join([str(x) for x in args]))` work better.
dcrosta
@dcrosta : +1 for pointing that out, -1 for using the list comprehension instead of a generator ;)
Stephen
@Stephen oops -- force of habit.
dcrosta
+1  A: 

Define a function that takes a variable number of arguments, you can operate on the parameter list args to print it how you'd like:

>>> def log(*args):
...   print args

>>> log("a", 1, "b")
("a", 1, "b")

Or:

>>> def log(*args):
...   for a in args:  # <- loop over the arguments
...     print a,   # <- notice the comma that says "no newline".
...   print        # <- force a newline after the log statement.

>>> log("a", 1, "b")
a 1 b

If you want to use logging.info:

logging.info(msg[, *args[, **kwargs]])

Logs a message with level INFO on the root logger. The arguments are interpreted as for debug().

>>> def log(*args):
...   logging.info(" ".join("%s" %a for a in args))
Stephen
A: 

The logging methods require a format-string as the first argument (or, as some others have suggested, a literal string to log). You can easily generate a format string for a given-number of arguments with code something like this:

def log(*args):
    fmt_string = ' '.join(['%s'] * len(args))
    logging.info(fmt_string, *args)

This works because the multiplication operator on lists is defined to extend the list with copies of the list's contents.

Note that I'm passing *args as the second "argument" to logging.info -- this is Python's syntax for expanding a sequence (args will be a tuple, I believe) into a series of positional arguments in the function call.

dcrosta
simply logging `' '.join(args)` as "format string" would be easier. or maybe `' '.join(str(a) for a in args)`.
hop
+1  A: 

How about:

def log(*args):
    logging.info(' '.join([str(arg) for arg in args]))

HTH!

blwy10
the extra list comprehension has not been necessary for a while now (2.4). `' '.join(str(arg) for arg in args)` should suffice.
hop
+2  A: 

This works:

def log(*args):
    logging.info(' '.join(map(str, args)))
compie
nice. +1.......
sje397
A: 

I do this, to make it accept a format string. Coming from a C world, I like my format strings. I use code exactly like this in several production systems.

def logf(fmt, *args):
    try: m = fmt % args
    except:
        # Catch mismatch between fmt/args; prevents logging.info from
        # failing below, as well.
        m = fmt
        fmt = "%s"
    if DEBUG:
        stderr.write("[%s] %s\n" % (time.asctime(), m))
    logging.info(fmt, *args)

Usage:

logf("There are %u entries in the list, and my mood is %s.", len(L), "sad")
logf("It works without arguments, as well")
logf("Test %d started", i)

Call me old-school, I guess. This is all Python 2, by the way - 3 is far different.

Jed Smith
A: 

One day I was reading the python docs and I came across the functools.partial() method (or I read about it somewhere -- I can't remember). A little playing around led to the following code I now put at the beginning of every python script I write:

import sys, functools

nl = "\n"

def StreamOut(stream, *s, **kw):
    k = kw.setdefault
    # Process keyword arguments
    sep     = k("sep", "")
    auto_nl = k("auto_nl", True)
    prefix  = k("prefix", "")
    convert = k("convert", str)
    # Convert position arguments to strings
    strings = map(convert, s)
    # Dump them to the stream
    stream.write(prefix + sep.join(strings))
    # Add a newline if desired
    if auto_nl:
        stream.write(nl)

out  = functools.partial(StreamOut, sys.stdout)
outs = functools.partial(StreamOut, sys.stdout, sep=" ")
dbg  = functools.partial(StreamOut, sys.stdout, sep=" ", prefix="+ ")
err  = functools.partial(StreamOut, sys.stderr)

out("Hi there", "how are you?")
outs("Hi there", "how are you?")

Put it into a file and try them out. This makes for some easily-extendible functions.