• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017, OpenCensus Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package io.opencensus.contrib.zpages;
18 
19 import static com.google.common.base.Preconditions.checkState;
20 
21 import com.sun.net.httpserver.HttpServer;
22 import io.opencensus.stats.Measure;
23 import io.opencensus.stats.Stats;
24 import io.opencensus.stats.View;
25 import io.opencensus.trace.Tracing;
26 import java.io.IOException;
27 import java.net.InetSocketAddress;
28 import java.util.logging.Logger;
29 import javax.annotation.Nullable;
30 import javax.annotation.concurrent.GuardedBy;
31 import javax.annotation.concurrent.ThreadSafe;
32 
33 /**
34  * A collection of HTML pages to display stats and trace data and allow library configuration
35  * control.
36  *
37  * <p>Example usage with private {@link HttpServer}:
38  *
39  * <pre>{@code
40  * public class Main {
41  *   public static void main(String[] args) throws Exception {
42  *     ZPageHandlers.startHttpServerAndRegisterAll(8000);
43  *     ... // do work
44  *   }
45  * }
46  * }</pre>
47  *
48  * <p>Example usage with shared {@link HttpServer}:
49  *
50  * <pre>{@code
51  * public class Main {
52  *   public static void main(String[] args) throws Exception {
53  *     HttpServer server = HttpServer.create(new InetSocketAddress(8000), 10);
54  *     ZPageHandlers.registerAllToHttpServer(server);
55  *     server.start();
56  *     ... // do work
57  *   }
58  * }
59  * }</pre>
60  *
61  * @since 0.6
62  */
63 @ThreadSafe
64 public final class ZPageHandlers {
65   // The HttpServer listening socket backlog (maximum number of queued incoming connections).
66   private static final int BACKLOG = 5;
67   // How many seconds to wait for the HTTP server to stop.
68   private static final int STOP_DELAY = 1;
69   private static final Logger logger = Logger.getLogger(ZPageHandler.class.getName());
70   private static final ZPageHandler tracezZPageHandler =
71       TracezZPageHandler.create(
72           Tracing.getExportComponent().getRunningSpanStore(),
73           Tracing.getExportComponent().getSampledSpanStore());
74   private static final ZPageHandler traceConfigzZPageHandler =
75       TraceConfigzZPageHandler.create(Tracing.getTraceConfig());
76   private static final ZPageHandler rpczZpageHandler =
77       RpczZPageHandler.create(Stats.getViewManager());
78   private static final ZPageHandler statszZPageHandler =
79       StatszZPageHandler.create(Stats.getViewManager());
80 
81   private static final Object monitor = new Object();
82 
83   @GuardedBy("monitor")
84   @Nullable
85   private static HttpServer server;
86 
87   /**
88    * Returns a {@code ZPageHandler} for tracing debug. The page displays information about all
89    * active spans and all sampled spans based on latency and errors.
90    *
91    * <p>It prints a summary table which contains one row for each span name and data about number of
92    * active and sampled spans.
93    *
94    * <p>If no sampled spans based on latency and error codes are available for a given name, make
95    * sure that the span name is registered to the {@code SampledSpanStore}.
96    *
97    * @return a {@code ZPageHandler} for tracing debug.
98    * @since 0.6
99    */
getTracezZPageHandler()100   public static ZPageHandler getTracezZPageHandler() {
101     return tracezZPageHandler;
102   }
103 
104   /**
105    * Returns a {@code ZPageHandler} for tracing config. The page displays information about all
106    * active configuration and allow changing the active configuration.
107    *
108    * @return a {@code ZPageHandler} for tracing config.
109    * @since 0.6
110    */
getTraceConfigzZPageHandler()111   public static ZPageHandler getTraceConfigzZPageHandler() {
112     return traceConfigzZPageHandler;
113   }
114 
115   /**
116    * Returns a {@code ZPageHandler} for gRPC stats.
117    *
118    * <p>It prints a summary table which contains rows for each gRPC method.
119    *
120    * @return a {@code ZPageHandler} for gRPC stats.
121    * @since 0.12.0
122    */
getRpczZpageHandler()123   public static ZPageHandler getRpczZpageHandler() {
124     return rpczZpageHandler;
125   }
126 
127   /**
128    * Returns a {@code ZPageHandler} for all registered {@link View}s and {@link Measure}s.
129    *
130    * <p>Only {@code Cumulative} views are exported. {@link View}s are grouped by directories.
131    *
132    * @return a {@code ZPageHandler} for all registered {@code View}s and {@code Measure}s.
133    * @since 0.12.0
134    */
getStatszZPageHandler()135   public static ZPageHandler getStatszZPageHandler() {
136     return statszZPageHandler;
137   }
138 
139   /**
140    * Registers all pages to the given {@code HttpServer}.
141    *
142    * @param server the server that exports the tracez page.
143    * @since 0.6
144    */
registerAllToHttpServer(HttpServer server)145   public static void registerAllToHttpServer(HttpServer server) {
146     server.createContext(tracezZPageHandler.getUrlPath(), new ZPageHttpHandler(tracezZPageHandler));
147     server.createContext(
148         traceConfigzZPageHandler.getUrlPath(), new ZPageHttpHandler(traceConfigzZPageHandler));
149     server.createContext(rpczZpageHandler.getUrlPath(), new ZPageHttpHandler(rpczZpageHandler));
150     server.createContext(statszZPageHandler.getUrlPath(), new ZPageHttpHandler(statszZPageHandler));
151   }
152 
153   /**
154    * Starts an {@code HttpServer} and registers all pages to it. When the JVM shuts down the server
155    * is stopped.
156    *
157    * <p>Users must call this function only once per process.
158    *
159    * @param port the port used to bind the {@code HttpServer}.
160    * @throws IllegalStateException if the server is already started.
161    * @throws IOException if the server cannot bind to the requested address.
162    * @since 0.6
163    */
startHttpServerAndRegisterAll(int port)164   public static void startHttpServerAndRegisterAll(int port) throws IOException {
165     synchronized (monitor) {
166       checkState(server == null, "The HttpServer is already started.");
167       server = HttpServer.create(new InetSocketAddress(port), BACKLOG);
168       ZPageHandlers.registerAllToHttpServer(server);
169       server.start();
170       logger.fine("HttpServer started on address " + server.getAddress().toString());
171     }
172 
173     // This does not need to be mutex protected because it is guaranteed that only one thread will
174     // get ever here.
175     Runtime.getRuntime()
176         .addShutdownHook(
177             new Thread() {
178               @Override
179               public void run() {
180                 // Use stderr here since the logger may have been reset by its JVM shutdown hook.
181                 logger.fine("*** Shutting down gRPC server (JVM shutting down)");
182                 ZPageHandlers.stop();
183                 logger.fine("*** Server shut down");
184               }
185             });
186   }
187 
stop()188   private static void stop() {
189     synchronized (monitor) {
190       // This should never happen because we register the shutdown hook only if we start the server.
191       if (server == null) {
192         throw new IllegalStateException("The HttpServer is already stopped.");
193       }
194       server.stop(STOP_DELAY);
195       server = null;
196     }
197   }
198 
ZPageHandlers()199   private ZPageHandlers() {}
200 }
201