关于页面加载时间测量的想法

Ale*_*rov 4 jsf jsf-2

问题是 - 你如何衡量页面加载的时间,你使用的技术,你可以提供哪些推荐,以及你有什么积极和消极的经验.

麻烦的是,即使是jsf中的轻页也可能需要10秒才能加载.这些页面不需要任何评估,渲染资源等.显而易见的答案 - 它在渲染队列中......好吧,但可能是其他的东西?

似乎需要从请求开始测量时间,包括渲染,评估,数据传输时间,客户端渲染时间等.

您是否有任何良好的工作方式,工具链,工具,可以在JSF中查看页面的完整生命周期时间?

使用Glassfish-3,JSF-2.机器有64个CPU.

Ale*_*oie 6

这是我刚刚制作和测试的一个简单的自定义解决方案.它提供了一些执行和渲染时间的统计信息.当然,所有信息仅来自服务器端处理.

结果示例:

Date                     ID request  URL                                  Phase              Execution time
2013-05-16 21:10:29.781  34          http://localhost:8080/web/page.jspx  RESTORE_VIEW 1     15
2013-05-16 21:10:29.796  34          http://localhost:8080/web/page.jspx  RENDER_RESPONSE 6  4438
2013-05-16 21:10:39.437  35          http://localhost:8080/web/page.jspx  RESTORE_VIEW 1     16
2013-05-16 21:10:39.453  35          http://localhost:8080/web/page.jspx  RENDER_RESPONSE 6  3937
Run Code Online (Sandbox Code Playgroud)

实施非常紧张.首先,你要在里面配置一个PhaseListenerfaces-config.xml

<lifecycle>
    <phase-listener>com.spectotechnologies.jsf.phaselisteners.PhaseProcessesAnalyserListener</phase-listener>
</lifecycle>
Run Code Online (Sandbox Code Playgroud)

这是帮助程序类,它保存有关每个处理的信息:

package com.spectotechnologies.website.common.helper;

import java.util.Date;
import javax.faces.event.PhaseId;

/**
 *
 * @author Alexandre Lavoie
 */
public class PhaseProcess
{
    private int m_nIDRequest;
    private String m_sURL;
    private Date m_oStart;
    private Date m_oEnd;
    private PhaseId m_oPhase;

    public void setIdRequest(int p_nIDRequest)
    {
        m_nIDRequest = p_nIDRequest;
    }

    public int getIdRequest()
    {
        return m_nIDRequest;
    }

    public void setUrl(String p_sURL)
    {
        m_sURL = p_sURL;
    }

    public String getUrl()
    {
        return m_sURL;
    }

    public void setStart(Date p_oStart)
    {
        m_oStart = p_oStart;
    }

    public Date getStart()
    {
        return m_oStart;
    }

    public void setEnd(Date p_oEnd)
    {
        m_oEnd = p_oEnd;
    }

    public Date getEnd()
    {
        return m_oEnd;
    }

    public void setPhase(PhaseId p_oPhase)
    {
        m_oPhase = p_oPhase;
    }

    public PhaseId getPhase()
    {
        return m_oPhase;
    }

    public long getExecutionTime()
    {
        long lExecutionTime = -1;

        if(getEnd() != null)
        {
            lExecutionTime = getEnd().getTime() - getStart().getTime();
        }

        return lExecutionTime;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是具有业务逻辑的类,请注意,目前统计数据只会增长并且永远不会被删除,因此可能是一个很好的更新,例如仅保留最后一小时:

package com.spectotechnologies.website.common.helper;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseId;

/**
 *
 * @author Alexandre Lavoie
 */
public class PhaseProcesses
{
    private List<PhaseProcess> m_lItems = new ArrayList();
    private int m_nNextIDRequest = 0;

    public static PhaseProcesses getInstance()
    {
        FacesContext oFaces = FacesContext.getCurrentInstance();

        PhaseProcesses oPhaseProcesses = (PhaseProcesses)oFaces.getExternalContext().getSessionMap().get("sessionPhaseProcesses");

        if(oPhaseProcesses == null)
        {
            oPhaseProcesses = new PhaseProcesses();

            FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("sessionPhaseProcesses",oPhaseProcesses);
        }

        return oPhaseProcesses;
    }

    public void set(int p_nIDRequest, String p_sURL, PhaseId p_oPhase, int p_nType)
    {
        PhaseProcess oPhaseProcess;

        // Phase start
        switch(p_nType)
        {
            case 0:
                // start
                oPhaseProcess = new PhaseProcess();

                oPhaseProcess.setIdRequest(p_nIDRequest);
                oPhaseProcess.setUrl(p_sURL);
                oPhaseProcess.setPhase(p_oPhase);
                oPhaseProcess.setStart(new Date());

                if(m_lItems.size() > 250)
            {
                m_lItems.remove(0);
            }

                m_lItems.add(oPhaseProcess);
                break;
            case 1:
                // end
                for(int nPhase = m_lItems.size() - 1;nPhase >= 0;nPhase--)
                {
                    if(m_lItems.get(nPhase).getIdRequest() == p_nIDRequest && m_lItems.get(nPhase).getPhase() == p_oPhase)
                    {
                        m_lItems.get(nPhase).setEnd(new Date());
                        break;
                    }
                }
                break;
        }
    }

    public List<PhaseProcess> getList()
    {
        return m_lItems;
    }

    public Integer getNextIDRequest()
    {
        return m_nNextIDRequest++;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是着名的PhaseListener,其中跟踪信息:

package com.spectotechnologies.jsf.phaselisteners;

import com.spectotechnologies.website.common.helper.PhaseProcesses;
import java.net.URLEncoder;
import java.util.Enumeration;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.http.HttpServletRequest;

/**
 *
 * @author Alexandre Lavoie
 */
public class PhaseProcessesAnalyserListener implements PhaseListener
{
    @Override
    public PhaseId getPhaseId()
    {
        return PhaseId.ANY_PHASE;
    }

    @Override
    public void beforePhase(PhaseEvent p_oEvent)
    {
        PhaseProcesses.getInstance().set(getIDRequest(),getURL(),p_oEvent.getPhaseId(),0);
    }

    @Override
    public void afterPhase(PhaseEvent p_oEvent)
    {
        PhaseProcesses.getInstance().set(getIDRequest(),getURL(),p_oEvent.getPhaseId(),1);
    }

    private Integer getIDRequest()
    {
        Integer iIDRequest = (Integer)FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get("idrequest");

        if(iIDRequest == null)
        {
            iIDRequest = PhaseProcesses.getInstance().getNextIDRequest();

            FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("idrequest",iIDRequest);
        }

        return iIDRequest;
    }

    private String getURL()
    {
        Enumeration<String> lParameters;
        String sParameter;
        StringBuilder sbURL = new StringBuilder();
        Object oRequest = FacesContext.getCurrentInstance().getExternalContext().getRequest();

        try
        {
            if(oRequest instanceof HttpServletRequest)
            {
                sbURL.append(((HttpServletRequest)oRequest).getRequestURL().toString());

                lParameters = ((HttpServletRequest)oRequest).getParameterNames();

                if(lParameters.hasMoreElements())
                {
                    if(!sbURL.toString().contains("?"))
                    {
                        sbURL.append("?");
                    }
                    else
                    {
                        sbURL.append("&");
                    }
                }

                while(lParameters.hasMoreElements())
                {
                    sParameter = lParameters.nextElement();

                    sbURL.append(sParameter);
                    sbURL.append("=");
                    sbURL.append(URLEncoder.encode(((HttpServletRequest)oRequest).getParameter(sParameter),"UTF-8"));

                    if(lParameters.hasMoreElements())
                    {
                        sbURL.append("&");
                    }
                }
            }
        }
        catch(Exception e)
        {
            // Do nothing
        }

        return sbURL.toString();
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,这是我创建的用于显示统计信息的简单页面.一个很好的改进可能是在页面处理上添加平均值,也就是每个idrequest处理时间.

Bean代码:

package com.spectotechnologies.website.common.beans;

import com.spectotechnologies.website.common.helper.PhaseProcess;
import com.spectotechnologies.website.common.helper.PhaseProcesses;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;

/**
 *
 * @author Alexandre Lavoie
 */
@ManagedBean
@RequestScoped
public class PagesStatisticsActions
{
    public List<PhaseProcess> getList()
    {
        return PhaseProcesses.getInstance().getList();
    }
}
Run Code Online (Sandbox Code Playgroud)

查看代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core">

    <f:view contentType="application/xhtml+xml">
        <h:head>
            <meta http-equiv="Content-Type" content="application/xhtml+xml;charset=UTF-8" />
        </h:head>

        <h:body>
            <h:dataTable value="#{pagesStatisticsActions.list}" var="item">
                <h:column>
                    <f:facet name="header">
                        Date
                    </f:facet>

                    <h:outputText value="#{item.start}">
                        <f:convertDateTime timeZone="America/Montreal" pattern="yyyy-MM-dd HH:mm:ss.SSS" />
                    </h:outputText>
                </h:column>

                <h:column>
                    <f:facet name="header">
                        ID request
                    </f:facet>

                    #{item.idRequest}
                </h:column>

                <h:column>
                    <f:facet name="header">
                        URL
                    </f:facet>

                    #{item.url}
                </h:column>

                <h:column>
                    <f:facet name="header">
                        Phase
                    </f:facet>

                    #{item.phase}
                </h:column>

                <h:column>
                    <f:facet name="header">
                        Execution time (ms)
                    </f:facet>

                    #{item.executionTime}
                </h:column>
            </h:dataTable>
        </h:body>
    </f:view>
</html>
Run Code Online (Sandbox Code Playgroud)

更新1:

  • 在URL中添加了参数
  • 添加了250个日志的限制