Builtin statistics gathering in mod_wsgi 3.0 subversion trunk for daemon mode.

15 views
Skip to first unread message

Graham Dumpleton

unread,
Oct 25, 2009, 1:18:31 AM10/25/09
to modwsgi
For mod_wsgi 3.0 in subversion trunk, you can all stop playing with
the previous Python code which had been posted around and fiddled
with. Instead, just update to latest subversion trunk for 3.0. Having
done that just use any WSGI application you have as per normal.

You can then do one of a few things. The first is to add in the
following WSGI application to your configuration and delegate it to
the same daemon process group as your existing WSGI application.

import mod_wsgi
import pprint
import StringIO

def application(environ, start_response):
status = '200 OK'

stream = StringIO.StringIO()
pprint.pprint(mod_wsgi.thread_statistics(), stream=stream)
output = stream.getvalue()

response_headers = [('Content-type', 'text/plain'),
('Content-Length', str(len(output)))]
start_response(status, response_headers)

return [output]

Second, you could add a custom handler within your existing
application which calls 'thread_statistics()' from the 'mod_wsgi'
module and then transforms the dictionary it returns into a pretty
formatted HTML page for display.

Finally, you could start a back ground thread running which
periodically calls 'thread_statistics()' from the 'mod_wsgi' module
and dumps the details out to the Apache error log for later analysis.

Note that this feature is only implemented for daemon mode. Also, it
monitors the whole daemon mode process and not just one application.
It doesn't even matter if the application generating the summary to a
HTML page is running in a different application group (interpreter) so
long as it is in same process group.

Also don't assume that it will ship with mod_wsgi 3.0 as is. The code
hasn't even been cleaned up yet let alone any sanity brought to naming
of information it returns or even how the information is accessed.

That all said, for a simple hello world program with a sleep of 0.001
second in it, with only 5 daemon threads and ab concurrency of 10
example results are:

{'threads': [{'id': 0,
'requests_time_average': 0.0014356310160427807,
'requests_time_maximum': 0.066059999999999994,
'requests_time_minimum': 0.0011249999999999999,
'requests_time_total': 3.2215560000000001,
'requests_total': 2244,
'running': False},
{'id': 1,
'requests_time_average': 0.0014802679063360882,
'requests_time_maximum': 0.017203,
'requests_time_minimum': 0.001119,
'requests_time_total': 2.149349,
'requests_total': 1452,
'running': True},
{'id': 2,
'requests_time_average': 0.0014544432432432432,
'requests_time_maximum': 0.048439999999999997,
'requests_time_minimum': 0.001124,
'requests_time_total': 2.6907199999999998,
'requests_total': 1850,
'running': False},
{'id': 3,
'requests_time_average': 0.001393129470348574,
'requests_time_maximum': 0.0092510000000000005,
'requests_time_minimum': 0.001126,
'requests_time_total': 3.077423,
'requests_total': 2209,
'running': False},
{'id': 4,
'requests_time_average': 0.0014082352156514007,
'requests_time_maximum': 0.020750000000000001,
'requests_time_minimum': 0.001122,
'requests_time_total': 3.1671209999999999,
'requests_total': 2249,
'running': False}],
'threads_active': 2,
'threads_active_maximum': 5,
'threads_requests_total': 10004,
'threads_time_average': 0.0014300448820471811,
'threads_time_total': 14.306169000000001}

One final point. The whole point of this statistics gathering is to
monitor you real WSGI application. Some of the results before posted
by some were just monitoring the statistics program itself and what is
the point of that.

I'll be interested in results for some real applications.

Graham

Jason Garber

unread,
Oct 25, 2009, 10:57:09 AM10/25/09
to mod...@googlegroups.com
Hi Graham,

This looks great! Thank you, and I will let you know our results.

Jason Garber

On Sunday, October 25, 2009, Graham Dumpleton

gert

unread,
Oct 25, 2009, 10:04:30 PM10/25/09
to modwsgi
import mod_wsgi
import pprint
import io

def application(environ, response):
stream = io.StringIO()
pprint.pprint(mod_wsgi.thread_statistics(), stream=stream)
output = stream.getvalue()
response('200 OK', [('Content-type', 'text/plain'),('Content-
Length', str(len(output)))])
return [output]

{'threads': [{'id': 0,
'requests_time_average': 0.0035506584158415838,
'requests_time_maximum': 0.005333,
'requests_time_minimum': 0.003503,
'requests_time_total': 0.717233,
'requests_total': 202,
'running': True},
{'id': 1,
'requests_time_average': 0.0,
'requests_time_maximum': 0.0,
'requests_time_minimum': 0.0,
'requests_time_total': 0.0,
'requests_total': 0,
'running': False},
{'id': 2,
'requests_time_average': 0.0,
'requests_time_maximum': 0.0,
'requests_time_minimum': 0.0,
'requests_time_total': 0.0,
'requests_total': 0,
'running': False},
{'id': 3,
'requests_time_average': 0.0,
'requests_time_maximum': 0.0,
'requests_time_minimum': 0.0,
'requests_time_total': 0.0,
'requests_total': 0,
'running': False},
{'id': 4,
'requests_time_average': 0.003535875,
'requests_time_maximum': 0.003659,
'requests_time_minimum': 0.003475,
'requests_time_total': 0.707175,
'requests_total': 200,
'running': False}],
'threads_active': 1,
'threads_active_maximum': 2,
'threads_requests_total': 402,
'threads_time_average': 0.0035433034825870647,
'threads_time_total': 1.424408}

{'threads': [{'id': 0,
'requests_time_average': 0.015793862569832402,
'requests_time_maximum': 0.038199,
'requests_time_minimum': 0.003342,
'requests_time_total': 42.406521,
'requests_total': 2685,
'running': False},
{'id': 1,
'requests_time_average': 0.018933746247654783,
'requests_time_maximum': 0.038302,
'requests_time_minimum': 0.003379,
'requests_time_total': 40.366747,
'requests_total': 2132,
'running': False},
{'id': 2,
'requests_time_average': 0.016715138844301765,
'requests_time_maximum': 0.03809,
'requests_time_minimum': 0.003391,
'requests_time_total': 41.654126,
'requests_total': 2492,
'running': True},
{'id': 3,
'requests_time_average': 0.018937471388367728,
'requests_time_maximum': 0.038053,
'requests_time_minimum': 0.003429,
'requests_time_total': 40.374689,
'requests_total': 2132,
'running': False},
{'id': 4,
'requests_time_average': 0.017544466069142128,
'requests_time_maximum': 0.051163,
'requests_time_minimum': 0.003348,
'requests_time_total': 41.106684,
'requests_total': 2343,
'running': False}],
'threads_active': 1,
'threads_active_maximum': 5,
'threads_requests_total': 11784,
'threads_time_average': 0.017473588509843856,
'threads_time_total': 205.908767}

On Oct 25, 3:57 pm, Jason Garber <b...@gahooa.com> wrote:
> Hi Graham,
>
> This looks great!  Thank you, and I will let you know our results.
>
> Jason Garber
>
> On Sunday, October 25, 2009, Graham Dumpleton
>

gert

unread,
Oct 25, 2009, 10:14:57 PM10/25/09
to modwsgi
Any reason why id 0, 4 is occupied first ?
and when there is less activity again id 0, 2 ?

gert

unread,
Oct 25, 2009, 10:23:11 PM10/25/09
to modwsgi
Why do i not see 10 threads when I launch 2 processes each 5 threads ?
Why do i see more active threads to handle the same amount of request
when i increase processes ?

gert

unread,
Oct 25, 2009, 10:29:31 PM10/25/09
to modwsgi
Aha one output is from the first process the other from other process.
Can you make it so all threads are visible for each process.
> ...
>
> read more »

Graham Dumpleton

unread,
Oct 25, 2009, 10:33:41 PM10/25/09
to mod...@googlegroups.com
I explained this before.

In the new scheme for thread handling, rather than the operating
system threads library effectively managing which thread next gets to
run, by virtue of which it let through the thread mutex, in the new
way there is a stack holding the threads with the thread on the top of
the stack being used for next request. When a thread has finished with
a request, it gets put on the top of the stack. The result being that
the thread which became most recently available will be next to be
used again.

So, thread 0 might as example be first to be listener for new
requests. It accepts request and then triggers wakeup of thread on top
of stack which then becomes new listener. In your first example that
was thread 4. When thread 0 finishes it sticks itself back on top of
the stack. Thread 4 then handles next request with thread 0 being
popped off of top of stack to become listener again.

Thus, if no concurrent requests, handling of them will alternate
between just two threads, in this case 0 and 4.

It is only when you actually get concurrent requests that more threads
need to be activated.

The value threads_active_maximum tells you the most number of threads
to be activated and will be one guiding factor as to how many threads
you actually need to configure daemon process group to use for single
process.

It is a bit more complicated than that overall and I need to add in
other tracking code. What I effectively need to record is how much
time the process is spent dealing with different numbers of concurrent
requests.

For example, one might find that for 70% of the requests there was
only ever 1 request being handled at that time. 25% of the request
count might then be where there were 2 requests being handled at a
time. 3% for 3 and 2% for 4%.

One might think that don't want to specify extra threads to handle
just that last 5%, but not that simple. If you look at time spent at
that level, you may find that as far as clock time goes, 80% of
process life time was where there were 3 concurrent requests. This
may be because of a small number of requests that take a long time to
be handled and thus skewing towards need to have more threads.

In other words, can't just count incidences of where concurrent
requests occurred, but how long those conditions prevailed.

So this code needs more work and extra tracking added to make it
completely useful for use as a guide of how many threads, and maybe
processes, is needed.

Graham

2009/10/26 gert <gert.c...@gmail.com>:

gert

unread,
Oct 25, 2009, 10:35:15 PM10/25/09
to modwsgi
can you add req/sec at the bottom

'threads_requests_total': 1917, / 'threads_time_total': 6.796871}
> ...
>
> read more »

Graham Dumpleton

unread,
Oct 25, 2009, 10:38:36 PM10/25/09
to mod...@googlegroups.com
2009/10/26 gert <gert.c...@gmail.com>:
>
> Aha one output is from the first process the other from other process.

My updated version, which hasn't been committed, also outputs process
ID in the results so can see that for different processes.

> Can you make it so all threads are visible for each process.

Not within results of a single request.

I mentioned the idea of how one could run a background thread which
periodically dumped out results to a log. One variant of that is that
the background thread on a periodic basis, as well as atexit
registered callback, pickle up the data and send it to a single
distinct process for accumulation with that process (web application)
then presenting a single unified view across all processes. This is
easier than dealing with shared memory of something else.

My updated code also tracks information like process start time and
time when sample was generated so that one can timeline the
accumulated data and thus generate live graphs for example.

Of course, since you like AJAX am expecting you to come up with some
really nice live graphing system for this. ;-)

Graham

gert

unread,
Oct 25, 2009, 10:53:31 PM10/25/09
to modwsgi


On Oct 26, 3:38 am, Graham Dumpleton <graham.dumple...@gmail.com>
wrote:
> 2009/10/26 gert <gert.cuyk...@gmail.com>:
>
>
>
> > Aha one output is from the first process the other from other process.
>
> My updated version, which hasn't been committed, also outputs process
> ID in the results so can see that for different processes.
>
> > Can you make it so all threads are visible for each process.
>
> Not within results of a single request.
>
> I mentioned the idea of how one could run a background thread which
> periodically dumped out results to a log. One variant of that is that
> the background thread on a periodic basis, as well as atexit
> registered callback, pickle up the data and send it to a single
> distinct process for accumulation with that process (web application)
> then presenting a single unified view across all processes. This is
> easier than dealing with shared memory of something else.
>
> My updated code also tracks information like process start time and
> time when sample was generated so that one can timeline the
> accumulated data and thus generate live graphs for example.
>
> Of course, since you like AJAX am expecting you to come up with some
> really nice live graphing system for this. ;-)

Sure if you make the output JSON so i can do

for (i in threads){document...}

in javascript, meaning ' need to be "
> ...
>
> read more »

Graham Dumpleton

unread,
Oct 25, 2009, 10:56:48 PM10/25/09
to mod...@googlegroups.com
I am looking at various things including that. Look at mod_status for
other possibilities such as kb/s etc.

Am also looking at trying to track how long WSGI application was
dealing with wsgi.input to read all content and how long it took to
send back response content. Both situations are complicated though by
streaming applications.

The intent of tracking these is so can show how placing nginx in front
can make dealing with slow HTTP clients much better, freeing up
threads due to nginx doing work of dealing with slow clients with
request/response content buffered by nginx.

In other words, nginx only hands request off to Apache when data would
actually be available to be processed, thus reducing time that thread
in Apache is doing stuff to just the processing rather than blocking
waiting for data.

Graham

2009/10/26 gert <gert.c...@gmail.com>:

gert

unread,
Oct 26, 2009, 12:36:19 AM10/26/09
to modwsgi
import mod_wsgi
import json

def application(environ, response):
output = json.dumps(mod_wsgi.thread_statistics())
response('200 OK', [('Content-type', 'text/javascript'),('Content-
Length', str(len(output)))])
return [output]

Never mind about the JSON output this works perfect :)
And for the love of god do not even think about changing to some XML
output... i hate xml data outputs

On Oct 26, 3:56 am, Graham Dumpleton <graham.dumple...@gmail.com>
wrote:
> I am looking at various things including that. Look at mod_status for
> other possibilities such as kb/s etc.
>
> Am also looking at trying to track how long WSGI application was
> dealing with wsgi.input to read all content and how long it took to
> send back response content. Both situations are complicated though by
> streaming applications.
>
> The intent of tracking these is so can show how placing nginx in front
> can make dealing with slow HTTP clients much better, freeing up
> threads due to nginx doing work of dealing with slow clients with
> request/response content buffered by nginx.
>
> In other words, nginx only hands request off to Apache when data would
> actually be available to be processed, thus reducing time that thread
> in Apache is doing stuff to just the processing rather than blocking
> waiting for data.
>
> Graham
>
> 2009/10/26 gert <gert.cuyk...@gmail.com>:
> ...
>
> read more »

Graham Dumpleton

unread,
Oct 26, 2009, 12:52:35 AM10/26/09
to mod...@googlegroups.com
2009/10/26 gert <gert.c...@gmail.com>:
>
> import mod_wsgi
> import json
>
> def application(environ, response):
>    output = json.dumps(mod_wsgi.thread_statistics())

The name of the function is going to change. As will the structure of
the returned data structure and names.

For now am just trying to get it recording information think is
worthwhile, will then clean it up after any feedback on what it is
capturing and peoples ideas on what structure is being returned.

>    response('200 OK', [('Content-type', 'text/javascript'),('Content-
> Length', str(len(output)))])
>    return [output]
>
> Never mind about the JSON output this works perfect :)
> And for the love of god do not even think about changing to some XML
> output... i hate xml data outputs

Okay, I'll use SGML instead. Or I'll define a custom data structure
format using ASN.1.

Will either of those be okay? ;-)

Graham

gert

unread,
Oct 26, 2009, 1:15:17 AM10/26/09
to modwsgi
On Oct 26, 5:52 am, Graham Dumpleton <graham.dumple...@gmail.com>
wrote:
> 2009/10/26 gert <gert.cuyk...@gmail.com>:
>
> > import mod_wsgi
> > import json
>
> > def application(environ, response):
> >    output = json.dumps(mod_wsgi.thread_statistics())
>
> The name of the function is going to change. As will the structure of
> the returned data structure and names.
>
> For now am just trying to get it recording information think is
> worthwhile, will then clean it up after any feedback on what it is
> capturing and peoples ideas on what structure is being returned.
>
> >    response('200 OK', [('Content-type', 'text/javascript'),('Content-
> > Length', str(len(output)))])
> >    return [output]
>
> > Never mind about the JSON output this works perfect :)
> > And for the love of god do not even think about changing to some XML
> > output... i hate xml data outputs
>
> Okay, I'll use SGML instead. Or I'll define a custom data structure
> format using ASN.1.
>
> Will either of those be okay? ;-)

!!!NO!!!
> ...
>
> read more »

gert

unread,
Oct 26, 2009, 11:36:45 PM10/26/09
to modwsgi
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/
TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head><title>bench</title></head>
<body>
<table>
<tr><th>Thread</th><th>Process1</th><th>Process2</th></tr>
<tr><td>0</td><td id="p1-t0"></td><td id="p2-t0"></td></tr>
<tr><td>1</td><td id="p1-t1"></td><td id="p2-t1"></td></tr>
<tr><td>2</td><td id="p1-t2"></td><td id="p2-t2"></td></tr>
<tr><td>3</td><td id="p1-t3"></td><td id="p2-t3"></td></tr>
<tr><td>4</td><td id="p1-t4"></td><td id="p2-t4"></td></tr>
</table>
<script type="text/javascript">
<![CDATA[
while(true)
{
xmlHttp=new XMLHttpRequest()
xmlHttp.open('GET','bench.wsgi',false)
xmlHttp.send()
v=JSON.parse(xmlHttp.responseText)
document.getElementById('p1-t0').innerHTML=v.threads
[0].requests_total
document.getElementById('p1-t1').innerHTML=v.threads
[1].requests_total
document.getElementById('p1-t2').innerHTML=v.threads
[2].requests_total
document.getElementById('p1-t3').innerHTML=v.threads
[3].requests_total
document.getElementById('p1-t4').innerHTML=v.threads
[4].requests_total
document.getElementById('p2-t0').innerHTML=v.threads
[0].requests_total
document.getElementById('p2-t1').innerHTML=v.threads
[1].requests_total
document.getElementById('p2-t2').innerHTML=v.threads
[2].requests_total
document.getElementById('p2-t3').innerHTML=v.threads
[3].requests_total
document.getElementById('p2-t4').innerHTML=v.threads
[4].requests_total
}
]]>
</script>
</body>
</html>

just a small illustration how straight forward it is. just need to add
stuff like this.
if(v.process==1) p1[0]=v.threads[0].requests_total
> ...
>
> read more »

gert

unread,
Oct 27, 2009, 12:03:46 AM10/27/09
to modwsgi
A 4 year old could make mod_wsgi statistics :)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/
TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head><title>bench</title></head>
<body>
<table>
<tr><th>Thread</th><th>Process1</th><th>Process2</th></tr>
<tr><td>0</td><td id="p1-t0"></td><td id="p2-t0"></td></tr>
<tr><td>1</td><td id="p1-t1"></td><td id="p2-t1"></td></tr>
<tr><td>2</td><td id="p1-t2"></td><td id="p2-t2"></td></tr>
<tr><td>3</td><td id="p1-t3"></td><td id="p2-t3"></td></tr>
<tr><td>4</td><td id="p1-t4"></td><td id="p2-t4"></td></tr>
</table>
<script type="text/javascript">
<![CDATA[
while(true)
{
xmlHttp=new XMLHttpRequest()
xmlHttp.open('GET','bench.wsgi',false)
xmlHttp.send()
v=JSON.parse(xmlHttp.responseText)
if(v.process==2)
{
document.getElementById('p2-t0').innerHTML=v.threads
[0].requests_total
document.getElementById('p2-t1').innerHTML=v.threads
[1].requests_total
document.getElementById('p2-t2').innerHTML=v.threads
[2].requests_total
document.getElementById('p2-t3').innerHTML=v.threads
[3].requests_total
document.getElementById('p2-t4').innerHTML=v.threads
[4].requests_total
}
else
{
document.getElementById('p1-t0').innerHTML=v.threads
[0].requests_total
document.getElementById('p1-t1').innerHTML=v.threads
[1].requests_total
document.getElementById('p1-t2').innerHTML=v.threads
[2].requests_total
document.getElementById('p1-t3').innerHTML=v.threads
[3].requests_total
document.getElementById('p1-t4').innerHTML=v.threads
[4].requests_total
}
}
]]>
</script>
</body>
</html>

Will work when Graham add the process value

Graham Dumpleton

unread,
Oct 27, 2009, 12:08:34 AM10/27/09
to mod...@googlegroups.com
Perform checkout. Change thread_statistics() to usage_statistics().

Problem I see is that you have hardwired in your JavaScript how many
threads. Doesn't JavaScript allow you to take length of array or to
say iterate over all entries and for you to adjust integer indexes
automatically? Does there need to be a separate variable listing the
number of threads even though it can be determined from length of
array?

Graham

2009/10/27 gert <gert.c...@gmail.com>:

gert

unread,
Oct 27, 2009, 12:15:31 AM10/27/09
to modwsgi
Sure but then we need a 6 year old :P
Anyway I will make a dynamic table.

On Oct 27, 5:08 am, Graham Dumpleton <graham.dumple...@gmail.com>
wrote:
> Perform checkout. Change thread_statistics() to usage_statistics().
>
> Problem I see is that you have hardwired in your JavaScript how many
> threads. Doesn't JavaScript allow you to take length of array or to
> say iterate over all entries and for you to adjust integer indexes
> automatically? Does there need to be a separate variable listing the
> number of threads even though it can be determined from length of
> array?
>
> Graham
>
> 2009/10/27 gert <gert.cuyk...@gmail.com>:

gert

unread,
Oct 27, 2009, 12:58:30 AM10/27/09
to modwsgi
I was thinking something like this

while(true)
{
xmlHttp=new XMLHttpRequest()
xmlHttp.open('GET','bench.wsgi',false)
xmlHttp.send()
v=JSON.parse(xmlHttp.responseText)
createmytable(v)
p=document.getElementById(v.process_id)
for(i in v.threads)p.getElementById(i).innerHTML=v.threads
[i].requests_total
}

I know the thread count on the first request but I do not know total
number of processes, is it possible to add it, or do I just code
around it so it wil generate a extra collum if it encounters a new
process_id ?

gert

unread,
Oct 27, 2009, 1:06:54 AM10/27/09
to modwsgi
actually I do not need the total number, I need every process id :)
can you make a process array containing all pid's ?
like i said i can code around it, if its not a good idea or too
confusing.

Graham Dumpleton

unread,
Oct 27, 2009, 1:12:01 AM10/27/09
to mod...@googlegroups.com
2009/10/27 gert <gert.c...@gmail.com>:
>
> actually I do not need the total number, I need every process id :)

You can't have a list of all process IDs as one process will not know
what the others are and because of processes being restarted they can
be changed.

> can you make a process array containing all pid's ?

No.

> like i said i can code around it, if its not a good idea or too
> confusing.

I told you before that to track multiple processes a periodic
background task within the process themselves would need to collect
data and send/save it to a central place that a single request can
then access.

The code has been updated anyway to show number of processes and
number of threads as separate values.

Make sure you change 'threads' to 'threads_details' in your code.

Yes the variable naming is getting messy and will get messier while
keep throwing more stuff in and before sit down and work out sane
naming scheme.

I presume that if I start using '.''s in names that JavaScript will
not like it. Ie., you will scream if have:

{ "process.id": 1234 }

Graham

gert

unread,
Oct 27, 2009, 1:26:13 AM10/27/09
to modwsgi


On Oct 27, 6:12 am, Graham Dumpleton <graham.dumple...@gmail.com>
wrote:
> 2009/10/27 gert <gert.cuyk...@gmail.com>:
>
>
>
> > actually I do not need the total number, I need every process id :)
>
> You can't have a list of all process IDs as one process will not know
> what the others are and because of processes being restarted they can
> be changed.
>
> > can you make a process array containing all pid's ?
>
> No.
>
> > like i said i can code around it, if its not a good idea or too
> > confusing.
>
> I told you before that to track multiple processes a periodic
> background task within the process themselves would need to collect
> data and send/save it to a central place that a single request can
> then access.
>
> The code has been updated anyway to show number of processes and
> number of threads as separate values.
>
> Make sure you change 'threads' to 'threads_details' in your code.
>
> Yes the variable naming is getting messy and will get messier while
> keep throwing more stuff in and before sit down and work out sane
> naming scheme.
>
> I presume that if I start using '.''s in names that JavaScript will
> not like it. Ie., you will scream if have:
>
>   { "process.id": 1234 }

And why would anybody do this to him self ??? Even if it works it
would seriously mess up my head while debugging

v['processs.id'] != v[processs.id]

gert

unread,
Oct 27, 2009, 1:36:22 AM10/27/09
to modwsgi
test = { "process.id": 1234 }
alert(test['process.id'])

yes it works, you can do this if you want, but you better have a damn
good excuse for it :)

Graham Dumpleton

unread,
Oct 27, 2009, 1:39:07 AM10/27/09
to mod...@googlegroups.com
2009/10/27 gert <gert.c...@gmail.com>:
Wont it stop you from doing:

p=document.getElementById(v.process_id)

Ie., cant have:

p=document.getElementById(v.process.id)

gert

unread,
Oct 27, 2009, 1:44:59 AM10/27/09
to modwsgi
On Oct 27, 6:39 am, Graham Dumpleton <graham.dumple...@gmail.com>
You would force me to do this v['process.id'] = UGLY AS HELL
Pyhton can learn a thing or two from js :)

test ={ "process": 1234 }
alert(test['process'])
alert(test.process)

Graham Dumpleton

unread,
Oct 27, 2009, 1:54:10 AM10/27/09
to mod...@googlegroups.com
2009/10/27 gert <gert.c...@gmail.com>:

You can do that in Python by using a custom dictionary class and
overriding setter/getter's etc for the class.

Graham

gert

unread,
Oct 27, 2009, 1:54:29 AM10/27/09
to modwsgi
anyway i can live with document.getElementById(v['process.id']) if i
have too

gert

unread,
Oct 27, 2009, 3:20:07 AM10/27/09
to modwsgi
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/
TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head><title>bench</title></head>
<body>
<table id="stat"></table>
<script type="text/javascript">
<![CDATA[

table=
{
'process':[],
'render':function()
{
var tb=document.getElementById('stat')
tb.innerHTML=""
for(var i in table.process)
{
var th=document.createElement('th')
th.innerHTML=i
tb.appendChild(th)
for(var j in table.process[i])
{
var tr=document.createElement('tr')
tb.appendChild(tr)
for(var k in table.process[i][j])
{
var td=document.createElement('td')
td.innerHTML=table.process[i][j][k]
tr.appendChild(td)
}
}
}
}
}

while(true)
{
xmlHttp=new XMLHttpRequest()
xmlHttp.open('GET','bench.wsgi',false)
xmlHttp.send()
v=JSON.parse(xmlHttp.responseText)
table['process'][v.process_id]=v.threads_details
table.render()
}

]]>
</script>
</body>
</html>

And now its time for css i think :)


gert

unread,
Oct 27, 2009, 3:35:47 AM10/27/09
to modwsgi
oops you need to replace <table></table> to make it xhtml1.1 valid
with <table id="stat"><tr><td></td></tr></table>
PS i am using firfox 3.5.4

gert

unread,
Oct 27, 2009, 4:06:13 AM10/27/09
to modwsgi
Improved version

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/
TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head><title>bench</title></head>
<body>
<table id="stat"><tr><td></td></tr></table>
<script type="text/javascript">
<![CDATA[

table=
{
'process':{},
'render':function()
{
var tb=document.getElementById('stat')
tb.innerHTML=""
for(var i in table.process)
{
var tr=document.createElement('tr')
var th=document.createElement('th')
th.innerHTML=i
tr.appendChild(th)
tb.appendChild(tr)
for(var j in table.process[i])
{
var tr=document.createElement('tr')
for(var k in table.process[i][j])
{
var td=document.createElement('td')
td.innerHTML=table.process[i][j][k]
tr.appendChild(td)
}
tb.appendChild(tr)

Robert Coup

unread,
Oct 28, 2009, 5:18:14 PM10/28/09
to mod...@googlegroups.com
On Tue, Oct 27, 2009 at 6:12 PM, Graham Dumpleton <graham.d...@gmail.com> wrote:
I presume that if I start using '.''s in names that JavaScript will
not like it. Ie., you will scream if have:

 { "process.id": 1234 }

{
  ... ,
  "process": {
    "id": 1234
  } 
}

would be a saner pattern, which is accessible via somedata.process.id

{ "process.id": 1234} is accessible via somedata["process.id"], but as Gert said, that's not ... the way to do it.

fwiw, Javascript normally uses a camelCase naming convention (vs Python's under_score) fwiw, so processId would work too.

Gert: have you ever heard of a pastebin? And snipping the emails you're replying to? :P

Rob :)
--
Koordinates Ltd.
PO Box 1604, Shortland St, Auckland 1140, New Zealand
Phone +64-9-966 0433 Fax +64-9-969 0045
Web http://koordinates.com/

gert

unread,
Oct 28, 2009, 6:52:51 PM10/28/09
to modwsgi
On Oct 28, 10:18 pm, Robert Coup <robert.c...@koordinates.com> wrote:
> On Tue, Oct 27, 2009 at 6:12 PM, Graham Dumpleton <
>
> graham.dumple...@gmail.com> wrote:
> > I presume that if I start using '.''s in names that JavaScript will
> > not like it. Ie., you will scream if have:
>
> >  { "process.id": 1234 }
>
> {
>   ... ,
>   "process": {
>     "id": 1234
>   }
>
> }
>
> would be a saner pattern, which is accessible via somedata.process.id
>
> { "process.id": 1234} is accessible via somedata["process.id"], but as Gert
> said, that's not ... the way to do it.
>
> fwiw, Javascript normally uses a camelCase naming convention (vs Python's
> under_score) fwiw, so processId would work too.
>
> Gert: have you ever heard of a pastebin? And snipping the emails you're
> replying to? :P
>

Pffff :)

Jason Garber

unread,
Oct 28, 2009, 8:40:11 PM10/28/09
to mod...@googlegroups.com
<snip>
oops! 

Graham Dumpleton

unread,
Oct 28, 2009, 10:34:59 PM10/28/09
to mod...@googlegroups.com
2009/10/29 Robert Coup <rober...@koordinates.com>:

> On Tue, Oct 27, 2009 at 6:12 PM, Graham Dumpleton
> <graham.d...@gmail.com> wrote:
>>
>> I presume that if I start using '.''s in names that JavaScript will
>> not like it. Ie., you will scream if have:
>>
>>  { "process.id": 1234 }
>
> {
>   ... ,
>   "process": {
>     "id": 1234
>   }
> }
> would be a saner pattern, which is accessible via somedata.process.id
> { "process.id": 1234} is accessible via somedata["process.id"], but as Gert
> said, that's not ... the way to do it.
> fwiw, Javascript normally uses a camelCase naming convention (vs Python's
> under_score) fwiw, so processId would work too.

Do remember that JavaScript isn't the target of this. The primary user
of it will be Python code. So usability within Python is actually more
important.

> Gert: have you ever heard of a pastebin? And snipping the emails you're
> replying to? :P

He hasn't learnt yet either to save up all his emails until he has
something completely working and so one gets a dribble of mails one
has to sort through until you get to the one where it actually works.

Graham

Robert Coup

unread,
Oct 29, 2009, 4:24:42 PM10/29/09
to mod...@googlegroups.com
On Thu, Oct 29, 2009 at 3:34 PM, Graham Dumpleton <graham.d...@gmail.com> wrote:

Do remember that JavaScript isn't the target of this. The primary user
of it will be Python code. So usability within Python is actually more
important.

Sure, but JSON is JSON is JSON.  

data['process.id'] is still kinda nasty in python code, since the "." is a logical hierarchy separator even though it occurs within a string.

It's in the same vein as avoiding ", ', (, [, etc in dictionary keys... data['process[id]'] or data['process(id)'] aren't nearly as easy to grok as data['process_id'].

Rob :)

Graham Dumpleton

unread,
Oct 29, 2009, 4:49:34 PM10/29/09
to mod...@googlegroups.com
2009/10/30 Robert Coup <rober...@koordinates.com>:

Please don't get worried overly about use of '.' in name. Mentioning
it was more to stir up Gert as I knew it probably wasn't going to work
for JavaScript. So, am unlikely to do it, although use of dots is
better where this feeds into publish/subscribe system as they usually
have flat namespace with '.' used as separator with name. If though
nested data structures are used, they can convert which ever way you
want.

Graham

Reply all
Reply to author
Forward
0 new messages