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