web/views/debug.py
changeset 11057 0b59724cb3f2
parent 11052 058bb3dc685f
child 11058 23eb30449fe5
equal deleted inserted replaced
11052:058bb3dc685f 11057:0b59724cb3f2
     1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     3 #
       
     4 # This file is part of CubicWeb.
       
     5 #
       
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
       
     7 # terms of the GNU Lesser General Public License as published by the Free
       
     8 # Software Foundation, either version 2.1 of the License, or (at your option)
       
     9 # any later version.
       
    10 #
       
    11 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT
       
    12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
       
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
       
    14 # details.
       
    15 #
       
    16 # You should have received a copy of the GNU Lesser General Public License along
       
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
       
    18 """management and error screens"""
       
    19 
       
    20 __docformat__ = "restructuredtext en"
       
    21 from cubicweb import _
       
    22 
       
    23 from time import strftime, localtime
       
    24 
       
    25 from six import text_type
       
    26 
       
    27 from logilab.mtconverter import xml_escape
       
    28 
       
    29 from cubicweb.predicates import none_rset, match_user_groups
       
    30 from cubicweb.view import StartupView
       
    31 from cubicweb.web.views import actions, tabs
       
    32 
       
    33 def dict_to_html(w, dict):
       
    34     # XHTML doesn't allow emtpy <ul> nodes
       
    35     if dict:
       
    36         w(u'<ul>')
       
    37         for key in sorted(dict):
       
    38             w(u'<li><span>%s</span>: <span>%s</span></li>' % (
       
    39                 xml_escape(str(key)), xml_escape(repr(dict[key]))))
       
    40         w(u'</ul>')
       
    41 
       
    42 
       
    43 class SiteInfoAction(actions.ManagersAction):
       
    44     __regid__ = 'siteinfo'
       
    45     __select__ = match_user_groups('users','managers')
       
    46     title = _('Site information')
       
    47     category = 'manage'
       
    48     order = 1000
       
    49 
       
    50 
       
    51 class SiteInfoView(tabs.TabsMixin, StartupView):
       
    52     __regid__ = 'siteinfo'
       
    53     title = _('Site information')
       
    54     tabs = [_('info'), _('registry'), _('gc')]
       
    55     default_tab = 'info'
       
    56 
       
    57     def call(self, **kwargs):
       
    58         """The default view representing the instance's management"""
       
    59         self.w(u'<h1>%s</h1>' % self._cw._(self.title))
       
    60         self.render_tabs(self.tabs, self.default_tab)
       
    61 
       
    62 
       
    63 class ProcessInformationView(StartupView):
       
    64     """display various web server /repository information"""
       
    65     __regid__ = 'info'
       
    66     __select__ = none_rset() & match_user_groups('managers', 'users')
       
    67 
       
    68     title = _('server information')
       
    69     cache_max_age = 0
       
    70 
       
    71     def call(self, **kwargs):
       
    72         req = self._cw
       
    73         dtformat = req.property_value('ui.datetime-format')
       
    74         _ = req._
       
    75         w = self.w
       
    76         repo = req.cnx.repo
       
    77         # generic instance information
       
    78         w(u'<h2>%s</h2>' % _('Instance'))
       
    79         pyvalue = ((_('config type'), self._cw.vreg.config.name),
       
    80                    (_('config mode'), self._cw.vreg.config.mode),
       
    81                    (_('instance home'), self._cw.vreg.config.apphome))
       
    82         self.wview('pyvaltable', pyvalue=pyvalue, header_column_idx=0)
       
    83         vcconf = repo.get_versions()
       
    84         w(u'<h3>%s</h3>' % _('versions configuration'))
       
    85         missing = _('no version information')
       
    86         pyvalue = [('CubicWeb', vcconf.get('cubicweb', missing))]
       
    87         pyvalue += [(cube, vcconf.get(cube, missing))
       
    88                     for cube in sorted(self._cw.vreg.config.cubes())]
       
    89         self.wview('pyvaltable', pyvalue=pyvalue, header_column_idx=0)
       
    90         # repository information
       
    91         w(u'<h2>%s</h2>' % _('Repository'))
       
    92         w(u'<h3>%s</h3>' % _('resources usage'))
       
    93         stats = self._cw.call_service('repo_stats')
       
    94         stats['looping_tasks'] = ', '.join('%s (%s seconds)' % (n, i) for n, i in stats['looping_tasks'])
       
    95         stats['threads'] = ', '.join(sorted(stats['threads']))
       
    96         for k in stats:
       
    97             if k in ('extid_cache_size', 'type_source_cache_size'):
       
    98                 continue
       
    99             if k.endswith('_cache_size'):
       
   100                 stats[k] = '%s / %s' % (stats[k]['size'], stats[k]['maxsize'])
       
   101         def format_stat(sname, sval):
       
   102             return '%s %s' % (xml_escape(text_type(sval)),
       
   103                               sname.endswith('percent') and '%' or '')
       
   104         pyvalue = [(sname, format_stat(sname, sval))
       
   105                     for sname, sval in sorted(stats.items())]
       
   106         self.wview('pyvaltable', pyvalue=pyvalue, header_column_idx=0)
       
   107         # open repo sessions
       
   108         if req.cnx.is_repo_in_memory and req.user.is_in_group('managers'):
       
   109             w(u'<h3>%s</h3>' % _('opened sessions'))
       
   110             sessions = repo._sessions.values()
       
   111             if sessions:
       
   112                 w(u'<ul>')
       
   113                 for session in sessions:
       
   114                     w(u'<li>%s (%s: %s)<br/>' % (
       
   115                         xml_escape(text_type(session)),
       
   116                         _('last usage'),
       
   117                         strftime(dtformat, localtime(session.timestamp))))
       
   118                     dict_to_html(w, session.data)
       
   119                     w(u'</li>')
       
   120                 w(u'</ul>')
       
   121             else:
       
   122                 w(u'<p>%s</p>' % _('no repository sessions found'))
       
   123         # web server information
       
   124         w(u'<h2>%s</h2>' % _('Web server'))
       
   125         pyvalue = ((_('base url'), req.base_url()),
       
   126                    (_('data directory url'), req.datadir_url))
       
   127         self.wview('pyvaltable', pyvalue=pyvalue, header_column_idx=0)
       
   128         from cubicweb.web.application import SESSION_MANAGER
       
   129         if SESSION_MANAGER is not None and req.user.is_in_group('managers'):
       
   130             sessions = SESSION_MANAGER.current_sessions()
       
   131             w(u'<h3>%s</h3>' % _('opened web sessions'))
       
   132             if sessions:
       
   133                 w(u'<ul>')
       
   134                 for session in sessions:
       
   135                     last_usage_time = session.mtime
       
   136                     w(u'<li>%s (%s: %s)<br/>' % (
       
   137                         session.sessionid,
       
   138                         _('last usage'),
       
   139                         strftime(dtformat, localtime(last_usage_time))))
       
   140                     dict_to_html(w, session.data)
       
   141                     w(u'</li>')
       
   142                 w(u'</ul>')
       
   143             else:
       
   144                 w(u'<p>%s</p>' % _('no web sessions found'))
       
   145 
       
   146 
       
   147 
       
   148 class RegistryView(StartupView):
       
   149     """display vregistry content"""
       
   150     __regid__ = 'registry'
       
   151     __select__ = StartupView.__select__ & match_user_groups('managers')
       
   152     title = _('registry')
       
   153     cache_max_age = 0
       
   154 
       
   155     def call(self, **kwargs):
       
   156         self.w(u'<h2>%s</h2>' % self._cw._("Registry's content"))
       
   157         keys = sorted(self._cw.vreg)
       
   158         url = xml_escape(self._cw.url())
       
   159         self.w(u'<p>%s</p>\n' % ' - '.join('<a href="%s#%s">%s</a>'
       
   160                                            % (url, key, key) for key in keys))
       
   161         for key in keys:
       
   162             if key in ('boxes', 'contentnavigation'): # those are bw compat registries
       
   163                 continue
       
   164             self.w(u'<h3 id="%s">%s</h3>' % (key, key))
       
   165             if self._cw.vreg[key]:
       
   166                 values = sorted(self._cw.vreg[key].items())
       
   167                 self.wview('pyvaltable', pyvalue=[(key, xml_escape(repr(val)))
       
   168                                                   for key, val in values])
       
   169             else:
       
   170                 self.w(u'<p>Empty</p>\n')
       
   171 
       
   172 
       
   173 class GCView(StartupView):
       
   174     """display garbage collector information"""
       
   175     __regid__ = 'gc'
       
   176     __select__ = StartupView.__select__ & match_user_groups('managers')
       
   177     title = _('memory leak debugging')
       
   178     cache_max_age = 0
       
   179 
       
   180     def call(self, **kwargs):
       
   181         stats = self._cw.call_service('repo_gc_stats')
       
   182         self.w(u'<h2>%s</h2>' % _('Garbage collection information'))
       
   183         self.w(u'<h3>%s</h3>' % self._cw._('Looked up classes'))
       
   184         self.wview('pyvaltable', pyvalue=stats['lookupclasses'])
       
   185         self.w(u'<h3>%s</h3>' % self._cw._('Most referenced classes'))
       
   186         self.wview('pyvaltable', pyvalue=stats['referenced'])
       
   187         if stats['unreachable']:
       
   188             self.w(u'<h3>%s</h3>' % self._cw._('Unreachable objects'))
       
   189             values = [xml_escape(val) for val in stats['unreachable']]
       
   190             self.wview('pyvallist', pyvalue=values)