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 |
|
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 | ; GUNICORN APPLICATION SERVER |
|
31 | ; GUNICORN APPLICATION SERVER | |
32 | ; ########################### |
|
32 | ; ########################### | |
33 |
|
33 | |||
34 |
; run with gunicorn -- |
|
34 | ; run with gunicorn --paste rhodecode.ini | |
35 |
|
35 | |||
36 | ; Module to use, this setting shouldn't be changed |
|
36 | ; Module to use, this setting shouldn't be changed | |
37 | #use = egg:gunicorn#main |
|
37 | #use = egg:gunicorn#main | |
@@ -86,7 +86,7 b' asyncore_use_poll = true' | |||||
86 | ; serving requests. Workers still alive after the timeout (starting from the |
|
86 | ; serving requests. Workers still alive after the timeout (starting from the | |
87 | ; receipt of the restart signal) are force killed. |
|
87 | ; receipt of the restart signal) are force killed. | |
88 | ; Examples: 1800 (30min), 3600 (1hr), 7200 (2hr), 43200 (12h) |
|
88 | ; Examples: 1800 (30min), 3600 (1hr), 7200 (2hr), 43200 (12h) | |
89 |
#graceful_timeout = |
|
89 | #graceful_timeout = 21600 | |
90 |
|
90 | |||
91 | # The number of seconds to wait for requests on a Keep-Alive connection. |
|
91 | # The number of seconds to wait for requests on a Keep-Alive connection. | |
92 | # Generally set in the 1-5 seconds range. |
|
92 | # Generally set in the 1-5 seconds range. | |
@@ -110,6 +110,17 b' asyncore_use_poll = true' | |||||
110 | [app:main] |
|
110 | [app:main] | |
111 | ; The %(here)s variable will be replaced with the absolute path of parent directory |
|
111 | ; The %(here)s variable will be replaced with the absolute path of parent directory | |
112 | ; of this file |
|
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 | use = egg:rhodecode-vcsserver |
|
124 | use = egg:rhodecode-vcsserver | |
114 |
|
125 | |||
115 |
|
126 | |||
@@ -133,13 +144,13 b' debugtoolbar.exclude_prefixes =' | |||||
133 | ; ################# |
|
144 | ; ################# | |
134 |
|
145 | |||
135 | ; Pyramid default locales, we need this to be set |
|
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 | ; default locale used by VCS systems |
|
149 | ; default locale used by VCS systems | |
139 | locale = en_US.UTF-8 |
|
150 | #locale = en_US.UTF-8 | |
140 |
|
151 | |||
141 | ; path to binaries for vcsserver, it should be set by the installer |
|
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 | ; it can also be a path to nix-build output in case of development |
|
154 | ; it can also be a path to nix-build output in case of development | |
144 | core.binary_dir = "" |
|
155 | core.binary_dir = "" | |
145 |
|
156 | |||
@@ -153,21 +164,21 b' core.binary_dir = ""' | |||||
153 |
|
164 | |||
154 | ; Default cache dir for caches. Putting this into a ramdisk can boost performance. |
|
165 | ; Default cache dir for caches. Putting this into a ramdisk can boost performance. | |
155 | ; eg. /tmpfs/data_ramdisk, however this directory might require large amount of space |
|
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 | ; `repo_object` cache, default file based |
|
170 | ; `repo_object` cache, default file based | |
160 | ; *************************************** |
|
171 | ; *************************************** | |
161 |
|
172 | |||
162 | ; `repo_object` cache settings for vcs methods for repositories |
|
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 | ; cache auto-expires after N seconds |
|
176 | ; cache auto-expires after N seconds | |
166 | ; Examples: 86400 (1Day), 604800 (7Days), 1209600 (14Days), 2592000 (30days), 7776000 (90Days) |
|
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 | ; file cache store path. Defaults to `cache_dir =` value or tempdir if both values are not set |
|
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 | ; `repo_object` cache with redis backend |
|
184 | ; `repo_object` cache with redis backend | |
@@ -202,55 +213,59 b' rc_cache.repo_object.expiration_time = 2' | |||||
202 | #statsd.statsd_prefix = |
|
213 | #statsd.statsd_prefix = | |
203 | #statsd.statsd_ipv6 = false |
|
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 | ; LOGGING CONFIGURATION |
|
224 | ; LOGGING CONFIGURATION | |
207 | ; ##################### |
|
225 | ; ##################### | |
208 | [loggers] |
|
226 | #[loggers] | |
209 | keys = root, vcsserver |
|
227 | #keys = root, vcsserver | |
210 |
|
228 | |||
211 | [handlers] |
|
229 | #[handlers] | |
212 | keys = console |
|
230 | #keys = console | |
213 |
|
231 | |||
214 | [formatters] |
|
232 | #[formatters] | |
215 | keys = generic |
|
233 | #keys = generic | |
216 |
|
234 | |||
217 | ; ####### |
|
235 | ; ####### | |
218 | ; LOGGERS |
|
236 | ; LOGGERS | |
219 | ; ####### |
|
237 | ; ####### | |
220 | [logger_root] |
|
238 | #[logger_root] | |
221 | level = NOTSET |
|
239 | #level = NOTSET | |
222 | handlers = console |
|
240 | #handlers = console | |
223 |
|
241 | |||
224 | [logger_vcsserver] |
|
242 | #[logger_vcsserver] | |
225 |
level = |
|
243 | #level = INFO | |
226 | handlers = |
|
244 | #handlers = | |
227 | qualname = vcsserver |
|
245 | #qualname = vcsserver | |
228 | propagate = 1 |
|
246 | #propagate = 1 | |
229 |
|
||||
230 |
|
247 | |||
231 | ; ######## |
|
248 | ; ######## | |
232 | ; HANDLERS |
|
249 | ; HANDLERS | |
233 | ; ######## |
|
250 | ; ######## | |
234 |
|
251 | |||
235 | [handler_console] |
|
252 | #[handler_console] | |
236 | class = StreamHandler |
|
253 | #class = StreamHandler | |
237 | args = (sys.stderr, ) |
|
254 | #args = (sys.stderr, ) | |
238 |
level = |
|
255 | #level = INFO | |
239 | formatter = generic |
|
|||
240 | ; To enable JSON formatted logs replace generic with json |
|
256 | ; To enable JSON formatted logs replace generic with json | |
241 | ; This allows sending properly formatted logs to grafana loki or elasticsearch |
|
257 | ; This allows sending properly formatted logs to grafana loki or elasticsearch | |
242 | #formatter = json |
|
258 | #formatter = json | |
243 |
|
259 | #formatter = generic | ||
244 |
|
260 | |||
245 | ; ########## |
|
261 | ; ########## | |
246 | ; FORMATTERS |
|
262 | ; FORMATTERS | |
247 | ; ########## |
|
263 | ; ########## | |
248 |
|
264 | |||
249 | [formatter_generic] |
|
265 | #[formatter_generic] | |
250 | format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s |
|
266 | #format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | |
251 | datefmt = %Y-%m-%d %H:%M:%S |
|
267 | #datefmt = %Y-%m-%d %H:%M:%S | |
252 |
|
268 | |||
253 | [formatter_json] |
|
269 | #[formatter_json] | |
254 | format = %(timestamp)s %(levelname)s %(name)s %(message)s %(req_id)s |
|
270 | #format = %(timestamp)s %(levelname)s %(name)s %(message)s %(req_id)s | |
255 | class = vcsserver.lib._vendor.jsonlogger.JsonFormatter |
|
271 | #class = vcsserver.lib._vendor.jsonlogger.JsonFormatter | |
256 |
|
@@ -30,12 +30,12 b' worker_tmp_dir = None' | |||||
30 | tmp_upload_dir = None |
|
30 | tmp_upload_dir = None | |
31 |
|
31 | |||
32 | # Custom log format |
|
32 | # Custom log format | |
33 | access_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"') |
|
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 | # loki format for easier parsing in grafana |
|
36 | # loki format for easier parsing in grafana | |
37 |
|
|
37 | access_log_format = ( | |
38 |
|
|
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 | # self adjust workers based on CPU count |
|
40 | # self adjust workers based on CPU count | |
41 | # workers = get_workers() |
|
41 | # workers = get_workers() | |
@@ -97,9 +97,12 b' def post_fork(server, worker):' | |||||
97 | if conf.has_option(section, 'memory_usage_recovery_threshold'): |
|
97 | if conf.has_option(section, 'memory_usage_recovery_threshold'): | |
98 | _memory_usage_recovery_threshold = conf.getfloat(section, 'memory_usage_recovery_threshold') |
|
98 | _memory_usage_recovery_threshold = conf.getfloat(section, 'memory_usage_recovery_threshold') | |
99 |
|
99 | |||
100 | worker._memory_max_usage = _memory_max_usage |
|
100 | worker._memory_max_usage = int(os.environ.get('RC_GUNICORN_MEMORY_MAX_USAGE', '') | |
101 | worker._memory_usage_check_interval = _memory_usage_check_interval |
|
101 | or _memory_max_usage) | |
102 | worker._memory_usage_recovery_threshold = _memory_usage_recovery_threshold |
|
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 | # register memory last check time, with some random offset so we don't recycle all |
|
107 | # register memory last check time, with some random offset so we don't recycle all | |
105 | # at once |
|
108 | # at once |
@@ -14,7 +14,7 b' port = 9900' | |||||
14 | ; GUNICORN APPLICATION SERVER |
|
14 | ; GUNICORN APPLICATION SERVER | |
15 | ; ########################### |
|
15 | ; ########################### | |
16 |
|
16 | |||
17 |
; run with gunicorn -- |
|
17 | ; run with gunicorn --paste rhodecode.ini | |
18 |
|
18 | |||
19 | ; Module to use, this setting shouldn't be changed |
|
19 | ; Module to use, this setting shouldn't be changed | |
20 | use = egg:gunicorn#main |
|
20 | use = egg:gunicorn#main | |
@@ -69,7 +69,7 b' limit_request_field_size = 0' | |||||
69 | ; serving requests. Workers still alive after the timeout (starting from the |
|
69 | ; serving requests. Workers still alive after the timeout (starting from the | |
70 | ; receipt of the restart signal) are force killed. |
|
70 | ; receipt of the restart signal) are force killed. | |
71 | ; Examples: 1800 (30min), 3600 (1hr), 7200 (2hr), 43200 (12h) |
|
71 | ; Examples: 1800 (30min), 3600 (1hr), 7200 (2hr), 43200 (12h) | |
72 |
graceful_timeout = |
|
72 | graceful_timeout = 21600 | |
73 |
|
73 | |||
74 | # The number of seconds to wait for requests on a Keep-Alive connection. |
|
74 | # The number of seconds to wait for requests on a Keep-Alive connection. | |
75 | # Generally set in the 1-5 seconds range. |
|
75 | # Generally set in the 1-5 seconds range. | |
@@ -93,16 +93,27 b' memory_usage_recovery_threshold = 0.8' | |||||
93 | [app:main] |
|
93 | [app:main] | |
94 | ; The %(here)s variable will be replaced with the absolute path of parent directory |
|
94 | ; The %(here)s variable will be replaced with the absolute path of parent directory | |
95 | ; of this file |
|
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 | use = egg:rhodecode-vcsserver |
|
107 | use = egg:rhodecode-vcsserver | |
97 |
|
108 | |||
98 | ; Pyramid default locales, we need this to be set |
|
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 | ; default locale used by VCS systems |
|
112 | ; default locale used by VCS systems | |
102 | locale = en_US.UTF-8 |
|
113 | #locale = en_US.UTF-8 | |
103 |
|
114 | |||
104 | ; path to binaries for vcsserver, it should be set by the installer |
|
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 | ; it can also be a path to nix-build output in case of development |
|
117 | ; it can also be a path to nix-build output in case of development | |
107 | core.binary_dir = "" |
|
118 | core.binary_dir = "" | |
108 |
|
119 | |||
@@ -116,21 +127,21 b' core.binary_dir = ""' | |||||
116 |
|
127 | |||
117 | ; Default cache dir for caches. Putting this into a ramdisk can boost performance. |
|
128 | ; Default cache dir for caches. Putting this into a ramdisk can boost performance. | |
118 | ; eg. /tmpfs/data_ramdisk, however this directory might require large amount of space |
|
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 | ; `repo_object` cache, default file based |
|
133 | ; `repo_object` cache, default file based | |
123 | ; *************************************** |
|
134 | ; *************************************** | |
124 |
|
135 | |||
125 | ; `repo_object` cache settings for vcs methods for repositories |
|
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 | ; cache auto-expires after N seconds |
|
139 | ; cache auto-expires after N seconds | |
129 | ; Examples: 86400 (1Day), 604800 (7Days), 1209600 (14Days), 2592000 (30days), 7776000 (90Days) |
|
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 | ; file cache store path. Defaults to `cache_dir =` value or tempdir if both values are not set |
|
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 | ; `repo_object` cache with redis backend |
|
147 | ; `repo_object` cache with redis backend | |
@@ -165,55 +176,59 b' rc_cache.repo_object.expiration_time = 2' | |||||
165 | #statsd.statsd_prefix = |
|
176 | #statsd.statsd_prefix = | |
166 | #statsd.statsd_ipv6 = false |
|
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 | ; LOGGING CONFIGURATION |
|
187 | ; LOGGING CONFIGURATION | |
170 | ; ##################### |
|
188 | ; ##################### | |
171 | [loggers] |
|
189 | #[loggers] | |
172 | keys = root, vcsserver |
|
190 | #keys = root, vcsserver | |
173 |
|
191 | |||
174 | [handlers] |
|
192 | #[handlers] | |
175 | keys = console |
|
193 | #keys = console | |
176 |
|
194 | |||
177 | [formatters] |
|
195 | #[formatters] | |
178 | keys = generic |
|
196 | #keys = generic | |
179 |
|
197 | |||
180 | ; ####### |
|
198 | ; ####### | |
181 | ; LOGGERS |
|
199 | ; LOGGERS | |
182 | ; ####### |
|
200 | ; ####### | |
183 | [logger_root] |
|
201 | #[logger_root] | |
184 | level = NOTSET |
|
202 | #level = NOTSET | |
185 | handlers = console |
|
203 | #handlers = console | |
186 |
|
204 | |||
187 | [logger_vcsserver] |
|
205 | #[logger_vcsserver] | |
188 |
level = |
|
206 | #level = INFO | |
189 | handlers = |
|
207 | #handlers = | |
190 | qualname = vcsserver |
|
208 | #qualname = vcsserver | |
191 | propagate = 1 |
|
209 | #propagate = 1 | |
192 |
|
||||
193 |
|
210 | |||
194 | ; ######## |
|
211 | ; ######## | |
195 | ; HANDLERS |
|
212 | ; HANDLERS | |
196 | ; ######## |
|
213 | ; ######## | |
197 |
|
214 | |||
198 | [handler_console] |
|
215 | #[handler_console] | |
199 | class = StreamHandler |
|
216 | #class = StreamHandler | |
200 | args = (sys.stderr, ) |
|
217 | #args = (sys.stderr, ) | |
201 | level = INFO |
|
218 | #level = INFO | |
202 | formatter = generic |
|
|||
203 | ; To enable JSON formatted logs replace generic with json |
|
219 | ; To enable JSON formatted logs replace generic with json | |
204 | ; This allows sending properly formatted logs to grafana loki or elasticsearch |
|
220 | ; This allows sending properly formatted logs to grafana loki or elasticsearch | |
205 | #formatter = json |
|
221 | #formatter = json | |
206 |
|
222 | #formatter = generic | ||
207 |
|
223 | |||
208 | ; ########## |
|
224 | ; ########## | |
209 | ; FORMATTERS |
|
225 | ; FORMATTERS | |
210 | ; ########## |
|
226 | ; ########## | |
211 |
|
227 | |||
212 | [formatter_generic] |
|
228 | #[formatter_generic] | |
213 | format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s |
|
229 | #format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | |
214 | datefmt = %Y-%m-%d %H:%M:%S |
|
230 | #datefmt = %Y-%m-%d %H:%M:%S | |
215 |
|
231 | |||
216 | [formatter_json] |
|
232 | #[formatter_json] | |
217 | format = %(timestamp)s %(levelname)s %(name)s %(message)s %(req_id)s |
|
233 | #format = %(timestamp)s %(levelname)s %(name)s %(message)s %(req_id)s | |
218 | class = vcsserver.lib._vendor.jsonlogger.JsonFormatter |
|
234 | #class = vcsserver.lib._vendor.jsonlogger.JsonFormatter | |
219 |
|
@@ -21,21 +21,22 b' import base64' | |||||
21 | import locale |
|
21 | import locale | |
22 | import logging |
|
22 | import logging | |
23 | import uuid |
|
23 | import uuid | |
|
24 | import time | |||
24 | import wsgiref.util |
|
25 | import wsgiref.util | |
25 | import traceback |
|
26 | import traceback | |
26 | import tempfile |
|
27 | import tempfile | |
27 | import psutil |
|
28 | import psutil | |
|
29 | ||||
28 | from itertools import chain |
|
30 | from itertools import chain | |
29 | from cStringIO import StringIO |
|
31 | from cStringIO import StringIO | |
30 |
|
32 | |||
31 | import simplejson as json |
|
33 | import simplejson as json | |
32 | import msgpack |
|
34 | import msgpack | |
33 | from pyramid.config import Configurator |
|
35 | from pyramid.config import Configurator | |
34 | from pyramid.settings import asbool, aslist |
|
|||
35 | from pyramid.wsgi import wsgiapp |
|
36 | from pyramid.wsgi import wsgiapp | |
36 | from pyramid.compat import configparser |
|
37 | from pyramid.compat import configparser | |
37 | from pyramid.response import Response |
|
38 | from pyramid.response import Response | |
38 |
|
39 | from vcsserver.config.settings_maker import SettingsMaker | ||
39 | from vcsserver.utils import safe_int |
|
40 | from vcsserver.utils import safe_int | |
40 | from vcsserver.lib.statsd_client import StatsdClient |
|
41 | from vcsserver.lib.statsd_client import StatsdClient | |
41 |
|
42 | |||
@@ -51,6 +52,7 b' except locale.Error as e:' | |||||
51 | 'LOCALE ERROR: failed to set LC_ALL, fallback to LC_ALL=C, org error: %s', e) |
|
52 | 'LOCALE ERROR: failed to set LC_ALL, fallback to LC_ALL=C, org error: %s', e) | |
52 | os.environ['LC_ALL'] = 'C' |
|
53 | os.environ['LC_ALL'] = 'C' | |
53 |
|
54 | |||
|
55 | ||||
54 | import vcsserver |
|
56 | import vcsserver | |
55 | from vcsserver import remote_wsgi, scm_app, settings, hgpatches |
|
57 | from vcsserver import remote_wsgi, scm_app, settings, hgpatches | |
56 | from vcsserver.git_lfs.app import GIT_LFS_CONTENT_TYPE, GIT_LFS_PROTO_PAT |
|
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 | return stream |
|
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 | def log_max_fd(): |
|
89 | def log_max_fd(): | |
122 | try: |
|
90 | try: | |
123 | maxfd = psutil.Process().rlimit(psutil.RLIMIT_NOFILE)[1] |
|
91 | maxfd = psutil.Process().rlimit(psutil.RLIMIT_NOFILE)[1] | |
@@ -241,7 +209,6 b' class HTTPApplication(object):' | |||||
241 | _use_echo_app = False |
|
209 | _use_echo_app = False | |
242 |
|
210 | |||
243 | def __init__(self, settings=None, global_config=None): |
|
211 | def __init__(self, settings=None, global_config=None): | |
244 | self._sanitize_settings_and_apply_defaults(settings) |
|
|||
245 |
|
212 | |||
246 | self.config = Configurator(settings=settings) |
|
213 | self.config = Configurator(settings=settings) | |
247 | # Init our statsd at very start |
|
214 | # Init our statsd at very start | |
@@ -285,40 +252,6 b' class HTTPApplication(object):' | |||||
285 | vcsserver.PYRAMID_SETTINGS = settings_merged |
|
252 | vcsserver.PYRAMID_SETTINGS = settings_merged | |
286 | vcsserver.CONFIG = settings_merged |
|
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 | def _configure(self): |
|
255 | def _configure(self): | |
323 | self.config.add_renderer(name='msgpack', factory=self._msgpack_renderer_factory) |
|
256 | self.config.add_renderer(name='msgpack', factory=self._msgpack_renderer_factory) | |
324 |
|
257 | |||
@@ -708,13 +641,110 b' class ResponseFilter(object):' | |||||
708 | return self._start_response(status, headers, exc_info) |
|
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 | def main(global_config, **settings): |
|
730 | def main(global_config, **settings): | |
|
731 | start_time = time.time() | |||
|
732 | log.info('Pyramid app config starting') | |||
|
733 | ||||
712 | if MercurialFactory: |
|
734 | if MercurialFactory: | |
713 | hgpatches.patch_largefiles_capabilities() |
|
735 | hgpatches.patch_largefiles_capabilities() | |
714 | hgpatches.patch_subrepo_type_mapping() |
|
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 | # init and bootstrap StatsdClient |
|
741 | # init and bootstrap StatsdClient | |
717 | StatsdClient.setup(settings) |
|
742 | StatsdClient.setup(settings) | |
718 |
|
743 | |||
719 | app = HTTPApplication(settings=settings, global_config=global_config) |
|
744 | pyramid_app = HTTPApplication(settings=settings, global_config=global_config).wsgi_app() | |
720 | return app.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