diff --git a/skywalking b/skywalking
index 8e529ee9560..4621e5191fc 160000
--- a/skywalking
+++ b/skywalking
@@ -1 +1 @@
-Subproject commit 8e529ee95604fb01a8bd31c272763393f3c70525
+Subproject commit 4621e5191fcc2fe8271a3049b788fd33c694f703
diff --git a/zipkin-server/health-query-plugin/src/main/java/zipkin/server/query/health/HealthQueryProvider.java b/zipkin-server/health-query-plugin/src/main/java/zipkin/server/query/health/HealthQueryProvider.java
index 005c67e2629..d7d164d2b59 100644
--- a/zipkin-server/health-query-plugin/src/main/java/zipkin/server/query/health/HealthQueryProvider.java
+++ b/zipkin-server/health-query-plugin/src/main/java/zipkin/server/query/health/HealthQueryProvider.java
@@ -24,6 +24,7 @@
import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedException;
import org.apache.skywalking.oap.server.library.server.http.HTTPServer;
import org.apache.skywalking.oap.server.library.server.http.HTTPServerConfig;
+import zipkin.server.core.services.HTTPConfigurableServer;
import java.util.Collections;
@@ -67,7 +68,7 @@ public void prepare() throws ServiceNotProvidedException, ModuleStartException {
.acceptQueueSize(moduleConfig.getRestAcceptQueueSize())
.maxRequestHeaderSize(moduleConfig.getRestMaxRequestHeaderSize())
.build();
- httpServer = new HTTPServer(httpServerConfig);
+ httpServer = new HTTPConfigurableServer(httpServerConfig);
httpServer.initialize();
}
}
diff --git a/zipkin-server/http-query-plugin/pom.xml b/zipkin-server/http-query-plugin/pom.xml
index f4371f49179..2ddb0df1f6f 100644
--- a/zipkin-server/http-query-plugin/pom.xml
+++ b/zipkin-server/http-query-plugin/pom.xml
@@ -18,6 +18,11 @@
zipkin-query-plugin
${skywalking.version}
+
+ io.zipkin
+ zipkin-server-core
+ ${project.version}
+
\ No newline at end of file
diff --git a/zipkin-server/http-query-plugin/src/main/java/zipkin/server/query/http/HTTPQueryConfig.java b/zipkin-server/http-query-plugin/src/main/java/zipkin/server/query/http/HTTPQueryConfig.java
index fd336dec3a0..65984b58ec7 100644
--- a/zipkin-server/http-query-plugin/src/main/java/zipkin/server/query/http/HTTPQueryConfig.java
+++ b/zipkin-server/http-query-plugin/src/main/java/zipkin/server/query/http/HTTPQueryConfig.java
@@ -37,6 +37,10 @@ public class HTTPQueryConfig extends ModuleConfig {
private String uiEnvironment = "";
private long uiDefaultLookback = 900000L;
private boolean uiSearchEnabled = true;
+ private String allowedOrigins = "*";
+
+ private boolean uiEnable = true;
+ private String uiBasePath = "/zipkin";
public ZipkinQueryConfig toSkyWalkingConfig() {
final ZipkinQueryConfig result = new ZipkinQueryConfig();
@@ -160,4 +164,28 @@ public int getRestMaxRequestHeaderSize() {
public void setRestMaxRequestHeaderSize(int restMaxRequestHeaderSize) {
this.restMaxRequestHeaderSize = restMaxRequestHeaderSize;
}
+
+ public String getUiBasePath() {
+ return uiBasePath;
+ }
+
+ public void setUiBasePath(String uiBasePath) {
+ this.uiBasePath = uiBasePath;
+ }
+
+ public boolean getUiEnable() {
+ return uiEnable;
+ }
+
+ public void setUiEnable(boolean uiEnable) {
+ this.uiEnable = uiEnable;
+ }
+
+ public String getAllowedOrigins() {
+ return allowedOrigins;
+ }
+
+ public void setAllowedOrigins(String allowedOrigins) {
+ this.allowedOrigins = allowedOrigins;
+ }
}
diff --git a/zipkin-server/http-query-plugin/src/main/java/zipkin/server/query/http/HTTPQueryProvider.java b/zipkin-server/http-query-plugin/src/main/java/zipkin/server/query/http/HTTPQueryProvider.java
index 4e62c90104c..84bf5d103f4 100644
--- a/zipkin-server/http-query-plugin/src/main/java/zipkin/server/query/http/HTTPQueryProvider.java
+++ b/zipkin-server/http-query-plugin/src/main/java/zipkin/server/query/http/HTTPQueryProvider.java
@@ -14,7 +14,18 @@
package zipkin.server.query.http;
+import com.linecorp.armeria.common.HttpData;
+import com.linecorp.armeria.common.HttpHeaderNames;
import com.linecorp.armeria.common.HttpMethod;
+import com.linecorp.armeria.common.HttpStatus;
+import com.linecorp.armeria.common.MediaType;
+import com.linecorp.armeria.common.ServerCacheControl;
+import com.linecorp.armeria.server.HttpService;
+import com.linecorp.armeria.server.RedirectService;
+import com.linecorp.armeria.server.cors.CorsService;
+import com.linecorp.armeria.server.cors.CorsServiceBuilder;
+import com.linecorp.armeria.server.file.FileService;
+import com.linecorp.armeria.server.file.HttpFile;
import org.apache.skywalking.oap.query.zipkin.ZipkinQueryModule;
import org.apache.skywalking.oap.server.core.CoreModule;
import org.apache.skywalking.oap.server.core.server.HTTPHandlerRegister;
@@ -25,12 +36,25 @@
import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedException;
import org.apache.skywalking.oap.server.library.server.http.HTTPServer;
import org.apache.skywalking.oap.server.library.server.http.HTTPServerConfig;
+import zipkin.server.core.services.HTTPConfigurableServer;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.concurrent.TimeUnit;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
public class HTTPQueryProvider extends ModuleProvider {
+ static final String DEFAULT_UI_BASEPATH = "/zipkin";
+
private HTTPQueryConfig moduleConfig;
private HTTPServer httpServer;
+
@Override
public String name() {
return "zipkin";
@@ -68,25 +92,88 @@ public void prepare() throws ServiceNotProvidedException, ModuleStartException {
.acceptQueueSize(moduleConfig.getRestAcceptQueueSize())
.maxRequestHeaderSize(moduleConfig.getRestMaxRequestHeaderSize())
.build();
- httpServer = new HTTPServer(httpServerConfig);
+ httpServer = new HTTPConfigurableServer(httpServerConfig);
httpServer.initialize();
}
}
@Override
public void start() throws ServiceNotProvidedException, ModuleStartException {
+ HTTPConfigurableServer.ServerConfiguration corsConfiguration = (server) -> {
+ CorsServiceBuilder corsBuilder = CorsService.builder(moduleConfig.getAllowedOrigins().split(","))
+ // NOTE: The property says query, and the UI does not use POST, but we allow POST?
+ //
+ // The reason is that our former CORS implementation accidentally allowed POST. People doing
+ // browser-based tracing relied on this, so we can't remove it by default. In the future, we
+ // could split the collector's CORS policy into a different property, still allowing POST
+ // with content-type by default.
+ .allowRequestMethods(HttpMethod.GET, HttpMethod.POST)
+ .allowRequestHeaders(HttpHeaderNames.CONTENT_TYPE,
+ // Use literals to avoid a runtime dependency on armeria-grpc types
+ HttpHeaderNames.of("X-GRPC-WEB"))
+ .exposeHeaders("grpc-status", "grpc-message", "armeria.grpc.ThrowableProto-bin");
+ server.decorator(corsBuilder::build);
+ };
+
+ final HTTPQueryHandler httpService = new HTTPQueryHandler(moduleConfig, getManager());
if (httpServer != null) {
- httpServer.addHandler(new HTTPQueryHandler(moduleConfig, getManager()),
- Collections.singletonList(HttpMethod.GET));
- } else {
- getManager().find(CoreModule.NAME).provider()
- .getService(HTTPHandlerRegister.class).addHandler(
- new HTTPQueryHandler(moduleConfig, getManager()),
- Collections.singletonList(HttpMethod.GET)
- );
+ httpServer.addHandler(httpService, Collections.singletonList(HttpMethod.GET));
+ httpServer.addHandler(corsConfiguration, Arrays.asList(HttpMethod.GET, HttpMethod.POST));
+
+ if (moduleConfig.getUiEnable()) {
+ loadUIServices((service, methods) -> httpServer.addHandler(service, methods), httpService);
+ }
+ return;
+ }
+
+ final HTTPHandlerRegister httpRegister = getManager().find(CoreModule.NAME).provider()
+ .getService(HTTPHandlerRegister.class);
+ httpRegister.addHandler(httpService, Collections.singletonList(HttpMethod.GET));
+ httpRegister.addHandler(corsConfiguration, Arrays.asList(HttpMethod.GET, HttpMethod.POST));
+
+ if (moduleConfig.getUiEnable()) {
+ loadUIServices(httpRegister, httpService);
}
}
+ private void loadUIServices(HTTPHandlerRegister httpRegister, HTTPQueryHandler httpService) {
+ HttpService lensIndex;
+ HttpService uiFileService;
+
+ final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ URL indexPage = contextClassLoader.getResource("zipkin-lens/index.html");
+ if (indexPage == null) {
+ throw new IllegalStateException("Cannot find ui pages");
+ }
+ final String uiBasePath = moduleConfig.getUiBasePath();
+ try {
+ lensIndex = maybeIndexService(uiBasePath, indexPage);
+ } catch (IOException e) {
+ throw new IllegalStateException("Cannot load ui", e);
+ }
+
+ ServerCacheControl maxAgeYear =
+ ServerCacheControl.builder().maxAgeSeconds(TimeUnit.DAYS.toSeconds(365)).build();
+ uiFileService = FileService.builder(contextClassLoader, "zipkin-lens")
+ .cacheControl(maxAgeYear)
+ .build();
+
+ httpRegister.addHandler((HTTPConfigurableServer.ServerConfiguration) builder -> {
+ builder.annotatedService().pathPrefix(uiBasePath + "/").build(httpService);
+ builder.serviceUnder(uiBasePath + "/", uiFileService);
+
+ builder.service(uiBasePath+ "/", lensIndex)
+ .service(uiBasePath + "/index.html", lensIndex)
+ .service(uiBasePath + "/traces/{id}", lensIndex)
+ .service(uiBasePath + "/dependency", lensIndex)
+ .service(uiBasePath + "/traceViewer", lensIndex);
+
+ builder.service("/favicon.ico", new RedirectService(HttpStatus.FOUND, uiBasePath + "/favicon.ico"))
+ .service("/", new RedirectService(HttpStatus.FOUND, uiBasePath + "/"))
+ .service(uiBasePath, new RedirectService(HttpStatus.FOUND, uiBasePath + "/"));
+ }, Collections.singletonList(HttpMethod.GET));
+ }
+
@Override
public void notifyAfterCompleted() throws ServiceNotProvidedException, ModuleStartException {
if (httpServer != null) {
@@ -100,4 +187,42 @@ public String[] requiredModules() {
CoreModule.NAME,
};
}
+
+ static HttpService maybeIndexService(String basePath, URL resource) throws IOException {
+ String maybeContent = maybeResource(basePath, resource);
+ if (maybeContent == null) return null;
+
+ ServerCacheControl maxAgeMinute = ServerCacheControl.builder().maxAgeSeconds(60).build();
+
+ return HttpFile.builder(HttpData.ofUtf8(maybeContent))
+ .contentType(MediaType.HTML_UTF_8).cacheControl(maxAgeMinute)
+ .build().asService();
+ }
+
+ static String maybeResource(String basePath, URL resource) throws IOException {
+ String content = copyToString(resource, UTF_8);
+ if (DEFAULT_UI_BASEPATH.equals(basePath)) return content;
+
+ String baseTagValue = "/".equals(basePath) ? "/" : basePath + "/";
+ // html-webpack-plugin seems to strip out quotes from the base tag when compiling so be
+ // careful with this matcher.
+ return content.replaceAll(
+ "]+>", ""
+ );
+ }
+
+ static String copyToString(URL in, Charset charset) throws IOException {
+ StringBuilder out = new StringBuilder(4096);
+ try (InputStream input = in.openStream(); InputStreamReader reader = new InputStreamReader(input, charset)) {
+ char[] buffer = new char[4096];
+
+ int charsRead;
+ while((charsRead = reader.read(buffer)) != -1) {
+ out.append(buffer, 0, charsRead);
+ }
+ }
+
+ return out.toString();
+ }
+
}
diff --git a/zipkin-server/pom.xml b/zipkin-server/pom.xml
index d812118a243..640b8e7a4d1 100644
--- a/zipkin-server/pom.xml
+++ b/zipkin-server/pom.xml
@@ -69,6 +69,7 @@
receiver-zipkin-scribe
http-query-plugin
health-query-plugin
+ telemetry-zipkin
@@ -216,23 +217,4 @@
-
-
- include-lens
-
-
- !skipLens
-
-
-
-
-
- ${project.groupId}
- zipkin-lens
- ${project.version}
-
-
-
-
-
diff --git a/zipkin-server/receiver-zipkin-http/src/main/java/zipkin/server/receiver/zipkin/http/ZipkinHTTPReceiverProvider.java b/zipkin-server/receiver-zipkin-http/src/main/java/zipkin/server/receiver/zipkin/http/ZipkinHTTPReceiverProvider.java
index 78e10fb6379..c9a3e4cabaa 100644
--- a/zipkin-server/receiver-zipkin-http/src/main/java/zipkin/server/receiver/zipkin/http/ZipkinHTTPReceiverProvider.java
+++ b/zipkin-server/receiver-zipkin-http/src/main/java/zipkin/server/receiver/zipkin/http/ZipkinHTTPReceiverProvider.java
@@ -27,6 +27,7 @@
import org.apache.skywalking.oap.server.library.server.http.HTTPServerConfig;
import org.apache.skywalking.oap.server.receiver.zipkin.handler.ZipkinSpanHTTPHandler;
import org.apache.skywalking.oap.server.receiver.zipkin.trace.SpanForward;
+import zipkin.server.core.services.HTTPConfigurableServer;
import zipkin.server.core.services.ZipkinConfigService;
import java.util.Arrays;
@@ -73,7 +74,7 @@ public void prepare() throws ServiceNotProvidedException, ModuleStartException {
.acceptQueueSize(moduleConfig.getRestAcceptQueueSize())
.maxRequestHeaderSize(moduleConfig.getRestMaxRequestHeaderSize())
.build();
- httpServer = new HTTPServer(httpServerConfig);
+ httpServer = new HTTPConfigurableServer(httpServerConfig);
httpServer.initialize();
}
}
diff --git a/zipkin-server/receiver-zipkin-http/src/test/java/zipkin/server/receiver/zipkin/http/ITHTTPReceiver.java b/zipkin-server/receiver-zipkin-http/src/test/java/zipkin/server/receiver/zipkin/http/ITHTTPReceiver.java
index a6ef6ec0e95..0d72caaee4e 100644
--- a/zipkin-server/receiver-zipkin-http/src/test/java/zipkin/server/receiver/zipkin/http/ITHTTPReceiver.java
+++ b/zipkin-server/receiver-zipkin-http/src/test/java/zipkin/server/receiver/zipkin/http/ITHTTPReceiver.java
@@ -102,7 +102,7 @@ public void test() throws Exception {
}
int responseCode = connection.getResponseCode();
- if (responseCode != HttpURLConnection.HTTP_OK) { // success
+ if (responseCode != HttpURLConnection.HTTP_ACCEPTED) { // success
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
diff --git a/zipkin-server/receiver-zipkin-scribe/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine b/zipkin-server/receiver-zipkin-scribe/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine
new file mode 100644
index 00000000000..ac22e0d7946
--- /dev/null
+++ b/zipkin-server/receiver-zipkin-scribe/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+#
+
+zipkin.server.receiver.zipkin.scribe.ZipkinScribeModule
diff --git a/zipkin-server/receiver-zipkin-scribe/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider b/zipkin-server/receiver-zipkin-scribe/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider
new file mode 100755
index 00000000000..b52d4407984
--- /dev/null
+++ b/zipkin-server/receiver-zipkin-scribe/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+#
+
+zipkin.server.receiver.zipkin.scribe.ZipkinScribeProvider
\ No newline at end of file
diff --git a/zipkin-server/server-core/src/main/java/zipkin/server/core/CoreModuleProvider.java b/zipkin-server/server-core/src/main/java/zipkin/server/core/CoreModuleProvider.java
index 437910e6230..1a53d44e44a 100644
--- a/zipkin-server/server-core/src/main/java/zipkin/server/core/CoreModuleProvider.java
+++ b/zipkin-server/server-core/src/main/java/zipkin/server/core/CoreModuleProvider.java
@@ -13,6 +13,7 @@
*/
package zipkin.server.core;
+import com.linecorp.armeria.common.HttpMethod;
import org.apache.skywalking.oap.server.core.CoreModule;
import org.apache.skywalking.oap.server.core.RunningMode;
import org.apache.skywalking.oap.server.core.analysis.meter.MeterSystem;
@@ -84,11 +85,13 @@
import org.apache.skywalking.oap.server.library.server.http.HTTPServerConfig;
import org.apache.skywalking.oap.server.telemetry.api.TelemetryRelatedContext;
import zipkin.server.core.services.EmptyComponentLibraryCatalogService;
-import zipkin.server.core.services.EmptyHTTPHandlerRegister;
import zipkin.server.core.services.EmptyNetworkAddressAliasCache;
+import zipkin.server.core.services.HTTPConfigurableServer;
+import zipkin.server.core.services.HTTPInfoHandler;
import zipkin.server.core.services.ZipkinConfigService;
import java.io.IOException;
+import java.util.Arrays;
import java.util.Collections;
public class CoreModuleProvider extends ModuleProvider {
@@ -165,8 +168,10 @@ public void prepare() throws ServiceNotProvidedException, ModuleStartException {
.maxRequestHeaderSize(
moduleConfig.getRestMaxRequestHeaderSize())
.build();
- httpServer = new HTTPServer(httpServerConfig);
+ httpServer = new HTTPConfigurableServer(httpServerConfig);
httpServer.initialize();
+ // "/info" handler
+ httpServer.addHandler(new HTTPInfoHandler(), Arrays.asList(HttpMethod.GET, HttpMethod.POST));
// grpc
if (moduleConfig.getGRPCSslEnabled()) {
diff --git a/zipkin-server/server-core/src/main/java/zipkin/server/core/services/HTTPConfigurableServer.java b/zipkin-server/server-core/src/main/java/zipkin/server/core/services/HTTPConfigurableServer.java
new file mode 100644
index 00000000000..05d9e219e0f
--- /dev/null
+++ b/zipkin-server/server-core/src/main/java/zipkin/server/core/services/HTTPConfigurableServer.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015-2023 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.core.services;
+
+import com.linecorp.armeria.common.HttpMethod;
+import com.linecorp.armeria.server.ServerBuilder;
+import org.apache.skywalking.oap.server.library.server.http.HTTPServer;
+import org.apache.skywalking.oap.server.library.server.http.HTTPServerConfig;
+
+import java.util.List;
+
+public class HTTPConfigurableServer extends HTTPServer {
+ public HTTPConfigurableServer(HTTPServerConfig config) {
+ super(config);
+ }
+
+ @Override
+ public void addHandler(Object handler, List httpMethods) {
+ if (handler instanceof ServerConfiguration) {
+ ((ServerConfiguration) handler).configure(sb);
+ allowedMethods.addAll(httpMethods);
+ return;
+ }
+ super.addHandler(handler, httpMethods);
+ }
+
+ public interface ServerConfiguration {
+ void configure(ServerBuilder builder);
+ }
+}
diff --git a/zipkin-server/server-core/src/main/java/zipkin/server/core/services/HTTPInfoHandler.java b/zipkin-server/server-core/src/main/java/zipkin/server/core/services/HTTPInfoHandler.java
new file mode 100644
index 00000000000..9b2bf1b3372
--- /dev/null
+++ b/zipkin-server/server-core/src/main/java/zipkin/server/core/services/HTTPInfoHandler.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2015-2023 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.core.services;
+
+import com.google.gson.Gson;
+import com.linecorp.armeria.common.AggregatedHttpResponse;
+import com.linecorp.armeria.common.HttpData;
+import com.linecorp.armeria.common.HttpStatus;
+import com.linecorp.armeria.common.MediaType;
+import com.linecorp.armeria.server.annotation.Get;
+import org.apache.skywalking.oap.server.core.version.Version;
+
+public class HTTPInfoHandler {
+ private static final Gson GSON = new Gson();
+
+ @Get("/info")
+ public AggregatedHttpResponse info() {
+ return AggregatedHttpResponse.of(HttpStatus.OK, MediaType.JSON, HttpData.ofUtf8(
+ GSON.toJson(Version.CURRENT.getProperties())
+ ));
+ }
+}
diff --git a/zipkin-server/server-starter/pom.xml b/zipkin-server/server-starter/pom.xml
index 6419d5f6773..9bfc243489e 100644
--- a/zipkin-server/server-starter/pom.xml
+++ b/zipkin-server/server-starter/pom.xml
@@ -34,9 +34,9 @@
- org.apache.skywalking
- telemetry-prometheus
- ${skywalking.version}
+ io.zipkin
+ telemetry-zipkin
+ ${project.version}
@@ -114,6 +114,25 @@
+
+
+ include-lens
+
+
+ !skipLens
+
+
+
+
+
+ ${project.groupId}
+ zipkin-lens
+ ${project.version}
+
+
+
+
+
diff --git a/zipkin-server/server-starter/src/main/resources/application.yml b/zipkin-server/server-starter/src/main/resources/application.yml
index 1ff4dd2ea63..8f280c886a6 100644
--- a/zipkin-server/server-starter/src/main/resources/application.yml
+++ b/zipkin-server/server-starter/src/main/resources/application.yml
@@ -220,6 +220,7 @@ query-zipkin:
restAcceptQueueSize: ${ZIPKIN_QUERY_REST_QUEUE_SIZE:0}
restMaxRequestHeaderSize: ${ZIPKIN_QUERY_REST_MAX_REQUEST_HEADER_SIZE:8192}
strictTraceId: ${ZIPKIN_QUERY_STRICT_TRACE_ID:true}
+ allowedOrigins: ${ZIPKIN_QUERY_ALLOWED_ORIGINS:"*"}
# Default look back for traces and autocompleteTags, 1 day in millis
lookback: ${ZIPKIN_QUERY_LOOKBACK:86400000}
# The Cache-Control max-age (seconds) for serviceNames, remoteServiceNames and spanNames
@@ -229,6 +230,8 @@ query-zipkin:
uiQueryLimit: ${ZIPKIN_QUERY_UI_QUERY_LIMIT:10}
# Default look back on the UI for search traces, 15 minutes in millis
uiDefaultLookback: ${ZIPKIN_QUERY_UI_DEFAULT_LOOKBACK:900000}
+ uiEnable: ${ZIPKIN_QUERY_UI_ENABLE:true}
+ uiBasePath: ${ZIPKIN_QUERY_UI_BASE_PATH:/zipkin}
query-health:
selector: ${ZIPKIN_QUERY_HEALTH:zipkin}
@@ -243,14 +246,17 @@ query-health:
restMaxRequestHeaderSize: ${ZIPKIN_QUERY_HEALTH_REST_MAX_REQUEST_HEADER_SIZE:8192}
telemetry:
- selector: ${ZIPKIN_TELEMETRY:none}
+ selector: ${ZIPKIN_TELEMETRY:zipkin}
none:
- prometheus:
- host: ${ZIPKIN_TELEMETRY_PROMETHEUS_HOST:0.0.0.0}
- port: ${ZIPKIN_TELEMETRY_PROMETHEUS_PORT:1234}
- sslEnabled: ${ZIPKIN_TELEMETRY_PROMETHEUS_SSL_ENABLED:false}
- sslKeyPath: ${ZIPKIN_TELEMETRY_PROMETHEUS_SSL_KEY_PATH:""}
- sslCertChainPath: ${ZIPKIN_TELEMETRY_PROMETHEUS_SSL_CERT_CHAIN_PATH:""}
+ zipkin:
+ restHost: ${ZIPKIN_QUERY_HEALTH_REST_HOST:0.0.0.0}
+ # The port number of the HTTP service, the default HTTP service in the core would be used if the value is smaller than 0.
+ restPort: ${ZIPKIN_QUERY_HEALTH_REST_PORT:-1}
+ restContextPath: ${ZIPKIN_QUERY_HEALTH_REST_CONTEXT_PATH:/}
+ restMaxThreads: ${ZIPKIN_QUERY_HEALTH_REST_MAX_THREADS:200}
+ restIdleTimeOut: ${ZIPKIN_QUERY_HEALTH_REST_IDLE_TIMEOUT:30000}
+ restAcceptQueueSize: ${ZIPKIN_QUERY_HEALTH_REST_QUEUE_SIZE:0}
+ restMaxRequestHeaderSize: ${ZIPKIN_QUERY_HEALTH_REST_MAX_REQUEST_HEADER_SIZE:8192}
cluster:
selector: standalone
diff --git a/zipkin-server/telemetry-zipkin/pom.xml b/zipkin-server/telemetry-zipkin/pom.xml
new file mode 100644
index 00000000000..cf74731f909
--- /dev/null
+++ b/zipkin-server/telemetry-zipkin/pom.xml
@@ -0,0 +1,28 @@
+
+
+ 4.0.0
+
+ zipkin-server-parent
+ io.zipkin
+ 2.24.4-SNAPSHOT
+
+
+ Telemetry Zipkin
+ telemetry-zipkin
+
+
+
+ org.apache.skywalking
+ telemetry-prometheus
+ ${skywalking.version}
+
+
+ io.zipkin
+ zipkin-server-core
+ ${project.version}
+
+
+
+
\ No newline at end of file
diff --git a/zipkin-server/telemetry-zipkin/src/main/java/zipkin/server/telemetry/ZipkinTelemetryConfig.java b/zipkin-server/telemetry-zipkin/src/main/java/zipkin/server/telemetry/ZipkinTelemetryConfig.java
new file mode 100644
index 00000000000..f5b81dda66a
--- /dev/null
+++ b/zipkin-server/telemetry-zipkin/src/main/java/zipkin/server/telemetry/ZipkinTelemetryConfig.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2015-2023 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.telemetry;
+
+import org.apache.skywalking.oap.server.library.module.ModuleConfig;
+
+public class ZipkinTelemetryConfig extends ModuleConfig {
+ private String restHost;
+ private int restPort;
+ private String restContextPath;
+ private int restMaxThreads = 200;
+ private long restIdleTimeOut = 30000;
+ private int restAcceptQueueSize = 0;
+ /**
+ * The maximum size in bytes allowed for request headers.
+ * Use -1 to disable it.
+ */
+ private int restMaxRequestHeaderSize = 8192;
+
+ public String getRestHost() {
+ return restHost;
+ }
+
+ public void setRestHost(String restHost) {
+ this.restHost = restHost;
+ }
+
+ public int getRestPort() {
+ return restPort;
+ }
+
+ public void setRestPort(int restPort) {
+ this.restPort = restPort;
+ }
+
+ public String getRestContextPath() {
+ return restContextPath;
+ }
+
+ public void setRestContextPath(String restContextPath) {
+ this.restContextPath = restContextPath;
+ }
+
+ public int getRestMaxThreads() {
+ return restMaxThreads;
+ }
+
+ public void setRestMaxThreads(int restMaxThreads) {
+ this.restMaxThreads = restMaxThreads;
+ }
+
+ public long getRestIdleTimeOut() {
+ return restIdleTimeOut;
+ }
+
+ public void setRestIdleTimeOut(long restIdleTimeOut) {
+ this.restIdleTimeOut = restIdleTimeOut;
+ }
+
+ public int getRestAcceptQueueSize() {
+ return restAcceptQueueSize;
+ }
+
+ public void setRestAcceptQueueSize(int restAcceptQueueSize) {
+ this.restAcceptQueueSize = restAcceptQueueSize;
+ }
+
+ public int getRestMaxRequestHeaderSize() {
+ return restMaxRequestHeaderSize;
+ }
+
+ public void setRestMaxRequestHeaderSize(int restMaxRequestHeaderSize) {
+ this.restMaxRequestHeaderSize = restMaxRequestHeaderSize;
+ }
+}
diff --git a/zipkin-server/telemetry-zipkin/src/main/java/zipkin/server/telemetry/ZipkinTelemetryHandler.java b/zipkin-server/telemetry-zipkin/src/main/java/zipkin/server/telemetry/ZipkinTelemetryHandler.java
new file mode 100644
index 00000000000..e13fadf4156
--- /dev/null
+++ b/zipkin-server/telemetry-zipkin/src/main/java/zipkin/server/telemetry/ZipkinTelemetryHandler.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2015-2023 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.telemetry;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.linecorp.armeria.common.AggregatedHttpResponse;
+import com.linecorp.armeria.common.HttpData;
+import com.linecorp.armeria.common.HttpStatus;
+import com.linecorp.armeria.common.MediaType;
+import com.linecorp.armeria.server.annotation.Get;
+import io.prometheus.client.Collector;
+import io.prometheus.client.CollectorRegistry;
+import io.prometheus.client.exporter.common.TextFormat;
+import org.apache.logging.log4j.core.util.StringBuilderWriter;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+public class ZipkinTelemetryHandler {
+ private final Gson gson = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
+ private final CollectorRegistry registry = CollectorRegistry.defaultRegistry;
+
+ @Get("/metrics")
+ public AggregatedHttpResponse metrics() throws IOException {
+ final JsonObject jsonObject = new JsonObject();
+ final Enumeration samples = registry.metricFamilySamples();
+ while (samples.hasMoreElements()) {
+ final Collector.MetricFamilySamples sampleFamily = samples.nextElement();
+ final JsonArray sampleFamilyJsonArray = new JsonArray();
+ jsonObject.add(sampleFamily.name, sampleFamilyJsonArray);
+ for (Collector.MetricFamilySamples.Sample sample : sampleFamily.samples) {
+ final JsonObject sampleJson = new JsonObject();
+ final JsonObject meterTags = new JsonObject();
+ sampleJson.add("tags", meterTags);
+ for (int i = 0; i < sample.labelNames.size(); i++) {
+ meterTags.addProperty(sample.labelNames.get(i), sample.labelValues.get(i));
+ }
+ sampleJson.addProperty("type", sampleFamily.type.name());
+ sampleJson.addProperty("value", sample.value);
+ sampleFamilyJsonArray.add(sampleJson);
+ }
+ }
+ return AggregatedHttpResponse.of(HttpStatus.OK, MediaType.JSON, HttpData.ofUtf8(gson.toJson(jsonObject)));
+ }
+
+ @Get("/prometheus")
+ public AggregatedHttpResponse prometheus() throws IOException {
+ StringBuilderWriter buf = new StringBuilderWriter();
+ TextFormat.write004(buf, registry.metricFamilySamples());
+ return AggregatedHttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, HttpData.ofUtf8(buf.toString()));
+ }
+}
diff --git a/zipkin-server/telemetry-zipkin/src/main/java/zipkin/server/telemetry/ZipkinTelemetryProvider.java b/zipkin-server/telemetry-zipkin/src/main/java/zipkin/server/telemetry/ZipkinTelemetryProvider.java
new file mode 100644
index 00000000000..839d2b1e152
--- /dev/null
+++ b/zipkin-server/telemetry-zipkin/src/main/java/zipkin/server/telemetry/ZipkinTelemetryProvider.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2015-2023 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.telemetry;
+
+import com.linecorp.armeria.common.HttpMethod;
+import io.prometheus.client.hotspot.DefaultExports;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.server.HTTPHandlerRegister;
+import org.apache.skywalking.oap.server.library.module.ModuleConfig;
+import org.apache.skywalking.oap.server.library.module.ModuleDefine;
+import org.apache.skywalking.oap.server.library.module.ModuleProvider;
+import org.apache.skywalking.oap.server.library.module.ModuleStartException;
+import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedException;
+import org.apache.skywalking.oap.server.library.server.http.HTTPServer;
+import org.apache.skywalking.oap.server.library.server.http.HTTPServerConfig;
+import org.apache.skywalking.oap.server.telemetry.TelemetryModule;
+import org.apache.skywalking.oap.server.telemetry.api.MetricsCollector;
+import org.apache.skywalking.oap.server.telemetry.api.MetricsCreator;
+import org.apache.skywalking.oap.server.telemetry.prometheus.PrometheusMetricsCollector;
+import org.apache.skywalking.oap.server.telemetry.prometheus.PrometheusMetricsCreator;
+import zipkin.server.core.services.HTTPConfigurableServer;
+
+import java.util.Arrays;
+
+public class ZipkinTelemetryProvider extends ModuleProvider {
+ private ZipkinTelemetryConfig moduleConfig;
+ private HTTPServer httpServer;
+ @Override
+ public String name() {
+ return "zipkin";
+ }
+
+ @Override
+ public Class extends ModuleDefine> module() {
+ return TelemetryModule.class;
+ }
+
+ @Override
+ public ConfigCreator extends ModuleConfig> newConfigCreator() {
+ return new ConfigCreator() {
+ @Override
+ public Class type() {
+ return ZipkinTelemetryConfig.class;
+ }
+
+ @Override
+ public void onInitialized(ZipkinTelemetryConfig initialized) {
+ moduleConfig = initialized;
+ }
+ };
+ }
+
+ @Override
+ public void prepare() throws ServiceNotProvidedException, ModuleStartException {
+ this.registerServiceImplementation(MetricsCreator.class, new PrometheusMetricsCreator());
+ this.registerServiceImplementation(MetricsCollector.class, new PrometheusMetricsCollector());
+
+ if (moduleConfig.getRestPort() > 0) {
+ HTTPServerConfig httpServerConfig = HTTPServerConfig.builder()
+ .host(moduleConfig.getRestHost())
+ .port(moduleConfig.getRestPort())
+ .contextPath(moduleConfig.getRestContextPath())
+ .idleTimeOut(moduleConfig.getRestIdleTimeOut())
+ .maxThreads(moduleConfig.getRestMaxThreads())
+ .acceptQueueSize(moduleConfig.getRestAcceptQueueSize())
+ .maxRequestHeaderSize(moduleConfig.getRestMaxRequestHeaderSize())
+ .build();
+ httpServer = new HTTPConfigurableServer(httpServerConfig);
+ httpServer.initialize();
+ }
+
+ DefaultExports.initialize();
+ }
+
+ @Override
+ public void start() throws ServiceNotProvidedException, ModuleStartException {
+ final ZipkinTelemetryHandler handler = new ZipkinTelemetryHandler();
+ if (httpServer != null) {
+ httpServer.addHandler(handler, Arrays.asList(HttpMethod.GET, HttpMethod.POST));
+ return;
+ }
+ final HTTPHandlerRegister httpRegister = getManager().find(CoreModule.NAME).provider()
+ .getService(HTTPHandlerRegister.class);
+ httpRegister.addHandler(handler, Arrays.asList(HttpMethod.GET, HttpMethod.POST));
+ }
+
+ @Override
+ public void notifyAfterCompleted() throws ServiceNotProvidedException, ModuleStartException {
+ if (httpServer != null) {
+ httpServer.start();
+ }
+ }
+
+ @Override
+ public String[] requiredModules() {
+ return new String[0];
+ }
+}
diff --git a/zipkin-server/telemetry-zipkin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider b/zipkin-server/telemetry-zipkin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider
new file mode 100755
index 00000000000..7e588ef8c28
--- /dev/null
+++ b/zipkin-server/telemetry-zipkin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+#
+
+zipkin.server.telemetry.ZipkinTelemetryProvider
\ No newline at end of file