1313import pwd
1414import grp
1515import re
16+ import pprint
17+ import time
18+ import traceback
1619
1720try :
1821 import Queue as queue
@@ -878,12 +881,115 @@ def close(self):
878881 self .debug_exception ()
879882 raise
880883
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+
881986class ApplicationHandler (object ):
882987
883988 def __init__ (self , entry_point , application_type = 'script' ,
884989 callable_object = 'application' , mount_point = '/' ,
885990 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 ):
887993
888994 self .entry_point = entry_point
889995 self .application_type = application_type
@@ -931,6 +1037,9 @@ def __init__(self, entry_point, application_type='script',
9311037 if enable_debugger :
9321038 self .setup_debugger (debugger_startup )
9331039
1040+ if enable_recorder :
1041+ self .setup_recorder (recorder_directory )
1042+
9341043 def setup_newrelic_agent (self ):
9351044 import newrelic .agent
9361045
@@ -950,6 +1059,9 @@ def setup_newrelic_agent(self):
9501059 def setup_debugger (self , startup ):
9511060 self .application = PostMortemDebugger (self .application , startup )
9521061
1062+ def setup_recorder (self , savedir ):
1063+ self .application = RequestRecorder (self .application , savedir )
1064+
9531065 def reload_required (self , environ ):
9541066 if self .debug_mode :
9551067 return False
@@ -1049,6 +1161,8 @@ def __call__(self, environ, start_response):
10491161coverage_directory = '%(coverage_directory)s'
10501162enable_profiler = %(enable_profiler)s
10511163profiler_directory = '%(profiler_directory)s'
1164+ enable_recorder = %(enable_recorder)s
1165+ recorder_directory = '%(recorder_directory)s'
10521166
10531167if python_paths:
10541168 sys.path.extend(python_paths)
@@ -1094,7 +1208,8 @@ def output_profiler_data():
10941208 application_type=application_type, callable_object=callable_object,
10951209 mount_point=mount_point, with_newrelic_agent=with_newrelic_agent,
10961210 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)
10981213
10991214reload_required = handler.reload_required
11001215handle_request = handler.handle_request
@@ -1792,6 +1907,14 @@ def check_percentage(option, opt_str, value, parser):
17921907 'which profiler data will be written when enabled under debug '
17931908 'mode.' ),
17941909
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+
17951918 optparse .make_option ('--setup-only' , action = 'store_true' , default = False ,
17961919 help = 'Flag indicating that after the configuration files have '
17971920 'been setup, that the command should then exit and not go on '
@@ -2179,10 +2302,24 @@ def _cmd_setup_server(command, args, options):
21792302 except Exception :
21802303 pass
21812304
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+
21822318 else :
21832319 options ['enable_debugger' ] = False
21842320 options ['enable_coverage' ] = False
21852321 options ['enable_profiler' ] = False
2322+ options ['enable_recorder' ] = False
21862323
21872324 options ['parent_domain' ] = 'unspecified'
21882325
@@ -2282,6 +2419,9 @@ def _cmd_setup_server(command, args, options):
22822419 if options ['enable_profiler' ]:
22832420 print ('Profiler Output :' , options ['profiler_directory' ])
22842421
2422+ if options ['enable_recorder' ]:
2423+ print ('Recorder Output :' , options ['recorder_directory' ])
2424+
22852425 if options ['envvars_script' ]:
22862426 print ('Environ Variables :' , options ['envvars_script' ])
22872427
0 commit comments