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..43db33e1803 100644 --- a/zipkin-server/http-query-plugin/pom.xml +++ b/zipkin-server/http-query-plugin/pom.xml @@ -18,6 +18,16 @@ zipkin-query-plugin ${skywalking.version} + + io.zipkin + zipkin-server-core + ${project.version} + + + io.zipkin + zipkin-dependency + ${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..d55fac3cdad 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,14 @@ 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"; + + private boolean dependencyEnabled = true; + private double dependencyLowErrorRate = 0.5; // 50% of calls in error turns line yellow + private double dependencyHighErrorRate = 0.75;// 75% of calls in error turns line red public ZipkinQueryConfig toSkyWalkingConfig() { final ZipkinQueryConfig result = new ZipkinQueryConfig(); @@ -160,4 +168,52 @@ 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; + } + + public boolean getDependencyEnabled() { + return dependencyEnabled; + } + + public void setDependencyEnabled(boolean dependencyEnabled) { + this.dependencyEnabled = dependencyEnabled; + } + + public double getDependencyLowErrorRate() { + return dependencyLowErrorRate; + } + + public void setDependencyLowErrorRate(double dependencyLowErrorRate) { + this.dependencyLowErrorRate = dependencyLowErrorRate; + } + + public double getDependencyHighErrorRate() { + return dependencyHighErrorRate; + } + + public void setDependencyHighErrorRate(double dependencyHighErrorRate) { + this.dependencyHighErrorRate = dependencyHighErrorRate; + } } diff --git a/zipkin-server/http-query-plugin/src/main/java/zipkin/server/query/http/HTTPQueryHandler.java b/zipkin-server/http-query-plugin/src/main/java/zipkin/server/query/http/HTTPQueryHandler.java index e3ae7ae5950..fab3dc224fc 100644 --- a/zipkin-server/http-query-plugin/src/main/java/zipkin/server/query/http/HTTPQueryHandler.java +++ b/zipkin-server/http-query-plugin/src/main/java/zipkin/server/query/http/HTTPQueryHandler.java @@ -14,27 +14,38 @@ package zipkin.server.query.http; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; 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.common.ResponseHeaders; +import com.linecorp.armeria.server.annotation.Blocking; +import com.linecorp.armeria.server.annotation.Get; +import com.linecorp.armeria.server.annotation.Param; import org.apache.skywalking.oap.query.zipkin.handler.ZipkinQueryHandler; import org.apache.skywalking.oap.server.core.storage.StorageModule; import org.apache.skywalking.oap.server.core.storage.query.IZipkinQueryDAO; import org.apache.skywalking.oap.server.library.module.ModuleManager; import org.apache.skywalking.oap.server.library.util.CollectionUtils; import org.apache.skywalking.oap.server.library.util.StringUtil; +import zipkin.server.dependency.IZipkinDependencyQueryDAO; +import zipkin.server.dependency.ZipkinDependencyModule; +import zipkin2.DependencyLink; import zipkin2.Span; +import zipkin2.codec.DependencyLinkBytesEncoder; import zipkin2.codec.SpanBytesEncoder; import java.io.IOException; +import java.io.StringWriter; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -47,12 +58,41 @@ public class HTTPQueryHandler extends ZipkinQueryHandler { private final ModuleManager moduleManager; private IZipkinQueryDAO zipkinQueryDAO; + private IZipkinDependencyQueryDAO dependencyQueryDAO; public HTTPQueryHandler(HTTPQueryConfig config, ModuleManager moduleManager) { super(config.toSkyWalkingConfig(), moduleManager); this.config = config; this.moduleManager = moduleManager; } + @Override + public AggregatedHttpResponse getUIConfig() throws IOException { + StringWriter writer = new StringWriter(); + JsonGenerator generator = new JsonFactory().createGenerator(writer); + generator.writeStartObject(); + generator.writeStringField("environment", config.getUiEnvironment()); + generator.writeNumberField("queryLimit", config.getUiQueryLimit()); + generator.writeNumberField("defaultLookback", config.getUiDefaultLookback()); + generator.writeBooleanField("searchEnabled", config.getUiSearchEnabled()); + generator.writeObjectFieldStart("dependency"); + generator.writeBooleanField("enabled", config.getDependencyEnabled()); + generator.writeNumberField("lowErrorRate", config.getDependencyLowErrorRate()); + generator.writeNumberField("highErrorRate", config.getDependencyHighErrorRate()); + generator.writeEndObject(); + generator.writeEndObject(); + generator.close(); + return AggregatedHttpResponse.of(HttpStatus.OK, MediaType.JSON, HttpData.ofUtf8(writer.toString())); + } + + @Get("/api/v2/dependencies") + @Blocking + public AggregatedHttpResponse getDependencies( + @Param("endTs") long endTs, + @Param("lookback") Optional lookback) throws IOException { + final List dependencies = getDependencyQueryDAO().getDependencies(endTs, lookback.orElse(config.getLookback())); + return response(DependencyLinkBytesEncoder.JSON_V1.encodeList(dependencies)); + } + @Override public AggregatedHttpResponse getTraceById(String traceId) throws IOException { if (StringUtil.isEmpty(traceId)) { @@ -129,4 +169,11 @@ private IZipkinQueryDAO getZipkinQueryDAO() { } return zipkinQueryDAO; } + + public IZipkinDependencyQueryDAO getDependencyQueryDAO() { + if (dependencyQueryDAO == null) { + dependencyQueryDAO = moduleManager.find(ZipkinDependencyModule.NAME).provider().getService(IZipkinDependencyQueryDAO.class); + } + return dependencyQueryDAO; + } } 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 83c620a8db7..f2bd95d2cf2 100644 --- a/zipkin-server/pom.xml +++ b/zipkin-server/pom.xml @@ -70,6 +70,9 @@ storage-cassandra http-query-plugin health-query-plugin + telemetry-zipkin + zipkin-dependency + zipkin-storage-ext @@ -217,23 +220,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/pom.xml b/zipkin-server/server-core/pom.xml index 315695c31cf..02b3525b5a0 100644 --- a/zipkin-server/server-core/pom.xml +++ b/zipkin-server/server-core/pom.xml @@ -24,6 +24,11 @@ zipkin-receiver-plugin ${skywalking.version} + + io.github.classgraph + classgraph + 4.8.162 + \ 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..7b41cf933f2 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 { @@ -96,14 +99,14 @@ public class CoreModuleProvider extends ModuleProvider { private EndpointNameGrouping endpointNameGrouping; private final ZipkinSourceReceiverImpl receiver; - private final AnnotationScan annotationScan; + private final ZipkinAnnotationScan annotationScan; private final StorageModels storageModels; private RemoteClientManager remoteClientManager; private GRPCServer grpcServer; private HTTPServer httpServer; public CoreModuleProvider() { - this.annotationScan = new AnnotationScan(); + this.annotationScan = new ZipkinAnnotationScan(); this.receiver = new ZipkinSourceReceiverImpl(); this.storageModels = new StorageModels(); } @@ -144,16 +147,9 @@ public void prepare() throws ServiceNotProvidedException, ModuleStartException { ); this.registerServiceImplementation(NamingControl.class, namingControl); + annotationScan.registerListener(new DefaultScopeDefine.Listener()); annotationScan.registerListener(new ZipkinStreamAnnotationListener(getManager())); - AnnotationScan scopeScan = new AnnotationScan(); - scopeScan.registerListener(new DefaultScopeDefine.Listener()); - try { - scopeScan.scan(); - } catch (Exception e) { - throw new ModuleStartException(e.getMessage(), e); - } - HTTPServerConfig httpServerConfig = HTTPServerConfig.builder() .host(moduleConfig.getRestHost()) .port(moduleConfig.getRestPort()) @@ -165,8 +161,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/ZipkinAnnotationScan.java b/zipkin-server/server-core/src/main/java/zipkin/server/core/ZipkinAnnotationScan.java new file mode 100644 index 00000000000..02c45b84d3d --- /dev/null +++ b/zipkin-server/server-core/src/main/java/zipkin/server/core/ZipkinAnnotationScan.java @@ -0,0 +1,91 @@ +/* + * 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; + +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ScanResult; +import org.apache.skywalking.oap.server.core.annotation.AnnotationListener; +import org.apache.skywalking.oap.server.core.storage.StorageException; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + +public class ZipkinAnnotationScan { + private final List listeners; + + public ZipkinAnnotationScan() { + this.listeners = new LinkedList<>(); + } + + /** + * Register the callback listener + * + * @param listener to be called after class found w/ annotation + */ + public void registerListener(AnnotationListener listener) { + listeners.add(new AnnotationListenerCache(listener)); + } + + public void scan() throws IOException, StorageException { + ClassGraph classGraph = new ClassGraph(); + classGraph.enableClassInfo(); + final ScanResult scan = classGraph.scan(); + for (ClassInfo classInfo : scan.getAllClasses()) { + // not skywalking package or a subclass should ignore + if (!classInfo.getName().startsWith("org.apache.skywalking") || classInfo.getName().contains("$")) { + continue; + } + final Class aClass = classInfo.loadClass(); + for (AnnotationListenerCache listener : listeners) { + if (aClass.isAnnotationPresent(listener.annotation())) { + listener.addMatch(aClass); + } + } + } + + for (AnnotationListenerCache listener : listeners) { + listener.complete(); + } + } + + private class AnnotationListenerCache { + private AnnotationListener listener; + private List> matchedClass; + + private AnnotationListenerCache(AnnotationListener listener) { + this.listener = listener; + matchedClass = new LinkedList<>(); + } + + private Class annotation() { + return this.listener.annotation(); + } + + private void addMatch(Class aClass) { + matchedClass.add(aClass); + } + + private void complete() throws StorageException { + matchedClass.sort(Comparator.comparing(Class::getName)); + for (Class aClass : matchedClass) { + listener.notify(aClass); + } + } + } + +} diff --git a/zipkin-server/server-core/src/main/java/zipkin/server/core/ZipkinDispatcherManager.java b/zipkin-server/server-core/src/main/java/zipkin/server/core/ZipkinDispatcherManager.java index c4c33d79d2e..81579eb44a1 100644 --- a/zipkin-server/server-core/src/main/java/zipkin/server/core/ZipkinDispatcherManager.java +++ b/zipkin-server/server-core/src/main/java/zipkin/server/core/ZipkinDispatcherManager.java @@ -14,11 +14,31 @@ package zipkin.server.core; +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ScanResult; import org.apache.skywalking.oap.server.core.analysis.DispatcherManager; import org.apache.skywalking.oap.server.core.analysis.manual.searchtag.TagAutocompleteDispatcher; +import java.io.IOException; + public class ZipkinDispatcherManager extends DispatcherManager { + @Override + public void scan() throws IOException, IllegalAccessException, InstantiationException { + ClassGraph classGraph = new ClassGraph(); + classGraph.enableClassInfo(); + final ScanResult scan = classGraph.scan(); + for (ClassInfo classInfo : scan.getAllClasses()) { + // not skywalking package or a subclass should ignore + if (!classInfo.getName().startsWith("org.apache.skywalking") || classInfo.getName().contains("$")) { + continue; + } + final Class aClass = classInfo.loadClass(); + addIfAsSourceDispatcher(aClass); + } + } + @Override public void addIfAsSourceDispatcher(Class aClass) throws IllegalAccessException, InstantiationException { if (aClass.getSimpleName().startsWith("Zipkin") || aClass.equals(TagAutocompleteDispatcher.class)) { diff --git a/zipkin-server/server-core/src/main/java/zipkin/server/core/ZipkinStreamAnnotationListener.java b/zipkin-server/server-core/src/main/java/zipkin/server/core/ZipkinStreamAnnotationListener.java index a1ba4398eb6..1d605b67b80 100644 --- a/zipkin-server/server-core/src/main/java/zipkin/server/core/ZipkinStreamAnnotationListener.java +++ b/zipkin-server/server-core/src/main/java/zipkin/server/core/ZipkinStreamAnnotationListener.java @@ -16,6 +16,7 @@ import org.apache.skywalking.oap.server.core.analysis.StreamAnnotationListener; import org.apache.skywalking.oap.server.core.analysis.manual.searchtag.TagAutocompleteData; +import org.apache.skywalking.oap.server.core.analysis.manual.spanattach.SpanAttachedEventRecord; import org.apache.skywalking.oap.server.core.storage.StorageException; import org.apache.skywalking.oap.server.library.module.ModuleDefineHolder; @@ -28,7 +29,7 @@ public ZipkinStreamAnnotationListener(ModuleDefineHolder moduleDefineHolder) { @Override public void notify(Class aClass) throws StorageException { // only including all zipkin streaming - if (aClass.getSimpleName().startsWith("Zipkin") || aClass.equals(TagAutocompleteData.class)) { + if (aClass.getSimpleName().startsWith("Zipkin") || aClass.equals(TagAutocompleteData.class) || aClass.equals(SpanAttachedEventRecord.class)) { super.notify(aClass); } } 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 bd21c9373ca..4bcb4288ff9 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} @@ -61,6 +61,23 @@ ${project.version} + + + io.zipkin + zipkin-dependency-storage-jdbc + ${project.version} + + + io.zipkin + zipkin-dependency-storage-elasticsearch + ${project.version} + + + io.zipkin + zipkin-dependency-storage-banyandb + ${project.version} + + io.zipkin @@ -117,8 +134,34 @@ slf4j-api ${slf4j.version} + + + + com.mysql + mysql-connector-j + 8.0.33 + + + + 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 d1f98c4406e..1bafe4e3b14 100644 --- a/zipkin-server/server-starter/src/main/resources/application.yml +++ b/zipkin-server/server-starter/src/main/resources/application.yml @@ -56,7 +56,7 @@ core: restAcceptQueueSize: ${ZIPKIN_REST_QUEUE_SIZE:0} restMaxRequestHeaderSize: ${ZIPKIN_REST_MAX_REQUEST_HEADER_SIZE:8192} -storage: +storage: &storage selector: ${ZIPKIN_STORAGE:h2} elasticsearch: namespace: ${ZIPKIN_NAMESPACE:""} @@ -164,6 +164,8 @@ storage: maxSizeOfBatchCql: ${ZIPKIN_STORAGE_CASSANDRA_MAX_SIZE_OF_BATCH_CQL:2000} asyncBatchPersistentPoolSize: ${ZIPKIN_STORAGE_CASSANDRA_ASYNC_BATCH_PERSISTENT_POOL_SIZE:4} +zipkin-dependency-storage-ext: *storage + receiver-zipkin-http: selector: ${ZIPKIN_RECEIVER_ZIPKIN_HTTP:default} default: @@ -237,6 +239,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 @@ -246,6 +249,11 @@ 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} + dependencyEnabled: ${ZIPKIN_QUERY_DEPENDENCY_ENABLED:true} + dependencyLowErrorRate: ${ZIPKIN_QUERY_DEPENDENCY_LOW_ERROR_RATE:0.5} + dependencyHighErrorRate: ${ZIPKIN_QUERY_DEPENDENCY_HIGH_ERROR_RATE:0.75} query-health: selector: ${ZIPKIN_QUERY_HEALTH:zipkin} @@ -260,14 +268,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 module() { + return TelemetryModule.class; + } + + @Override + public ConfigCreator 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 diff --git a/zipkin-server/zipkin-dependency/pom.xml b/zipkin-server/zipkin-dependency/pom.xml new file mode 100644 index 00000000000..5eb2c4d7879 --- /dev/null +++ b/zipkin-server/zipkin-dependency/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + zipkin-server-parent + io.zipkin + 2.24.4-SNAPSHOT + + + zipkin-dependency + Zipkin Dependency + + + + io.zipkin + zipkin-server-core + ${project.version} + + + + \ No newline at end of file diff --git a/zipkin-server/zipkin-dependency/src/main/java/org/apache/skywalking/zipkin/dependency/entity/ZipkinDependency.java b/zipkin-server/zipkin-dependency/src/main/java/org/apache/skywalking/zipkin/dependency/entity/ZipkinDependency.java new file mode 100644 index 00000000000..af62d54dd4f --- /dev/null +++ b/zipkin-server/zipkin-dependency/src/main/java/org/apache/skywalking/zipkin/dependency/entity/ZipkinDependency.java @@ -0,0 +1,176 @@ +/* + * 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 org.apache.skywalking.zipkin.dependency.entity; + +import org.apache.skywalking.oap.server.core.analysis.MetricsExtension; +import org.apache.skywalking.oap.server.core.analysis.Stream; +import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics; +import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor; +import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData; +import org.apache.skywalking.oap.server.core.source.ScopeDeclaration; +import org.apache.skywalking.oap.server.core.storage.StorageID; +import org.apache.skywalking.oap.server.core.storage.annotation.BanyanDB; +import org.apache.skywalking.oap.server.core.storage.annotation.Column; +import org.apache.skywalking.oap.server.core.storage.type.Convert2Entity; +import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage; +import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder; + +import java.util.Objects; + +@ScopeDeclaration(id = 10001, name = "ZipkinDependency") +@Stream(name = ZipkinDependency.INDEX_NAME, scopeId = 10001, builder = ZipkinDependency.Builder.class, processor = MetricsStreamProcessor.class) +@MetricsExtension(supportDownSampling = false, supportUpdate = false) +@BanyanDB.TimestampColumn(ZipkinDependency.DAY) +public class ZipkinDependency extends Metrics { + public static final String INDEX_NAME = "zipkin_dependency"; + public static final String DAY = "analyze_day"; + public static final String PARENT = "parent"; + public static final String CHILD = "child"; + public static final String CALL_COUNT = "call_count"; + public static final String ERROR_COUNT = "error_count"; + + @Column(name = DAY) + @BanyanDB.SeriesID(index = 0) + private long day; + @Column(name = PARENT) + @BanyanDB.SeriesID(index = 1) + private String parent; + @Column(name = CHILD) + @BanyanDB.SeriesID(index = 2) + private String child; + @Column(name = CALL_COUNT) + @BanyanDB.MeasureField + private long callCount; + @Column(name = ERROR_COUNT) + @BanyanDB.MeasureField + private long errorCount; + + @Override + public boolean combine(Metrics metrics) { + return true; + } + + @Override + public void calculate() { + } + + @Override + public Metrics toHour() { + return null; + } + + @Override + public Metrics toDay() { + return null; + } + + @Override + protected StorageID id0() { + return new StorageID().append(DAY, day) + .append(PARENT, parent).append(CHILD, child); + } + + @Override + public void deserialize(RemoteData remoteData) { + } + + @Override + public RemoteData.Builder serialize() { + // only query from the storage + return null; + } + + @Override + public int remoteHashCode() { + return (int) this.day; + } + + public static class Builder implements StorageBuilder { + + @Override + public ZipkinDependency storage2Entity(Convert2Entity converter) { + final ZipkinDependency record = new ZipkinDependency(); + record.setDay(((Number) converter.get(DAY)).longValue()); + record.setParent((String) converter.get(PARENT)); + record.setChild((String) converter.get(CHILD)); + record.setCallCount(((Number) converter.get(CALL_COUNT)).longValue()); + record.setErrorCount(((Number) converter.get(ERROR_COUNT)).longValue()); + return record; + } + + @Override + public void entity2Storage(ZipkinDependency entity, Convert2Storage converter) { + converter.accept(DAY, entity.getDay()); + converter.accept(PARENT, entity.getParent()); + converter.accept(CHILD, entity.getChild()); + converter.accept(CALL_COUNT, entity.getCallCount()); + converter.accept(ERROR_COUNT, entity.getErrorCount()); + } + } + + public Long getDay() { + return day; + } + + public void setDay(Long day) { + this.day = day; + } + + public String getParent() { + return parent; + } + + public void setParent(String parent) { + this.parent = parent; + } + + public String getChild() { + return child; + } + + public void setChild(String child) { + this.child = child; + } + + public Long getCallCount() { + return callCount; + } + + public void setCallCount(Long callCount) { + this.callCount = callCount; + } + + public Long getErrorCount() { + return errorCount; + } + + public void setErrorCount(Long errorCount) { + this.errorCount = errorCount; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ZipkinDependency)) return false; + if (!super.equals(o)) return false; + ZipkinDependency that = (ZipkinDependency) o; + return getDay() == that.getDay() && Objects.equals(getParent(), that.getParent()) && Objects.equals(getChild(), that.getChild()); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), getDay(), getParent(), getChild()); + } +} diff --git a/zipkin-server/zipkin-dependency/src/main/java/zipkin/server/dependency/IZipkinDependencyQueryDAO.java b/zipkin-server/zipkin-dependency/src/main/java/zipkin/server/dependency/IZipkinDependencyQueryDAO.java new file mode 100644 index 00000000000..10586b2e31e --- /dev/null +++ b/zipkin-server/zipkin-dependency/src/main/java/zipkin/server/dependency/IZipkinDependencyQueryDAO.java @@ -0,0 +1,26 @@ +/* + * 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.dependency; + +import org.apache.skywalking.oap.server.library.module.Service; +import zipkin2.DependencyLink; + +import java.io.IOException; +import java.util.List; + +public interface IZipkinDependencyQueryDAO extends Service { + + List getDependencies(long endTs, long lookback) throws IOException; +} diff --git a/zipkin-server/zipkin-dependency/src/main/java/zipkin/server/dependency/ZipkinDependencyModule.java b/zipkin-server/zipkin-dependency/src/main/java/zipkin/server/dependency/ZipkinDependencyModule.java new file mode 100644 index 00000000000..1680003eb6a --- /dev/null +++ b/zipkin-server/zipkin-dependency/src/main/java/zipkin/server/dependency/ZipkinDependencyModule.java @@ -0,0 +1,30 @@ +/* + * 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.dependency; + +import org.apache.skywalking.oap.server.library.module.ModuleDefine; + +public class ZipkinDependencyModule extends ModuleDefine { + public static final String NAME = "zipkin-dependency-storage-ext"; + + public ZipkinDependencyModule() { + super(NAME); + } + + @Override + public Class[] services() { + return new Class[] {IZipkinDependencyQueryDAO.class}; + } +} diff --git a/zipkin-server/zipkin-dependency/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine b/zipkin-server/zipkin-dependency/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine new file mode 100644 index 00000000000..578ab0f83a8 --- /dev/null +++ b/zipkin-server/zipkin-dependency/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.dependency.ZipkinDependencyModule \ No newline at end of file diff --git a/zipkin-server/zipkin-storage-ext/pom.xml b/zipkin-server/zipkin-storage-ext/pom.xml new file mode 100644 index 00000000000..66c0033b42c --- /dev/null +++ b/zipkin-server/zipkin-storage-ext/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + pom + + zipkin-server-parent + io.zipkin + 2.24.4-SNAPSHOT + + + zipkin-storage-ext + Zipkin Storage Extension + + + zipkin-dependency-storage-jdbc + zipkin-dependency-storage-elasticsearch + zipkin-dependency-storage-banyandb + + + + + io.zipkin + zipkin-dependency + ${project.version} + + + + \ No newline at end of file diff --git a/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-banyandb/pom.xml b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-banyandb/pom.xml new file mode 100644 index 00000000000..17f0c460bbc --- /dev/null +++ b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-banyandb/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + zipkin-storage-ext + io.zipkin + 2.24.4-SNAPSHOT + + + zipkin-dependency-storage-banyandb + Zipkin Dependency BanyanDB Extension + + + + org.apache.skywalking + storage-banyandb-plugin + ${skywalking.version} + + + + \ No newline at end of file diff --git a/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-banyandb/src/main/java/zipkin/server/dependency/storage/banyandb/ZipkinDependencyBanyanDBQueryDAO.java b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-banyandb/src/main/java/zipkin/server/dependency/storage/banyandb/ZipkinDependencyBanyanDBQueryDAO.java new file mode 100644 index 00000000000..67eb7f897b2 --- /dev/null +++ b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-banyandb/src/main/java/zipkin/server/dependency/storage/banyandb/ZipkinDependencyBanyanDBQueryDAO.java @@ -0,0 +1,60 @@ +/* + * 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.dependency.storage.banyandb; + +import com.google.common.collect.ImmutableSet; +import org.apache.skywalking.banyandb.v1.client.MeasureQuery; +import org.apache.skywalking.banyandb.v1.client.MeasureQueryResponse; +import org.apache.skywalking.banyandb.v1.client.TimestampRange; +import org.apache.skywalking.oap.server.core.query.enumeration.Step; +import org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageClient; +import org.apache.skywalking.oap.server.storage.plugin.banyandb.MetadataRegistry; +import org.apache.skywalking.zipkin.dependency.entity.ZipkinDependency; +import zipkin.server.dependency.IZipkinDependencyQueryDAO; +import zipkin2.DependencyLink; +import zipkin2.internal.DependencyLinker; + +import java.io.IOException; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static zipkin2.internal.DateUtil.epochDays; + +public class ZipkinDependencyBanyanDBQueryDAO implements IZipkinDependencyQueryDAO { + protected BanyanDBStorageClient client; + final Set tags = ImmutableSet.of(ZipkinDependency.DAY, ZipkinDependency.PARENT, ZipkinDependency.CHILD); + final Set fields = ImmutableSet.of(ZipkinDependency.CALL_COUNT, ZipkinDependency.ERROR_COUNT); + + @Override + public List getDependencies(long endTs, long lookback) throws IOException { + final List days = epochDays(endTs, lookback); + final TimestampRange timeRange = new TimestampRange(days.get(0), days.get(days.size() - 1) + 1); + MetadataRegistry.Schema schema = MetadataRegistry.INSTANCE.findMetadata(ZipkinDependency.INDEX_NAME, Step.MINUTE); + final MeasureQuery query = new MeasureQuery(schema.getMetadata().getGroup(), schema.getMetadata().name(), timeRange, tags, fields); + final MeasureQueryResponse result = client.query(query); + return DependencyLinker.merge(result.getDataPoints().stream().map(s -> DependencyLink.newBuilder() + .parent(s.getTagValue(ZipkinDependency.PARENT)) + .child(s.getTagValue(ZipkinDependency.CHILD)) + .callCount(((Number)s.getFieldValue(ZipkinDependency.CALL_COUNT)).longValue()) + .errorCount(s.getFieldValue(ZipkinDependency.ERROR_COUNT) != null ? ((Number)s.getFieldValue(ZipkinDependency.ERROR_COUNT)).longValue() : 0) + .build()).collect(Collectors.toList())); + } + + public void setClient(BanyanDBStorageClient client) { + this.client = client; + } + +} diff --git a/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-banyandb/src/main/java/zipkin/server/dependency/storage/banyandb/ZipkinDependencyBanyanDBStorageProvider.java b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-banyandb/src/main/java/zipkin/server/dependency/storage/banyandb/ZipkinDependencyBanyanDBStorageProvider.java new file mode 100644 index 00000000000..0f7571077e8 --- /dev/null +++ b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-banyandb/src/main/java/zipkin/server/dependency/storage/banyandb/ZipkinDependencyBanyanDBStorageProvider.java @@ -0,0 +1,91 @@ +/* + * 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.dependency.storage.banyandb; + +import org.apache.skywalking.oap.server.core.CoreModule; +import org.apache.skywalking.oap.server.core.storage.StorageModule; +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.storage.plugin.banyandb.BanyanDBStorageClient; +import org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageConfig; +import org.apache.skywalking.oap.server.storage.plugin.banyandb.BanyanDBStorageProvider; +import zipkin.server.dependency.IZipkinDependencyQueryDAO; +import zipkin.server.dependency.ZipkinDependencyModule; + +import java.lang.reflect.Field; + +public class ZipkinDependencyBanyanDBStorageProvider extends ModuleProvider { + private BanyanDBStorageConfig config; + private ZipkinDependencyBanyanDBQueryDAO queryDAO; + + @Override + public String name() { + return "banyandb"; + } + + @Override + public Class module() { + return ZipkinDependencyModule.class; + } + + @Override + public ConfigCreator newConfigCreator() { + return new ConfigCreator() { + + @Override + public Class type() { + return BanyanDBStorageConfig.class; + } + + @Override + public void onInitialized(BanyanDBStorageConfig initialized) { + config = initialized; + } + }; + } + + @Override + public void prepare() throws ServiceNotProvidedException, ModuleStartException { + this.queryDAO = new ZipkinDependencyBanyanDBQueryDAO(); + this.registerServiceImplementation(IZipkinDependencyQueryDAO.class, this.queryDAO); + } + + @Override + public void start() throws ServiceNotProvidedException, ModuleStartException { + + } + + @Override + public void notifyAfterCompleted() throws ServiceNotProvidedException, ModuleStartException { + BanyanDBStorageProvider provider = + (BanyanDBStorageProvider) getManager().find(StorageModule.NAME).provider(); + try { + Field field = BanyanDBStorageProvider.class.getDeclaredField("client"); + field.setAccessible(true); + BanyanDBStorageClient client = (BanyanDBStorageClient) field.get(provider); + queryDAO.setClient(client); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new ModuleStartException("Failed to get BanyanDBStorageClient.", e); + } + } + + @Override + public String[] requiredModules() { + return new String[] {CoreModule.NAME, StorageModule.NAME}; + } +} diff --git a/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-banyandb/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-banyandb/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider new file mode 100644 index 00000000000..dbee1d7b454 --- /dev/null +++ b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-banyandb/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.dependency.storage.banyandb.ZipkinDependencyBanyanDBStorageProvider \ No newline at end of file diff --git a/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-elasticsearch/pom.xml b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-elasticsearch/pom.xml new file mode 100644 index 00000000000..18589f758b8 --- /dev/null +++ b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-elasticsearch/pom.xml @@ -0,0 +1,23 @@ + + + + zipkin-storage-ext + io.zipkin + 2.24.4-SNAPSHOT + + 4.0.0 + + zipkin-dependency-storage-elasticsearch + Zipkin Dependency Elasticsearch Extension + + + + org.apache.skywalking + storage-elasticsearch-plugin + ${skywalking.version} + + + + \ No newline at end of file diff --git a/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-elasticsearch/src/main/java/zipkin/server/dependency/storage/elasticsearch/ZipkinDependencyElasticsearchQueryDAO.java b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-elasticsearch/src/main/java/zipkin/server/dependency/storage/elasticsearch/ZipkinDependencyElasticsearchQueryDAO.java new file mode 100644 index 00000000000..9615d8ef842 --- /dev/null +++ b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-elasticsearch/src/main/java/zipkin/server/dependency/storage/elasticsearch/ZipkinDependencyElasticsearchQueryDAO.java @@ -0,0 +1,63 @@ +/* + * 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.dependency.storage.elasticsearch; + +import org.apache.skywalking.library.elasticsearch.requests.search.BoolQueryBuilder; +import org.apache.skywalking.library.elasticsearch.requests.search.Query; +import org.apache.skywalking.library.elasticsearch.requests.search.Search; +import org.apache.skywalking.library.elasticsearch.requests.search.SearchBuilder; +import org.apache.skywalking.library.elasticsearch.response.search.SearchResponse; +import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient; +import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.IndexController; +import org.apache.skywalking.zipkin.dependency.entity.ZipkinDependency; +import zipkin.server.dependency.IZipkinDependencyQueryDAO; +import zipkin2.DependencyLink; +import zipkin2.internal.DependencyLinker; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import static zipkin2.internal.DateUtil.epochDays; + +public class ZipkinDependencyElasticsearchQueryDAO implements IZipkinDependencyQueryDAO { + private ElasticSearchClient client; + @Override + public List getDependencies(long endTs, long lookback) throws IOException { + final List days = epochDays(endTs, lookback); + + final String index = + IndexController.LogicIndicesRegister.getPhysicalTableName(ZipkinDependency.INDEX_NAME); + final BoolQueryBuilder query = Query.bool(); + if (IndexController.LogicIndicesRegister.isMergedTable(ZipkinDependency.INDEX_NAME)) { + query.must(Query.term(IndexController.LogicIndicesRegister.METRIC_TABLE_NAME, ZipkinDependency.INDEX_NAME)); + } + query.must(Query.terms(ZipkinDependency.DAY, days)); + final SearchBuilder search = Search.builder().query(query) + .size(days.size()); + + final SearchResponse response = client.search(index, search.build()); + return DependencyLinker.merge(response.getHits().getHits().stream().map(h -> DependencyLink.newBuilder() + .parent((String) h.getSource().get(ZipkinDependency.PARENT)) + .child((String) h.getSource().get(ZipkinDependency.CHILD)) + .callCount(((Number) h.getSource().get(ZipkinDependency.CALL_COUNT)).longValue()) + .errorCount(((Number) h.getSource().get(ZipkinDependency.ERROR_COUNT)).longValue()) + .build()).collect(Collectors.toList())); + } + + public void setClient(ElasticSearchClient client) { + this.client = client; + } +} diff --git a/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-elasticsearch/src/main/java/zipkin/server/dependency/storage/elasticsearch/ZipkinDependencyElasticsearchStorageProvider.java b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-elasticsearch/src/main/java/zipkin/server/dependency/storage/elasticsearch/ZipkinDependencyElasticsearchStorageProvider.java new file mode 100644 index 00000000000..39d318c73ab --- /dev/null +++ b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-elasticsearch/src/main/java/zipkin/server/dependency/storage/elasticsearch/ZipkinDependencyElasticsearchStorageProvider.java @@ -0,0 +1,92 @@ +/* + * 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.dependency.storage.elasticsearch; + +import org.apache.skywalking.oap.server.core.CoreModule; +import org.apache.skywalking.oap.server.core.storage.StorageModule; +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.storage.plugin.elasticsearch.StorageModuleElasticsearchConfig; +import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.StorageModuleElasticsearchProvider; +import zipkin.server.dependency.IZipkinDependencyQueryDAO; +import zipkin.server.dependency.ZipkinDependencyModule; + +import java.lang.reflect.Field; + +public class ZipkinDependencyElasticsearchStorageProvider extends ModuleProvider { + private StorageModuleElasticsearchConfig config; + private ZipkinDependencyElasticsearchQueryDAO queryDAO; + + @Override + public String name() { + return "elasticsearch"; + } + + @Override + public Class module() { + return ZipkinDependencyModule.class; + } + + @Override + public ConfigCreator newConfigCreator() { + return new ConfigCreator() { + + @Override + public Class type() { + return StorageModuleElasticsearchConfig.class; + } + + @Override + public void onInitialized(StorageModuleElasticsearchConfig initialized) { + config = initialized; + } + }; + } + + @Override + public void prepare() throws ServiceNotProvidedException, ModuleStartException { + this.queryDAO = new ZipkinDependencyElasticsearchQueryDAO(); + this.registerServiceImplementation(IZipkinDependencyQueryDAO.class, this.queryDAO); + } + + @Override + public void start() throws ServiceNotProvidedException, ModuleStartException { + + } + + @Override + public void notifyAfterCompleted() throws ServiceNotProvidedException, ModuleStartException { + StorageModuleElasticsearchProvider provider = (StorageModuleElasticsearchProvider) getManager().find(StorageModule.NAME) + .provider(); + queryDAO.setClient(getFieldValue(provider, StorageModuleElasticsearchProvider.class, "elasticSearchClient")); + } + + private T getFieldValue(Object from, Class fieldBelongClass, String fieldName) throws ModuleStartException { + try { + Field field = fieldBelongClass.getDeclaredField(fieldName); + field.setAccessible(true); + return (T) field.get(from); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new ModuleStartException("Failed to get " + fieldName, e); + } + } + + @Override + public String[] requiredModules() { + return new String[] {CoreModule.NAME, StorageModule.NAME}; + } +} diff --git a/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-elasticsearch/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-elasticsearch/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider new file mode 100644 index 00000000000..49876f6e19c --- /dev/null +++ b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-elasticsearch/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.dependency.storage.elasticsearch.ZipkinDependencyElasticsearchStorageProvider \ No newline at end of file diff --git a/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/pom.xml b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/pom.xml new file mode 100644 index 00000000000..5cc241a35a3 --- /dev/null +++ b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/pom.xml @@ -0,0 +1,23 @@ + + + + zipkin-storage-ext + io.zipkin + 2.24.4-SNAPSHOT + + 4.0.0 + + zipkin-dependency-storage-jdbc + Zipkin Dependency JDBC Extension + + + + org.apache.skywalking + storage-jdbc-hikaricp-plugin + ${skywalking.version} + + + + \ No newline at end of file diff --git a/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/java/zipkin/server/dependency/storage/jdbc/common/ZipkinDependencyJDBCStorageProvider.java b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/java/zipkin/server/dependency/storage/jdbc/common/ZipkinDependencyJDBCStorageProvider.java new file mode 100644 index 00000000000..b3eb49ad88b --- /dev/null +++ b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/java/zipkin/server/dependency/storage/jdbc/common/ZipkinDependencyJDBCStorageProvider.java @@ -0,0 +1,89 @@ +/* + * 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.dependency.storage.jdbc.common; + +import org.apache.skywalking.oap.server.core.CoreModule; +import org.apache.skywalking.oap.server.core.storage.StorageModule; +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.storage.plugin.jdbc.common.JDBCStorageConfig; +import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.JDBCStorageProvider; +import zipkin.server.dependency.IZipkinDependencyQueryDAO; +import zipkin.server.dependency.ZipkinDependencyModule; +import zipkin.server.dependency.storage.jdbc.common.dao.ZipkinDependencyJDBCQueryDAO; + +import java.lang.reflect.Field; + +public abstract class ZipkinDependencyJDBCStorageProvider extends ModuleProvider { + private JDBCStorageConfig config; + private ZipkinDependencyJDBCQueryDAO queryDAO; + + @Override + public Class module() { + return ZipkinDependencyModule.class; + } + + @Override + public ConfigCreator newConfigCreator() { + return new ConfigCreator() { + @Override + public Class type() { + return JDBCStorageConfig.class; + } + + @Override + public void onInitialized(JDBCStorageConfig initialized) { + config = initialized; + } + }; + } + + @Override + public void prepare() throws ServiceNotProvidedException, ModuleStartException { + this.queryDAO = new ZipkinDependencyJDBCQueryDAO(); + this.registerServiceImplementation(IZipkinDependencyQueryDAO.class, queryDAO); + } + + @Override + public void start() throws ServiceNotProvidedException, ModuleStartException { + + } + + @Override + public void notifyAfterCompleted() throws ServiceNotProvidedException, ModuleStartException { + JDBCStorageProvider provider = + (JDBCStorageProvider) getManager().find(StorageModule.NAME).provider(); + queryDAO.setClient(getFieldValue(provider, JDBCStorageProvider.class, "jdbcClient")); + queryDAO.setTableHelper(getFieldValue(provider, JDBCStorageProvider.class, "tableHelper")); + } + + private T getFieldValue(Object from, Class fieldBelongClass, String fieldName) throws ModuleStartException { + try { + Field field = fieldBelongClass.getDeclaredField(fieldName); + field.setAccessible(true); + return (T) field.get(from); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new ModuleStartException("Failed to get " + fieldName, e); + } + } + + @Override + public String[] requiredModules() { + return new String[] {CoreModule.NAME, StorageModule.NAME}; + } +} diff --git a/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/java/zipkin/server/dependency/storage/jdbc/common/dao/ZipkinDependencyJDBCQueryDAO.java b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/java/zipkin/server/dependency/storage/jdbc/common/dao/ZipkinDependencyJDBCQueryDAO.java new file mode 100644 index 00000000000..17a8cee50b1 --- /dev/null +++ b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/java/zipkin/server/dependency/storage/jdbc/common/dao/ZipkinDependencyJDBCQueryDAO.java @@ -0,0 +1,75 @@ +/* + * 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.dependency.storage.jdbc.common.dao; + +import org.apache.skywalking.oap.server.core.analysis.DownSampling; +import org.apache.skywalking.oap.server.core.analysis.TimeBucket; +import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCClient; +import org.apache.skywalking.oap.server.storage.plugin.jdbc.common.TableHelper; +import org.apache.skywalking.zipkin.dependency.entity.ZipkinDependency; +import zipkin.server.dependency.IZipkinDependencyQueryDAO; +import zipkin2.DependencyLink; +import zipkin2.internal.DependencyLinker; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import static java.util.stream.Collectors.joining; +import static zipkin2.internal.DateUtil.epochDays; + +public class ZipkinDependencyJDBCQueryDAO implements IZipkinDependencyQueryDAO { + private JDBCClient client; + private TableHelper tableHelper; + + @Override + public List getDependencies(long endTs, long lookback) throws IOException { + final List days = epochDays(endTs, lookback); + + final long startBucket = TimeBucket.getTimeBucket(endTs - lookback, DownSampling.Day); + final long endBucket = TimeBucket.getTimeBucket(endTs, DownSampling.Day); + final List result = new ArrayList<>(); + + for (String table : tableHelper.getTablesForRead(ZipkinDependency.INDEX_NAME, startBucket, endBucket)) { + try { + client.executeQuery("select * from " + table + " where " + ZipkinDependency.DAY + " in " + + days.stream().map(it -> "?").collect(joining(",", "(", ")")), + resultSet -> { + while (resultSet.next()) { + result.add(DependencyLink.newBuilder() + .parent(resultSet.getString(ZipkinDependency.PARENT)) + .child(resultSet.getString(ZipkinDependency.CHILD)) + .callCount(resultSet.getLong(ZipkinDependency.CALL_COUNT)) + .errorCount(resultSet.getLong(ZipkinDependency.ERROR_COUNT)) + .build()); + } + return null; + }, days.toArray()); + } catch (SQLException e) { + throw new IOException(e); + } + } + return DependencyLinker.merge(result); + } + + public void setClient(JDBCClient client) { + this.client = client; + } + + public void setTableHelper(TableHelper tableHelper) { + this.tableHelper = tableHelper; + } +} diff --git a/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/java/zipkin/server/dependency/storage/jdbc/h2/ZipkinDependencyH2StorageProvider.java b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/java/zipkin/server/dependency/storage/jdbc/h2/ZipkinDependencyH2StorageProvider.java new file mode 100644 index 00000000000..3ab0f6beb14 --- /dev/null +++ b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/java/zipkin/server/dependency/storage/jdbc/h2/ZipkinDependencyH2StorageProvider.java @@ -0,0 +1,24 @@ +/* + * 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.dependency.storage.jdbc.h2; + +import zipkin.server.dependency.storage.jdbc.common.ZipkinDependencyJDBCStorageProvider; + +public class ZipkinDependencyH2StorageProvider extends ZipkinDependencyJDBCStorageProvider { + @Override + public String name() { + return "h2"; + } +} diff --git a/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/java/zipkin/server/dependency/storage/jdbc/mysql/ZipkinDependencyMySQLStorageProvider.java b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/java/zipkin/server/dependency/storage/jdbc/mysql/ZipkinDependencyMySQLStorageProvider.java new file mode 100644 index 00000000000..8adad7198d8 --- /dev/null +++ b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/java/zipkin/server/dependency/storage/jdbc/mysql/ZipkinDependencyMySQLStorageProvider.java @@ -0,0 +1,24 @@ +/* + * 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.dependency.storage.jdbc.mysql; + +import zipkin.server.dependency.storage.jdbc.common.ZipkinDependencyJDBCStorageProvider; + +public class ZipkinDependencyMySQLStorageProvider extends ZipkinDependencyJDBCStorageProvider { + @Override + public String name() { + return "mysql"; + } +} diff --git a/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/java/zipkin/server/dependency/storage/jdbc/postgres/ZipkinDependencyPostgresStorageProvider.java b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/java/zipkin/server/dependency/storage/jdbc/postgres/ZipkinDependencyPostgresStorageProvider.java new file mode 100644 index 00000000000..485a49e482d --- /dev/null +++ b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/java/zipkin/server/dependency/storage/jdbc/postgres/ZipkinDependencyPostgresStorageProvider.java @@ -0,0 +1,24 @@ +/* + * 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.dependency.storage.jdbc.postgres; + +import zipkin.server.dependency.storage.jdbc.common.ZipkinDependencyJDBCStorageProvider; + +public class ZipkinDependencyPostgresStorageProvider extends ZipkinDependencyJDBCStorageProvider { + @Override + public String name() { + return "postgresql"; + } +} diff --git a/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider new file mode 100644 index 00000000000..60a365293b3 --- /dev/null +++ b/zipkin-server/zipkin-storage-ext/zipkin-dependency-storage-jdbc/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider @@ -0,0 +1,21 @@ +# +# 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.dependency.storage.jdbc.h2.ZipkinDependencyH2StorageProvider +zipkin.server.dependency.storage.jdbc.mysql.ZipkinDependencyMySQLStorageProvider +zipkin.server.dependency.storage.jdbc.postgres.ZipkinDependencyPostgresStorageProvider \ No newline at end of file