Package rosgraph :: Module roslogging
[frames] | no frames]

Source Code for Module rosgraph.roslogging

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2008, Willow Garage, Inc. 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  # 
 10  #  * Redistributions of source code must retain the above copyright 
 11  #    notice, this list of conditions and the following disclaimer. 
 12  #  * Redistributions in binary form must reproduce the above 
 13  #    copyright notice, this list of conditions and the following 
 14  #    disclaimer in the documentation and/or other materials provided 
 15  #    with the distribution. 
 16  #  * Neither the name of Willow Garage, Inc. nor the names of its 
 17  #    contributors may be used to endorse or promote products derived 
 18  #    from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 23  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 24  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 25  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 26  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 27  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 29  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 30  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  # POSSIBILITY OF SUCH DAMAGE. 
 32   
 33  """ 
 34  Library for configuring python logging to standard ROS locations (e.g. ROS_LOG_DIR). 
 35  """ 
 36   
 37  import os 
 38  import sys 
 39  import time 
 40  import logging 
 41  import logging.config 
 42   
 43  import rospkg 
 44  from rospkg.environment import ROS_LOG_DIR 
 45   
46 -class LoggingException(Exception): pass
47
48 -def renew_latest_logdir(logfile_dir):
49 log_dir = os.path.dirname(logfile_dir) 50 latest_dir = os.path.join(log_dir, 'latest') 51 if os.path.lexists(latest_dir): 52 if not os.path.islink(latest_dir): 53 return False 54 os.remove(latest_dir) 55 os.symlink(logfile_dir, latest_dir) 56 return True
57
58 -def configure_logging(logname, level=logging.INFO, filename=None, env=None):
59 """ 60 Configure Python logging package to send log files to ROS-specific log directory 61 :param logname str: name of logger, ``str`` 62 :param filename: filename to log to. If not set, a log filename 63 will be generated using logname, ``str`` 64 :param env: override os.environ dictionary, ``dict`` 65 :returns: log file name, ``str`` 66 :raises: :exc:`LoggingException` If logging cannot be configured as specified 67 """ 68 if env is None: 69 env = os.environ 70 71 logname = logname or 'unknown' 72 log_dir = rospkg.get_log_dir(env=env) 73 74 # if filename is not explicitly provided, generate one using logname 75 if not filename: 76 log_filename = os.path.join(log_dir, '%s-%s.log'%(logname, os.getpid())) 77 else: 78 log_filename = os.path.join(log_dir, filename) 79 80 logfile_dir = os.path.dirname(log_filename) 81 if not os.path.exists(logfile_dir): 82 try: 83 makedirs_with_parent_perms(logfile_dir) 84 except OSError: 85 # cannot print to screen because command-line tools with output use this 86 if os.path.exists(logfile_dir): 87 # We successfully created the logging folder, but could not change 88 # permissions of the new folder to the same as the parent folder 89 sys.stderr.write("WARNING: Could not change permissions for folder [%s], make sure that the parent folder has correct permissions.\n"%logfile_dir) 90 else: 91 # Could not create folder 92 sys.stderr.write("WARNING: cannot create log directory [%s]. Please set %s to a writable location.\n"%(logfile_dir, ROS_LOG_DIR)) 93 return None 94 elif os.path.isfile(logfile_dir): 95 raise LoggingException("Cannot save log files: file [%s] is in the way"%logfile_dir) 96 97 # the log dir itself should not be symlinked as latest 98 if logfile_dir != log_dir: 99 if sys.platform not in ['win32']: 100 try: 101 success = renew_latest_logdir(logfile_dir) 102 if not success: 103 sys.stderr.write("INFO: cannot create a symlink to latest log directory\n") 104 except OSError as e: 105 sys.stderr.write("INFO: cannot create a symlink to latest log directory: %s\n" % e) 106 107 if 'ROS_PYTHON_LOG_CONFIG_FILE' in os.environ: 108 config_file = os.environ['ROS_PYTHON_LOG_CONFIG_FILE'] 109 else: 110 # search for logging config file in /etc/. If it's not there, 111 # look for it package-relative. 112 fname = 'python_logging.conf' 113 rosgraph_d = rospkg.RosPack().get_path('rosgraph') 114 for f in [os.path.join(rospkg.get_ros_home(), 'config', fname), 115 '/etc/ros/%s'%(fname), 116 os.path.join(rosgraph_d, 'conf', fname)]: 117 if os.path.isfile(f): 118 config_file = f 119 break 120 else: 121 config_file = None 122 123 if config_file is None or not os.path.isfile(config_file): 124 # logging is considered soft-fail 125 sys.stderr.write("WARNING: cannot load logging configuration file, logging is disabled\n") 126 logging.getLogger(logname).setLevel(logging.CRITICAL) 127 return log_filename 128 129 # pass in log_filename as argument to pylogging.conf 130 os.environ['ROS_LOG_FILENAME'] = log_filename 131 # #3625: disabling_existing_loggers=False 132 logging.config.fileConfig(config_file, disable_existing_loggers=False) 133 return log_filename
134
135 -def makedirs_with_parent_perms(p):
136 """ 137 Create the directory using the permissions of the nearest 138 (existing) parent directory. This is useful for logging, where a 139 root process sometimes has to log in the user's space. 140 :param p: directory to create, ``str`` 141 """ 142 p = os.path.abspath(p) 143 parent = os.path.dirname(p) 144 # recurse upwards, checking to make sure we haven't reached the 145 # top 146 if not os.path.exists(p) and p and parent != p: 147 makedirs_with_parent_perms(parent) 148 s = os.stat(parent) 149 os.mkdir(p) 150 151 # if perms of new dir don't match, set anew 152 s2 = os.stat(p) 153 if s.st_uid != s2.st_uid or s.st_gid != s2.st_gid: 154 os.chown(p, s.st_uid, s.st_gid) 155 if s.st_mode != s2.st_mode: 156 os.chmod(p, s.st_mode)
157 158 _logging_to_rospy_names = { 159 'DEBUG': ('DEBUG', '\033[32m'), 160 'INFO': ('INFO', None), 161 'WARNING': ('WARN', '\033[33m'), 162 'ERROR': ('ERROR', '\033[31m'), 163 'CRITICAL': ('FATAL', '\033[31m') 164 } 165 _color_reset = '\033[0m' 166 _defaultFormatter = logging.Formatter() 167
168 -class RosStreamHandler(logging.Handler):
169 - def __init__(self, colorize=True):
170 super(RosStreamHandler, self).__init__() 171 self._colorize = colorize 172 try: 173 from rospy.rostime import get_time, is_wallclock 174 self._get_time = get_time 175 self._is_wallclock = is_wallclock 176 except ImportError: 177 self._get_time = None 178 self._is_wallclock = None
179
180 - def emit(self, record):
181 level, color = _logging_to_rospy_names[record.levelname] 182 record_message = _defaultFormatter.format(record) 183 msg = os.environ.get( 184 'ROSCONSOLE_FORMAT', '[${severity}] [${time}]: ${message}') 185 msg = msg.replace('${severity}', level) 186 msg = msg.replace('${message}', str(record_message)) 187 msg = msg.replace('${walltime}', '%f' % time.time()) 188 msg = msg.replace('${thread}', str(record.thread)) 189 msg = msg.replace('${logger}', str(record.name)) 190 msg = msg.replace('${file}', str(record.pathname)) 191 msg = msg.replace('${line}', str(record.lineno)) 192 msg = msg.replace('${function}', str(record.funcName)) 193 try: 194 from rospy import get_name 195 node_name = get_name() 196 except ImportError: 197 node_name = '<unknown_node_name>' 198 msg = msg.replace('${node}', node_name) 199 time_str = '%f' % time.time() 200 if self._get_time is not None and not self._is_wallclock(): 201 time_str += ', %f' % self._get_time() 202 msg = msg.replace('${time}', time_str) 203 msg += '\n' 204 if record.levelno < logging.WARNING: 205 self._write(sys.stdout, msg, color) 206 else: 207 self._write(sys.stderr, msg, color)
208
209 - def _write(self, fd, msg, color):
210 if self._colorize and color and hasattr(fd, 'isatty') and fd.isatty(): 211 msg = color + msg + _color_reset 212 fd.write(msg)
213