From 7fa786e57600a0710f442e68b4e20c9d6e6df641 Mon Sep 17 00:00:00 2001 From: Adrian Cole <acole@pivotal.io> Date: Wed, 16 Mar 2016 18:11:32 +0800 Subject: [PATCH] Hosts zipkin-ui static assets on zipkin-server This hosts the `zipkin-ui` static assets on zipkin-server. By doing, so, this allows us the following: * Single-node deployment model * Ex. Simplest deployment of in-memory storage has no external dependencies * The opportunity to use the standard port 8080 * Since web assets are hosted locally, there's no port dodging anymore Implementation note: this currently cherry-picks routes the client-side is responsible for. --- zipkin-server/README.md | 5 +- zipkin-server/pom.xml | 9 +++ .../zipkin/server/EnableZipkinServer.java | 2 +- .../zipkin/server/ZipkinServerProperties.java | 27 +++++++ .../zipkin/server/ZipkinUiConfiguration.java | 74 +++++++++++++++++++ .../src/main/resources/zipkin-server.yml | 6 ++ 6 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 zipkin-server/src/main/java/zipkin/server/ZipkinUiConfiguration.java diff --git a/zipkin-server/README.md b/zipkin-server/README.md index 98ab9271d86..b4cd8dbc594 100644 --- a/zipkin-server/README.md +++ b/zipkin-server/README.md @@ -1,5 +1,8 @@ # zipkin-server -The receives spans via HTTP POST and respond to queries from zipkin-web. +The hosts the Zipkin [Api](http://zipkin.io/zipkin-api/#/) and [UI](https://github.com/openzipkin/zipkin/tree/master/zipkin-ui). + +Span storage and transports are configurable. By default storage is +in-memory and the http span transport (POST /spans endpoint) is enabled. Note that the server requires minimum JRE 8. diff --git a/zipkin-server/pom.xml b/zipkin-server/pom.xml index b2b28416d00..26417b97ef0 100644 --- a/zipkin-server/pom.xml +++ b/zipkin-server/pom.xml @@ -29,6 +29,7 @@ <properties> <main.basedir>${project.basedir}/..</main.basedir> <brave.version>3.5.0</brave.version> + <zipkin-ui.version>1.38.0</zipkin-ui.version> <start-class>zipkin.server.ZipkinServer</start-class> <maven-invoker-plugin.version>2.0.0</maven-invoker-plugin.version> </properties> @@ -75,6 +76,14 @@ <artifactId>zipkin</artifactId> </dependency> + <!-- Static content for the web UI --> + <dependency> + <groupId>io.zipkin</groupId> + <artifactId>zipkin-ui</artifactId> + <version>${zipkin-ui.version}</version> + <optional>true</optional> + </dependency> + <!-- Cassandra backend --> <dependency> <groupId>${project.groupId}</groupId> diff --git a/zipkin-server/src/main/java/zipkin/server/EnableZipkinServer.java b/zipkin-server/src/main/java/zipkin/server/EnableZipkinServer.java index f40815fb741..5e7b98453d0 100644 --- a/zipkin-server/src/main/java/zipkin/server/EnableZipkinServer.java +++ b/zipkin-server/src/main/java/zipkin/server/EnableZipkinServer.java @@ -24,7 +24,7 @@ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented -@Import({ZipkinServerConfiguration.class, BraveConfiguration.class, ZipkinQueryApiV1.class, ZipkinSpanWriter.class}) +@Import({ZipkinServerConfiguration.class, BraveConfiguration.class, ZipkinQueryApiV1.class, ZipkinUiConfiguration.class, ZipkinSpanWriter.class}) public @interface EnableZipkinServer { } diff --git a/zipkin-server/src/main/java/zipkin/server/ZipkinServerProperties.java b/zipkin-server/src/main/java/zipkin/server/ZipkinServerProperties.java index 5caeb9c393c..c2cf8d91908 100644 --- a/zipkin-server/src/main/java/zipkin/server/ZipkinServerProperties.java +++ b/zipkin-server/src/main/java/zipkin/server/ZipkinServerProperties.java @@ -23,6 +23,12 @@ public Store getStore() { return store; } + private Ui ui = new Ui(); + + public Ui getUi() { + return ui; + } + static class Store { enum Type { cassandra, mysql, mem @@ -38,4 +44,25 @@ public void setType(Type type) { this.type = type; } } + + static class Ui { + private String environment; + private int queryLimit = 10; + + public String getEnvironment() { + return environment; + } + + public void setEnvironment(String environment) { + this.environment = environment; + } + + public int getQueryLimit() { + return queryLimit; + } + + public void setQueryLimit(int queryLimit) { + this.queryLimit = queryLimit; + } + } } diff --git a/zipkin-server/src/main/java/zipkin/server/ZipkinUiConfiguration.java b/zipkin-server/src/main/java/zipkin/server/ZipkinUiConfiguration.java new file mode 100644 index 00000000000..9623243e4c7 --- /dev/null +++ b/zipkin-server/src/main/java/zipkin/server/ZipkinUiConfiguration.java @@ -0,0 +1,74 @@ +/** + * Copyright 2015-2016 The OpenZipkin 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 zipkin.server; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnResource; +import org.springframework.context.annotation.Configuration; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +/** + * Zipkin-UI is a single-page application that reads configuration from /config.json. + * + * <p>When looking at a trace, the browser is sent to the path "/traces/{id}". For the single-page + * app to serve that route, the server needs to forward the request to "/index.html". The same + * forwarding applies to "/dependencies" and any other routes the UI controls. + * + * <p>Under the scenes the JavaScript code looks at {@code window.location} to figure out what the + * UI should do. This is handled by a route api defined in the crossroads library. + */ +@Configuration +@ConditionalOnResource(resources = "classpath:zipkin-ui") // from io.zipkin:zipkin-ui +public class ZipkinUiConfiguration extends WebMvcConfigurerAdapter { + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/**").addResourceLocations("classpath:/zipkin-ui/"); + } + + @RestController + public static class ZipkinUi { + + @Autowired + ZipkinServerProperties server; + + @RequestMapping(value = "/config.json", method = RequestMethod.GET, produces = APPLICATION_JSON_VALUE) + public ZipkinServerProperties.Ui getUiConfig() { + return server.getUi(); + } + + /** + * This cherry-picks well-known routes the single-page app serves, and forwards to that as + * opposed to returning a 404. + */ + // TODO This approach requires maintenance when new UI routes are added. Change to the following: + // If the path is a a file w/an extension, treat normally. + // Otherwise instead of returning 404, forward to the index. + // See https://github.com/twitter/finatra/blob/458c6b639c3afb4e29873d123125eeeb2b02e2cd/http/src/main/scala/com/twitter/finatra/http/response/ResponseBuilder.scala#L321 + @RequestMapping(value = {"/", "/traces/{id}", "/dependency"}, method = RequestMethod.GET) + public ModelAndView forwardUiEndpoints(ModelMap model) { + // Note: RequestMapping "/" requires us to use ModelAndView result vs just a string. + // When "/" is mapped, the server literally returns "forward:/index.html" vs forwarding. + return new ModelAndView("forward:/index.html", model); + } + } +} diff --git a/zipkin-server/src/main/resources/zipkin-server.yml b/zipkin-server/src/main/resources/zipkin-server.yml index 0499cad460f..49b6db480ea 100644 --- a/zipkin-server/src/main/resources/zipkin-server.yml +++ b/zipkin-server/src/main/resources/zipkin-server.yml @@ -41,6 +41,12 @@ zipkin: lookback: ${QUERY_LOOKBACK:86400000} store: type: ${STORAGE_TYPE:mem} + # Values here are read by Zipkin UI's javascript at /config.json + ui: + # Default limit for Find Traces + query-limit: 10 + # The value here becomes a label in the top-right corner + environment: server: port: ${QUERY_PORT:9411} compression: