2 # Copyright (c) 2011, 2012 Nicira, Inc.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
18 import logging.handlers
26 FACILITIES = {"console": "info", "file": "info", "syslog": "info"}
30 "warn": logging.WARNING,
32 "emer": logging.CRITICAL,
33 "off": logging.CRITICAL
37 def get_level(level_str):
38 return LEVELS.get(level_str.lower())
44 __mfl = {} # Module -> facility -> level
48 def __init__(self, name):
49 """Creates a new Vlog object representing a module called 'name'. The
50 created Vlog object will do nothing until the Vlog.init() static method
51 is called. Once called, no more Vlog objects may be created."""
53 assert not Vlog.__inited
54 self.name = name.lower()
55 if name not in Vlog.__mfl:
56 Vlog.__mfl[self.name] = FACILITIES.copy()
58 def __log(self, level, message, **kwargs):
62 now = datetime.datetime.now().strftime("%b %d %H:%M:%S")
63 message = ("%s|%s|%s|%s|%s"
64 % (now, Vlog.__msg_num, self.name, level, message))
66 level = LEVELS.get(level.lower(), logging.DEBUG)
69 for f, f_level in Vlog.__mfl[self.name].iteritems():
70 f_level = LEVELS.get(f_level, logging.CRITICAL)
72 logging.getLogger(f).log(level, message, **kwargs)
74 def emer(self, message, **kwargs):
75 self.__log("EMER", message, **kwargs)
77 def err(self, message, **kwargs):
78 self.__log("ERR", message, **kwargs)
80 def warn(self, message, **kwargs):
81 self.__log("WARN", message, **kwargs)
83 def info(self, message, **kwargs):
84 self.__log("INFO", message, **kwargs)
86 def dbg(self, message, **kwargs):
87 self.__log("DBG", message, **kwargs)
89 def exception(self, message):
90 """Logs 'message' at ERR log level. Includes a backtrace when in
92 self.err(message, exc_info=True)
95 def init(log_file=None):
96 """Intializes the Vlog module. Causes Vlog to write to 'log_file' if
97 not None. Should be called after all Vlog objects have been created.
98 No logging will occur until this function is called."""
104 logging.raiseExceptions = False
105 Vlog.__log_file = log_file
107 logger = logging.getLogger(f)
108 logger.setLevel(logging.DEBUG)
112 logger.addHandler(logging.StreamHandler(sys.stderr))
114 logger.addHandler(logging.handlers.SysLogHandler(
116 facility=logging.handlers.SysLogHandler.LOG_DAEMON))
117 elif f == "file" and Vlog.__log_file:
118 Vlog.__file_handler = logging.FileHandler(Vlog.__log_file)
119 logger.addHandler(Vlog.__file_handler)
120 except (IOError, socket.error):
121 logger.setLevel(logging.CRITICAL)
123 ovs.unixctl.command_register("vlog/reopen", "", 0, 0,
124 Vlog._unixctl_vlog_reopen, None)
127 def set_level(module, facility, level):
128 """ Sets the log level of the 'module'-'facility' tuple to 'level'.
129 All three arguments are strings which are interpreted the same as
130 arguments to the --verbose flag. Should be called after all Vlog
131 objects have already been created."""
133 module = module.lower()
134 facility = facility.lower()
135 level = level.lower()
137 if facility != "any" and facility not in FACILITIES:
140 if module != "any" and module not in Vlog.__mfl:
143 if level not in LEVELS:
147 modules = Vlog.__mfl.keys()
151 if facility == "any":
152 facilities = FACILITIES.keys()
154 facilities = [facility]
158 Vlog.__mfl[m][f] = level
161 def reopen_log_file():
162 """Closes and then attempts to re-open the current log file. (This is
163 useful just after log rotation, to ensure that the new log file starts
167 logger = logging.getLogger("file")
168 logger.removeHandler(Vlog.__file_handler)
169 Vlog.__file_handler = logging.FileHandler(Vlog.__log_file)
170 logger.addHandler(Vlog.__file_handler)
173 def _unixctl_vlog_reopen(conn, unused_argv, unused_aux):
175 Vlog.reopen_log_file()
178 conn.reply("Logging to file not configured")
180 def add_args(parser):
181 """Adds vlog related options to 'parser', an ArgumentParser object. The
182 resulting arguments parsed by 'parser' should be passed to handle_args."""
184 group = parser.add_argument_group(title="Logging Options")
185 group.add_argument("--log-file", nargs="?", const="default",
186 help="Enables logging to a file. Default log file"
187 " is used if LOG_FILE is omitted.")
188 group.add_argument("-v", "--verbose", nargs="*",
189 help="Sets logging levels, see ovs-vswitchd(8)."
190 " Defaults to ANY:ANY:dbg.")
193 def handle_args(args):
194 """ Handles command line arguments ('args') parsed by an ArgumentParser.
195 The ArgumentParser should have been primed by add_args(). Also takes care
196 of initializing the Vlog module."""
198 log_file = args.log_file
199 if log_file == "default":
200 log_file = "%s/%s.log" % (ovs.dirs.LOGDIR, ovs.util.PROGRAM_NAME)
202 if args.verbose is None:
204 elif args.verbose == []:
205 args.verbose = ["any:any:dbg"]
207 for verbose in args.verbose:
208 args = verbose.split(':')
225 Vlog.set_level(module, facility, level)