Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c69690e

Browse files
committed
[profiler] initial port of WDT from Symfony2
1 parent 8ce2582 commit c69690e

39 files changed

+2342
-61
lines changed

docs/images/profiler_view_config.png

164 KB
Loading

docs/images/profiler_wdt.png

176 KB
Loading

docs/plugins/profiler.rst

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
.. note::
2-
3-
This documentation is under construction, more to come soon
4-
5-
61
Profiler
72
========
83

@@ -27,3 +22,23 @@ Usage
2722

2823
The feature is enabled on dev mode, it does not work for threaded environment.
2924

25+
Preview
26+
-------
27+
28+
.. figure:: ../images/profiler_wdt.png
29+
:align: center
30+
31+
The wdt display memory usage, processing time, controller and python version
32+
33+
34+
.. figure:: ../images/profiler_view_config.png
35+
:align: center
36+
37+
Display more detailed information profiling panel: config, request, etc ..
38+
39+
40+
Credits
41+
-------
42+
43+
The WDT is a python port of the `Symfony2 Profiler <http://symfony.com>`_.
44+
Icons created by `Sensio <http://sension.com>`_ are shared under a `Creative Commons Attribution license <http://creativecommons.org/licenses/by-sa/3.0/>`_.

element/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
# vim: set fileencoding=utf-8 :
1+
# vim: set fileencoding=utf-8 :
2+
from pkg_resources import get_distribution
3+
4+
__version__ = get_distribution('element').version

element/plugins/profiler/collector.py

Lines changed: 185 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,32 @@
1-
class RequestCollector(object):
1+
import element
2+
import sys
3+
import platform
4+
import os
5+
import inspect, importlib
6+
from datetime import datetime
7+
import resource
28

9+
class BaseCollector(object):
10+
def on_request(self, request_handler, run):
11+
pass
12+
13+
def on_callback(self, request_handler, run, name, callback, parameters):
14+
pass
15+
16+
def on_terminate(self, request_handler, run):
17+
pass
18+
19+
def on_response(self, request_handler, run):
20+
pass
21+
22+
def get_template(self, run):
23+
return False
24+
25+
class RequestCollector(BaseCollector):
326
def on_request(self, request_handler, run):
427
request = request_handler.request
528

6-
request_handler.run.add_metric('request', {
29+
run.add_metric('request', {
730
'method': request.method,
831
'uri': request.uri,
932
'path': request.path,
@@ -17,7 +40,166 @@ def on_request(self, request_handler, run):
1740
'body_arguments': request.body_arguments,
1841
'cookies': request.cookies.output(),
1942
'remote_ip': request.remote_ip,
43+
44+
# this will be set on other events
45+
'status_code': False,
46+
'route': False,
47+
'controller': {
48+
'class': False,
49+
'file': False,
50+
'line': False,
51+
'method': False
52+
}
53+
})
54+
55+
def get_class_name(self, method):
56+
# <class 'tests.plugins.profiler.test_collector.NodeHandler'>
57+
return ("%s" % method.im_class)[8:-2]
58+
59+
def get_method_name(self, method):
60+
# <function execute at 0x2a60ed8>
61+
return ("%s" % method.im_func).split(" ")[1]
62+
63+
def on_callback(self, request_handler, run, name, callback, parameters):
64+
run.get_metric('request').update({
65+
'route': name,
66+
'controller': {
67+
'class': self.get_class_name(callback),
68+
'method': self.get_method_name(callback)
69+
},
70+
'route_parameters': parameters
71+
})
72+
73+
def on_response(self, request_handler, run):
74+
run.get_metric('request').update({
75+
'status_code': int(request_handler.get_status())
76+
})
77+
78+
79+
80+
def get_template(self, run):
81+
return 'element.plugins.profiler:collector/request.html'
82+
83+
class PyInfo(object):
84+
def __init__(self):
85+
self._buid = False
86+
self.system = {}
87+
self.build()
88+
89+
def build(self):
90+
self.build_system()
91+
self._buid = True
92+
93+
def get_system(self, name=None):
94+
if not name:
95+
return self.system
96+
97+
return self.system[name]
98+
99+
def build_system(self):
100+
"""
101+
from https://github.com/Dreyer/pyinfo/blob/master/pyinfo.py
102+
"""
103+
system = {
104+
'path': False,
105+
'os_path': False,
106+
'os_version': False,
107+
'version': False,
108+
'subversion': False,
109+
'prefix': False,
110+
'build_date': platform.python_build()[1],
111+
'executable': False,
112+
'compiler': platform.python_compiler(),
113+
'api_version': False,
114+
'implementation': platform.python_implementation(),
115+
'system': platform.system(),
116+
}
117+
118+
if platform.dist()[0] != '' and platform.dist()[1] != '':
119+
system['os_version'] = '%s %s (%s %s)' % ( platform.system(), platform.release(), platform.dist()[0].capitalize(), platform.dist()[1] )
120+
else:
121+
system['os_version'] = '%s %s' % ( platform.system(), platform.release() )
122+
123+
if hasattr( os, 'path' ): system['os_path'] = os.environ['PATH']
124+
if hasattr( sys, 'version' ): system['version'] = platform.python_version()
125+
if hasattr( sys, 'subversion' ): system['subversion'] = ', '.join( sys.subversion )
126+
if hasattr( sys, 'prefix' ): system['prefix'] = sys.prefix
127+
if hasattr( sys, 'path' ): system['path'] = sys.path
128+
if hasattr( sys, 'executable' ): system['executable'] = sys.executable
129+
if hasattr( sys, 'api_version' ): system['api'] = sys.api_version
130+
131+
self.system = system
132+
133+
class TimeCollector(BaseCollector):
134+
def on_request(self, request_handler, run):
135+
run.add_metric('time', {
136+
'start': datetime.now(),
137+
'delta': False,
138+
'delta_format': False,
139+
'end': False
140+
})
141+
142+
def on_terminate(self, request_handler, run):
143+
now = datetime.now()
144+
start = run.get_metric('time')['start']
145+
delta = (now - start).total_seconds() * 1000
146+
147+
run.get_metric('time').update({
148+
'end': now,
149+
'delta': delta,
150+
'delta_format': "%.2f ms" % delta
151+
})
152+
153+
def get_template(self, run):
154+
return 'element.plugins.profiler:collector/time.html'
155+
156+
class MemoryCollector(BaseCollector):
157+
def on_request(self, request_handler, run):
158+
run.add_metric('memory', {
159+
'start': resource.getrusage(resource.RUSAGE_SELF).ru_maxrss,
160+
'delta': False,
161+
'delta_format': False,
162+
'end': False
20163
})
21164

22165
def on_terminate(self, request_handler, run):
23-
pass
166+
now = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
167+
start = run.get_metric('memory')['start']
168+
delta = now - start
169+
170+
run.get_metric('memory').update({
171+
'end': now,
172+
'delta': delta,
173+
'delta_format': "%f" % delta
174+
})
175+
176+
def get_template(self, run):
177+
return 'element.plugins.profiler:collector/memory.html'
178+
179+
class ConfigCollector(BaseCollector):
180+
def __init__(self, container):
181+
self.container = container
182+
183+
def on_request(self, request_handler, run):
184+
185+
info = PyInfo()
186+
run.add_metric('config', {
187+
'element_version': element.__version__,
188+
'app_name': 'element',
189+
'application_name': 'n/a',
190+
'application_version': 'n/a',
191+
'debug': self.container.parameters.get('ioc.debug'),
192+
'env': self.container.parameters.get('ioc.env'),
193+
'python': info.get_system(),
194+
'extensions': self.get_extensions()
195+
})
196+
197+
def get_extensions(self):
198+
extensions = {}
199+
for extension in self.container.parameters.get('ioc.extensions'):
200+
extensions[extension] = inspect.getfile(importlib.import_module(extension))
201+
202+
return extensions
203+
204+
def get_template(self, run):
205+
return 'element.plugins.profiler:collector/config.html'

0 commit comments

Comments
 (0)