Show More
@@ -0,0 +1,53 b'' | |||
|
1 | ; ##################### | |
|
2 | ; LOGGING CONFIGURATION | |
|
3 | ; ##################### | |
|
4 | ; Logging template, used for configure the logging | |
|
5 | ; some variables here are replaced by RhodeCode to default values | |
|
6 | ||
|
7 | [loggers] | |
|
8 | keys = root, vcsserver | |
|
9 | ||
|
10 | [handlers] | |
|
11 | keys = console | |
|
12 | ||
|
13 | [formatters] | |
|
14 | keys = generic, json | |
|
15 | ||
|
16 | ; ####### | |
|
17 | ; LOGGERS | |
|
18 | ; ####### | |
|
19 | [logger_root] | |
|
20 | level = NOTSET | |
|
21 | handlers = console | |
|
22 | ||
|
23 | [logger_vcsserver] | |
|
24 | level = $RC_LOGGING_LEVEL | |
|
25 | handlers = | |
|
26 | qualname = vcsserver | |
|
27 | propagate = 1 | |
|
28 | ||
|
29 | ; ######## | |
|
30 | ; HANDLERS | |
|
31 | ; ######## | |
|
32 | ||
|
33 | [handler_console] | |
|
34 | class = StreamHandler | |
|
35 | args = (sys.stderr, ) | |
|
36 | level = $RC_LOGGING_LEVEL | |
|
37 | ; To enable JSON formatted logs replace generic with json | |
|
38 | ; This allows sending properly formatted logs to grafana loki or elasticsearch | |
|
39 | #formatter = json | |
|
40 | #formatter = generic | |
|
41 | formatter = $RC_LOGGING_FORMATTER | |
|
42 | ||
|
43 | ; ########## | |
|
44 | ; FORMATTERS | |
|
45 | ; ########## | |
|
46 | ||
|
47 | [formatter_generic] | |
|
48 | format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | |
|
49 | datefmt = %Y-%m-%d %H:%M:%S | |
|
50 | ||
|
51 | [formatter_json] | |
|
52 | format = %(timestamp)s %(levelname)s %(name)s %(message)s %(req_id)s | |
|
53 | class = vcsserver.lib._vendor.jsonlogger.JsonFormatter |
|
1 | NO CONTENT: new file 100644 |
@@ -0,0 +1,177 b'' | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | ||
|
3 | # Copyright (C) 2010-2020 RhodeCode GmbH | |
|
4 | # | |
|
5 | # This program is free software: you can redistribute it and/or modify | |
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |
|
7 | # (only), as published by the Free Software Foundation. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU Affero General Public License | |
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
|
16 | # | |
|
17 | # This program is dual-licensed. If you wish to learn more about the | |
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
|
20 | ||
|
21 | import os | |
|
22 | import textwrap | |
|
23 | import string | |
|
24 | import functools | |
|
25 | import logging | |
|
26 | import tempfile | |
|
27 | import logging.config | |
|
28 | log = logging.getLogger(__name__) | |
|
29 | ||
|
30 | ||
|
31 | def str2bool(_str): | |
|
32 | """ | |
|
33 | returns True/False value from given string, it tries to translate the | |
|
34 | string into boolean | |
|
35 | ||
|
36 | :param _str: string value to translate into boolean | |
|
37 | :rtype: boolean | |
|
38 | :returns: boolean from given string | |
|
39 | """ | |
|
40 | if _str is None: | |
|
41 | return False | |
|
42 | if _str in (True, False): | |
|
43 | return _str | |
|
44 | _str = str(_str).strip().lower() | |
|
45 | return _str in ('t', 'true', 'y', 'yes', 'on', '1') | |
|
46 | ||
|
47 | ||
|
48 | def aslist(obj, sep=None, strip=True): | |
|
49 | """ | |
|
50 | Returns given string separated by sep as list | |
|
51 | ||
|
52 | :param obj: | |
|
53 | :param sep: | |
|
54 | :param strip: | |
|
55 | """ | |
|
56 | if isinstance(obj, (basestring,)): | |
|
57 | lst = obj.split(sep) | |
|
58 | if strip: | |
|
59 | lst = [v.strip() for v in lst] | |
|
60 | return lst | |
|
61 | elif isinstance(obj, (list, tuple)): | |
|
62 | return obj | |
|
63 | elif obj is None: | |
|
64 | return [] | |
|
65 | else: | |
|
66 | return [obj] | |
|
67 | ||
|
68 | ||
|
69 | class SettingsMaker(object): | |
|
70 | ||
|
71 | def __init__(self, app_settings): | |
|
72 | self.settings = app_settings | |
|
73 | ||
|
74 | @classmethod | |
|
75 | def _bool_func(cls, input_val): | |
|
76 | if isinstance(input_val, unicode): | |
|
77 | input_val = input_val.encode('utf8') | |
|
78 | return str2bool(input_val) | |
|
79 | ||
|
80 | @classmethod | |
|
81 | def _int_func(cls, input_val): | |
|
82 | return int(input_val) | |
|
83 | ||
|
84 | @classmethod | |
|
85 | def _list_func(cls, input_val, sep=','): | |
|
86 | return aslist(input_val, sep=sep) | |
|
87 | ||
|
88 | @classmethod | |
|
89 | def _string_func(cls, input_val, lower=True): | |
|
90 | if lower: | |
|
91 | input_val = input_val.lower() | |
|
92 | return input_val | |
|
93 | ||
|
94 | @classmethod | |
|
95 | def _float_func(cls, input_val): | |
|
96 | return float(input_val) | |
|
97 | ||
|
98 | @classmethod | |
|
99 | def _dir_func(cls, input_val, ensure_dir=False, mode=0o755): | |
|
100 | ||
|
101 | # ensure we have our dir created | |
|
102 | if not os.path.isdir(input_val) and ensure_dir: | |
|
103 | os.makedirs(input_val, mode=mode) | |
|
104 | ||
|
105 | if not os.path.isdir(input_val): | |
|
106 | raise Exception('Dir at {} does not exist'.format(input_val)) | |
|
107 | return input_val | |
|
108 | ||
|
109 | @classmethod | |
|
110 | def _file_path_func(cls, input_val, ensure_dir=False, mode=0o755): | |
|
111 | dirname = os.path.dirname(input_val) | |
|
112 | cls._dir_func(dirname, ensure_dir=ensure_dir) | |
|
113 | return input_val | |
|
114 | ||
|
115 | @classmethod | |
|
116 | def _key_transformator(cls, key): | |
|
117 | return "{}_{}".format('RC'.upper(), key.upper().replace('.', '_').replace('-', '_')) | |
|
118 | ||
|
119 | def enable_logging(self, logging_conf=None): | |
|
120 | """ | |
|
121 | Helper to enable debug on running instance | |
|
122 | :return: | |
|
123 | """ | |
|
124 | if not str2bool(self.settings.get('logging.autoconfigure')): | |
|
125 | log.info('logging configuration based on main .ini file') | |
|
126 | return | |
|
127 | ||
|
128 | if logging_conf is None: | |
|
129 | logging_conf = self.settings.get('logging.logging_conf_file') or '' | |
|
130 | ||
|
131 | if not os.path.isfile(logging_conf): | |
|
132 | log.error('Unable to setup logging based on %s, file does not exist...', logging_conf) | |
|
133 | return | |
|
134 | ||
|
135 | with open(logging_conf, 'rb') as f: | |
|
136 | ini_template = textwrap.dedent(f.read()) | |
|
137 | ini_template = string.Template(ini_template).safe_substitute( | |
|
138 | RC_LOGGING_LEVEL=os.environ.get('RC_LOGGING_LEVEL', '') or 'INFO', | |
|
139 | RC_LOGGING_FORMATTER=os.environ.get('RC_LOGGING_FORMATTER', '') or 'generic' | |
|
140 | ) | |
|
141 | ||
|
142 | with tempfile.NamedTemporaryFile(prefix='rc_logging_', suffix='.ini', delete=False) as f: | |
|
143 | log.info('Saved Temporary LOGGING config at %s', f.name) | |
|
144 | f.write(ini_template) | |
|
145 | ||
|
146 | logging.config.fileConfig(f.name) | |
|
147 | os.remove(f.name) | |
|
148 | ||
|
149 | def make_setting(self, key, default, lower=False, default_when_empty=False, parser=None): | |
|
150 | ||
|
151 | input_val = self.settings.get(key, default) | |
|
152 | ||
|
153 | if default_when_empty and not input_val: | |
|
154 | # use default value when value is set in the config but it is empty | |
|
155 | input_val = default | |
|
156 | ||
|
157 | parser_func = { | |
|
158 | 'bool': self._bool_func, | |
|
159 | 'int': self._int_func, | |
|
160 | 'list': self._list_func, | |
|
161 | 'list:newline': functools.partial(self._list_func, sep='/n'), | |
|
162 | 'string': functools.partial(self._string_func, lower=lower), | |
|
163 | 'dir': self._dir_func, | |
|
164 | 'dir:ensured': functools.partial(self._dir_func, ensure_dir=True), | |
|
165 | 'file': self._file_path_func, | |
|
166 | 'file:ensured': functools.partial(self._file_path_func, ensure_dir=True), | |
|
167 | None: lambda i: i | |
|
168 | }[parser] | |
|
169 | ||
|
170 | # now maybe we have this KEY in env, search and use the value with higher priority. | |
|
171 | transformed_key = self._key_transformator(key) | |
|
172 | envvar_value = os.environ.get(transformed_key) | |
|
173 | if envvar_value: | |
|
174 | log.debug('using `%s` key instead of `%s` key for config', transformed_key, key) | |
|
175 | input_val = envvar_value | |
|
176 | self.settings[key] = parser_func(input_val) | |
|
177 | return self.settings[key] |
@@ -31,7 +31,7 b' asyncore_use_poll = true' | |||
|
31 | 31 | ; GUNICORN APPLICATION SERVER |
|
32 | 32 | ; ########################### |
|
33 | 33 | |
|
34 |
; run with gunicorn -- |
|
|
34 | ; run with gunicorn --paste rhodecode.ini | |
|
35 | 35 | |
|
36 | 36 | ; Module to use, this setting shouldn't be changed |
|
37 | 37 | #use = egg:gunicorn#main |
@@ -86,7 +86,7 b' asyncore_use_poll = true' | |||
|
86 | 86 | ; serving requests. Workers still alive after the timeout (starting from the |
|
87 | 87 | ; receipt of the restart signal) are force killed. |
|
88 | 88 | ; Examples: 1800 (30min), 3600 (1hr), 7200 (2hr), 43200 (12h) |
|
89 |
#graceful_timeout = |
|
|
89 | #graceful_timeout = 21600 | |
|
90 | 90 | |
|
91 | 91 | # The number of seconds to wait for requests on a Keep-Alive connection. |
|
92 | 92 | # Generally set in the 1-5 seconds range. |
@@ -110,6 +110,17 b' asyncore_use_poll = true' | |||
|
110 | 110 | [app:main] |
|
111 | 111 | ; The %(here)s variable will be replaced with the absolute path of parent directory |
|
112 | 112 | ; of this file |
|
113 | ; Each option in the app:main can be override by an environmental variable | |
|
114 | ; | |
|
115 | ;To override an option: | |
|
116 | ; | |
|
117 | ;RC_<KeyName> | |
|
118 | ;Everything should be uppercase, . and - should be replaced by _. | |
|
119 | ;For example, if you have these configuration settings: | |
|
120 | ;rc_cache.repo_object.backend = foo | |
|
121 | ;can be overridden by | |
|
122 | ;export RC_CACHE_REPO_OBJECT_BACKEND=foo | |
|
123 | ||
|
113 | 124 | use = egg:rhodecode-vcsserver |
|
114 | 125 | |
|
115 | 126 | |
@@ -133,13 +144,13 b' debugtoolbar.exclude_prefixes =' | |||
|
133 | 144 | ; ################# |
|
134 | 145 | |
|
135 | 146 | ; Pyramid default locales, we need this to be set |
|
136 | pyramid.default_locale_name = en | |
|
147 | #pyramid.default_locale_name = en | |
|
137 | 148 | |
|
138 | 149 | ; default locale used by VCS systems |
|
139 | locale = en_US.UTF-8 | |
|
150 | #locale = en_US.UTF-8 | |
|
140 | 151 | |
|
141 | 152 | ; path to binaries for vcsserver, it should be set by the installer |
|
142 | ; at installation time, e.g /home/user/vcsserver-1/profile/bin | |
|
153 | ; at installation time, e.g /home/user/.rccontrol/vcsserver-1/profile/bin | |
|
143 | 154 | ; it can also be a path to nix-build output in case of development |
|
144 | 155 | core.binary_dir = "" |
|
145 | 156 | |
@@ -153,21 +164,21 b' core.binary_dir = ""' | |||
|
153 | 164 | |
|
154 | 165 | ; Default cache dir for caches. Putting this into a ramdisk can boost performance. |
|
155 | 166 | ; eg. /tmpfs/data_ramdisk, however this directory might require large amount of space |
|
156 | cache_dir = %(here)s/data | |
|
167 | #cache_dir = %(here)s/data | |
|
157 | 168 | |
|
158 | 169 | ; *************************************** |
|
159 | 170 | ; `repo_object` cache, default file based |
|
160 | 171 | ; *************************************** |
|
161 | 172 | |
|
162 | 173 | ; `repo_object` cache settings for vcs methods for repositories |
|
163 | rc_cache.repo_object.backend = dogpile.cache.rc.file_namespace | |
|
174 | #rc_cache.repo_object.backend = dogpile.cache.rc.file_namespace | |
|
164 | 175 | |
|
165 | 176 | ; cache auto-expires after N seconds |
|
166 | 177 | ; Examples: 86400 (1Day), 604800 (7Days), 1209600 (14Days), 2592000 (30days), 7776000 (90Days) |
|
167 | rc_cache.repo_object.expiration_time = 2592000 | |
|
178 | #rc_cache.repo_object.expiration_time = 2592000 | |
|
168 | 179 | |
|
169 | 180 | ; file cache store path. Defaults to `cache_dir =` value or tempdir if both values are not set |
|
170 | #rc_cache.repo_object.arguments.filename = /tmp/vcsserver_cache.db | |
|
181 | #rc_cache.repo_object.arguments.filename = /tmp/vcsserver_cache_repo_object.db | |
|
171 | 182 | |
|
172 | 183 | ; *********************************************************** |
|
173 | 184 | ; `repo_object` cache with redis backend |
@@ -202,55 +213,59 b' rc_cache.repo_object.expiration_time = 2' | |||
|
202 | 213 | #statsd.statsd_prefix = |
|
203 | 214 | #statsd.statsd_ipv6 = false |
|
204 | 215 | |
|
216 | ; configure logging automatically at server startup set to false | |
|
217 | ; to use the below custom logging config. | |
|
218 | #logging.autoconfigure = true | |
|
219 | ||
|
220 | ; specify your own custom logging config file to configure logging | |
|
221 | #logging.logging_conf_file = /path/to/custom_logging.ini | |
|
222 | ||
|
205 | 223 | ; ##################### |
|
206 | 224 | ; LOGGING CONFIGURATION |
|
207 | 225 | ; ##################### |
|
208 | [loggers] | |
|
209 | keys = root, vcsserver | |
|
226 | #[loggers] | |
|
227 | #keys = root, vcsserver | |
|
210 | 228 | |
|
211 | [handlers] | |
|
212 | keys = console | |
|
229 | #[handlers] | |
|
230 | #keys = console | |
|
213 | 231 | |
|
214 | [formatters] | |
|
215 | keys = generic | |
|
232 | #[formatters] | |
|
233 | #keys = generic | |
|
216 | 234 | |
|
217 | 235 | ; ####### |
|
218 | 236 | ; LOGGERS |
|
219 | 237 | ; ####### |
|
220 | [logger_root] | |
|
221 | level = NOTSET | |
|
222 | handlers = console | |
|
238 | #[logger_root] | |
|
239 | #level = NOTSET | |
|
240 | #handlers = console | |
|
223 | 241 | |
|
224 | [logger_vcsserver] | |
|
225 |
level = |
|
|
226 | handlers = | |
|
227 | qualname = vcsserver | |
|
228 | propagate = 1 | |
|
229 | ||
|
242 | #[logger_vcsserver] | |
|
243 | #level = INFO | |
|
244 | #handlers = | |
|
245 | #qualname = vcsserver | |
|
246 | #propagate = 1 | |
|
230 | 247 | |
|
231 | 248 | ; ######## |
|
232 | 249 | ; HANDLERS |
|
233 | 250 | ; ######## |
|
234 | 251 | |
|
235 | [handler_console] | |
|
236 | class = StreamHandler | |
|
237 | args = (sys.stderr, ) | |
|
238 |
level = |
|
|
239 | formatter = generic | |
|
252 | #[handler_console] | |
|
253 | #class = StreamHandler | |
|
254 | #args = (sys.stderr, ) | |
|
255 | #level = INFO | |
|
240 | 256 | ; To enable JSON formatted logs replace generic with json |
|
241 | 257 | ; This allows sending properly formatted logs to grafana loki or elasticsearch |
|
242 | 258 | #formatter = json |
|
243 | ||
|
259 | #formatter = generic | |
|
244 | 260 | |
|
245 | 261 | ; ########## |
|
246 | 262 | ; FORMATTERS |
|
247 | 263 | ; ########## |
|
248 | 264 | |
|
249 | [formatter_generic] | |
|
250 | format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | |
|
251 | datefmt = %Y-%m-%d %H:%M:%S | |
|
265 | #[formatter_generic] | |
|
266 | #format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | |
|
267 | #datefmt = %Y-%m-%d %H:%M:%S | |
|
252 | 268 | |
|
253 | [formatter_json] | |
|
254 | format = %(timestamp)s %(levelname)s %(name)s %(message)s %(req_id)s | |
|
255 | class = vcsserver.lib._vendor.jsonlogger.JsonFormatter | |
|
256 | ||
|
269 | #[formatter_json] | |
|
270 | #format = %(timestamp)s %(levelname)s %(name)s %(message)s %(req_id)s | |
|
271 | #class = vcsserver.lib._vendor.jsonlogger.JsonFormatter |
@@ -30,12 +30,12 b' worker_tmp_dir = None' | |||
|
30 | 30 | tmp_upload_dir = None |
|
31 | 31 | |
|
32 | 32 | # Custom log format |
|
33 | access_log_format = ( | |
|
34 | '%(t)s %(p)s INFO [GNCRN] %(h)-15s rqt:%(L)s %(s)s %(b)-6s "%(m)s:%(U)s %(q)s" usr:%(u)s "%(f)s" "%(a)s"') | |
|
33 | #access_log_format = ( | |
|
34 | # '%(t)s %(p)s INFO [GNCRN] %(h)-15s rqt:%(L)s %(s)s %(b)-6s "%(m)s:%(U)s %(q)s" usr:%(u)s "%(f)s" "%(a)s"') | |
|
35 | 35 | |
|
36 | 36 | # loki format for easier parsing in grafana |
|
37 |
|
|
|
38 |
|
|
|
37 | access_log_format = ( | |
|
38 | 'time="%(t)s" pid=%(p)s level="INFO" type="[GNCRN]" ip="%(h)-15s" rqt="%(L)s" response_code="%(s)s" response_bytes="%(b)-6s" uri="%(m)s:%(U)s %(q)s" user=":%(u)s" user_agent="%(a)s"') | |
|
39 | 39 | |
|
40 | 40 | # self adjust workers based on CPU count |
|
41 | 41 | # workers = get_workers() |
@@ -97,9 +97,12 b' def post_fork(server, worker):' | |||
|
97 | 97 | if conf.has_option(section, 'memory_usage_recovery_threshold'): |
|
98 | 98 | _memory_usage_recovery_threshold = conf.getfloat(section, 'memory_usage_recovery_threshold') |
|
99 | 99 | |
|
100 | worker._memory_max_usage = _memory_max_usage | |
|
101 | worker._memory_usage_check_interval = _memory_usage_check_interval | |
|
102 | worker._memory_usage_recovery_threshold = _memory_usage_recovery_threshold | |
|
100 | worker._memory_max_usage = int(os.environ.get('RC_GUNICORN_MEMORY_MAX_USAGE', '') | |
|
101 | or _memory_max_usage) | |
|
102 | worker._memory_usage_check_interval = int(os.environ.get('RC_GUNICORN_MEMORY_USAGE_CHECK_INTERVAL', '') | |
|
103 | or _memory_usage_check_interval) | |
|
104 | worker._memory_usage_recovery_threshold = float(os.environ.get('RC_GUNICORN_MEMORY_USAGE_RECOVERY_THRESHOLD', '') | |
|
105 | or _memory_usage_recovery_threshold) | |
|
103 | 106 | |
|
104 | 107 | # register memory last check time, with some random offset so we don't recycle all |
|
105 | 108 | # at once |
@@ -14,7 +14,7 b' port = 9900' | |||
|
14 | 14 | ; GUNICORN APPLICATION SERVER |
|
15 | 15 | ; ########################### |
|
16 | 16 | |
|
17 |
; run with gunicorn -- |
|
|
17 | ; run with gunicorn --paste rhodecode.ini | |
|
18 | 18 | |
|
19 | 19 | ; Module to use, this setting shouldn't be changed |
|
20 | 20 | use = egg:gunicorn#main |
@@ -69,7 +69,7 b' limit_request_field_size = 0' | |||
|
69 | 69 | ; serving requests. Workers still alive after the timeout (starting from the |
|
70 | 70 | ; receipt of the restart signal) are force killed. |
|
71 | 71 | ; Examples: 1800 (30min), 3600 (1hr), 7200 (2hr), 43200 (12h) |
|
72 |
graceful_timeout = |
|
|
72 | graceful_timeout = 21600 | |
|
73 | 73 | |
|
74 | 74 | # The number of seconds to wait for requests on a Keep-Alive connection. |
|
75 | 75 | # Generally set in the 1-5 seconds range. |
@@ -93,16 +93,27 b' memory_usage_recovery_threshold = 0.8' | |||
|
93 | 93 | [app:main] |
|
94 | 94 | ; The %(here)s variable will be replaced with the absolute path of parent directory |
|
95 | 95 | ; of this file |
|
96 | ; Each option in the app:main can be override by an environmental variable | |
|
97 | ; | |
|
98 | ;To override an option: | |
|
99 | ; | |
|
100 | ;RC_<KeyName> | |
|
101 | ;Everything should be uppercase, . and - should be replaced by _. | |
|
102 | ;For example, if you have these configuration settings: | |
|
103 | ;rc_cache.repo_object.backend = foo | |
|
104 | ;can be overridden by | |
|
105 | ;export RC_CACHE_REPO_OBJECT_BACKEND=foo | |
|
106 | ||
|
96 | 107 | use = egg:rhodecode-vcsserver |
|
97 | 108 | |
|
98 | 109 | ; Pyramid default locales, we need this to be set |
|
99 | pyramid.default_locale_name = en | |
|
110 | #pyramid.default_locale_name = en | |
|
100 | 111 | |
|
101 | 112 | ; default locale used by VCS systems |
|
102 | locale = en_US.UTF-8 | |
|
113 | #locale = en_US.UTF-8 | |
|
103 | 114 | |
|
104 | 115 | ; path to binaries for vcsserver, it should be set by the installer |
|
105 | ; at installation time, e.g /home/user/vcsserver-1/profile/bin | |
|
116 | ; at installation time, e.g /home/user/.rccontrol/vcsserver-1/profile/bin | |
|
106 | 117 | ; it can also be a path to nix-build output in case of development |
|
107 | 118 | core.binary_dir = "" |
|
108 | 119 | |
@@ -116,21 +127,21 b' core.binary_dir = ""' | |||
|
116 | 127 | |
|
117 | 128 | ; Default cache dir for caches. Putting this into a ramdisk can boost performance. |
|
118 | 129 | ; eg. /tmpfs/data_ramdisk, however this directory might require large amount of space |
|
119 | cache_dir = %(here)s/data | |
|
130 | #cache_dir = %(here)s/data | |
|
120 | 131 | |
|
121 | 132 | ; *************************************** |
|
122 | 133 | ; `repo_object` cache, default file based |
|
123 | 134 | ; *************************************** |
|
124 | 135 | |
|
125 | 136 | ; `repo_object` cache settings for vcs methods for repositories |
|
126 | rc_cache.repo_object.backend = dogpile.cache.rc.file_namespace | |
|
137 | #rc_cache.repo_object.backend = dogpile.cache.rc.file_namespace | |
|
127 | 138 | |
|
128 | 139 | ; cache auto-expires after N seconds |
|
129 | 140 | ; Examples: 86400 (1Day), 604800 (7Days), 1209600 (14Days), 2592000 (30days), 7776000 (90Days) |
|
130 | rc_cache.repo_object.expiration_time = 2592000 | |
|
141 | #rc_cache.repo_object.expiration_time = 2592000 | |
|
131 | 142 | |
|
132 | 143 | ; file cache store path. Defaults to `cache_dir =` value or tempdir if both values are not set |
|
133 | #rc_cache.repo_object.arguments.filename = /tmp/vcsserver_cache.db | |
|
144 | #rc_cache.repo_object.arguments.filename = /tmp/vcsserver_cache_repo_object.db | |
|
134 | 145 | |
|
135 | 146 | ; *********************************************************** |
|
136 | 147 | ; `repo_object` cache with redis backend |
@@ -165,55 +176,59 b' rc_cache.repo_object.expiration_time = 2' | |||
|
165 | 176 | #statsd.statsd_prefix = |
|
166 | 177 | #statsd.statsd_ipv6 = false |
|
167 | 178 | |
|
179 | ; configure logging automatically at server startup set to false | |
|
180 | ; to use the below custom logging config. | |
|
181 | #logging.autoconfigure = true | |
|
182 | ||
|
183 | ; specify your own custom logging config file to configure logging | |
|
184 | #logging.logging_conf_file = /path/to/custom_logging.ini | |
|
185 | ||
|
168 | 186 | ; ##################### |
|
169 | 187 | ; LOGGING CONFIGURATION |
|
170 | 188 | ; ##################### |
|
171 | [loggers] | |
|
172 | keys = root, vcsserver | |
|
189 | #[loggers] | |
|
190 | #keys = root, vcsserver | |
|
173 | 191 | |
|
174 | [handlers] | |
|
175 | keys = console | |
|
192 | #[handlers] | |
|
193 | #keys = console | |
|
176 | 194 | |
|
177 | [formatters] | |
|
178 | keys = generic | |
|
195 | #[formatters] | |
|
196 | #keys = generic | |
|
179 | 197 | |
|
180 | 198 | ; ####### |
|
181 | 199 | ; LOGGERS |
|
182 | 200 | ; ####### |
|
183 | [logger_root] | |
|
184 | level = NOTSET | |
|
185 | handlers = console | |
|
201 | #[logger_root] | |
|
202 | #level = NOTSET | |
|
203 | #handlers = console | |
|
186 | 204 | |
|
187 | [logger_vcsserver] | |
|
188 |
level = |
|
|
189 | handlers = | |
|
190 | qualname = vcsserver | |
|
191 | propagate = 1 | |
|
192 | ||
|
205 | #[logger_vcsserver] | |
|
206 | #level = INFO | |
|
207 | #handlers = | |
|
208 | #qualname = vcsserver | |
|
209 | #propagate = 1 | |
|
193 | 210 | |
|
194 | 211 | ; ######## |
|
195 | 212 | ; HANDLERS |
|
196 | 213 | ; ######## |
|
197 | 214 | |
|
198 | [handler_console] | |
|
199 | class = StreamHandler | |
|
200 | args = (sys.stderr, ) | |
|
201 | level = INFO | |
|
202 | formatter = generic | |
|
215 | #[handler_console] | |
|
216 | #class = StreamHandler | |
|
217 | #args = (sys.stderr, ) | |
|
218 | #level = INFO | |
|
203 | 219 | ; To enable JSON formatted logs replace generic with json |
|
204 | 220 | ; This allows sending properly formatted logs to grafana loki or elasticsearch |
|
205 | 221 | #formatter = json |
|
206 | ||
|
222 | #formatter = generic | |
|
207 | 223 | |
|
208 | 224 | ; ########## |
|
209 | 225 | ; FORMATTERS |
|
210 | 226 | ; ########## |
|
211 | 227 | |
|
212 | [formatter_generic] | |
|
213 | format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | |
|
214 | datefmt = %Y-%m-%d %H:%M:%S | |
|
228 | #[formatter_generic] | |
|
229 | #format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | |
|
230 | #datefmt = %Y-%m-%d %H:%M:%S | |
|
215 | 231 | |
|
216 | [formatter_json] | |
|
217 | format = %(timestamp)s %(levelname)s %(name)s %(message)s %(req_id)s | |
|
218 | class = vcsserver.lib._vendor.jsonlogger.JsonFormatter | |
|
219 | ||
|
232 | #[formatter_json] | |
|
233 | #format = %(timestamp)s %(levelname)s %(name)s %(message)s %(req_id)s | |
|
234 | #class = vcsserver.lib._vendor.jsonlogger.JsonFormatter |
@@ -21,21 +21,22 b' import base64' | |||
|
21 | 21 | import locale |
|
22 | 22 | import logging |
|
23 | 23 | import uuid |
|
24 | import time | |
|
24 | 25 | import wsgiref.util |
|
25 | 26 | import traceback |
|
26 | 27 | import tempfile |
|
27 | 28 | import psutil |
|
29 | ||
|
28 | 30 | from itertools import chain |
|
29 | 31 | from cStringIO import StringIO |
|
30 | 32 | |
|
31 | 33 | import simplejson as json |
|
32 | 34 | import msgpack |
|
33 | 35 | from pyramid.config import Configurator |
|
34 | from pyramid.settings import asbool, aslist | |
|
35 | 36 | from pyramid.wsgi import wsgiapp |
|
36 | 37 | from pyramid.compat import configparser |
|
37 | 38 | from pyramid.response import Response |
|
38 | ||
|
39 | from vcsserver.config.settings_maker import SettingsMaker | |
|
39 | 40 | from vcsserver.utils import safe_int |
|
40 | 41 | from vcsserver.lib.statsd_client import StatsdClient |
|
41 | 42 | |
@@ -51,6 +52,7 b' except locale.Error as e:' | |||
|
51 | 52 | 'LOCALE ERROR: failed to set LC_ALL, fallback to LC_ALL=C, org error: %s', e) |
|
52 | 53 | os.environ['LC_ALL'] = 'C' |
|
53 | 54 | |
|
55 | ||
|
54 | 56 | import vcsserver |
|
55 | 57 | from vcsserver import remote_wsgi, scm_app, settings, hgpatches |
|
56 | 58 | from vcsserver.git_lfs.app import GIT_LFS_CONTENT_TYPE, GIT_LFS_PROTO_PAT |
@@ -84,40 +86,6 b' def _is_request_chunked(environ):' | |||
|
84 | 86 | return stream |
|
85 | 87 | |
|
86 | 88 | |
|
87 | def _int_setting(settings, name, default): | |
|
88 | settings[name] = int(settings.get(name, default)) | |
|
89 | return settings[name] | |
|
90 | ||
|
91 | ||
|
92 | def _bool_setting(settings, name, default): | |
|
93 | input_val = settings.get(name, default) | |
|
94 | if isinstance(input_val, unicode): | |
|
95 | input_val = input_val.encode('utf8') | |
|
96 | settings[name] = asbool(input_val) | |
|
97 | return settings[name] | |
|
98 | ||
|
99 | ||
|
100 | def _list_setting(settings, name, default): | |
|
101 | raw_value = settings.get(name, default) | |
|
102 | ||
|
103 | # Otherwise we assume it uses pyramids space/newline separation. | |
|
104 | settings[name] = aslist(raw_value) | |
|
105 | return settings[name] | |
|
106 | ||
|
107 | ||
|
108 | def _string_setting(settings, name, default, lower=True, default_when_empty=False): | |
|
109 | value = settings.get(name, default) | |
|
110 | ||
|
111 | if default_when_empty and not value: | |
|
112 | # use default value when value is empty | |
|
113 | value = default | |
|
114 | ||
|
115 | if lower: | |
|
116 | value = value.lower() | |
|
117 | settings[name] = value | |
|
118 | return settings[name] | |
|
119 | ||
|
120 | ||
|
121 | 89 | def log_max_fd(): |
|
122 | 90 | try: |
|
123 | 91 | maxfd = psutil.Process().rlimit(psutil.RLIMIT_NOFILE)[1] |
@@ -241,7 +209,6 b' class HTTPApplication(object):' | |||
|
241 | 209 | _use_echo_app = False |
|
242 | 210 | |
|
243 | 211 | def __init__(self, settings=None, global_config=None): |
|
244 | self._sanitize_settings_and_apply_defaults(settings) | |
|
245 | 212 | |
|
246 | 213 | self.config = Configurator(settings=settings) |
|
247 | 214 | # Init our statsd at very start |
@@ -285,40 +252,6 b' class HTTPApplication(object):' | |||
|
285 | 252 | vcsserver.PYRAMID_SETTINGS = settings_merged |
|
286 | 253 | vcsserver.CONFIG = settings_merged |
|
287 | 254 | |
|
288 | def _sanitize_settings_and_apply_defaults(self, settings): | |
|
289 | temp_store = tempfile.gettempdir() | |
|
290 | default_cache_dir = os.path.join(temp_store, 'rc_cache') | |
|
291 | ||
|
292 | # save default, cache dir, and use it for all backends later. | |
|
293 | default_cache_dir = _string_setting( | |
|
294 | settings, | |
|
295 | 'cache_dir', | |
|
296 | default_cache_dir, lower=False, default_when_empty=True) | |
|
297 | ||
|
298 | # ensure we have our dir created | |
|
299 | if not os.path.isdir(default_cache_dir): | |
|
300 | os.makedirs(default_cache_dir, mode=0o755) | |
|
301 | ||
|
302 | # exception store cache | |
|
303 | _string_setting( | |
|
304 | settings, | |
|
305 | 'exception_tracker.store_path', | |
|
306 | temp_store, lower=False, default_when_empty=True) | |
|
307 | ||
|
308 | # repo_object cache | |
|
309 | _string_setting( | |
|
310 | settings, | |
|
311 | 'rc_cache.repo_object.backend', | |
|
312 | 'dogpile.cache.rc.file_namespace', lower=False) | |
|
313 | _int_setting( | |
|
314 | settings, | |
|
315 | 'rc_cache.repo_object.expiration_time', | |
|
316 | 30 * 24 * 60 * 60) | |
|
317 | _string_setting( | |
|
318 | settings, | |
|
319 | 'rc_cache.repo_object.arguments.filename', | |
|
320 | os.path.join(default_cache_dir, 'vcsserver_cache_1'), lower=False) | |
|
321 | ||
|
322 | 255 | def _configure(self): |
|
323 | 256 | self.config.add_renderer(name='msgpack', factory=self._msgpack_renderer_factory) |
|
324 | 257 | |
@@ -708,13 +641,110 b' class ResponseFilter(object):' | |||
|
708 | 641 | return self._start_response(status, headers, exc_info) |
|
709 | 642 | |
|
710 | 643 | |
|
644 | def sanitize_settings_and_apply_defaults(global_config, settings): | |
|
645 | global_settings_maker = SettingsMaker(global_config) | |
|
646 | settings_maker = SettingsMaker(settings) | |
|
647 | ||
|
648 | settings_maker.make_setting( | |
|
649 | 'logging.autoconfigure', | |
|
650 | default=True, | |
|
651 | parser='bool') | |
|
652 | ||
|
653 | logging_conf = os.path.join(os.path.dirname(global_config.get('__file__')), 'logging.ini') | |
|
654 | settings_maker.enable_logging(logging_conf) | |
|
655 | ||
|
656 | # Default includes, possible to change as a user | |
|
657 | pyramid_includes = settings_maker.make_setting('pyramid.includes', [], parser='list:newline') | |
|
658 | log.debug( | |
|
659 | "Using the following pyramid.includes: %s", | |
|
660 | pyramid_includes) | |
|
661 | ||
|
662 | settings_maker.make_setting('__file__', global_config.get('__file__')) | |
|
663 | ||
|
664 | settings_maker.make_setting( | |
|
665 | 'pyramid.default_locale_name', | |
|
666 | default='en', | |
|
667 | parser='string') | |
|
668 | settings_maker.make_setting( | |
|
669 | 'locale', | |
|
670 | default='en_US.UTF-8', | |
|
671 | parser='string') | |
|
672 | ||
|
673 | settings_maker.make_setting( | |
|
674 | 'core.binary_dir', | |
|
675 | default='', | |
|
676 | parser='string') | |
|
677 | ||
|
678 | temp_store = tempfile.gettempdir() | |
|
679 | default_cache_dir = os.path.join(temp_store, 'rc_cache') | |
|
680 | # save default, cache dir, and use it for all backends later. | |
|
681 | default_cache_dir = settings_maker.make_setting( | |
|
682 | 'cache_dir', | |
|
683 | default=default_cache_dir, default_when_empty=True, | |
|
684 | parser='dir:ensured') | |
|
685 | ||
|
686 | # exception store cache | |
|
687 | settings_maker.make_setting( | |
|
688 | 'exception_tracker.store_path', | |
|
689 | default=os.path.join(default_cache_dir, 'exc_store'), default_when_empty=True, | |
|
690 | parser='dir:ensured' | |
|
691 | ) | |
|
692 | ||
|
693 | # repo_object cache defaults | |
|
694 | settings_maker.make_setting( | |
|
695 | 'rc_cache.repo_object.backend', | |
|
696 | default='dogpile.cache.rc.file_namespace', | |
|
697 | parser='string') | |
|
698 | settings_maker.make_setting( | |
|
699 | 'rc_cache.repo_object.expiration_time', | |
|
700 | default=30 * 24 * 60 * 60, # 30days | |
|
701 | parser='int') | |
|
702 | settings_maker. make_setting( | |
|
703 | 'rc_cache.repo_object.arguments.filename', | |
|
704 | default=os.path.join(default_cache_dir, 'vcsserver_cache_repo_object.db'), | |
|
705 | parser='string') | |
|
706 | ||
|
707 | # statsd | |
|
708 | settings_maker. make_setting( | |
|
709 | 'statsd.enabled', | |
|
710 | default=False, | |
|
711 | parser='bool') | |
|
712 | settings_maker. make_setting( | |
|
713 | 'statsd.statsd_host', | |
|
714 | default='statsd-exporter', | |
|
715 | parser='string') | |
|
716 | settings_maker. make_setting( | |
|
717 | 'statsd.statsd_port', | |
|
718 | default=9125, | |
|
719 | parser='int') | |
|
720 | settings_maker. make_setting( | |
|
721 | 'statsd.statsd_prefix', | |
|
722 | default='', | |
|
723 | parser='string') | |
|
724 | settings_maker. make_setting( | |
|
725 | 'statsd.statsd_ipv6', | |
|
726 | default=False, | |
|
727 | parser='bool') | |
|
728 | ||
|
729 | ||
|
711 | 730 | def main(global_config, **settings): |
|
731 | start_time = time.time() | |
|
732 | log.info('Pyramid app config starting') | |
|
733 | ||
|
712 | 734 | if MercurialFactory: |
|
713 | 735 | hgpatches.patch_largefiles_capabilities() |
|
714 | 736 | hgpatches.patch_subrepo_type_mapping() |
|
715 | 737 | |
|
738 | # Fill in and sanitize the defaults & do ENV expansion | |
|
739 | sanitize_settings_and_apply_defaults(global_config, settings) | |
|
740 | ||
|
716 | 741 | # init and bootstrap StatsdClient |
|
717 | 742 | StatsdClient.setup(settings) |
|
718 | 743 | |
|
719 | app = HTTPApplication(settings=settings, global_config=global_config) | |
|
720 | return app.wsgi_app() | |
|
744 | pyramid_app = HTTPApplication(settings=settings, global_config=global_config).wsgi_app() | |
|
745 | total_time = time.time() - start_time | |
|
746 | log.info('Pyramid app `%s` created and configured in %.2fs', | |
|
747 | getattr(pyramid_app, 'func_name', 'pyramid_app'), total_time) | |
|
748 | return pyramid_app | |
|
749 | ||
|
750 |
General Comments 0
You need to be logged in to leave comments.
Login now