Wednesday, January 18, 2017

Re: StreamingHttpResponse response length in a stats middleware

On Wed, Jan 18, 2017 at 11:42 AM, Stefano Tranquillini
<stefano.tranquillini@gmail.com> wrote:
> Hi there,
>
> I'm using the StreamingHttpResponse to stream a response, it works great.
> Now, I've a middleware that measures the size of req/response that users do.
> For normal HttpResponse i use len(response.content) [i know that it does not
> give the bytes, but it's pretty close], for the streaming I can't, and I
> can't use the streaming_content as well.
>
> the docs says ` Because the content can't be accessed, many middlewares
> can't function normally.`
> Thus, is there a way to get the length of the response for a
> StreamingHttpResponse?
>
> If I would be able to know the size of the response at some point in time
> (it's an iterator, so i just need to count) and i could put it in the
> request object, how can I make it working with the middleware? beacuse the
> process_response is fired just after the first yield, no

This is for 1.8 middleware, same method can be applied to 1.10

It's not very clean, but from your middleware you can return a new
response object. The new object would also be a streaming response,
but for each chunk it emits (by calling the generator on the original
response), it would also count the size of the chunk and store a
rolling sum on the response object. After the final chunk is emitted,
your logging middleware can then be called with the resulting value.
Something like:

class WrappedStreamingResponse(StreamingHttpResponse):
def __init__(self, orig_response, middleware):
self.orig_response = orig_response
self.middleware = middleware
self.response_length = 0
super(WrappedStreamingResponse, self).__init__(self.chunks())

def chunks(self):
for chunk in self.orig_response.streaming_content:
self.response_length += len(chunk)
yield chunk
self.middleware.log_response_size(self.orig_response, self.response_length)


class MeasureMiddleware:
def process_response(self, request, response):
if response.streaming:
return WrappedStreamingResponse(response, self)
else:
self.log_response_size(response, len(response.content))

def log_response_size(self, response, length):
pass

Cheers

Tom

PS: 1 big caveat for this is that if a middleware class returns a new
response, middleware classes further down the chain are not called at
all, so StreamingHttpResponse would not get handled by the same
middleware as a regular HttpResponse.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CAFHbX1JwmOqv%3D9Soj0CqWmL%3DMBPsPsfhPA-Qhh-DvtCoyZfctA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment