Changeset 1073

Show
Ignore:
Timestamp:
06/07/08 19:37:37 (3 months ago)
Author:
kris
Message:

adjusted exception handling, and added metrics support to Servlet

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/mango/net/servlet/Servlet.d

    r1069 r1073  
    1515private import  tango.time.Time; 
    1616 
     17private import  tango.time.StopWatch; 
     18 
    1719public  import  tango.util.log.Log; 
    1820 
     
    5052        /********************************************************************** 
    5153 
     54                Servlet metrics 
     55 
     56        **********************************************************************/ 
     57 
     58        struct Metrics 
     59        { 
     60                char[]  name; 
     61                double  time = 0, 
     62                        average = 0, 
     63                        average2 = 0, 
     64                        average4 = 0, 
     65                        average8 = 0; 
     66                ulong   requests = 0, 
     67                        failures = 0; 
     68                          
     69 
     70                void update (double time) 
     71                { 
     72                        ++requests; 
     73                        this.time = time; 
     74                        average2 = (average2 + time) / 2.0; 
     75                        average4 = (average4 + average2) / 2.0; 
     76                        average8 = (average8 + average4) / 2.0; 
     77                        average  = (average  + average8) / 2.0; 
     78                } 
     79        } 
     80 
     81        /********************************************************************** 
     82 
    5283                Init is called when the servlet is first registered. 
    5384 
     
    5687        void init (ServletConfig config) 
    5788        { 
    58         } 
    59  
    60         /********************************************************************** 
    61  
    62                 return an optional logger instance 
    63  
    64         **********************************************************************/ 
    65  
    66         Logger logger () 
    67         { 
    68                 return null; 
    6989        } 
    7090} 
     
    80100class MethodServlet : Servlet 
    81101{ 
     102        Logger          log; 
     103        Metrics[]       metrics; 
     104 
     105        private alias void delegate (IServletRequest, IServletResponse) Handler; 
    82106 
    83107        /********************************************************************** 
    84108         
    85                 Default response for unimplemented requests. 
    86  
    87         **********************************************************************/ 
    88  
    89         static private void error (IServletResponse response) 
    90         { 
    91                 response.sendError (HttpResponses.MethodNotAllowed); 
     109 
     110        **********************************************************************/ 
     111 
     112        this (char[] log = null) 
     113        {        
     114                if (log.length) 
     115                    this.log = Log.lookup (log); 
     116 
     117                metrics = new Metrics [7]; 
     118        } 
     119 
     120        /********************************************************************** 
     121 
     122                return an optional logger instance 
     123 
     124        **********************************************************************/ 
     125 
     126        Logger logger () 
     127        { 
     128                return log; 
    92129        } 
    93130 
     
    220257        void service (IServletRequest request, IServletResponse response) 
    221258        { 
    222                 char[] method = request.method; 
     259                StopWatch       timer; 
     260                Metrics*        metric; 
     261                Handler         handler; 
     262                char[]          method = request.method; 
     263 
     264                // begin timer 
     265                timer.start; 
    223266 
    224267                switch (method[0]) 
    225268                       { 
    226269                       case 'G': 
    227                             get (request, response); 
     270                            handler = &get; 
     271                            metric = &metrics [0]; 
    228272                            break; 
    229273 
    230274                       case 'H': 
    231                             doHead (request, response); 
     275                            handler = &doHead; 
     276                            metric = &metrics [1]; 
    232277                            break; 
    233278 
    234279                       case 'O': 
    235                             doOptions (request, response); 
     280                            handler = &doOptions; 
     281                            metric = &metrics [2]; 
    236282                            break; 
    237283 
    238284                       case 'T': 
    239                             doTrace (request, response); 
     285                            handler = &doTrace; 
     286                            metric = &metrics [3]; 
    240287                            break; 
    241288 
    242289                       case 'D': 
    243                             doDelete (request, response); 
     290                            handler = &doDelete; 
     291                            metric = &metrics [4]; 
    244292                            break; 
    245293 
    246294                       case 'P': 
    247295                            if (method[1] == 'O') 
    248                                 doPost (request, response); 
     296                               { 
     297                               handler = &doPost; 
     298                               metric = &metrics [5]; 
     299                               } 
    249300                            else 
    250                                doPut (request, response); 
     301                               { 
     302                               handler = &doPut; 
     303                               metric = &metrics [6]; 
     304                               } 
    251305                            break; 
    252306 
     
    255309                            break; 
    256310                       } 
     311 
     312                // log execution time 
     313                auto log = logger; 
     314                try { 
     315                    // invoke handler 
     316                    handler (request, response); 
     317                     
     318                    // update metrics 
     319                    metric.update (timer.stop); 
     320 
     321                    if (log) 
     322                        log.trace (Log.format() ("{} {}, {} failures, {} requests, average {}us",  
     323                                   method, request.path, metric.failures, metric.requests,  
     324                                   metric.average * 1_000_000)); 
     325 
     326                    } catch (Exception e) 
     327                            { 
     328                            ++metric.failures; 
     329                            if (log) 
     330                                log.error (Log.format() ("{} {}, {} failures: {}",  
     331                                           method, request.path, metric.failures, e)); 
     332                            throw e; 
     333                            } 
     334 
     335        } 
     336 
     337        /********************************************************************** 
     338         
     339                Default response for unimplemented requests. 
     340 
     341        **********************************************************************/ 
     342 
     343        private static void error (IServletResponse response) 
     344        { 
     345                response.sendError (HttpResponses.MethodNotAllowed); 
    257346        } 
    258347} 
    259348 
    260349 
    261 /****************************************************************************** 
    262  
    263         This class is intended to be compatible with a Java GenericServlet. 
    264         Note that the ServletContext is available from the ServletRequest 
    265         class, so this error-prone approach of accessing context via the 
    266         configuration is rendered totally redundant. 
    267  
    268 ******************************************************************************/ 
    269  
    270 class CompatibleServlet : MethodServlet 
    271 
    272         private ServletConfig config; 
    273  
    274         /********************************************************************** 
    275  
    276                 Servlet must implement the init() method 
    277  
    278         **********************************************************************/ 
    279  
    280         abstract void init (); 
    281  
    282         /********************************************************************** 
    283  
    284                 Optional init() with ServletConfig passed to it. 
    285  
    286         **********************************************************************/ 
    287  
    288         void init (ServletConfig config) 
    289         { 
    290                 this.config = config; 
    291                 init (); 
    292         } 
    293  
    294         /********************************************************************** 
    295  
    296                 Return the configuration passed with init() 
    297  
    298         **********************************************************************/ 
    299  
    300         ServletConfig getConfig () 
    301         { 
    302                 return config; 
    303         } 
    304 
    305  
    306  
     350 
  • trunk/mango/net/servlet/ServletProvider.d

    r1069 r1073  
    1616 
    1717private import  tango.util.log.Log; 
    18  
    19 private import  tango.time.StopWatch; 
    2018 
    2119private import  tango.text.Regex, 
     
    384382                PathMapping             pm; 
    385383                char[]                  path; 
    386                 StopWatch               timer; 
    387384                ServletRequest          request; 
    388385                ServletResponse         response; 
    389386                bool                    addToCache; 
    390387         
    391                 // begin timer 
    392                 timer.start; 
    393  
    394388                // we know what these are since we created them (above) 
    395389                request = cast(ServletRequest) req; 
     
    423417 
    424418                    // execute servlet 
    425                     auto servlet = pm.mapping.proxy.getServlet; 
    426                     servlet.service (request, response); 
    427          
    428                     // log execution time 
    429                     auto log = servlet.logger; 
    430                     if (log) 
    431                         log.info (Log.format() ("took {}us", timer.microsec)); 
    432  
     419                    pm.mapping.proxy.getServlet.service (request, response); 
     420         
    433421                    // flush output on behalf of servlet ... 
    434422                    response.flush; 
     
    438426                        cache.put (pm.path, pm); 
    439427 
    440                     } catch (UnavailableException ux) 
    441                              response.sendError (HttpResponses.ServiceUnavailable, ux.toString); 
    442  
    443                       catch (ServletException sx) 
    444                              error (response, sx); 
    445  
    446                       catch (Object ex) 
    447                              error (response, ex); 
    448         } 
    449  
    450         /********************************************************************** 
    451  
    452                 handle internal errors 
    453  
    454         **********************************************************************/ 
    455  
    456         private void error (ServletResponse response, Object x) 
    457         { 
    458                 response.sendError (HttpResponses.InternalServerError, x.toString); 
    459                 getDefaultContext.log ("Internal error:", x); 
     428                    } catch (ServletException sx) 
     429                             response.sendError (HttpResponses.ServiceUnavailable, "please retry"); 
     430 
     431                      catch (Object o) 
     432                            { 
     433                            response.sendError (HttpResponses.InternalServerError, o.toString); 
     434                            getDefaultContext.log ("Internal exception: ", o); 
     435                            } 
    460436        } 
    461437}