Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rospy] Write log for class method with class name for rospy #877

Closed
19 changes: 19 additions & 0 deletions tools/rosgraph/src/rosgraph/roslogging.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,31 @@
import time
import logging
import logging.config
import inspect

import rospkg
from rospkg.environment import ROS_LOG_DIR

class LoggingException(Exception): pass

class RospyLogger(logging.Logger):
def findCaller(self):
"""
Find the stack frame of the caller so that we can note the source
file name, line number, and function name with class name if possible.
"""
frame, _, lineno, _, _, _ = inspect.stack()[3]
file_name = inspect.getabsfile(frame)
func_name = frame.f_code.co_name
try:
class_name = frame.f_locals['self'].__class__.__name__
func_name = '%s.%s' % (class_name, func_name)
except KeyError:
pass
return file_name, lineno, func_name

logging.setLoggerClass(RospyLogger)
Copy link
Member

@dirk-thomas dirk-thomas Aug 31, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should ensure not to overwrite custom logger classes already being set by user code. See https://docs.python.org/2/library/logging.html#logging.getLoggerClass on how to achieve this.

Could you please also cover that case in the test.


def renew_latest_logdir(logfile_dir):
log_dir = os.path.dirname(logfile_dir)
latest_dir = os.path.join(log_dir, 'latest')
Expand Down
79 changes: 79 additions & 0 deletions tools/rosgraph/test/test_roslogging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import logging
import os
from StringIO import StringIO
import sys

from nose.tools import assert_regexp_matches
import rosgraph.roslogging


os.environ['ROSCONSOLE_FORMAT'] = ' '.join([
'${severity}',
'${message}',
'${walltime}',
'${thread}',
'${logger}',
'${file}',
'${line}',
'${function}',
'${node}',
'${time}',
])
rosgraph.roslogging.configure_logging('test_rosgraph', logging.INFO)
loginfo = logging.getLogger('rosout').info

# Remap stdout for testing
f = StringIO()
sys.stdout = f


loginfo('on module')


def logging_on_function():
loginfo('on function')

logging_on_function()


class LoggingOnClass(object):

def __init__(self):
loginfo('on method')

LoggingOnClass()


def test_rosconsole__logging_format():
this_file = os.path.abspath(__file__)
# this is necessary to avoid test fails because of .pyc cache file
base, ext = os.path.splitext(this_file)
if ext == '.pyc':
this_file = base + '.py'

for i, loc in enumerate(['module', 'function', 'method']):
if loc == 'module':
function = '<module>'
elif loc == 'function':
function = 'logging_on_function'
elif loc == 'method':
function = 'LoggingOnClass.__init__'
else:
raise ValueError

log_out = ' '.join([
'INFO',
'on ' + loc,
'[0-9]*\.[0-9]*',
'[0-9]*',
'rosout',
this_file,
'[0-9]*',
function,
'/unnamed',
'[0-9]*\.[0-9]*',
])
assert_regexp_matches(f.getvalue().splitlines()[i], log_out)


sys.stdout = sys.__stdout__