ó
ú2ec           @   s  d  Z  d d l Z d d l Z d d l Z d d l Z d d l m Z d d l m Z d d l	 m
 Z
 d d l m Z m Z d d l m Z m Z e d d	 d
 ƒZ d e f d „  ƒ  YZ d „  Z d g Z d „  Z d „  Z d „  Z e d „ Z e j  e _  d d „ Z d S(   sv   
Watches the key ``paste.httpserver.thread_pool`` to see how many
threads there are and report on any wedged threads.
iÿÿÿÿN(   t   StringIO(   t	   get_ident(   t   httpexceptions(   t   construct_urlt   parse_formvars(   t   HTMLTemplatet   bunchss  
<html>
 <head>
  <style type="text/css">
   body {
     font-family: sans-serif;
   }
   table.environ tr td {
     border-bottom: #bbb 1px solid;
   }
   table.environ tr td.bottom {
     border-bottom: none;
   }
   table.thread {
     border: 1px solid #000;
     margin-bottom: 1em;
   }
   table.thread tr td {
     border-bottom: #999 1px solid;
     padding-right: 1em;
   }
   table.thread tr td.bottom {
     border-bottom: none;
   }
   table.thread tr.this_thread td {
     background-color: #006;
     color: #fff;
   }
   a.button {
     background-color: #ddd;
     border: #aaa outset 2px;
     text-decoration: none;
     margin-top: 10px;
     font-size: 80%;
     color: #000;
   }
   a.button:hover {
     background-color: #eee;
     border: #bbb outset 2px;
   }
   a.button:active {
     border: #bbb inset 2px;
   }
  </style>
  <title>{{title}}</title>
 </head>
 <body>
  <h1>{{title}}</h1>
  {{if kill_thread_id}}
  <div style="background-color: #060; color: #fff;
              border: 2px solid #000;">
  Thread {{kill_thread_id}} killed
  </div>
  {{endif}}
  <div>Pool size: {{nworkers}}
       {{if actual_workers > nworkers}}
         + {{actual_workers-nworkers}} extra
       {{endif}}
       ({{nworkers_used}} used including current request)<br>
       idle: {{len(track_threads["idle"])}},
       busy: {{len(track_threads["busy"])}},
       hung: {{len(track_threads["hung"])}},
       dying: {{len(track_threads["dying"])}},
       zombie: {{len(track_threads["zombie"])}}</div>

{{for thread in threads}}

<table class="thread">
 <tr {{if thread.thread_id == this_thread_id}}class="this_thread"{{endif}}>
  <td>
   <b>Thread</b>
   {{if thread.thread_id == this_thread_id}}
   (<i>this</i> request)
   {{endif}}</td>
  <td>
   <b>{{thread.thread_id}}
    {{if allow_kill}}
    <form action="{{script_name}}/kill" method="POST"
          style="display: inline">
      <input type="hidden" name="thread_id" value="{{thread.thread_id}}">
      <input type="submit" value="kill">
    </form>
    {{endif}}
   </b>
  </td>
 </tr>
 <tr>
  <td>Time processing request</td>
  <td>{{thread.time_html|html}}</td>
 </tr>
 <tr>
  <td>URI</td>
  <td>{{if thread.uri == 'unknown'}}
      unknown
      {{else}}<a href="{{thread.uri}}">{{thread.uri_short}}</a>
      {{endif}}
  </td>
 <tr>
  <td colspan="2" class="bottom">
   <a href="#" class="button" style="width: 9em; display: block"
      onclick="
        var el = document.getElementById('environ-{{thread.thread_id}}');
        if (el.style.display) {
            el.style.display = '';
            this.innerHTML = '&#9662; Hide environ';
        } else {
            el.style.display = 'none';
            this.innerHTML = '&#9656; Show environ';
        }
        return false
      ">&#9656; Show environ</a>

   <div id="environ-{{thread.thread_id}}" style="display: none">
    {{if thread.environ:}}
    <table class="environ">
     {{for loop, item in looper(sorted(thread.environ.items()))}}
     {{py:key, value=item}}
     <tr>
      <td {{if loop.last}}class="bottom"{{endif}}>{{key}}</td>
      <td {{if loop.last}}class="bottom"{{endif}}>{{value}}</td>
     </tr>
     {{endfor}}
    </table>
    {{else}}
    Thread is in process of starting
    {{endif}}
   </div>

   {{if thread.traceback}}
   <a href="#" class="button" style="width: 9em; display: block"
      onclick="
        var el = document.getElementById('traceback-{{thread.thread_id}}');
        if (el.style.display) {
            el.style.display = '';
            this.innerHTML = '&#9662; Hide traceback';
        } else {
            el.style.display = 'none';
            this.innerHTML = '&#9656; Show traceback';
        }
        return false
      ">&#9656; Show traceback</a>

    <div id="traceback-{{thread.thread_id}}" style="display: none">
      <pre class="traceback">{{thread.traceback}}</pre>
    </div>
    {{endif}}

  </td>
 </tr>
</table>

{{endfor}}

 </body>
</html>
t   names   watchthreads.page_templatet   WatchThreadsc           B   s5   e  Z d  Z e d „ Z d „  Z d „  Z d „  Z RS(   si  
    Application that watches the threads in ``paste.httpserver``,
    showing the length each thread has been working on a request.

    If allow_kill is true, then you can kill errant threads through
    this application.

    This application can expose private information (specifically in
    the environment, like cookies), so it should be protected.
    c         C   s   | |  _  d  S(   N(   t
   allow_kill(   t   selfR	   (    (    sB   /usr/local/lib/python2.7/dist-packages/paste/debug/watchthreads.pyt   __init__¹   s    c         C   s\   d | k r# | d d g ƒ d g S| j  d ƒ d k rH |  j | | ƒ S|  j | | ƒ Sd  S(	   Ns   paste.httpserver.thread_pools   403 Forbiddens   Content-types
   text/plainsC   You must use the threaded Paste HTTP server to use this applicationt	   PATH_INFOs   /kill(   s   Content-types
   text/plain(   t   gett   killt   show(   R
   t   environt   start_response(    (    sB   /usr/local/lib/python2.7/dist-packages/paste/debug/watchthreads.pyt   __call__¼   s    c         C   s  | d d g ƒ t  | ƒ } | j d ƒ r8 | d } n d  } | d } | j } t j ƒ  } | j j ƒ  } | j d d „  ƒ g  }	 x— | D] \ }
 \ } } t ƒ  } |	 j	 | ƒ | rÌ t
 | ƒ | _ n	 d | _ |
 | _ t | | ƒ | _ t | j ƒ | _ | | _ t |
 ƒ | _ qŒ Wt j d	 d
 d | d t | j ƒ d t | ƒ d | d d | d |  j d |	 d t ƒ  d | j ƒ  ƒ 
} | g S(   Ns   200 OKs   Content-types	   text/htmlR   s   paste.httpserver.thread_poolt   keyc         S   s   |  d d S(   Ni   i    (    (   t   v(    (    sB   /usr/local/lib/python2.7/dist-packages/paste/debug/watchthreads.pyt   <lambda>Ò   t    t   unknownt   titles   Thread Pool Worker Trackert   nworkerst   actual_workerst   nworkers_usedt   script_namet   SCRIPT_NAMEt   kill_thread_idR	   t   threadst   this_thread_idt   track_threads(   s   Content-types	   text/html(   R   R   t   NoneR   t   timet   worker_trackert   itemst   sortR   t   appendR   t   urit	   thread_idt   format_timet	   time_htmlt   shortent	   uri_shortR   t   traceback_threadt	   tracebackt   page_templatet
   substitutet   lent   workersR	   R   R!   (   R
   R   R   t   formR   t   thread_poolR   t   nowR3   R   R)   t   time_startedt   worker_environt   threadt   page(    (    sB   /usr/local/lib/python2.7/dist-packages/paste/debug/watchthreads.pyR   Å   sD    
						
		c         C   sÇ   |  j  s% t j d ƒ } | | | ƒ St | ƒ } t | d ƒ } | d } | | j k rz t j d | ƒ } | | | ƒ S| j | ƒ | d p” d } t j d d | d	 | f g ƒ } | | | ƒ S(
   Ns?   Killing threads has not been enabled.  Shame on you for trying!R)   s   paste.httpserver.thread_poolsB   You tried to kill thread %s, but it is not working on any requestsR   t   /t   headerst   Locations   ?kill=%s(	   R	   R   t   HTTPForbiddenR   t   intR$   t   PreconditionFailedt   kill_workert	   HTTPFound(   R
   R   R   t   exct   varsR)   R5   R   (    (    sB   /usr/local/lib/python2.7/dist-packages/paste/debug/watchthreads.pyR   ï   s"    		

	(   t   __name__t
   __module__t   __doc__t   FalseR   R   R   R   (    (    (    sB   /usr/local/lib/python2.7/dist-packages/paste/debug/watchthreads.pyR   ¬   s
   			*c         C   s_   t  t d ƒ s d St j ƒ  } |  | k r/ d S| |  } t ƒ  } t j | d | ƒ| j ƒ  S(   sf   
    Returns a plain-text traceback of the given thread, or None if it
    can't get a traceback.
    t   _current_framest   fileN(   t   hasattrt   sysR"   RI   R    R/   t   print_stackt   getvalue(   R)   t   framest   framet   out(    (    sB   /usr/local/lib/python2.7/dist-packages/paste/debug/watchthreads.pyR.     s    
	s   paste.httpserver.thread_poolc      	   C   s  |  d  k r" t j d d d d ƒ Sg  } xÜ t |  j ƒ  ƒ D]È \ } } | t k rY q; n  yb | j ƒ  | k r} t | ƒ } n  | j t j d t	 j
 t | ƒ ƒ d t	 j
 t | ƒ ƒ ƒ ƒ Wq; t k
 r} | j t j d t	 j
 t | ƒ ƒ d d | ƒ ƒ q; Xq; Wd j | ƒ S(   NR   s   ---t   values-   No environment registered for this thread yets    Error in <code>repr()</code>: %sR   (   R"   t   environ_templateR1   t   sortedR%   t	   hide_keyst   uppert   reprR'   t   cgit   escapet   strt	   Exceptiont   join(   R   t   environ_rowsR   RR   t   e(    (    sB   /usr/local/lib/python2.7/dist-packages/paste/debug/watchthreads.pyt   format_environ  s*    			c         C   sÛ   |  d k rB d t  |  d d ƒ t  |  d ƒ d |  d f } ni |  d k ro d t  |  d ƒ |  d f } n< |  d k rˆ d |  } n# |  d k r¡ d |  } n
 d |  } |  d	 k  r» | S|  d k  rÏ d
 | Sd | Sd  S(   Ni<   s   %i:%02i:%02iix   s   %i:%02is   %i seci   s	   %0.1f secs	   %0.2f seci   s#   <span style="color: #900">%s</span>s;   <span style="background-color: #600; color: #fff">%s</span>i  (   R?   (   t   time_lengtht   time_string(    (    sB   /usr/local/lib/python2.7/dist-packages/paste/debug/watchthreads.pyR*   ,  s"    
c         C   s.   t  |  ƒ d k r& |  d  d |  d S|  Sd  S(   Ni<   i(   s   ...iöÿÿÿ(   R2   (   t   s(    (    sB   /usr/local/lib/python2.7/dist-packages/paste/debug/watchthreads.pyR,   B  s    c         C   s#   d d l  m } t d | | ƒ ƒ S(   Niÿÿÿÿ(   t   asboolR	   (   t   paste.deploy.convertersRc   R   (   t   global_confR	   Rc   (    (    sB   /usr/local/lib/python2.7/dist-packages/paste/debug/watchthreads.pyt   make_watch_threadsH  s    i    c            s   t  ˆ  ƒ ‰  ‡  f d †  } | S(   Nc            sv   d d  l  } ˆ  r" t j ˆ  ƒ n9 d } x0 d | | j ƒ  f GHt j d ƒ | d 7} q+ W| d d
 g ƒ d	 ˆ  g S(   Niÿÿÿÿi    s   I'm alive %s (%s)i
   i   s   200 OKs   content-types
   text/plains   OK, paused %s seconds(   s   content-types
   text/plain(   R9   R#   t   sleepR   (   R   R   R9   t   count(   t   pause(    sB   /usr/local/lib/python2.7/dist-packages/paste/debug/watchthreads.pyt   bad_appO  s    (   R?   (   Re   Ri   Rj   (    (   Ri   sB   /usr/local/lib/python2.7/dist-packages/paste/debug/watchthreads.pyt   make_bad_appM  s    (   RG   RL   RX   R#   R/   t	   cStringIOR    R9   R   t   pasteR   t   paste.requestR   R   t   paste.util.templateR   R   R0   t   objectR   R.   RU   R_   R*   R,   RH   Rf   Rk   (    (    (    sB   /usr/local/lib/python2.7/dist-packages/paste/debug/watchthreads.pyt   <module>   s(   ›W					