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