OLD | NEW |
1 # Copyright 2013 The Swarming Authors. All rights reserved. | 1 # Copyright 2013 The Swarming Authors. All rights reserved. |
2 # Use of this source code is governed under the Apache License, Version 2.0 that | 2 # Use of this source code is governed under the Apache License, Version 2.0 that |
3 # can be found in the LICENSE file. | 3 # can be found in the LICENSE file. |
4 | 4 |
5 """Various utility functions and classes not specific to any single area.""" | 5 """Various utility functions and classes not specific to any single area.""" |
6 | 6 |
7 import argparse | |
8 import atexit | 7 import atexit |
9 import cStringIO | 8 import cStringIO |
10 import functools | 9 import functools |
11 import json | 10 import json |
12 import logging | 11 import logging |
13 import logging.handlers | |
14 import optparse | |
15 import os | 12 import os |
16 import re | 13 import re |
17 import sys | 14 import sys |
18 import threading | 15 import threading |
19 import time | 16 import time |
20 | 17 |
21 import utils | 18 import utils |
22 from utils import zip_package | 19 from utils import zip_package |
23 | 20 |
24 | 21 |
25 # Path to (possibly extracted from zip) cacert.pem bundle file. | 22 # Path to (possibly extracted from zip) cacert.pem bundle file. |
26 # See get_cacerts_bundle(). | 23 # See get_cacerts_bundle(). |
27 _ca_certs = None | 24 _ca_certs = None |
28 _ca_certs_lock = threading.Lock() | 25 _ca_certs_lock = threading.Lock() |
29 | 26 |
30 | 27 |
31 # @cached decorators registered by report_cache_stats_at_exit. | 28 # @cached decorators registered by report_cache_stats_at_exit. |
32 _caches = [] | 29 _caches = [] |
33 _caches_lock = threading.Lock() | 30 _caches_lock = threading.Lock() |
34 | 31 |
35 | 32 |
36 class OptionParserWithLogging(optparse.OptionParser): | |
37 """Adds --verbose option.""" | |
38 | |
39 # Set to True to enable --log-file options. | |
40 enable_log_file = True | |
41 | |
42 def __init__(self, verbose=0, log_file=None, **kwargs): | |
43 kwargs.setdefault('description', sys.modules['__main__'].__doc__) | |
44 optparse.OptionParser.__init__(self, **kwargs) | |
45 self.group_logging = optparse.OptionGroup(self, 'Logging') | |
46 self.group_logging.add_option( | |
47 '-v', '--verbose', | |
48 action='count', | |
49 default=verbose, | |
50 help='Use multiple times to increase verbosity') | |
51 if self.enable_log_file: | |
52 self.group_logging.add_option( | |
53 '-l', '--log-file', | |
54 default=log_file, | |
55 help='The name of the file to store rotating log details') | |
56 self.group_logging.add_option( | |
57 '--no-log', action='store_const', const='', dest='log_file', | |
58 help='Disable log file') | |
59 | |
60 def parse_args(self, *args, **kwargs): | |
61 # Make sure this group is always the last one. | |
62 self.add_option_group(self.group_logging) | |
63 | |
64 options, args = optparse.OptionParser.parse_args(self, *args, **kwargs) | |
65 levels = [logging.ERROR, logging.INFO, logging.DEBUG] | |
66 level = levels[min(len(levels) - 1, options.verbose)] | |
67 | |
68 logging_console = logging.StreamHandler() | |
69 logging_console.setFormatter(logging.Formatter( | |
70 '%(levelname)5s %(relativeCreated)6d %(module)15s(%(lineno)3d): ' | |
71 '%(message)s')) | |
72 logging_console.setLevel(level) | |
73 logging.getLogger().setLevel(level) | |
74 logging.getLogger().addHandler(logging_console) | |
75 | |
76 if self.enable_log_file and options.log_file: | |
77 # This is necessary otherwise attached handler will miss the messages. | |
78 logging.getLogger().setLevel(logging.DEBUG) | |
79 | |
80 logging_rotating_file = logging.handlers.RotatingFileHandler( | |
81 options.log_file, | |
82 maxBytes=10 * 1024 * 1024, | |
83 backupCount=5, | |
84 encoding='utf-8') | |
85 # log files are always at DEBUG level. | |
86 logging_rotating_file.setLevel(logging.DEBUG) | |
87 logging_rotating_file.setFormatter(logging.Formatter( | |
88 '%(asctime)s %(levelname)-8s %(module)15s(%(lineno)3d): %(message)s')) | |
89 logging.getLogger().addHandler(logging_rotating_file) | |
90 | |
91 return options, args | |
92 | |
93 | |
94 class ArgumentParserWithLogging(argparse.ArgumentParser): | |
95 """Adds --verbose option.""" | |
96 | |
97 # Set to True to enable --log-file options. | |
98 enable_log_file = True | |
99 | |
100 def __init__(self, verbose=0, log_file=None, **kwargs): | |
101 kwargs.setdefault('description', sys.modules['__main__'].__doc__) | |
102 kwargs.setdefault('conflict_handler', 'resolve') | |
103 self.__verbose = verbose | |
104 self.__log_file = log_file | |
105 super(ArgumentParserWithLogging, self).__init__(**kwargs) | |
106 | |
107 def _add_logging_group(self): | |
108 group = self.add_argument_group('Logging') | |
109 group.add_argument( | |
110 '-v', '--verbose', | |
111 action='count', | |
112 default=self.__verbose, | |
113 help='Use multiple times to increase verbosity') | |
114 if self.enable_log_file: | |
115 group.add_argument( | |
116 '-l', '--log-file', | |
117 default=self.__log_file, | |
118 help='The name of the file to store rotating log details') | |
119 group.add_argument( | |
120 '--no-log', action='store_const', const='', dest='log_file', | |
121 help='Disable log file') | |
122 | |
123 def parse_args(self, *args, **kwargs): | |
124 # Make sure this group is always the last one. | |
125 self._add_logging_group() | |
126 | |
127 args = super(ArgumentParserWithLogging, self).parse_args(*args, **kwargs) | |
128 levels = [logging.ERROR, logging.INFO, logging.DEBUG] | |
129 level = levels[min(len(levels) - 1, args.verbose)] | |
130 | |
131 logging_console = logging.StreamHandler() | |
132 logging_console.setFormatter(logging.Formatter( | |
133 '%(levelname)5s %(relativeCreated)6d %(module)15s(%(lineno)3d): ' | |
134 '%(message)s')) | |
135 logging_console.setLevel(level) | |
136 logging.getLogger().setLevel(level) | |
137 logging.getLogger().addHandler(logging_console) | |
138 | |
139 if self.enable_log_file and args.log_file: | |
140 # This is necessary otherwise attached handler will miss the messages. | |
141 logging.getLogger().setLevel(logging.DEBUG) | |
142 | |
143 logging_rotating_file = logging.handlers.RotatingFileHandler( | |
144 args.log_file, | |
145 maxBytes=10 * 1024 * 1024, | |
146 backupCount=5, | |
147 encoding='utf-8') | |
148 # log files are always at DEBUG level. | |
149 logging_rotating_file.setLevel(logging.DEBUG) | |
150 logging_rotating_file.setFormatter(logging.Formatter( | |
151 '%(asctime)s %(levelname)-8s %(module)15s(%(lineno)3d): %(message)s')) | |
152 logging.getLogger().addHandler(logging_rotating_file) | |
153 | |
154 return args | |
155 | |
156 | |
157 class Profiler(object): | 33 class Profiler(object): |
158 """Context manager that records time spend inside its body.""" | 34 """Context manager that records time spend inside its body.""" |
159 def __init__(self, name): | 35 def __init__(self, name): |
160 self.name = name | 36 self.name = name |
161 self.start_time = None | 37 self.start_time = None |
162 | 38 |
163 def __enter__(self): | 39 def __enter__(self): |
164 self.start_time = time.time() | 40 self.start_time = time.time() |
165 return self | 41 return self |
166 | 42 |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
433 a zip archive, we need to extract the file first. | 309 a zip archive, we need to extract the file first. |
434 """ | 310 """ |
435 global _ca_certs | 311 global _ca_certs |
436 with _ca_certs_lock: | 312 with _ca_certs_lock: |
437 if _ca_certs is not None and os.path.exists(_ca_certs): | 313 if _ca_certs is not None and os.path.exists(_ca_certs): |
438 return _ca_certs | 314 return _ca_certs |
439 # Some rogue process clears /tmp and causes cacert.pem to disappear. Extract | 315 # Some rogue process clears /tmp and causes cacert.pem to disappear. Extract |
440 # to current directory instead. We use our own bundled copy of cacert.pem. | 316 # to current directory instead. We use our own bundled copy of cacert.pem. |
441 _ca_certs = zip_package.extract_resource(utils, 'cacert.pem', temp_dir='.') | 317 _ca_certs = zip_package.extract_resource(utils, 'cacert.pem', temp_dir='.') |
442 return _ca_certs | 318 return _ca_certs |
OLD | NEW |