View Javadoc
1   /*
2    * Licensed under the Apache License, Version 2.0 (the "License");
3    * you may not use this file except in compliance with the License.
4    * You may obtain a copy of the License at
5    *
6    * http://www.apache.org/licenses/LICENSE-2.0
7    *
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS,
10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11   * See the License for the specific language governing permissions and
12   * limitations under the License.
13   *
14   */
15  
16  package org.esigate.extension.monitoring;
17  
18  import com.codahale.metrics.MetricRegistry;
19  import com.codahale.metrics.ScheduledReporter;
20  import com.codahale.metrics.Slf4jReporter;
21  import org.apache.http.HttpStatus;
22  import org.apache.http.client.cache.CacheResponseStatus;
23  import org.apache.http.client.cache.HttpCacheContext;
24  import org.esigate.Driver;
25  import org.esigate.events.Event;
26  import org.esigate.events.EventDefinition;
27  import org.esigate.events.EventManager;
28  import org.esigate.events.IEventListener;
29  import org.esigate.events.impl.FetchEvent;
30  import org.esigate.events.impl.ProxyEvent;
31  import org.esigate.extension.Extension;
32  import org.esigate.util.Parameter;
33  import org.esigate.util.ParameterInteger;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  
37  import java.util.Properties;
38  import java.util.concurrent.TimeUnit;
39  
40  /**
41   * This extension will record proxy request, and backend request to generate statistics.
42   * <p>
43   * Result will be logged using SLF4J in INFO level every 60 seconds. Period can be configured in driver properties :
44   * <p>
45   * <code>metricPeriod=60</code>
46   * <p>
47   * <p>
48   * Created by alexis on 20/03/14.
49   */
50  public class Metric implements Extension, IEventListener {
51      private static final Logger LOG = LoggerFactory.getLogger(Metric.class);
52      private static final Parameter<Integer> PARAM_METRIC_PERIOD = new ParameterInteger("metricPeriod", 60);
53  
54      private MetricRegistry metric = new MetricRegistry();
55      private Driver driver;
56  
57      @Override
58      public void init(Driver d, Properties properties) {
59          this.driver = d;
60          LOG.debug("Initialize Metric");
61          driver.getEventManager().register(EventManager.EVENT_PROXY_POST, this);
62          driver.getEventManager().register(EventManager.EVENT_FETCH_POST, this);
63  
64          ScheduledReporter reporter =
65                  Slf4jReporter.forRegistry(this.metric).outputTo(LOG).convertRatesTo(TimeUnit.SECONDS)
66                          .convertDurationsTo(TimeUnit.MILLISECONDS).build();
67  
68          reporter.start(PARAM_METRIC_PERIOD.getValue(properties), TimeUnit.SECONDS);
69      }
70  
71      @Override
72      public boolean event(EventDefinition id, Event event) {
73  
74          String timerName =
75                  MetricRegistry.name(this.getClass().getSimpleName(), driver.getConfiguration().getInstanceName(),
76                          id.getId());
77  
78          if (EventManager.EVENT_PROXY_POST.equals(id)) {
79              if (((ProxyEvent) event).getErrorPage() != null) {
80                  String statusCode =
81                          String.valueOf(((ProxyEvent) event).getErrorPage().getHttpResponse().getStatusLine()
82                                  .getStatusCode());
83                  timerName = MetricRegistry.name(timerName, "error", statusCode);
84              }
85          } else if (EventManager.EVENT_FETCH_POST.equals(id)) {
86              // Retrieve HTTP response status code and cache status
87              FetchEvent e = (FetchEvent) event;
88              int statusCode = e.getHttpResponse().getStatusLine().getStatusCode();
89              CacheResponseStatus cacheResponseStatus =
90                      (CacheResponseStatus) e.getHttpContext().getAttribute(HttpCacheContext.CACHE_RESPONSE_STATUS);
91  
92              // Adding status code when error
93              if (statusCode >= HttpStatus.SC_BAD_REQUEST) {
94                  timerName = MetricRegistry.name(timerName, "error", String.valueOf(statusCode));
95              }
96              // Adding cache if not MISS
97              if (cacheResponseStatus != null && !cacheResponseStatus.equals(CacheResponseStatus.CACHE_MISS)) {
98                  timerName = MetricRegistry.name(timerName, cacheResponseStatus.name().toLowerCase());
99              }
100         }
101 
102         metric.meter(timerName).mark();
103 
104         return true;
105     }
106 }