I have a codebase of Python and C++ code, including heavy use of ROS. Logging is done throughout the Python code with both system logger and rospy logging -- contrived example:
import logging
import rospy
logging.basicConfig(level=logging.INFO)
LOG = logging.getLogger(__name__)
def run():
rospy.loginfo("This is a ROS log message")
LOG.info("And now from Python")
if __name__ == '__main__':
runt()
As for C++ code we need to add logging, probably with glog but I'm open to other options.
Is there a way to integrate the various loggers into one module? Ideally a user could do something like my_logger = AwesomeLogger(level='info', output='my_logs.txt')
and then AwesomeLogger
behind the scenes sets up the Python and C++ loggers, and combines all log outputs (including from ROS) into clean console messages output text file.
Note we target support for ubuntu 16.04, ROS-kinetic, C++11, Python 2.7*
*If a solution provides rational for moving to Python 3.6 you get bonus points!
UPDATE If I load a dict config from yaml (as described in this post on logging best practices I can specify handlers and loggers for ROS. But with the yaml below I get duplicated rospy log messages to the console, one in the standard rospy log format and the other in my specified format. Why??
version: 1
disable_existing_loggers: True
formatters:
my_std:
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
datefmt: "%Y/%m/%d %H:%M:%S"
handlers:
console:
class: logging.StreamHandler
formatter: my_std
level: DEBUG
stream: ext://sys.stdout
info_file_handler:
class: logging.handlers.RotatingFileHandler
level: INFO
formatter: my_std
filename: info.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
rosconsole:
class: rosgraph.roslogging.RosStreamHandler
level: DEBUG
formatter: my_std
colorize: True
loggers:
my_module:
level: INFO
handlers: [console]
propagate: no
rosout:
level: INFO
handlers: [rosconsole]
propagate: yes
qualname: rosout
root:
level: INFO
handlers: [console, info_file_handler, rosconsole]
This config yaml does the trick:
version: 1
disable_existing_loggers: True
formatters:
my_std:
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
datefmt: "%Y/%m/%d %H:%M:%S"
handlers:
console:
class: logging.StreamHandler
formatter: my_std
level: DEBUG
stream: ext://sys.stdout
info_file_handler:
class: logging.handlers.RotatingFileHandler
level: INFO
formatter: my_std
filename: info.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
loggers:
__main__:
level: DEBUG
handlers: [console]
propagate: no
rosout:
level: INFO
propagate: yes
qualname: rosout
root:
level: INFO
handlers: [console, info_file_handler]
And to load it,
import logging
import yaml
if os.path.exists(config_path):
with open(config_path, 'rt') as f:
config = yaml.safe_load(f.read())
logging.config.dictConfig(config)