##// END OF EJS Templates
core: added more accurate time measurements
marcink -
r737:b969aed6 default
parent child Browse files
Show More
@@ -1,154 +1,154 b''
1 1 """
2 2 gunicorn config extension and hooks. Sets additional configuration that is
3 3 available post the .ini config.
4 4
5 5 - workers = ${cpu_number}
6 6 - threads = 1
7 7 - proc_name = ${gunicorn_proc_name}
8 8 - worker_class = sync
9 9 - worker_connections = 10
10 10 - max_requests = 1000
11 11 - max_requests_jitter = 30
12 12 - timeout = 21600
13 13
14 14 """
15 15
16 16 import multiprocessing
17 17 import sys
18 18 import time
19 19 import datetime
20 20 import threading
21 21 import traceback
22 22 from gunicorn.glogging import Logger
23 23
24 24
25 25 # GLOBAL
26 26 errorlog = '-'
27 27 accesslog = '-'
28 28 loglevel = 'debug'
29 29
30 30 # SECURITY
31 31
32 32 # The maximum size of HTTP request line in bytes.
33 33 # 0 for unlimited
34 34 limit_request_line = 0
35 35
36 36 # Limit the number of HTTP headers fields in a request.
37 37 # By default this value is 100 and can’t be larger than 32768.
38 38 limit_request_fields = 10240
39 39
40 40 # Limit the allowed size of an HTTP request header field.
41 41 # Value is a positive number or 0.
42 42 # Setting it to 0 will allow unlimited header field sizes.
43 43 limit_request_field_size = 0
44 44
45 45
46 46 # Timeout for graceful workers restart.
47 47 # After receiving a restart signal, workers have this much time to finish
48 48 # serving requests. Workers still alive after the timeout (starting from the
49 49 # receipt of the restart signal) are force killed.
50 50 graceful_timeout = 30
51 51
52 52
53 53 # The number of seconds to wait for requests on a Keep-Alive connection.
54 54 # Generally set in the 1-5 seconds range.
55 55 keepalive = 2
56 56
57 57
58 58 # SERVER MECHANICS
59 59 # None == system temp dir
60 60 # worker_tmp_dir is recommended to be set to some tmpfs
61 61 worker_tmp_dir = None
62 62 tmp_upload_dir = None
63 63
64 64 # Custom log format
65 65 access_log_format = (
66 66 '%(t)s [%(p)-8s] GNCRN %(h)-15s rqt:%(L)s %(s)s %(b)-6s "%(m)s:%(U)s %(q)s" usr:%(u)s "%(f)s" "%(a)s"')
67 67
68 68 # self adjust workers based on CPU count
69 69 # workers = multiprocessing.cpu_count() * 2 + 1
70 70
71 71
72 72 def post_fork(server, worker):
73 73 server.log.info("[<%-10s>] WORKER spawned", worker.pid)
74 74
75 75
76 76 def pre_fork(server, worker):
77 77 pass
78 78
79 79
80 80 def pre_exec(server):
81 81 server.log.info("Forked child, re-executing.")
82 82
83 83
84 84 def on_starting(server):
85 85 server.log.info("Server is starting.")
86 86
87 87
88 88 def when_ready(server):
89 89 server.log.info("Server is ready. Spawning workers")
90 90
91 91
92 92 def on_reload(server):
93 93 pass
94 94
95 95
96 96 def worker_int(worker):
97 97 worker.log.info("[<%-10s>] worker received INT or QUIT signal", worker.pid)
98 98
99 99 # get traceback info, on worker crash
100 100 id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
101 101 code = []
102 102 for thread_id, stack in sys._current_frames().items():
103 103 code.append(
104 104 "\n# Thread: %s(%d)" % (id2name.get(thread_id, ""), thread_id))
105 105 for fname, lineno, name, line in traceback.extract_stack(stack):
106 106 code.append('File: "%s", line %d, in %s' % (fname, lineno, name))
107 107 if line:
108 108 code.append(" %s" % (line.strip()))
109 109 worker.log.debug("\n".join(code))
110 110
111 111
112 112 def worker_abort(worker):
113 113 worker.log.info("[<%-10s>] worker received SIGABRT signal", worker.pid)
114 114
115 115
116 116 def worker_exit(server, worker):
117 117 worker.log.info("[<%-10s>] worker exit", worker.pid)
118 118
119 119
120 120 def child_exit(server, worker):
121 121 worker.log.info("[<%-10s>] worker child exit", worker.pid)
122 122
123 123
124 124 def pre_request(worker, req):
125 125 worker.start_time = time.time()
126 126 worker.log.debug(
127 127 "GNCRN PRE WORKER [cnt:%s]: %s %s", worker.nr, req.method, req.path)
128 128
129 129
130 130 def post_request(worker, req, environ, resp):
131 131 total_time = time.time() - worker.start_time
132 132 worker.log.debug(
133 "GNCRN POST WORKER [cnt:%s]: %s %s resp: %s, Load Time: %.3fs",
133 "GNCRN POST WORKER [cnt:%s]: %s %s resp: %s, Load Time: %.4fs",
134 134 worker.nr, req.method, req.path, resp.status_code, total_time)
135 135
136 136
137 137 class RhodeCodeLogger(Logger):
138 138 """
139 139 Custom Logger that allows some customization that gunicorn doesn't allow
140 140 """
141 141
142 142 datefmt = r"%Y-%m-%d %H:%M:%S"
143 143
144 144 def __init__(self, cfg):
145 145 Logger.__init__(self, cfg)
146 146
147 147 def now(self):
148 148 """ return date in RhodeCode Log format """
149 149 now = time.time()
150 150 msecs = int((now - long(now)) * 1000)
151 151 return time.strftime(self.datefmt, time.localtime(now)) + '.{0:03d}'.format(msecs)
152 152
153 153
154 154 logger_class = RhodeCodeLogger
@@ -1,58 +1,58 b''
1 1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 2 # Copyright (C) 2014-2019 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
19 19
20 20 import time
21 21 import logging
22 22
23 23
24 24 from vcsserver.utils import safe_str
25 25
26 26
27 27 log = logging.getLogger(__name__)
28 28
29 29
30 30 def get_access_path(request):
31 31 environ = request.environ
32 32 return environ.get('PATH_INFO')
33 33
34 34
35 35 class RequestWrapperTween(object):
36 36 def __init__(self, handler, registry):
37 37 self.handler = handler
38 38 self.registry = registry
39 39
40 40 # one-time configuration code goes here
41 41
42 42 def __call__(self, request):
43 43 start = time.time()
44 44 try:
45 45 response = self.handler(request)
46 46 finally:
47 47 end = time.time()
48 48
49 log.info('IP: %s Request to path: `%s` time: %.3fs',
49 log.info('IP: %s Request to path: `%s` time: %.4fs',
50 50 '127.0.0.1', safe_str(get_access_path(request)), end - start)
51 51
52 52 return response
53 53
54 54
55 55 def includeme(config):
56 56 config.add_tween(
57 57 'vcsserver.tweens.RequestWrapperTween',
58 58 )
General Comments 0
You need to be logged in to leave comments. Login now