##// END OF EJS Templates
logging: skip certain very large args/kwargs reporting in logs of called methods
super-admin -
r1073:176bb96a python3
parent child Browse files
Show More
@@ -1,741 +1,751 b''
1 1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 2 # Copyright (C) 2014-2020 RhodeCode GmbH
3 3 #
4 4 # This program is free software; you can redistribute it and/or modify
5 5 # it under the terms of the GNU General Public License as published by
6 6 # the Free Software Foundation; either version 3 of the License, or
7 7 # (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software Foundation,
16 16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 17
18 18 import io
19 19 import os
20 20 import sys
21 21 import base64
22 22 import locale
23 23 import logging
24 24 import uuid
25 25 import time
26 26 import wsgiref.util
27 27 import traceback
28 28 import tempfile
29 29 import psutil
30 30
31 31 from itertools import chain
32 32
33 33 import msgpack
34 34 import configparser
35 35
36 36 from pyramid.config import Configurator
37 37 from pyramid.wsgi import wsgiapp
38 38 from pyramid.response import Response
39 39
40 40 from vcsserver.lib.rc_json import json
41 41 from vcsserver.config.settings_maker import SettingsMaker
42 42 from vcsserver.str_utils import safe_int, safe_bytes, safe_str
43 43 from vcsserver.lib.statsd_client import StatsdClient
44 44
45 45 log = logging.getLogger(__name__)
46 46
47 47 # due to Mercurial/glibc2.27 problems we need to detect if locale settings are
48 48 # causing problems and "fix" it in case they do and fallback to LC_ALL = C
49 49
50 50 try:
51 51 locale.setlocale(locale.LC_ALL, '')
52 52 except locale.Error as e:
53 53 log.error(
54 54 'LOCALE ERROR: failed to set LC_ALL, fallback to LC_ALL=C, org error: %s', e)
55 55 os.environ['LC_ALL'] = 'C'
56 56
57 57
58 58 import vcsserver
59 59 from vcsserver import remote_wsgi, scm_app, settings, hgpatches
60 60 from vcsserver.git_lfs.app import GIT_LFS_CONTENT_TYPE, GIT_LFS_PROTO_PAT
61 61 from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub
62 62 from vcsserver.echo_stub.echo_app import EchoApp
63 63 from vcsserver.exceptions import HTTPRepoLocked, HTTPRepoBranchProtected
64 64 from vcsserver.lib.exc_tracking import store_exception
65 65 from vcsserver.server import VcsServer
66 66
67 67 strict_vcs = True
68 68
69 69 git_import_err = None
70 70 try:
71 71 from vcsserver.remote.git import GitFactory, GitRemote
72 72 except ImportError as e:
73 73 GitFactory = None
74 74 GitRemote = None
75 75 git_import_err = e
76 76 if strict_vcs:
77 77 raise
78 78
79 79
80 80 hg_import_err = None
81 81 try:
82 82 from vcsserver.remote.hg import MercurialFactory, HgRemote
83 83 except ImportError as e:
84 84 MercurialFactory = None
85 85 HgRemote = None
86 86 hg_import_err = e
87 87 if strict_vcs:
88 88 raise
89 89
90 90
91 91 svn_import_err = None
92 92 try:
93 93 from vcsserver.remote.svn import SubversionFactory, SvnRemote
94 94 except ImportError as e:
95 95 SubversionFactory = None
96 96 SvnRemote = None
97 97 svn_import_err = e
98 98 if strict_vcs:
99 99 raise
100 100
101 101
102 102 def _is_request_chunked(environ):
103 103 stream = environ.get('HTTP_TRANSFER_ENCODING', '') == 'chunked'
104 104 return stream
105 105
106 106
107 107 def log_max_fd():
108 108 try:
109 109 maxfd = psutil.Process().rlimit(psutil.RLIMIT_NOFILE)[1]
110 110 log.info('Max file descriptors value: %s', maxfd)
111 111 except Exception:
112 112 pass
113 113
114 114
115 115 class VCS(object):
116 116 def __init__(self, locale_conf=None, cache_config=None):
117 117 self.locale = locale_conf
118 118 self.cache_config = cache_config
119 119 self._configure_locale()
120 120
121 121 log_max_fd()
122 122
123 123 if GitFactory and GitRemote:
124 124 git_factory = GitFactory()
125 125 self._git_remote = GitRemote(git_factory)
126 126 else:
127 127 log.error("Git client import failed: %s", git_import_err)
128 128
129 129 if MercurialFactory and HgRemote:
130 130 hg_factory = MercurialFactory()
131 131 self._hg_remote = HgRemote(hg_factory)
132 132 else:
133 133 log.error("Mercurial client import failed: %s", hg_import_err)
134 134
135 135 if SubversionFactory and SvnRemote:
136 136 svn_factory = SubversionFactory()
137 137
138 138 # hg factory is used for svn url validation
139 139 hg_factory = MercurialFactory()
140 140 self._svn_remote = SvnRemote(svn_factory, hg_factory=hg_factory)
141 141 else:
142 142 log.error("Subversion client import failed: %s", svn_import_err)
143 143
144 144 self._vcsserver = VcsServer()
145 145
146 146 def _configure_locale(self):
147 147 if self.locale:
148 148 log.info('Settings locale: `LC_ALL` to %s', self.locale)
149 149 else:
150 150 log.info('Configuring locale subsystem based on environment variables')
151 151 try:
152 152 # If self.locale is the empty string, then the locale
153 153 # module will use the environment variables. See the
154 154 # documentation of the package `locale`.
155 155 locale.setlocale(locale.LC_ALL, self.locale)
156 156
157 157 language_code, encoding = locale.getlocale()
158 158 log.info(
159 159 'Locale set to language code "%s" with encoding "%s".',
160 160 language_code, encoding)
161 161 except locale.Error:
162 162 log.exception('Cannot set locale, not configuring the locale system')
163 163
164 164
165 165 class WsgiProxy(object):
166 166 def __init__(self, wsgi):
167 167 self.wsgi = wsgi
168 168
169 169 def __call__(self, environ, start_response):
170 170 input_data = environ['wsgi.input'].read()
171 171 input_data = msgpack.unpackb(input_data)
172 172
173 173 error = None
174 174 try:
175 175 data, status, headers = self.wsgi.handle(
176 176 input_data['environment'], input_data['input_data'],
177 177 *input_data['args'], **input_data['kwargs'])
178 178 except Exception as e:
179 179 data, status, headers = [], None, None
180 180 error = {
181 181 'message': str(e),
182 182 '_vcs_kind': getattr(e, '_vcs_kind', None)
183 183 }
184 184
185 185 start_response(200, {})
186 186 return self._iterator(error, status, headers, data)
187 187
188 188 def _iterator(self, error, status, headers, data):
189 189 initial_data = [
190 190 error,
191 191 status,
192 192 headers,
193 193 ]
194 194
195 195 for d in chain(initial_data, data):
196 196 yield msgpack.packb(d)
197 197
198 198
199 199 def not_found(request):
200 200 return {'status': '404 NOT FOUND'}
201 201
202 202
203 203 class VCSViewPredicate(object):
204 204 def __init__(self, val, config):
205 205 self.remotes = val
206 206
207 207 def text(self):
208 208 return 'vcs view method = %s' % (list(self.remotes.keys()),)
209 209
210 210 phash = text
211 211
212 212 def __call__(self, context, request):
213 213 """
214 214 View predicate that returns true if given backend is supported by
215 215 defined remotes.
216 216 """
217 217 backend = request.matchdict.get('backend')
218 218 return backend in self.remotes
219 219
220 220
221 221 class HTTPApplication(object):
222 222 ALLOWED_EXCEPTIONS = ('KeyError', 'URLError')
223 223
224 224 remote_wsgi = remote_wsgi
225 225 _use_echo_app = False
226 226
227 227 def __init__(self, settings=None, global_config=None):
228 228
229 229 self.config = Configurator(settings=settings)
230 230 # Init our statsd at very start
231 231 self.config.registry.statsd = StatsdClient.statsd
232 232
233 233 self.global_config = global_config
234 234 self.config.include('vcsserver.lib.rc_cache')
235 235
236 236 settings_locale = settings.get('locale', '') or 'en_US.UTF-8'
237 237 vcs = VCS(locale_conf=settings_locale, cache_config=settings)
238 238 self._remotes = {
239 239 'hg': vcs._hg_remote,
240 240 'git': vcs._git_remote,
241 241 'svn': vcs._svn_remote,
242 242 'server': vcs._vcsserver,
243 243 }
244 244 if settings.get('dev.use_echo_app', 'false').lower() == 'true':
245 245 self._use_echo_app = True
246 246 log.warning("Using EchoApp for VCS operations.")
247 247 self.remote_wsgi = remote_wsgi_stub
248 248
249 249 self._configure_settings(global_config, settings)
250 250
251 251 self._configure()
252 252
253 253 def _configure_settings(self, global_config, app_settings):
254 254 """
255 255 Configure the settings module.
256 256 """
257 257 settings_merged = global_config.copy()
258 258 settings_merged.update(app_settings)
259 259
260 260 git_path = app_settings.get('git_path', None)
261 261 if git_path:
262 262 settings.GIT_EXECUTABLE = git_path
263 263 binary_dir = app_settings.get('core.binary_dir', None)
264 264 if binary_dir:
265 265 settings.BINARY_DIR = binary_dir
266 266
267 267 # Store the settings to make them available to other modules.
268 268 vcsserver.PYRAMID_SETTINGS = settings_merged
269 269 vcsserver.CONFIG = settings_merged
270 270
271 271 def _configure(self):
272 272 self.config.add_renderer(name='msgpack', factory=self._msgpack_renderer_factory)
273 273
274 274 self.config.add_route('service', '/_service')
275 275 self.config.add_route('status', '/status')
276 276 self.config.add_route('hg_proxy', '/proxy/hg')
277 277 self.config.add_route('git_proxy', '/proxy/git')
278 278
279 279 # rpc methods
280 280 self.config.add_route('vcs', '/{backend}')
281 281
282 282 # streaming rpc remote methods
283 283 self.config.add_route('vcs_stream', '/{backend}/stream')
284 284
285 285 # vcs operations clone/push as streaming
286 286 self.config.add_route('stream_git', '/stream/git/*repo_name')
287 287 self.config.add_route('stream_hg', '/stream/hg/*repo_name')
288 288
289 289 self.config.add_view(self.status_view, route_name='status', renderer='json')
290 290 self.config.add_view(self.service_view, route_name='service', renderer='msgpack')
291 291
292 292 self.config.add_view(self.hg_proxy(), route_name='hg_proxy')
293 293 self.config.add_view(self.git_proxy(), route_name='git_proxy')
294 294 self.config.add_view(self.vcs_view, route_name='vcs', renderer='msgpack',
295 295 vcs_view=self._remotes)
296 296 self.config.add_view(self.vcs_stream_view, route_name='vcs_stream',
297 297 vcs_view=self._remotes)
298 298
299 299 self.config.add_view(self.hg_stream(), route_name='stream_hg')
300 300 self.config.add_view(self.git_stream(), route_name='stream_git')
301 301
302 302 self.config.add_view_predicate('vcs_view', VCSViewPredicate)
303 303
304 304 self.config.add_notfound_view(not_found, renderer='json')
305 305
306 306 self.config.add_view(self.handle_vcs_exception, context=Exception)
307 307
308 308 self.config.add_tween(
309 309 'vcsserver.tweens.request_wrapper.RequestWrapperTween',
310 310 )
311 311 self.config.add_request_method(
312 312 'vcsserver.lib.request_counter.get_request_counter',
313 313 'request_count')
314 314
315 315 def wsgi_app(self):
316 316 return self.config.make_wsgi_app()
317 317
318 318 def _vcs_view_params(self, request):
319 319 remote = self._remotes[request.matchdict['backend']]
320 320 payload = msgpack.unpackb(request.body, use_list=True)
321 321
322 322 method = payload.get('method')
323 323 params = payload['params']
324 324 wire = params.get('wire')
325 325 args = params.get('args')
326 326 kwargs = params.get('kwargs')
327 327 context_uid = None
328 328
329 329 if wire:
330 330 try:
331 331 wire['context'] = context_uid = uuid.UUID(wire['context'])
332 332 except KeyError:
333 333 pass
334 334 args.insert(0, wire)
335 335 repo_state_uid = wire.get('repo_state_uid') if wire else None
336 336
337 337 # NOTE(marcink): trading complexity for slight performance
338 338 if log.isEnabledFor(logging.DEBUG):
339 no_args_methods = [
340
341 ]
342 if method in no_args_methods:
339 # also we SKIP printing out any of those methods args since they maybe excessive
340 just_args_methods = {
341 'commitctx': ('content', 'removed', 'updated')
342 }
343 if method in just_args_methods:
344 skip_args = just_args_methods[method]
343 345 call_args = ''
346 call_kwargs = {}
347 for k in kwargs:
348 if k in skip_args:
349 # replace our skip key with dummy
350 call_kwargs[k] = f'RemovedParam({k})'
351 else:
352 call_kwargs[k] = kwargs[k]
344 353 else:
345 354 call_args = args[1:]
355 call_kwargs = kwargs
346 356
347 357 log.debug('Method requested:`%s` with args:%s kwargs:%s context_uid: %s, repo_state_uid:%s',
348 method, call_args, kwargs, context_uid, repo_state_uid)
358 method, call_args, call_kwargs, context_uid, repo_state_uid)
349 359
350 360 statsd = request.registry.statsd
351 361 if statsd:
352 362 statsd.incr(
353 363 'vcsserver_method_total', tags=[
354 364 "method:{}".format(method),
355 365 ])
356 366 return payload, remote, method, args, kwargs
357 367
358 368 def vcs_view(self, request):
359 369
360 370 payload, remote, method, args, kwargs = self._vcs_view_params(request)
361 371 payload_id = payload.get('id')
362 372
363 373 try:
364 374 resp = getattr(remote, method)(*args, **kwargs)
365 375 except Exception as e:
366 376 exc_info = list(sys.exc_info())
367 377 exc_type, exc_value, exc_traceback = exc_info
368 378
369 379 org_exc = getattr(e, '_org_exc', None)
370 380 org_exc_name = None
371 381 org_exc_tb = ''
372 382 if org_exc:
373 383 org_exc_name = org_exc.__class__.__name__
374 384 org_exc_tb = getattr(e, '_org_exc_tb', '')
375 385 # replace our "faked" exception with our org
376 386 exc_info[0] = org_exc.__class__
377 387 exc_info[1] = org_exc
378 388
379 389 should_store_exc = True
380 390 if org_exc:
381 391 def get_exc_fqn(_exc_obj):
382 392 module_name = getattr(org_exc.__class__, '__module__', 'UNKNOWN')
383 393 return module_name + '.' + org_exc_name
384 394
385 395 exc_fqn = get_exc_fqn(org_exc)
386 396
387 397 if exc_fqn in ['mercurial.error.RepoLookupError',
388 398 'vcsserver.exceptions.RefNotFoundException']:
389 399 should_store_exc = False
390 400
391 401 if should_store_exc:
392 402 store_exception(id(exc_info), exc_info, request_path=request.path)
393 403
394 404 tb_info = ''.join(
395 405 traceback.format_exception(exc_type, exc_value, exc_traceback))
396 406
397 407 type_ = e.__class__.__name__
398 408 if type_ not in self.ALLOWED_EXCEPTIONS:
399 409 type_ = None
400 410
401 411 resp = {
402 412 'id': payload_id,
403 413 'error': {
404 414 'message': str(e),
405 415 'traceback': tb_info,
406 416 'org_exc': org_exc_name,
407 417 'org_exc_tb': org_exc_tb,
408 418 'type': type_
409 419 }
410 420 }
411 421
412 422 try:
413 423 resp['error']['_vcs_kind'] = getattr(e, '_vcs_kind', None)
414 424 except AttributeError:
415 425 pass
416 426 else:
417 427 resp = {
418 428 'id': payload_id,
419 429 'result': resp
420 430 }
421
431 log.debug('Serving data for method %s', method)
422 432 return resp
423 433
424 434 def vcs_stream_view(self, request):
425 435 payload, remote, method, args, kwargs = self._vcs_view_params(request)
426 436 # this method has a stream: marker we remove it here
427 437 method = method.split('stream:')[-1]
428 438 chunk_size = safe_int(payload.get('chunk_size')) or 4096
429 439
430 440 try:
431 441 resp = getattr(remote, method)(*args, **kwargs)
432 442 except Exception as e:
433 443 raise
434 444
435 445 def get_chunked_data(method_resp):
436 446 stream = io.BytesIO(method_resp)
437 447 while 1:
438 448 chunk = stream.read(chunk_size)
439 449 if not chunk:
440 450 break
441 451 yield chunk
442 452
443 453 response = Response(app_iter=get_chunked_data(resp))
444 454 response.content_type = 'application/octet-stream'
445 455
446 456 return response
447 457
448 458 def status_view(self, request):
449 459 import vcsserver
450 460 return {'status': 'OK', 'vcsserver_version': safe_str(vcsserver.__version__),
451 461 'pid': os.getpid()}
452 462
453 463 def service_view(self, request):
454 464 import vcsserver
455 465
456 466 payload = msgpack.unpackb(request.body, use_list=True)
457 467 server_config, app_config = {}, {}
458 468
459 469 try:
460 470 path = self.global_config['__file__']
461 471 config = configparser.RawConfigParser()
462 472
463 473 config.read(path)
464 474
465 475 if config.has_section('server:main'):
466 476 server_config = dict(config.items('server:main'))
467 477 if config.has_section('app:main'):
468 478 app_config = dict(config.items('app:main'))
469 479
470 480 except Exception:
471 481 log.exception('Failed to read .ini file for display')
472 482
473 483 environ = list(os.environ.items())
474 484
475 485 resp = {
476 486 'id': payload.get('id'),
477 487 'result': dict(
478 488 version=safe_str(vcsserver.__version__),
479 489 config=server_config,
480 490 app_config=app_config,
481 491 environ=environ,
482 492 payload=payload,
483 493 )
484 494 }
485 495 return resp
486 496
487 497 def _msgpack_renderer_factory(self, info):
488 498 def _render(value, system):
489 499 request = system.get('request')
490 500 if request is not None:
491 501 response = request.response
492 502 ct = response.content_type
493 503 if ct == response.default_content_type:
494 504 response.content_type = 'application/x-msgpack'
495 505
496 506 return msgpack.packb(value, use_bin_type=False)
497 507 return _render
498 508
499 509 def set_env_from_config(self, environ, config):
500 510 dict_conf = {}
501 511 try:
502 512 for elem in config:
503 513 if elem[0] == 'rhodecode':
504 514 dict_conf = json.loads(elem[2])
505 515 break
506 516 except Exception:
507 517 log.exception('Failed to fetch SCM CONFIG')
508 518 return
509 519
510 520 username = dict_conf.get('username')
511 521 if username:
512 522 environ['REMOTE_USER'] = username
513 523 # mercurial specific, some extension api rely on this
514 524 environ['HGUSER'] = username
515 525
516 526 ip = dict_conf.get('ip')
517 527 if ip:
518 528 environ['REMOTE_HOST'] = ip
519 529
520 530 if _is_request_chunked(environ):
521 531 # set the compatibility flag for webob
522 532 environ['wsgi.input_terminated'] = True
523 533
524 534 def hg_proxy(self):
525 535 @wsgiapp
526 536 def _hg_proxy(environ, start_response):
527 537 app = WsgiProxy(self.remote_wsgi.HgRemoteWsgi())
528 538 return app(environ, start_response)
529 539 return _hg_proxy
530 540
531 541 def git_proxy(self):
532 542 @wsgiapp
533 543 def _git_proxy(environ, start_response):
534 544 app = WsgiProxy(self.remote_wsgi.GitRemoteWsgi())
535 545 return app(environ, start_response)
536 546 return _git_proxy
537 547
538 548 def hg_stream(self):
539 549 if self._use_echo_app:
540 550 @wsgiapp
541 551 def _hg_stream(environ, start_response):
542 552 app = EchoApp('fake_path', 'fake_name', None)
543 553 return app(environ, start_response)
544 554 return _hg_stream
545 555 else:
546 556 @wsgiapp
547 557 def _hg_stream(environ, start_response):
548 558 log.debug('http-app: handling hg stream')
549 559 repo_path = environ['HTTP_X_RC_REPO_PATH']
550 560 repo_name = environ['HTTP_X_RC_REPO_NAME']
551 561 packed_config = base64.b64decode(
552 562 environ['HTTP_X_RC_REPO_CONFIG'])
553 563 config = msgpack.unpackb(packed_config)
554 564 app = scm_app.create_hg_wsgi_app(
555 565 repo_path, repo_name, config)
556 566
557 567 # Consistent path information for hgweb
558 568 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
559 569 environ['REPO_NAME'] = repo_name
560 570 self.set_env_from_config(environ, config)
561 571
562 572 log.debug('http-app: starting app handler '
563 573 'with %s and process request', app)
564 574 return app(environ, ResponseFilter(start_response))
565 575 return _hg_stream
566 576
567 577 def git_stream(self):
568 578 if self._use_echo_app:
569 579 @wsgiapp
570 580 def _git_stream(environ, start_response):
571 581 app = EchoApp('fake_path', 'fake_name', None)
572 582 return app(environ, start_response)
573 583 return _git_stream
574 584 else:
575 585 @wsgiapp
576 586 def _git_stream(environ, start_response):
577 587 log.debug('http-app: handling git stream')
578 588 repo_path = environ['HTTP_X_RC_REPO_PATH']
579 589 repo_name = environ['HTTP_X_RC_REPO_NAME']
580 590 packed_config = base64.b64decode(
581 591 environ['HTTP_X_RC_REPO_CONFIG'])
582 592 config = msgpack.unpackb(packed_config)
583 593
584 594 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
585 595 self.set_env_from_config(environ, config)
586 596
587 597 content_type = environ.get('CONTENT_TYPE', '')
588 598
589 599 path = environ['PATH_INFO']
590 600 is_lfs_request = GIT_LFS_CONTENT_TYPE in content_type
591 601 log.debug(
592 602 'LFS: Detecting if request `%s` is LFS server path based '
593 603 'on content type:`%s`, is_lfs:%s',
594 604 path, content_type, is_lfs_request)
595 605
596 606 if not is_lfs_request:
597 607 # fallback detection by path
598 608 if GIT_LFS_PROTO_PAT.match(path):
599 609 is_lfs_request = True
600 610 log.debug(
601 611 'LFS: fallback detection by path of: `%s`, is_lfs:%s',
602 612 path, is_lfs_request)
603 613
604 614 if is_lfs_request:
605 615 app = scm_app.create_git_lfs_wsgi_app(
606 616 repo_path, repo_name, config)
607 617 else:
608 618 app = scm_app.create_git_wsgi_app(
609 619 repo_path, repo_name, config)
610 620
611 621 log.debug('http-app: starting app handler '
612 622 'with %s and process request', app)
613 623
614 624 return app(environ, start_response)
615 625
616 626 return _git_stream
617 627
618 628 def handle_vcs_exception(self, exception, request):
619 629 _vcs_kind = getattr(exception, '_vcs_kind', '')
620 630 if _vcs_kind == 'repo_locked':
621 631 # Get custom repo-locked status code if present.
622 632 status_code = request.headers.get('X-RC-Locked-Status-Code')
623 633 return HTTPRepoLocked(
624 634 title=exception.message, status_code=status_code)
625 635
626 636 elif _vcs_kind == 'repo_branch_protected':
627 637 # Get custom repo-branch-protected status code if present.
628 638 return HTTPRepoBranchProtected(title=exception.message)
629 639
630 640 exc_info = request.exc_info
631 641 store_exception(id(exc_info), exc_info)
632 642
633 643 traceback_info = 'unavailable'
634 644 if request.exc_info:
635 645 exc_type, exc_value, exc_tb = request.exc_info
636 646 traceback_info = ''.join(traceback.format_exception(exc_type, exc_value, exc_tb))
637 647
638 648 log.error(
639 649 'error occurred handling this request for path: %s, \n tb: %s',
640 650 request.path, traceback_info)
641 651
642 652 statsd = request.registry.statsd
643 653 if statsd:
644 654 exc_type = "{}.{}".format(exception.__class__.__module__, exception.__class__.__name__)
645 655 statsd.incr('vcsserver_exception_total',
646 656 tags=["type:{}".format(exc_type)])
647 657 raise exception
648 658
649 659
650 660 class ResponseFilter(object):
651 661
652 662 def __init__(self, start_response):
653 663 self._start_response = start_response
654 664
655 665 def __call__(self, status, response_headers, exc_info=None):
656 666 headers = tuple(
657 667 (h, v) for h, v in response_headers
658 668 if not wsgiref.util.is_hop_by_hop(h))
659 669 return self._start_response(status, headers, exc_info)
660 670
661 671
662 672 def sanitize_settings_and_apply_defaults(global_config, settings):
663 673 global_settings_maker = SettingsMaker(global_config)
664 674 settings_maker = SettingsMaker(settings)
665 675
666 676 settings_maker.make_setting('logging.autoconfigure', False, parser='bool')
667 677
668 678 logging_conf = os.path.join(os.path.dirname(global_config.get('__file__')), 'logging.ini')
669 679 settings_maker.enable_logging(logging_conf)
670 680
671 681 # Default includes, possible to change as a user
672 682 pyramid_includes = settings_maker.make_setting('pyramid.includes', [], parser='list:newline')
673 683 log.debug("Using the following pyramid.includes: %s", pyramid_includes)
674 684
675 685 settings_maker.make_setting('__file__', global_config.get('__file__'))
676 686
677 687 settings_maker.make_setting('pyramid.default_locale_name', 'en')
678 688 settings_maker.make_setting('locale', 'en_US.UTF-8')
679 689
680 690 settings_maker.make_setting('core.binary_dir', '')
681 691
682 692 temp_store = tempfile.gettempdir()
683 693 default_cache_dir = os.path.join(temp_store, 'rc_cache')
684 694 # save default, cache dir, and use it for all backends later.
685 695 default_cache_dir = settings_maker.make_setting(
686 696 'cache_dir',
687 697 default=default_cache_dir, default_when_empty=True,
688 698 parser='dir:ensured')
689 699
690 700 # exception store cache
691 701 settings_maker.make_setting(
692 702 'exception_tracker.store_path',
693 703 default=os.path.join(default_cache_dir, 'exc_store'), default_when_empty=True,
694 704 parser='dir:ensured'
695 705 )
696 706
697 707 # repo_object cache defaults
698 708 settings_maker.make_setting(
699 709 'rc_cache.repo_object.backend',
700 710 default='dogpile.cache.rc.file_namespace',
701 711 parser='string')
702 712 settings_maker.make_setting(
703 713 'rc_cache.repo_object.expiration_time',
704 714 default=30 * 24 * 60 * 60, # 30days
705 715 parser='int')
706 716 settings_maker.make_setting(
707 717 'rc_cache.repo_object.arguments.filename',
708 718 default=os.path.join(default_cache_dir, 'vcsserver_cache_repo_object.db'),
709 719 parser='string')
710 720
711 721 # statsd
712 722 settings_maker.make_setting('statsd.enabled', False, parser='bool')
713 723 settings_maker.make_setting('statsd.statsd_host', 'statsd-exporter', parser='string')
714 724 settings_maker.make_setting('statsd.statsd_port', 9125, parser='int')
715 725 settings_maker.make_setting('statsd.statsd_prefix', '')
716 726 settings_maker.make_setting('statsd.statsd_ipv6', False, parser='bool')
717 727
718 728 settings_maker.env_expand()
719 729
720 730
721 731 def main(global_config, **settings):
722 732 start_time = time.time()
723 733 log.info('Pyramid app config starting')
724 734
725 735 if MercurialFactory:
726 736 hgpatches.patch_largefiles_capabilities()
727 737 hgpatches.patch_subrepo_type_mapping()
728 738
729 739 # Fill in and sanitize the defaults & do ENV expansion
730 740 sanitize_settings_and_apply_defaults(global_config, settings)
731 741
732 742 # init and bootstrap StatsdClient
733 743 StatsdClient.setup(settings)
734 744
735 745 pyramid_app = HTTPApplication(settings=settings, global_config=global_config).wsgi_app()
736 746 total_time = time.time() - start_time
737 747 log.info('Pyramid app `%s` created and configured in %.2fs',
738 748 getattr(pyramid_app, 'func_name', 'pyramid_app'), total_time)
739 749 return pyramid_app
740 750
741 751
General Comments 0
You need to be logged in to leave comments. Login now