View Javadoc
1   /*
2    * Licensed under the GPL License. You may not use this file except in compliance with the License.
3    * You may obtain a copy of the License at
4    *
5    *   https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
6    *
7    * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
8    * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
9    * PURPOSE.
10   */
11  package psiprobe.beans.stats.collectors;
12  
13  import jakarta.inject.Inject;
14  import jakarta.servlet.ServletContext;
15  
16  import org.apache.catalina.Context;
17  import org.slf4j.Logger;
18  import org.slf4j.LoggerFactory;
19  import org.springframework.beans.factory.annotation.Value;
20  import org.springframework.web.context.ServletContextAware;
21  
22  import psiprobe.TomcatContainer;
23  import psiprobe.beans.ContainerWrapperBean;
24  import psiprobe.model.Application;
25  import psiprobe.tools.ApplicationUtils;
26  import psiprobe.tools.TimeExpression;
27  
28  /**
29   * Collects application statistics.
30   */
31  public class AppStatsCollectorBean extends AbstractStatsCollectorBean
32      implements ServletContextAware {
33  
34    /** The Constant logger. */
35    private static final Logger logger = LoggerFactory.getLogger(AppStatsCollectorBean.class);
36  
37    /** The container wrapper. */
38    @Inject
39    private ContainerWrapperBean containerWrapper;
40  
41    /** The servlet context. */
42    @Inject
43    private ServletContext servletContext;
44  
45    /** The self ignored. */
46    @Value("${psiprobe.beans.stats.collectors.app.selfIgnored}")
47    private boolean selfIgnored;
48  
49    @Override
50    public void collect() throws InterruptedException {
51  
52      long currentTime = System.currentTimeMillis();
53  
54      if (containerWrapper == null) {
55        logger.error("Cannot collect application stats. Container wrapper is not set.");
56      } else {
57        TomcatContainer tomcatContainer = containerWrapper.getTomcatContainer();
58  
59        // check if the containerWtapper has been initialized
60        if (tomcatContainer != null) {
61          long totalReqDelta = 0;
62          long totalErrDelta = 0;
63          long totalAvgProcTime = 0;
64          int participatingAppCount = 0;
65  
66          for (Context ctx : tomcatContainer.findContexts()) {
67            if (ctx != null && ctx.getName() != null) {
68              Application app = new Application();
69              ApplicationUtils.collectApplicationServletStats(ctx, app);
70  
71              String appName = ctx.getName().isEmpty() ? "/" : ctx.getName();
72  
73              long reqDelta =
74                  buildDeltaStats("app.requests." + appName, app.getRequestCount(), currentTime);
75              long errDelta = buildDeltaStats("app.errors." + appName, app.getErrorCount());
76              long procTimeDelta =
77                  buildDeltaStats("app.proc_time." + appName, app.getProcessingTime(), currentTime);
78  
79              long avgProcTime = reqDelta == 0 ? 0 : procTimeDelta / reqDelta;
80              buildAbsoluteStats("app.avg_proc_time." + appName, avgProcTime, currentTime);
81  
82              /*
83               * make sure applications that did not serve any requests do not participate in average
84               * response time equation thus diluting the value
85               */
86              if (reqDelta > 0 && !excludeFromTotal(ctx)) {
87                totalReqDelta += reqDelta;
88                totalErrDelta += errDelta;
89                totalAvgProcTime += avgProcTime;
90                participatingAppCount++;
91              }
92            }
93          }
94          // build totals for all applications
95          buildAbsoluteStats("total.requests", totalReqDelta, currentTime);
96          buildAbsoluteStats("total.errors", totalErrDelta, currentTime);
97          buildAbsoluteStats("total.avg_proc_time",
98              participatingAppCount == 0 ? 0 : totalAvgProcTime / participatingAppCount, currentTime);
99        }
100       logger.debug("app stats collected in {}ms", System.currentTimeMillis() - currentTime);
101     }
102   }
103 
104   /**
105    * Exclude from total.
106    *
107    * @param ctx the ctx
108    *
109    * @return true, if successful
110    */
111   private boolean excludeFromTotal(Context ctx) {
112     return selfIgnored && servletContext.equals(ctx.getServletContext());
113   }
114 
115   /**
116    * Reset.
117    */
118   public void reset() {
119     if (containerWrapper == null) {
120       logger.error("Cannot reset application stats. Container wrapper is not set.");
121     } else {
122       TomcatContainer tomcatContainer = containerWrapper.getTomcatContainer();
123       if (tomcatContainer != null) {
124         for (Context ctx : tomcatContainer.findContexts()) {
125           if (ctx != null && ctx.getName() != null) {
126             String appName = ctx.getName().isEmpty() ? "/" : ctx.getName();
127             reset(appName);
128           }
129         }
130       }
131     }
132     resetStats("total.requests");
133     resetStats("total.errors");
134     resetStats("total.avg_proc_time");
135   }
136 
137   /**
138    * Reset.
139    *
140    * @param appName the app name
141    */
142   public void reset(String appName) {
143     resetStats("app.requests." + appName);
144     resetStats("app.proc_time." + appName);
145     resetStats("app.errors." + appName);
146     resetStats("app.avg_proc_time." + appName);
147   }
148 
149   /**
150    * Sets the max series expression.
151    *
152    * @param period the period
153    * @param span the span
154    */
155   public void setMaxSeries(@Value("${psiprobe.beans.stats.collectors.app.period}") String period,
156       @Value("${psiprobe.beans.stats.collectors.app.span}") String span) {
157     super.setMaxSeries((int) TimeExpression.dataPoints(period, span));
158   }
159 
160   @Override
161   public void setServletContext(ServletContext servletContext) {
162     // Do not set servlet context as set via injection
163   }
164 
165 }