Commit 4ca9d5f7 by Dave Syer

Break up hystrix dashboard

parent cf96d6dd
......@@ -159,6 +159,21 @@
<artifactId>jersey-server</artifactId>
<version>1.13</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>d3js</artifactId>
<version>3.4.11</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.2.0</version>
</dependency>
</dependencies>
</dependencyManagement>
......
package org.springframework.cloud.netflix.hystrix;
import com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
......@@ -8,7 +9,6 @@ import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.cloud.netflix.hystrix.annotations.EnableHystrix;
import org.springframework.cloud.netflix.endpoint.HystrixStreamEndpoint;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
......
package io.spring.cloud.netflix.hystrix.stream;
package org.springframework.cloud.netflix.hystrix;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
......@@ -11,142 +21,148 @@ import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Proxy an EventStream request (data.stream via proxy.stream) since EventStream does not yet support CORS (https://bugs.webkit.org/show_bug.cgi?id=61862)
* so that a UI can request a stream from a different server.
* @author Dave Syer
*/
public class ProxyStreamServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(ProxyStreamServlet.class);
@SuppressWarnings("deprecation")
@Configuration
public class HystrixDashboardConfiguration {
@Bean
public ServletRegistrationBean proxyStreamServlet() {
return new ServletRegistrationBean(new ProxyStreamServlet(), "/proxy.stream");
}
/**
* Proxy an EventStream request (data.stream via proxy.stream) since EventStream does not yet support CORS (https://bugs.webkit.org/show_bug.cgi?id=61862)
* so that a UI can request a stream from a different server.
*/
public static class ProxyStreamServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(ProxyStreamServlet.class);
public ProxyStreamServlet() {
super();
}
public ProxyStreamServlet() {
super();
}
/**
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String origin = request.getParameter("origin");
if (origin == null) {
response.setStatus(500);
response.getWriter().println("Required parameter 'origin' missing. Example: 107.20.175.135:7001");
}
origin = origin.trim();
HttpGet httpget = null;
InputStream is = null;
boolean hasFirstParameter = false;
StringBuilder url = new StringBuilder();
if (!origin.startsWith("http")) {
url.append("http://");
}
url.append(origin);
if (origin.contains("?")) {
hasFirstParameter = true;
}
@SuppressWarnings("unchecked")
Map<String, String[]> params = request.getParameterMap();
for (String key : params.keySet()) {
if (!key.equals("origin")) {
String[] values = params.get(key);
String value = values[0].trim();
if (hasFirstParameter) {
url.append("&");
} else {
url.append("?");
hasFirstParameter = true;
}
url.append(key).append("=").append(value);
}
}
String proxyUrl = url.toString();
logger.info("\n\nProxy opening connection to: " + proxyUrl + "\n\n");
try {
httpget = new HttpGet(proxyUrl);
HttpClient client = ProxyConnectionManager.httpClient;
HttpResponse httpResponse = client.execute(httpget);
int statusCode = httpResponse.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
// writeTo swallows exceptions and never quits even if outputstream is throwing IOExceptions (such as broken pipe) ... since the inputstream is infinite
// httpResponse.getEntity().writeTo(new OutputStreamWrapper(response.getOutputStream()));
// so I copy it manually ...
is = httpResponse.getEntity().getContent();
/**
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String origin = request.getParameter("origin");
if (origin == null) {
response.setStatus(500);
response.getWriter().println("Required parameter 'origin' missing. Example: 107.20.175.135:7001");
}
origin = origin.trim();
HttpGet httpget = null;
InputStream is = null;
boolean hasFirstParameter = false;
StringBuilder url = new StringBuilder();
if (!origin.startsWith("http")) {
url.append("http://");
}
url.append(origin);
if (origin.contains("?")) {
hasFirstParameter = true;
}
Map<String, String[]> params = request.getParameterMap();
for (String key : params.keySet()) {
if (!key.equals("origin")) {
String[] values = params.get(key);
String value = values[0].trim();
if (hasFirstParameter) {
url.append("&");
} else {
url.append("?");
hasFirstParameter = true;
}
url.append(key).append("=").append(value);
}
}
String proxyUrl = url.toString();
logger.info("\n\nProxy opening connection to: " + proxyUrl + "\n\n");
try {
httpget = new HttpGet(proxyUrl);
HttpClient client = ProxyConnectionManager.httpClient;
HttpResponse httpResponse = client.execute(httpget);
int statusCode = httpResponse.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
// writeTo swallows exceptions and never quits even if outputstream is throwing IOExceptions (such as broken pipe) ... since the inputstream is infinite
// httpResponse.getEntity().writeTo(new OutputStreamWrapper(response.getOutputStream()));
// so I copy it manually ...
is = httpResponse.getEntity().getContent();
// set headers
for (Header header : httpResponse.getAllHeaders()) {
response.addHeader(header.getName(), header.getValue());
}
// set headers
for (Header header : httpResponse.getAllHeaders()) {
response.addHeader(header.getName(), header.getValue());
}
// copy data from source to response
OutputStream os = response.getOutputStream();
int b = -1;
while ((b = is.read()) != -1) {
try {
os.write(b);
if (b == 10 /** flush buffer on line feed */) {
os.flush();
}
} catch (Exception e) {
if (e.getClass().getSimpleName().equalsIgnoreCase("ClientAbortException")) {
// don't throw an exception as this means the user closed the connection
logger.debug("Connection closed by client. Will stop proxying ...");
// break out of the while loop
break;
} else {
// received unknown error while writing so throw an exception
throw new RuntimeException(e);
}
}
}
}
} catch (Exception e) {
logger.error("Error proxying request: " + url, e);
} finally {
if (httpget != null) {
try {
httpget.abort();
} catch (Exception e) {
logger.error("failed aborting proxy connection.", e);
}
}
// copy data from source to response
OutputStream os = response.getOutputStream();
int b = -1;
while ((b = is.read()) != -1) {
try {
os.write(b);
if (b == 10 /** flush buffer on line feed */) {
os.flush();
}
} catch (Exception e) {
if (e.getClass().getSimpleName().equalsIgnoreCase("ClientAbortException")) {
// don't throw an exception as this means the user closed the connection
logger.debug("Connection closed by client. Will stop proxying ...");
// break out of the while loop
break;
} else {
// received unknown error while writing so throw an exception
throw new RuntimeException(e);
}
}
}
}
} catch (Exception e) {
logger.error("Error proxying request: " + url, e);
} finally {
if (httpget != null) {
try {
httpget.abort();
} catch (Exception e) {
logger.error("failed aborting proxy connection.", e);
}
}
// httpget.abort() MUST be called first otherwise is.close() hangs (because data is still streaming?)
if (is != null) {
// this should already be closed by httpget.abort() above
try {
is.close();
} catch (Exception e) {
// e.printStackTrace();
}
}
}
}
// httpget.abort() MUST be called first otherwise is.close() hangs (because data is still streaming?)
if (is != null) {
// this should already be closed by httpget.abort() above
try {
is.close();
} catch (Exception e) {
// e.printStackTrace();
}
}
}
}
private static class ProxyConnectionManager {
private final static PoolingClientConnectionManager threadSafeConnectionManager = new PoolingClientConnectionManager();
private final static HttpClient httpClient = new DefaultHttpClient(threadSafeConnectionManager);
private static class ProxyConnectionManager {
private final static PoolingClientConnectionManager threadSafeConnectionManager = new PoolingClientConnectionManager();
private final static HttpClient httpClient = new DefaultHttpClient(threadSafeConnectionManager);
static {
logger.debug("Initialize ProxyConnectionManager");
/* common settings */
HttpParams httpParams = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
HttpConnectionParams.setSoTimeout(httpParams, 10000);
static {
logger.debug("Initialize ProxyConnectionManager");
/* common settings */
HttpParams httpParams = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
HttpConnectionParams.setSoTimeout(httpParams, 10000);
/* number of connections to allow */
threadSafeConnectionManager.setDefaultMaxPerRoute(400);
threadSafeConnectionManager.setMaxTotal(400);
}
}
/* number of connections to allow */
threadSafeConnectionManager.setDefaultMaxPerRoute(400);
threadSafeConnectionManager.setMaxTotal(400);
}
}
}
}
package org.springframework.cloud.netflix.endpoint;
package org.springframework.cloud.netflix.hystrix;
import org.springframework.cloud.netflix.endpoint.ServletWrappingEndpoint;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
......
package org.springframework.cloud.netflix.hystrix.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.cloud.netflix.hystrix.HystrixDashboardConfiguration;
import org.springframework.context.annotation.Import;
/**
* Created by sgibb on 6/19/14.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(HystrixDashboardConfiguration.class)
public @interface EnableHystrixDashboard {
}
\ No newline at end of file
package io.spring.cloud.netflix.hystrix;
import io.spring.cloud.netflix.hystrix.stream.MockStreamServlet;
import io.spring.cloud.netflix.hystrix.stream.ProxyStreamServlet;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.cloud.netflix.hystrix.annotations.EnableHystrixDashboard;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
......@@ -15,16 +16,17 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
@ComponentScan
@EnableHystrixDashboard
@EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {
public class HystrixDashboardApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class).web(true);
return application.sources(HystrixDashboardApplication.class).web(true);
}
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
new SpringApplicationBuilder(HystrixDashboardApplication.class).web(true).run(args);
}
@Bean
......@@ -32,8 +34,4 @@ public class Application extends SpringBootServletInitializer {
return new ServletRegistrationBean(new MockStreamServlet(), "/mock.stream");
}
@Bean
public ServletRegistrationBean proxyStreamServlet() {
return new ServletRegistrationBean(new ProxyStreamServlet(), "/proxy.stream");
}
}
......@@ -9,7 +9,6 @@ endpoints:
server:
port: 7979
context-path: /hystrix-dashboard
logging:
level: INFO
......
package io.spring.cloud.netflix.zuul;
import com.netflix.zuul.context.ContextLifecycleFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.cloud.netflix.endpoint.HystrixStreamEndpoint;
import org.springframework.cloud.netflix.hystrix.HystrixStreamEndpoint;
import org.springframework.cloud.netflix.zuul.Routes;
import org.springframework.scheduling.annotation.EnableScheduling;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment