Hello again, Etienne!

The way you coded that, you are counting how many requests the server has 
replied before your request has been processed.

A bit differently than you, I implemented it as a view (which is not hard 
to convert into middleware component) that uses bootstrap, so some small 
changes are needed.

Let me paste some code from my *views.py*:
"""
import json
from urllib.request import urlopen

class ServerStatsView(TemplateView):
    template_name = 'server-stats.html'
    def get(self, request):
        stats = json.loads(ServerStatsJsonGetter(request).content.decode())
        processed_stats = dict()
        processed_stats['workers_total'] = 0
        processed_stats['workers_busy'] = 0
        processed_stats['workers_accepting_connections'] = 0
        processed_stats['threads_total'] = 0
        processed_stats['threads_busy'] = 0
        processed_stats['requests_processed'] = 0
        processed_stats['requests_processing'] = 0
        for worker in stats['workers']:
            processed_stats['workers_total']+=1
            processed_stats['workers_accepting_connections']+= 
int(bool(worker['accepting']))
            processed_stats['workers_busy']+=int(worker['status']=='busy')
            for thread in worker['cores']:
                processed_stats['threads_total']+=1
                
processed_stats['threads_busy']+=int(bool(thread['in_request']))
            processed_stats['requests_processed']+=worker['requests']
        
processed_stats['requests_processing']=processed_stats['threads_busy']
        processed_stats['workers_busy_pct'] = 
100*processed_stats['workers_busy']/processed_stats['workers_total']
        processed_stats['workers_avail_pct'] = 
100*processed_stats['workers_accepting_connections']/processed_stats['workers_total']
        processed_stats['threads_busy_pct'] = 
100*processed_stats['threads_busy']/processed_stats['threads_total']
        return render(request, self.template_name, {
            'stats':processed_stats,
        })

def ServerStatsJsonGetter(request):
    with urlopen('http://127.0.0.1:14549') as urlstream:
        return HttpResponse(
            json.dumps(
                json.loads(urlstream.read().decode()),
                indent=4
            ),
            content_type='application/json'
        )
"""

and now the template *server-stats.html*:
"""
{% extends "base.html" %}
{% load i18n %}

{% block content %}
<h5>
    {% trans "Workers available for new connections" %}
</h5>
<div class="progress">
     <div class="progress-bar" role="progressbar" style="width: 
{{stats.workers_avail_pct}}%" 
aria-valuenow="{{stats.workers_accepting_connections}}" 
aria-valuemax="{{stats.workers_total}}" aria-valuemin="0">
         {{stats.workers_accepting_connections}}
         {% trans "of" %}
         {{stats.workers_total}}
     </div>
</div>
<hr>
<h5>
    {% trans "Workers busy" %}
</h5>
<div class="progress">
     <div class="progress-bar" role="progressbar" style="width: 
{{stats.workers_busy_pct}}%" aria-valuenow="{{stats.workers_busy}}" 
aria-valuemax="{{stats.workers_total}}" aria-valuemin="0">
         {{stats.workers_busy}}
         {% trans "of" %}
         {{stats.workers_total}}
     </div>
</div>
<hr>
<h5>
    {% trans "Threads busy" %}
</h5>
<div class="progress">
     <div class="progress-bar" role="progressbar" style="width: 
{{stats.threads_busy_pct}}%" aria-valuenow="{{stats.threads_busy}}" 
aria-valuemax="{{stats.threads_total}}" aria-valuemin="0">
         {{stats.threads_busy}}
         {% trans "of" %}
         {{stats.threads_total}}
     </div>
</div>
<hr>
<h5>
    Table
</h5>
<div>
    <table class="table">
        <thead>
            <tr>
                <th>Aspect</th>
                <th>Count</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>
                    {% trans "Total workers" %}
                </td>
                <td>
                    {{stats.workers_total}}
                </td>
            </tr>
            <tr>
                <td>
                    {% trans "Busy workers" %}
                </td>
                <td>
                    {{stats.workers_busy}}
                </td>
            </tr>
            <tr>
                <td>
                    {% trans "Workers accepting connections" %}
                </td>
                <td>
                    {{stats.workers_accepting_connections}}
                </td>
            </tr>
            <tr>
                <td>
                    {% trans "Total threads" %}
                </td>
                <td>
                    {{stats.threads_total}}
                </td>
            </tr>
            <tr>
                <td>
                    {% trans "Busy threads" %}
                </td>
                <td>
                    {{stats.threads_busy}}
                </td>
            </tr>
            <tr>
                <td>
                    {% trans "Total processed requests" %}
                </td>
                <td>
                    {{stats.requests_processed}}
                </td>
            </tr>
        </tbody>
    </table>
</div>
{% endblock content %}
"""

A request dispatched while ApacheBench was generating some load 
(concurrency = 15) into the server rendered the image you can find attached 
to this message.

Sincerely,
Adler

Em sexta-feira, 8 de dezembro de 2017 10:09:41 UTC-2, Etienne Robillard 
escreveu:
>
> Hi Ádler,
>
> Thank you for your reply. 
>
> Can you please review this code before I commit?  
>
>
> """uWSGIController API Version 0.8.3 
>
> Middleware for storing uWSGI statistics into the environ object. 
> """ 
>
> import sys 
> import os 
> import logging 
> import demjson 
> import urllib 
>
> logger = logging.getLogger(__name__) 
>
> from notmm.controllers.wsgi import WSGIController 
>
> __all__ = ('uWSGIController',) 
>
>
> class uWSGIController(WSGIController): 
>
>     def __init__(self, wsgi_app, stats_url='http://localhost:9001'): 
>
>         self.wsgi_app = wsgi_app 
>         self.stats_url = stats_url 
>         super(uWSGIController, self).__init__() # hack 
>
>     def init_request(self, request): 
>         logger.debug('In uWSGIController.init_request...') 
>         request.environ['uwsgi.requests'] = 
> self.connections(self.stats_url) 
>         self._request = request 
>         self._environ = request.environ 
>         return self._request 
>
>     def connections(self, url): 
>         """Return the amount of live connections (requests) for all 
> workers""" 
>         fp = urllib.urlopen(url) 
>         json = demjson.decode(fp.read()) 
>
>         connections = 0 
>
>         for worker in json['workers']: 
>             connections += worker['requests'] 
>
>         fp.close() 
>
>         return connections
>
>
> Best regards,
>
> Etienne
>
> Le 2017-12-07 à 13:29, Ádler Oliveira Silva Neves a écrit :
>
> Sounds like you want retrieving statistics from uWSGI's stats server.
>
> http://uwsgi-docs.readthedocs.io/en/latest/StatsServer.html
> In order to get that JSON via HTTP requests, your server ".ini" should 
> receive extra arguments to start an stats server listening to the specified 
> port and application must be somehow aware of such port number, which has a 
> side-effect of increasing coupling.
>
> Sincerely,
>
> Adler
>
> On 07/12/2017 13:13, Etienne Robillard wrote:
>
> Hi, 
>
> I would like to access the uWSGI stats API from within Django by creating 
> a custom WSGI middleware. 
>
> Could it be possible to compute the number of requests currently being 
> used by uWSGI workers in Python/Django ? 
>
> Ideally, i could then retrieve the active connections in use in a standard 
> Django view: 
>
> def someview(request): 
>
>     # retrieve the number of active requests (connections) 
>
>     connections = request.environ['uwsgi.requests'] 
>
>
> What do you think? 
>
>
> Etienne 
>
>
>
> -- 
> 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...@googlegroups.com <javascript:>.
> To post to this group, send email to django...@googlegroups.com 
> <javascript:>.
> 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/c6d79973-28b8-5236-a64e-4c24ed3c30a7%40gmail.com
>  
> <https://groups.google.com/d/msgid/django-users/c6d79973-28b8-5236-a64e-4c24ed3c30a7%40gmail.com?utm_medium=email&utm_source=footer>
> .
> For more options, visit https://groups.google.com/d/optout.
>
>
> -- 
> Etienne robillardtka...@yandex.com 
> <javascript:>https://www.isotopesoftware.ca/
>
>

-- 
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+unsubscr...@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/e3c7e959-7a14-41db-b7e1-b034216a6f60%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to