Global replace of Nicira Networks.
[sliver-openvswitch.git] / python / ovs / vlog.py
1
2 # Copyright (c) 2011 Nicira, Inc.
3 #
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:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
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.
15
16 import datetime
17 import logging
18 import logging.handlers
19 import socket
20 import sys
21
22 import ovs.dirs
23 import ovs.util
24
25 FACILITIES = {"console": "info", "file": "info", "syslog": "info"}
26 LEVELS = {
27     "dbg": logging.DEBUG,
28     "info": logging.INFO,
29     "warn": logging.WARNING,
30     "err": logging.ERROR,
31     "emer": logging.CRITICAL,
32     "off": logging.CRITICAL
33 }
34
35
36 def get_level(level_str):
37     return LEVELS.get(level_str.lower())
38
39
40 class Vlog:
41     __inited = False
42     __msg_num = 0
43     __mfl = {}  # Module -> facility -> level
44
45     def __init__(self, name):
46         """Creates a new Vlog object representing a module called 'name'.  The
47         created Vlog object will do nothing until the Vlog.init() static method
48         is called.  Once called, no more Vlog objects may be created."""
49
50         assert not Vlog.__inited
51         self.name = name.lower()
52         if name not in Vlog.__mfl:
53             Vlog.__mfl[self.name] = FACILITIES.copy()
54
55     def __log(self, level, message, **kwargs):
56         if not Vlog.__inited:
57             return
58
59         now = datetime.datetime.now().strftime("%b %d %H:%M:%S")
60         message = ("%s|%s|%s|%s|%s"
61                    % (now, Vlog.__msg_num, self.name, level, message))
62
63         level = LEVELS.get(level.lower(), logging.DEBUG)
64         Vlog.__msg_num += 1
65
66         for f, f_level in Vlog.__mfl[self.name].iteritems():
67             f_level = LEVELS.get(f_level, logging.CRITICAL)
68             if level >= f_level:
69                 logging.getLogger(f).log(level, message, **kwargs)
70
71     def emer(self, message, **kwargs):
72         self.__log("EMER", message, **kwargs)
73
74     def err(self, message, **kwargs):
75         self.__log("ERR", message, **kwargs)
76
77     def warn(self, message, **kwargs):
78         self.__log("WARN", message, **kwargs)
79
80     def info(self, message, **kwargs):
81         self.__log("INFO", message, **kwargs)
82
83     def dbg(self, message, **kwargs):
84         self.__log("DBG", message, **kwargs)
85
86     def exception(self, message):
87         """Logs 'message' at ERR log level.  Includes a backtrace when in
88         exception context."""
89         self.err(message, exc_info=True)
90
91     @staticmethod
92     def init(log_file=None):
93         """Intializes the Vlog module.  Causes Vlog to write to 'log_file' if
94         not None.  Should be called after all Vlog objects have been created.
95         No logging will occur until this function is called."""
96
97         if Vlog.__inited:
98             return
99
100         Vlog.__inited = True
101         logging.raiseExceptions = False
102         for f in FACILITIES:
103             logger = logging.getLogger(f)
104             logger.setLevel(logging.DEBUG)
105
106             try:
107                 if f == "console":
108                     logger.addHandler(logging.StreamHandler(sys.stderr))
109                 elif f == "syslog":
110                     logger.addHandler(logging.handlers.SysLogHandler(
111                         address="/dev/log",
112                         facility=logging.handlers.SysLogHandler.LOG_DAEMON))
113                 elif f == "file" and log_file:
114                     logger.addHandler(logging.FileHandler(log_file))
115             except (IOError, socket.error):
116                 logger.setLevel(logging.CRITICAL)
117
118     @staticmethod
119     def set_level(module, facility, level):
120         """ Sets the log level of the 'module'-'facility' tuple to 'level'.
121         All three arguments are strings which are interpreted the same as
122         arguments to the --verbose flag.  Should be called after all Vlog
123         objects have already been created."""
124
125         module = module.lower()
126         facility = facility.lower()
127         level = level.lower()
128
129         if facility != "any" and facility not in FACILITIES:
130             return
131
132         if module != "any" and module not in Vlog.__mfl:
133             return
134
135         if level not in LEVELS:
136             return
137
138         if module == "any":
139             modules = Vlog.__mfl.keys()
140         else:
141             modules = [module]
142
143         if facility == "any":
144             facilities = FACILITIES.keys()
145         else:
146             facilities = [facility]
147
148         for m in modules:
149             for f in facilities:
150                 Vlog.__mfl[m][f] = level
151
152
153 def add_args(parser):
154     """Adds vlog related options to 'parser', an ArgumentParser object.  The
155     resulting arguments parsed by 'parser' should be passed to handle_args."""
156
157     group = parser.add_argument_group(title="Logging Options")
158     group.add_argument("--log-file", nargs="?", const="default",
159                        help="Enables logging to a file.  Default log file"
160                        " is used if LOG_FILE is omitted.")
161     group.add_argument("-v", "--verbose", nargs="*",
162                        help="Sets logging levels, see ovs-vswitchd(8)."
163                        "  Defaults to ANY:ANY:dbg.")
164
165
166 def handle_args(args):
167     """ Handles command line arguments ('args') parsed by an ArgumentParser.
168     The ArgumentParser should have been primed by add_args().  Also takes care
169     of initializing the Vlog module."""
170
171     log_file = args.log_file
172     if log_file == "default":
173         log_file = "%s/%s.log" % (ovs.dirs.LOGDIR, ovs.util.PROGRAM_NAME)
174
175     if args.verbose is None:
176         args.verbose = []
177     elif args.verbose == []:
178         args.verbose = ["any:any:dbg"]
179
180     for verbose in args.verbose:
181         args = verbose.split(':')
182
183         if len(args) >= 3:
184             level = args[2]
185         else:
186             level = "dbg"
187
188         if len(args) >= 2:
189             facility = args[1]
190         else:
191             facility = "any"
192
193         if len(args) >= 1:
194             module = args[0]
195         else:
196             module = "any"
197
198         Vlog.set_level(module, facility, level)
199
200     Vlog.init(log_file)