Implemented index page for zPages (#1423)
* Added two abstract getter method for obtaining page information * Added page information getter method * Implemented index zPage handler * Implemented index page for zPages * Added unit test for index zPage * Small style and comment fixes * Increased font size, code style fix * Fixed font size issue
This commit is contained in:
parent
98cb75695d
commit
df14623402
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020, OpenTelemetry Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.sdk.extensions.zpages;
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
final class IndexZPageHandler extends ZPageHandler {
|
||||||
|
private static final String INDEX_URL = "/";
|
||||||
|
private static final String INDEX_NAME = "Index";
|
||||||
|
private static final String INDEX_DESCRITION = "Index page of zPages";
|
||||||
|
private static final Logger logger = Logger.getLogger(IndexZPageHandler.class.getName());
|
||||||
|
@Nullable private final List<ZPageHandler> availableHandlers;
|
||||||
|
|
||||||
|
IndexZPageHandler(@Nullable List<ZPageHandler> availableHandlers) {
|
||||||
|
this.availableHandlers = availableHandlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUrlPath() {
|
||||||
|
return INDEX_URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPageName() {
|
||||||
|
return INDEX_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPageDescription() {
|
||||||
|
return INDEX_DESCRITION;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void emitPageLinkAndInfo(PrintStream out, ZPageHandler handler) {
|
||||||
|
out.print("<a href=\"" + handler.getUrlPath() + "\">");
|
||||||
|
out.print("<h2 style=\"text-align: left;\">" + handler.getPageName() + "</h2>");
|
||||||
|
out.print("</a>");
|
||||||
|
out.print("<p>" + handler.getPageDescription() + "</p>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void emitHtml(Map<String, String> queryMap, OutputStream outputStream) {
|
||||||
|
// PrintStream for emiting HTML contents
|
||||||
|
try (PrintStream out = new PrintStream(outputStream, /* autoFlush= */ false, "UTF-8")) {
|
||||||
|
out.print("<!DOCTYPE html>");
|
||||||
|
out.print("<html lang=\"en\">");
|
||||||
|
out.print("<head>");
|
||||||
|
out.print("<meta charset=\"UTF-8\">");
|
||||||
|
out.print(
|
||||||
|
"<link rel=\"shortcut icon\" href=\"data:image/png;base64,"
|
||||||
|
+ ZPageLogo.getFaviconBase64()
|
||||||
|
+ "\" type=\"image/png\">");
|
||||||
|
out.print(
|
||||||
|
"<link href=\"https://fonts.googleapis.com/css?family=Open+Sans:300\""
|
||||||
|
+ "rel=\"stylesheet\">");
|
||||||
|
out.print(
|
||||||
|
"<link href=\"https://fonts.googleapis.com/css?family=Roboto\" rel=\"stylesheet\">");
|
||||||
|
out.print("<title>zPages</title>");
|
||||||
|
out.print("<style>");
|
||||||
|
out.print(ZPageStyle.style);
|
||||||
|
out.print("</style>");
|
||||||
|
out.print("</head>");
|
||||||
|
out.print("<body>");
|
||||||
|
out.print(
|
||||||
|
"<a href=\"/\"><img style=\"height: 90px;\" src=\"data:image/png;base64,"
|
||||||
|
+ ZPageLogo.getLogoBase64()
|
||||||
|
+ "\" /></a>");
|
||||||
|
out.print("<h1 style=\"text-align: left;\">zPages</h1>");
|
||||||
|
out.print(
|
||||||
|
"<p>OpenTelemetry provides in-process web pages that display collected data from"
|
||||||
|
+ " the process that they are attached to. These are called \"zPages\"."
|
||||||
|
+ " They are useful for in-process diagnostics without having to depend on"
|
||||||
|
+ " any backend to examine traces or metrics.</p>");
|
||||||
|
|
||||||
|
out.print(
|
||||||
|
"<p>zPages can be useful during the development time or "
|
||||||
|
+ "when the process to be inspected is known in production.</p>");
|
||||||
|
if (this.availableHandlers != null) {
|
||||||
|
for (ZPageHandler handler : this.availableHandlers) {
|
||||||
|
emitPageLinkAndInfo(out, handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.print("</body>");
|
||||||
|
out.print("</html>");
|
||||||
|
} catch (Throwable t) {
|
||||||
|
logger.log(Level.WARNING, "error while generating HTML", t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -82,6 +82,10 @@ final class TracezZPageHandler extends ZPageHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String TRACEZ_URL = "/tracez";
|
private static final String TRACEZ_URL = "/tracez";
|
||||||
|
private static final String TRACEZ_NAME = "TraceZ";
|
||||||
|
private static final String TRACEZ_DESCRIPTION =
|
||||||
|
"TraceZ displays information about all the running spans"
|
||||||
|
+ " and all the sampled spans based on latency and errors";
|
||||||
// Background color used for zebra striping rows of summary table
|
// Background color used for zebra striping rows of summary table
|
||||||
private static final String ZEBRA_STRIPE_COLOR = "#e6e6e6";
|
private static final String ZEBRA_STRIPE_COLOR = "#e6e6e6";
|
||||||
// Color for sampled traceIds
|
// Color for sampled traceIds
|
||||||
|
|
@ -114,6 +118,16 @@ final class TracezZPageHandler extends ZPageHandler {
|
||||||
return TRACEZ_URL;
|
return TRACEZ_URL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPageName() {
|
||||||
|
return TRACEZ_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPageDescription() {
|
||||||
|
return TRACEZ_DESCRIPTION;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emits CSS Styles to the {@link PrintStream} {@code out}. Content emitted by this function
|
* Emits CSS Styles to the {@link PrintStream} {@code out}. Content emitted by this function
|
||||||
* should be enclosed by <head></head> tag.
|
* should be enclosed by <head></head> tag.
|
||||||
|
|
@ -452,9 +466,9 @@ final class TracezZPageHandler extends ZPageHandler {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
out.print(
|
out.print(
|
||||||
"<img style=\"height: 90px;\" src=\"data:image/png;base64,"
|
"<a href=\"/\"><img style=\"height: 90px;\" src=\"data:image/png;base64,"
|
||||||
+ ZPageLogo.getLogoBase64()
|
+ ZPageLogo.getLogoBase64()
|
||||||
+ "\" />");
|
+ "\" /></a>");
|
||||||
out.print("<h1>TraceZ Summary</h1>");
|
out.print("<h1>TraceZ Summary</h1>");
|
||||||
emitSummaryTable(out);
|
emitSummaryTable(out);
|
||||||
// spanName will be null if the query parameter doesn't exist in the URL
|
// spanName will be null if the query parameter doesn't exist in the URL
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,20 @@ public abstract class ZPageHandler {
|
||||||
*/
|
*/
|
||||||
public abstract String getUrlPath();
|
public abstract String getUrlPath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the zPage.
|
||||||
|
*
|
||||||
|
* @return the name of the zPage.
|
||||||
|
*/
|
||||||
|
public abstract String getPageName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the description of the zPage.
|
||||||
|
*
|
||||||
|
* @return the description of the zPage.
|
||||||
|
*/
|
||||||
|
public abstract String getPageDescription();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emits the generated HTML page to the {@code outputStream}.
|
* Emits the generated HTML page to the {@code outputStream}.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package io.opentelemetry.sdk.extensions.zpages;
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.sun.net.httpserver.HttpServer;
|
import com.sun.net.httpserver.HttpServer;
|
||||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||||
import io.opentelemetry.sdk.trace.TracerSdkProvider;
|
import io.opentelemetry.sdk.trace.TracerSdkProvider;
|
||||||
|
|
@ -71,6 +72,9 @@ public final class ZPageServer {
|
||||||
// Handler for /tracez page
|
// Handler for /tracez page
|
||||||
private static final ZPageHandler tracezZPageHandler =
|
private static final ZPageHandler tracezZPageHandler =
|
||||||
new TracezZPageHandler(tracezDataAggregator);
|
new TracezZPageHandler(tracezDataAggregator);
|
||||||
|
// Handler for index page, **please include all available zPages in the constructor**
|
||||||
|
private static final ZPageHandler indexZPageHandler =
|
||||||
|
new IndexZPageHandler(ImmutableList.of(tracezZPageHandler));
|
||||||
|
|
||||||
private static final Object mutex = new Object();
|
private static final Object mutex = new Object();
|
||||||
private static final AtomicBoolean isTracezSpanProcesserAdded = new AtomicBoolean(false);
|
private static final AtomicBoolean isTracezSpanProcesserAdded = new AtomicBoolean(false);
|
||||||
|
|
@ -88,7 +92,17 @@ public final class ZPageServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a {@code ZPageHandler} for tracing debug to the server. The page displays information
|
* Registers a {@link ZPageHandler} for the index page of zPages. The page displays information
|
||||||
|
* about all available zPages with links to those zPages.
|
||||||
|
*
|
||||||
|
* @param server the {@link HttpServer} for the page to register to.
|
||||||
|
*/
|
||||||
|
static void registerIndexZPageHandler(HttpServer server) {
|
||||||
|
server.createContext(indexZPageHandler.getUrlPath(), new ZPageHttpHandler(indexZPageHandler));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a {@link ZPageHandler} for tracing debug to the server. The page displays information
|
||||||
* about all running spans and all sampled spans based on latency and error.
|
* about all running spans and all sampled spans based on latency and error.
|
||||||
*
|
*
|
||||||
* <p>It displays a summary table which contains one row for each span name and data about number
|
* <p>It displays a summary table which contains one row for each span name and data about number
|
||||||
|
|
@ -99,6 +113,8 @@ public final class ZPageServer {
|
||||||
*
|
*
|
||||||
* <p>This method will add the TracezSpanProcessor to the tracerProvider, it should only be called
|
* <p>This method will add the TracezSpanProcessor to the tracerProvider, it should only be called
|
||||||
* once.
|
* once.
|
||||||
|
*
|
||||||
|
* @param server the {@link HttpServer} for the page to register to.
|
||||||
*/
|
*/
|
||||||
static void registerTracezZPageHandler(HttpServer server) {
|
static void registerTracezZPageHandler(HttpServer server) {
|
||||||
addTracezSpanProcessor();
|
addTracezSpanProcessor();
|
||||||
|
|
@ -108,10 +124,11 @@ public final class ZPageServer {
|
||||||
/**
|
/**
|
||||||
* Registers all zPages to the given {@link HttpServer} {@code server}.
|
* Registers all zPages to the given {@link HttpServer} {@code server}.
|
||||||
*
|
*
|
||||||
* @param server the server that exports the zPages.
|
* @param server the {@link HttpServer} for the page to register to.
|
||||||
*/
|
*/
|
||||||
public static void registerAllPagesToHttpServer(HttpServer server) {
|
public static void registerAllPagesToHttpServer(HttpServer server) {
|
||||||
// For future zPages, register them to the server in here
|
// For future zPages, register them to the server in here
|
||||||
|
registerIndexZPageHandler(server);
|
||||||
registerTracezZPageHandler(server);
|
registerTracezZPageHandler(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,11 @@ final class ZPageStyle {
|
||||||
|
|
||||||
/** Style here will be applied to the generated HTML pages for all zPages. */
|
/** Style here will be applied to the generated HTML pages for all zPages. */
|
||||||
static String style =
|
static String style =
|
||||||
"body{font-family: \"Roboto\", sans-serif; font-size: 14px;"
|
"body{font-family: \"Roboto\", sans-serif; font-size: 16px;"
|
||||||
+ "background-color: #fff;}"
|
+ "background-color: #fff;}"
|
||||||
+ "h1{color: #363636; text-align: center; margin-bottom 20px;}"
|
+ "h1{padding: 0 20px; color: #363636; text-align: center; margin-bottom: 20px;}"
|
||||||
+ "h2{color: #363636; text-align: center; margin-top: 30px;}"
|
+ "h2{padding: 0 20px; color: #363636; text-align: center; margin-bottom: 20px;}"
|
||||||
+ "p{padding: 0 0.5em; color: #363636;}"
|
+ "p{padding: 0 20px; color: #363636;}"
|
||||||
+ "tr.bg-color{background-color: #4b5fab;}"
|
+ "tr.bg-color{background-color: #4b5fab;}"
|
||||||
+ "table{margin: 0 auto;}"
|
+ "table{margin: 0 auto;}"
|
||||||
+ "th{padding: 0 1em; line-height: 2.0}"
|
+ "th{padding: 0 1em; line-height: 2.0}"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020, OpenTelemetry Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.sdk.extensions.zpages;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
|
/** Unit tests for {@link IndexZPageHandler}. */
|
||||||
|
@RunWith(JUnit4.class)
|
||||||
|
public final class IndexZPageHandlerTest {
|
||||||
|
private static final ZPageHandler tracezZPageHandler = new TracezZPageHandler(null);
|
||||||
|
private final Map<String, String> emptyQueryMap = ImmutableMap.of();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void emitHtmlCorrectly() {
|
||||||
|
OutputStream output = new ByteArrayOutputStream();
|
||||||
|
IndexZPageHandler indexZPageHandler =
|
||||||
|
new IndexZPageHandler(ImmutableList.of(tracezZPageHandler));
|
||||||
|
|
||||||
|
indexZPageHandler.emitHtml(emptyQueryMap, output);
|
||||||
|
|
||||||
|
assertThat(output.toString()).contains("<a href=\"" + tracezZPageHandler.getUrlPath() + "\">");
|
||||||
|
assertThat(output.toString()).contains(">" + tracezZPageHandler.getPageName() + "</h2></a>");
|
||||||
|
assertThat(output.toString())
|
||||||
|
.contains("<p>" + tracezZPageHandler.getPageDescription() + "</p>");
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue