2010-07-10 14 views
13

Mi rendo conto che si tratta di un problema di pollo e uova e che non è possibile risolvere con precisione il tempo necessario per il rendering di una pagina (o la dimensione della risposta) e inserirlo nella pagina stessa senza influire su nessuna misura. Tuttavia, sto cercando un modo per inserire entrambi i numeri parzialmente in una pagina di un'applicazione JSF/Facelets/Seam.Come inserire il tempo di rendering della pagina JSF e la dimensione della risposta nella pagina stessa, almeno in parte?

esempio in fondo a una pagina JSF da qualche parte:

<!-- page size: 10.3Kb --> 
<!-- render time: 0.2s --> 

ho incontrato JSFUnit di JSFTimer, che è davvero a portata di mano. Tuttavia, l'approccio dell'ascoltatore di fase non consente di inserire i risultati della fase RENDER_RESPONSE nella pagina. Non sai come accedere alla dimensione della risposta codificata finora.

C'è un modo rapido e sporco per collegarsi a una sorta di evento di post-elaborazione alla fine di RENDER_RESPONSE o per iniettare entrambi i numeri nella pagina che deve essere visualizzata? Un modo per approcciare questo è forse attraverso i filtri servlet, ma sto cercando qualcosa di più semplice; forse un trucco con Seam o Facelets ...

Grazie,
-A

risposta

22

Questo è un caso d'uso perfetto per il Apache Commons IOCountingOutputStream. È necessario creare un Filter che utilizzi HttpServletResponseWrapper per sostituire lo OutputStream della risposta con questo e sostituisca anche lo Writer che dovrebbe avvolgere l'involucro OutputStream. Quindi acquisire l'istanza HttpServletResponseWrapper nell'ambito della richiesta in modo da poter ottenere getByteCount() da CountingOutputStream.

Ecco un esempio calcio d'inizio della CountingFilter:

public class CountingFilter implements Filter { 

    @Override 
    public void init(FilterConfig arg0) throws ServletException { 
     // NOOP. 
    } 

    @Override 
    public void doFilter(ServletRequest request, final ServletResponse response, FilterChain chain) throws IOException, ServletException { 
     HttpServletResponse httpres = (HttpServletResponse) response; 
     CountingServletResponse counter = new CountingServletResponse(httpres); 
     HttpServletRequest httpreq = (HttpServletRequest) request; 
     httpreq.setAttribute("counter", counter); 
     chain.doFilter(request, counter); 
     counter.flushBuffer(); // Push the last bits containing HTML comment. 
    } 

    @Override 
    public void destroy() { 
     // NOOP. 
    } 

} 

Il CountingServletResponse:

public class CountingServletResponse extends HttpServletResponseWrapper { 

    private final long startTime; 
    private final CountingServletOutputStream output; 
    private final PrintWriter writer; 

    public CountingServletResponse(HttpServletResponse response) throws IOException { 
     super(response); 
     startTime = System.nanoTime(); 
     output = new CountingServletOutputStream(response.getOutputStream()); 
     writer = new PrintWriter(output, true); 
    } 

    @Override 
    public ServletOutputStream getOutputStream() throws IOException { 
     return output; 
    } 

    @Override 
    public PrintWriter getWriter() throws IOException { 
     return writer; 
    } 

    @Override 
    public void flushBuffer() throws IOException { 
     writer.flush(); 
    } 

    public long getElapsedTime() { 
     return System.nanoTime() - startTime; 
    } 

    public long getByteCount() throws IOException { 
     flushBuffer(); // Ensure that all bytes are written at this point. 
     return output.getByteCount(); 
    } 

} 

Il CountingServletOutputStream:

public class CountingServletOutputStream extends ServletOutputStream { 

    private final CountingOutputStream output; 

    public CountingServletOutputStream(ServletOutputStream output) { 
     this.output = new CountingOutputStream(output); 
    } 

    @Override 
    public void write(int b) throws IOException { 
     output.write(b); 
    } 

    @Override 
    public void flush() throws IOException { 
     output.flush(); 
    } 

    public long getByteCount() { 
     return output.getByteCount(); 
    } 

} 

è possibile utilizzarlo in qualsiasi (anche non-JSF pagina come segue:

<!DOCTYPE html> 
<html 
    xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:h="http://java.sun.com/jsf/html"> 
    <h:head> 
     <title>Counting demo</title> 
    </h:head> 
    <h:body> 
     <h1>Hello World</h1> 
    </h:body> 
</html> 
<!-- page size: #{counter.byteCount/1000}KB --> 
<!-- render time: #{counter.elapsedTime/1000000}ms --> 
+0

Per quanto volessi evitare i filtri, questo sembra l'approccio migliore. Grazie per il suggerimento! Ecco alcune cose da tenere a mente: 1) con Seam, i filtri sono piuttosto facili da configurare con annotazioni, ad esempio: @Scope (APPLICATION) @Name ("org.myorg.countingFilter") @BypassInterceptors @Filter (circa = "org.jboss.seam.web.ajax4jsfFilter") CountingFilter 2) a causa di problemi di pollo/uova annotati sopra i numeri non sono completamente accurati. Sotto JSF, ViewState viene escluso dal byteCount, che può essere un numero significativo. Lo stesso vale per il rendering del tempo. Entrambi sono abbastanza buoni per un'immagine approssimativa però. – anikitin

+0

Ancora cose fantastiche. Tuttavia, ho diverse richieste di postback, che generano diverse risposte. Come trovo la risposta corretta, cioè quella che intendevo per profilo? – Kawu

+0

@Kawu: modifica il pattern URL del filtro in modo che venga eseguito solo sugli URL desiderati. – BalusC

0

o avere un asincrono JavaScript chiamata che ottiene il tempo di risposta e la dimensione dal server dopo la sua pronta? Tratta come una richiamata da eseguire dopo che la pagina è stata caricata e i valori sono pronti per essere inseriti.

2

Ho scritto un post sul blog che spiega come è possibile creare un Interceptor che misura ogni metodo chiama il punto di giuntura dove si utilizza.

È possibile trovare il post del blog here. È necessario scorrere verso il basso fino alla seconda parte.

In sostanza, tutto quello che dovete fare è annotare il metodo che si vuole misurare con @MeasureCalls e che verrà automaticamente prelevato dal intercettore

@Name("fooBean") 
@MeasureCalls 
public class FooBean 

Un'uscita sarebbe qualcosa di simile, che mostra il tempo ci sono voluti in millisecondi e quante volte è stato chiamato ogni metodo:

284.94 ms 1 FooBean.getRandomDroplets() 
284.56 ms 1 GahBean.getRandomDroplets() 
201.60 ms 2 SohBean.searchRatedDoodlesWithinHead() 
185.94 ms 1 FroBean.doSearchPopular() 
157.63 ms 1 FroBean.doSearchRecent() 
42.34 ms 1 FooBean.fetchMostRecentYodel() 
41.94 ms 1 GahBean.getMostRecentYodel() 
15.89 ms 1 FooBean.getNoOfYodels() 
15.00 ms 1 GahBean.getNoOfYodels() 
    9.14 ms 1 SohBean.mainYodels() 
    1.11 ms 2 SohBean.trackHoorayEvent() 
    0.32 ms 1 FroBean.reset() 
    0.22 ms 43 NohBean.thumbPicture() 
    0.03 ms 18 FooBean.getMostRecentYodels() 
    0.01 ms 1 NohBean.profilePicture() 
    0.01 ms 1 FroBean.setToDefault() 
    0.01 ms 1 FroBean.getRecentMarker() 
+0

404 pagina non trovata. – BalusC

+0

Grazie a @BalusC, collegamento aggiornato –

+0

Sembra utile. Suggerimento per il tuo 'toString()': c'è un 'Class # getSimpleName()' e 'String # format()'. – BalusC

Problemi correlati