13
13
import pwd
14
14
import grp
15
15
import re
16
+ import pprint
17
+ import time
18
+ import traceback
16
19
17
20
try :
18
21
import Queue as queue
@@ -878,12 +881,115 @@ def close(self):
878
881
self .debug_exception ()
879
882
raise
880
883
884
+ class RequestRecorder (object ):
885
+
886
+ def __init__ (self , application , savedir ):
887
+ self .application = application
888
+ self .savedir = savedir
889
+ self .lock = threading .Lock ()
890
+ self .pid = os .getpid ()
891
+ self .count = 0
892
+
893
+ def __call__ (self , environ , start_response ):
894
+ with self .lock :
895
+ self .count += 1
896
+ count = self .count
897
+
898
+ key = "%s-%s-%s" % (int (time .time ()* 1000000 ), self .pid , count )
899
+
900
+ iheaders = os .path .join (self .savedir , key + ".iheaders" )
901
+ iheaders_fp = open (iheaders , 'w' )
902
+
903
+ icontent = os .path .join (self .savedir , key + ".icontent" )
904
+ icontent_fp = open (icontent , 'w+b' )
905
+
906
+ oheaders = os .path .join (self .savedir , key + ".oheaders" )
907
+ oheaders_fp = open (oheaders , 'w' )
908
+
909
+ ocontent = os .path .join (self .savedir , key + ".ocontent" )
910
+ ocontent_fp = open (ocontent , 'w+b' )
911
+
912
+ oaexcept = os .path .join (self .savedir , key + ".oaexcept" )
913
+ oaexcept_fp = open (oaexcept , 'w' )
914
+
915
+ orexcept = os .path .join (self .savedir , key + ".orexcept" )
916
+ orexcept_fp = open (orexcept , 'w' )
917
+
918
+ ofexcept = os .path .join (self .savedir , key + ".ofexcept" )
919
+ ofexcept_fp = open (ofexcept , 'w' )
920
+
921
+ errors = environ ['wsgi.errors' ]
922
+ pprint .pprint (environ , stream = iheaders_fp )
923
+ iheaders_fp .close ()
924
+
925
+ input = environ ['wsgi.input' ]
926
+
927
+ data = input .read (8192 )
928
+
929
+ while data :
930
+ icontent_fp .write (data )
931
+ data = input .read (8192 )
932
+
933
+ icontent_fp .flush ()
934
+ icontent_fp .seek (0 , os .SEEK_SET )
935
+
936
+ environ ['wsgi.input' ] = icontent_fp
937
+
938
+ def _start_response (status , response_headers , * args ):
939
+ pprint .pprint (((status , response_headers )+ args ),
940
+ stream = oheaders_fp )
941
+
942
+ _write = start_response (status , response_headers , * args )
943
+
944
+ def write (self , data ):
945
+ ocontent_fp .write (data )
946
+ ocontent_fp .flush ()
947
+ return _write (data )
948
+
949
+ return write
950
+
951
+ try :
952
+ try :
953
+ result = self .application (environ , _start_response )
954
+
955
+ except :
956
+ traceback .print_exception (* sys .exc_info (), file = oaexcept_fp )
957
+ raise
958
+
959
+ try :
960
+ for data in result :
961
+ ocontent_fp .write (data )
962
+ ocontent_fp .flush ()
963
+ yield data
964
+
965
+ except :
966
+ traceback .print_exception (* sys .exc_info (), file = orexcept_fp )
967
+ raise
968
+
969
+ finally :
970
+ try :
971
+ if hasattr (result , 'close' ):
972
+ result .close ()
973
+
974
+ except :
975
+ traceback .print_exception (* sys .exc_info (),
976
+ file = ofexcept_fp )
977
+ raise
978
+
979
+ finally :
980
+ oheaders_fp .close ()
981
+ ocontent_fp .close ()
982
+ oaexcept_fp .close ()
983
+ orexcept_fp .close ()
984
+ ofexcept_fp .close ()
985
+
881
986
class ApplicationHandler (object ):
882
987
883
988
def __init__ (self , entry_point , application_type = 'script' ,
884
989
callable_object = 'application' , mount_point = '/' ,
885
990
with_newrelic_agent = False , debug_mode = False ,
886
- enable_debugger = False , debugger_startup = False ):
991
+ enable_debugger = False , debugger_startup = False ,
992
+ enable_recorder = False , recorder_directory = None ):
887
993
888
994
self .entry_point = entry_point
889
995
self .application_type = application_type
@@ -931,6 +1037,9 @@ def __init__(self, entry_point, application_type='script',
931
1037
if enable_debugger :
932
1038
self .setup_debugger (debugger_startup )
933
1039
1040
+ if enable_recorder :
1041
+ self .setup_recorder (recorder_directory )
1042
+
934
1043
def setup_newrelic_agent (self ):
935
1044
import newrelic .agent
936
1045
@@ -950,6 +1059,9 @@ def setup_newrelic_agent(self):
950
1059
def setup_debugger (self , startup ):
951
1060
self .application = PostMortemDebugger (self .application , startup )
952
1061
1062
+ def setup_recorder (self , savedir ):
1063
+ self .application = RequestRecorder (self .application , savedir )
1064
+
953
1065
def reload_required (self , environ ):
954
1066
if self .debug_mode :
955
1067
return False
@@ -1049,6 +1161,8 @@ def __call__(self, environ, start_response):
1049
1161
coverage_directory = '%(coverage_directory)s'
1050
1162
enable_profiler = %(enable_profiler)s
1051
1163
profiler_directory = '%(profiler_directory)s'
1164
+ enable_recorder = %(enable_recorder)s
1165
+ recorder_directory = '%(recorder_directory)s'
1052
1166
1053
1167
if python_paths:
1054
1168
sys.path.extend(python_paths)
@@ -1094,7 +1208,8 @@ def output_profiler_data():
1094
1208
application_type=application_type, callable_object=callable_object,
1095
1209
mount_point=mount_point, with_newrelic_agent=with_newrelic_agent,
1096
1210
debug_mode=debug_mode, enable_debugger=enable_debugger,
1097
- debugger_startup=debugger_startup)
1211
+ debugger_startup=debugger_startup, enable_recorder=enable_recorder,
1212
+ recorder_directory=recorder_directory)
1098
1213
1099
1214
reload_required = handler.reload_required
1100
1215
handle_request = handler.handle_request
@@ -1792,6 +1907,14 @@ def check_percentage(option, opt_str, value, parser):
1792
1907
'which profiler data will be written when enabled under debug '
1793
1908
'mode.' ),
1794
1909
1910
+ optparse .make_option ('--enable-recorder' , action = 'store_true' ,
1911
+ default = False , help = 'Flag indicating whether recording of '
1912
+ 'requests is enabled when running in debug mode.' ),
1913
+ optparse .make_option ('--recorder-directory' , metavar = 'DIRECTORY-PATH' ,
1914
+ default = '' , help = 'Override the path to the directory into '
1915
+ 'which recorder data will be written when enabled under debug '
1916
+ 'mode.' ),
1917
+
1795
1918
optparse .make_option ('--setup-only' , action = 'store_true' , default = False ,
1796
1919
help = 'Flag indicating that after the configuration files have '
1797
1920
'been setup, that the command should then exit and not go on '
@@ -2179,10 +2302,24 @@ def _cmd_setup_server(command, args, options):
2179
2302
except Exception :
2180
2303
pass
2181
2304
2305
+ if options ['enable_recorder' ]:
2306
+ if not options ['recorder_directory' ]:
2307
+ options ['recorder_directory' ] = os .path .join (
2308
+ options ['server_root' ], 'archive' )
2309
+ else :
2310
+ options ['recorder_directory' ] = os .path .abspath (
2311
+ options ['recorder_directory' ])
2312
+
2313
+ try :
2314
+ os .mkdir (options ['recorder_directory' ])
2315
+ except Exception :
2316
+ pass
2317
+
2182
2318
else :
2183
2319
options ['enable_debugger' ] = False
2184
2320
options ['enable_coverage' ] = False
2185
2321
options ['enable_profiler' ] = False
2322
+ options ['enable_recorder' ] = False
2186
2323
2187
2324
options ['parent_domain' ] = 'unspecified'
2188
2325
@@ -2282,6 +2419,9 @@ def _cmd_setup_server(command, args, options):
2282
2419
if options ['enable_profiler' ]:
2283
2420
print ('Profiler Output :' , options ['profiler_directory' ])
2284
2421
2422
+ if options ['enable_recorder' ]:
2423
+ print ('Recorder Output :' , options ['recorder_directory' ])
2424
+
2285
2425
if options ['envvars_script' ]:
2286
2426
print ('Environ Variables :' , options ['envvars_script' ])
2287
2427
0 commit comments