def __call__(self, environ, start_response): CurrentRequestId.set(None) # Never profile calls to the profiler itself to avoid endless recursion. if (not config.should_profile() or environ.get("PATH_INFO", "").startswith("/gae_mini_profiler/")): result = self.app(environ, start_response) for value in result: yield value else: # Set a random ID for this request so we can look up stats later import base64 CurrentRequestId.set(base64.urlsafe_b64encode(os.urandom(5))) # Send request id in headers so jQuery ajax calls can pick # up profiles. def profiled_start_response(status, headers, exc_info = None): if status.startswith("302 "): # Temporary redirect. Add request identifier to redirect location # so next rendered page can show this request's profile. headers = ProfilerWSGIMiddleware.headers_with_modified_redirect(environ, headers) # Access the profiler in closure scope profiler.temporary_redirect = True # Append headers used when displaying profiler results from ajax requests headers.append(("X-MiniProfiler-Id", CurrentRequestId.get())) headers.append(("X-MiniProfiler-QS", environ.get("QUERY_STRING"))) return start_response(status, headers, exc_info) # As a simple form of rate-limiting, appstats protects all # its work with a memcache lock to ensure that only one # appstats request ever runs at a time, across all # appengine instances. (GvR confirmed this is the purpose # of the lock). So our attempt to profile will fail if # appstats is running on another instance. Boo-urns! We # just turn off the lock-checking for us, which means we # don't rate-limit quite as much with the mini-profiler as # we would do without. old_memcache_add = memcache.add old_memcache_delete = memcache.delete memcache.add = (lambda key, *args, **kwargs: (True if key == recording.lock_key() else old_memcache_add(key, *args, **kwargs))) memcache.delete = (lambda key, *args, **kwargs: (True if key == recording.lock_key() else old_memcache_delete(key, *args, **kwargs))) try: profiler = RequestProfiler(CurrentRequestId.get(), Mode.get_mode(environ)) result = profiler.profile_start_response(self.app, environ, profiled_start_response) for value in result: yield value finally: CurrentRequestId.set(None) memcache.add = old_memcache_add memcache.delete = old_memcache_delete
def end_recording(status, firepython_set_extension_data=None): rec = recording.recorder_proxy.get_for_current_request() recording.recorder_proxy.clear_for_current_request() if recording.config.DEBUG: logging.debug('Cleared recorder') if rec is not None: try: if save_record(status): rec.record_http_status(status) rec.save() if (firepython_set_extension_data and (os.getenv('SERVER_SOFTWARE', '').startswith('Dev') or recording.users.is_current_user_admin())): logging.info('Passing data to firepython') firepython_set_extension_data('appengine_appstats', rec.json()) finally: memcache.delete(recording.lock_key(), namespace=recording.config.KEY_NAMESPACE)