diff --git a/README.md b/README.md index 7abfb85..7bc5757 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ For a Maven project, add the following to your pom.xml file: group.rxcloud capa-sdk - 1.0.6.RELEASE + 1.0.7.RELEASE ... @@ -140,7 +140,7 @@ Sample implementation library: group.rxcloud capa-sdk-spi-demo - 1.0.6.RELEASE + 1.0.7.RELEASE ... diff --git a/README_ZH.md b/README_ZH.md index 15e2d00..a13a2ae 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -118,7 +118,7 @@ For a Maven project, add the following to your pom.xml file: group.rxcloud capa-sdk - 1.0.6.RELEASE + 1.0.7.RELEASE ... @@ -138,7 +138,7 @@ Sample implementation library: group.rxcloud capa-sdk-spi-demo - 1.0.6.RELEASE + 1.0.7.RELEASE ... diff --git a/examples/pom.xml b/examples/pom.xml index 8af886a..739a0b7 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ capa-parent group.rxcloud - 1.0.6.RELEASE + 1.0.7.RELEASE capa-examples @@ -31,7 +31,9 @@ capa-sdk-examples - 2.14.1 + 2.8.2 + 1.1.7 + 1.7.32 @@ -58,21 +60,23 @@ - + org.apache.logging.log4j log4j-slf4j-impl ${log4j.version} - - - log4j-core - org.apache.logging.log4j - - - log4j-api - org.apache.logging.log4j - - + + + + + + org.projectlombok + lombok + 1.18.2 diff --git a/examples/src/main/java/group/rxcloud/capa/examples/log/DemoLog.java b/examples/src/main/java/group/rxcloud/capa/examples/log/DemoLog.java new file mode 100644 index 0000000..20ac7e2 --- /dev/null +++ b/examples/src/main/java/group/rxcloud/capa/examples/log/DemoLog.java @@ -0,0 +1,35 @@ +/* + * 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. + */ +package group.rxcloud.capa.examples.log; + +import lombok.extern.slf4j.Slf4j; + +/** + * An application cannot use log4j and logback configuration to print logs at the same time. + * So if you want to test the log4j2 configuration to print logs, then you need to copy the resources/xml/log4j2.xml file to the resources directory, and then add log4j-slf4j-impl dependency to the pom file. + * Else if you want to use logback configuration to print logs, then the resources/xml/logback.xml file needs to be copied to the resources path, and the logback-classic dependency needs to be added to the pom file. + * Notice: + * 1. Resources cannot contain log4j2.xml and logback.xml files at the same time, + * 2. log4j-slf4j-impl and logback-classic cannot exist at the same time. + */ +@Slf4j +public class DemoLog { + + public static void main(String[] args) { + log.info("test"); + } +} diff --git a/examples/src/main/java/group/rxcloud/capa/examples/telemetry/DemoTelemetryClient.java b/examples/src/main/java/group/rxcloud/capa/examples/telemetry/DemoTelemetryClient.java new file mode 100644 index 0000000..8ef4efd --- /dev/null +++ b/examples/src/main/java/group/rxcloud/capa/examples/telemetry/DemoTelemetryClient.java @@ -0,0 +1,61 @@ +/* + * 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. + */ +package group.rxcloud.capa.examples.telemetry; + +import group.rxcloud.capa.component.telemetry.metrics.MetricsReaderConfig; +import group.rxcloud.capa.telemetry.CapaTelemetryClient; +import group.rxcloud.capa.telemetry.CapaTelemetryClientBuilder; +import io.opentelemetry.api.metrics.LongCounter; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; + +import java.util.concurrent.TimeUnit; + +public class DemoTelemetryClient { + + public static void main(String[] args) throws InterruptedException { + MetricsReaderConfig readerConfig = new MetricsReaderConfig(); + readerConfig.setExporterType(MetricTestExporter.class.getName()); + readerConfig.setName("metric-reader"); + readerConfig.setExportInterval(1, TimeUnit.SECONDS); + CapaTelemetryClient capaTelemetryClient = new CapaTelemetryClientBuilder() + .addProcessor(new TraceProcessor()) + .addMetricReaderConfig(readerConfig) + .build(); + + // tracer + Tracer tracer = capaTelemetryClient.buildTracer("tracer-test") + .block(); + + LongCounter counter = capaTelemetryClient.buildMeter("meter-test") + .block() + .counterBuilder("counter-test") + .build(); + + Span span = tracer.spanBuilder("span-test") + .setAttribute("key1", 1) + .setAttribute("key2", 2) + .startSpan(); + // working + for (int i = 0; i < 50; i++) { + Thread.sleep(200); + counter.add(i); + } + + span.end(); + } +} diff --git a/examples/src/main/java/group/rxcloud/capa/examples/telemetry/MetricTestExporter.java b/examples/src/main/java/group/rxcloud/capa/examples/telemetry/MetricTestExporter.java new file mode 100644 index 0000000..2615920 --- /dev/null +++ b/examples/src/main/java/group/rxcloud/capa/examples/telemetry/MetricTestExporter.java @@ -0,0 +1,42 @@ +/* + * 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. + */ +package group.rxcloud.capa.examples.telemetry; + +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.export.MetricExporter; + +import java.util.Collection; + +public class MetricTestExporter implements MetricExporter { + + @Override + public CompletableResultCode export(Collection metrics) { + metrics.forEach(System.out::println); + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode flush() { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode shutdown() { + return CompletableResultCode.ofSuccess(); + } +} diff --git a/examples/src/main/java/group/rxcloud/capa/examples/telemetry/TraceProcessor.java b/examples/src/main/java/group/rxcloud/capa/examples/telemetry/TraceProcessor.java new file mode 100644 index 0000000..63f5589 --- /dev/null +++ b/examples/src/main/java/group/rxcloud/capa/examples/telemetry/TraceProcessor.java @@ -0,0 +1,45 @@ +/* + * 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. + */ +package group.rxcloud.capa.examples.telemetry; + +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.trace.ReadWriteSpan; +import io.opentelemetry.sdk.trace.ReadableSpan; +import io.opentelemetry.sdk.trace.SpanProcessor; + +public class TraceProcessor implements SpanProcessor { + + @Override + public void onStart(Context context, ReadWriteSpan span) { + + } + + @Override + public boolean isStartRequired() { + return false; + } + + @Override + public void onEnd(ReadableSpan span) { + System.out.println(span.toSpanData()); + } + + @Override + public boolean isEndRequired() { + return true; + } +} diff --git a/examples/src/main/resources/log4j2.xml b/examples/src/main/resources/log4j2.xml index f923cdb..3587353 100644 --- a/examples/src/main/resources/log4j2.xml +++ b/examples/src/main/resources/log4j2.xml @@ -20,10 +20,12 @@ + - + + \ No newline at end of file diff --git a/examples/src/main/resources/xml/log4j2.xml b/examples/src/main/resources/xml/log4j2.xml new file mode 100644 index 0000000..3587353 --- /dev/null +++ b/examples/src/main/resources/xml/log4j2.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/src/main/resources/xml/logback.xml b/examples/src/main/resources/xml/logback.xml new file mode 100644 index 0000000..268d16c --- /dev/null +++ b/examples/src/main/resources/xml/logback.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 352e1ab..8928e20 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ group.rxcloud capa-parent pom - 1.0.6.RELEASE + 1.0.7.RELEASE capa-sdk-parent SDK for Capa. https://github.com/reactivegroup @@ -73,8 +73,12 @@ 8 UTF-8 3.8.1 - 1.0.7.RELEASE + 1.0.9.RELEASE 3.3.22.RELEASE + 1.7.21 + 1.9.0 + 1.9.0-alpha + 5.3.1 3.6.0 3.1.2 @@ -132,6 +136,25 @@ true + + + org.slf4j + slf4j-api + ${slf4j.version} + + + + + io.opentelemetry + opentelemetry-api + ${open.telemetry.version} + + + io.opentelemetry + opentelemetry-api-metrics + ${open.telemetry.version.alpha} + + org.junit.jupiter @@ -308,6 +331,7 @@ docs/** spec/** **/generated/** + **/*.json diff --git a/sdk-component/pom.xml b/sdk-component/pom.xml index 5cea9fb..22941a3 100644 --- a/sdk-component/pom.xml +++ b/sdk-component/pom.xml @@ -23,7 +23,7 @@ group.rxcloud capa-parent - 1.0.6.RELEASE + 1.0.7.RELEASE capa-sdk-component @@ -33,6 +33,8 @@ 4.9.1 1.4.10 + 2.8.2 + 1.1.7 @@ -42,6 +44,17 @@ capa-sdk-infrastructure + + io.opentelemetry + opentelemetry-sdk + 1.9.0 + + + io.opentelemetry + opentelemetry-sdk-metrics + 1.9.0-alpha + + com.squareup.okhttp3 @@ -71,6 +84,21 @@ ${kotlin-stdlib.version} + + + org.apache.logging.log4j + log4j-core + true + ${log4j.version} + + + + ch.qos.logback + logback-core + true + ${logback.version} + + org.junit.jupiter junit-jupiter-engine diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/configstore/CapaConfigStore.java b/sdk-component/src/main/java/group/rxcloud/capa/component/configstore/CapaConfigStore.java index b6513bb..c4dd186 100644 --- a/sdk-component/src/main/java/group/rxcloud/capa/component/configstore/CapaConfigStore.java +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/configstore/CapaConfigStore.java @@ -55,6 +55,8 @@ public CapaConfigStore(CapaObjectSerializer objectSerializer) { /** * Init the configuration store. + * + * @param storeConfig storeConfig */ public void init(StoreConfig storeConfig) { this.storeName = storeConfig.getStoreName(); @@ -68,6 +70,8 @@ public void init(StoreConfig storeConfig) { /** * Gets store name. + * + * @return storeName */ public String getStoreName() { return this.storeName; @@ -75,26 +79,42 @@ public String getStoreName() { /** * GetSpecificKeysValue get specific key value. + * + * @param getRequest request + * @param type response type + * @param type + * @return mono of response */ public abstract Mono>> get(GetRequest getRequest, TypeRef type); /** * Subscribe the configurations updates. + * + * @param subscribeReq request + * @param type response type + * @param type + * @return flux of subscribe */ public abstract Flux> subscribe(SubscribeReq subscribeReq, TypeRef type); /** * StopSubscribe stop subs + * + * @return result */ public abstract String stopSubscribe(); /** * GetDefaultGroup returns default group.This method will be invoked if a request doesn't specify the group field + * + * @return default */ public abstract String getDefaultGroup(); /** * GetDefaultLabel returns default label + * + * @return default */ public abstract String getDefaultLabel(); } diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/configstore/CapaConfigStoreBuilder.java b/sdk-component/src/main/java/group/rxcloud/capa/component/configstore/CapaConfigStoreBuilder.java index fe5baef..c12e3c8 100644 --- a/sdk-component/src/main/java/group/rxcloud/capa/component/configstore/CapaConfigStoreBuilder.java +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/configstore/CapaConfigStoreBuilder.java @@ -81,6 +81,7 @@ public CapaConfigStore build() { * @return Instance of {@link CapaConfigStore} implementor */ private CapaConfigStore buildCapaConfigStore() { + // TODO: 2021/11/30 build multi component // load spi capa config store impl return CapaClassLoader.loadComponentClassObj( "configuration", diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/http/CapaHttpBuilder.java b/sdk-component/src/main/java/group/rxcloud/capa/component/http/CapaHttpBuilder.java index 2d3d9c5..087ceba 100644 --- a/sdk-component/src/main/java/group/rxcloud/capa/component/http/CapaHttpBuilder.java +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/http/CapaHttpBuilder.java @@ -108,7 +108,9 @@ private CapaHttp buildCapaHttp() { return CapaClassLoader.loadComponentClassObj( "rpc", CapaHttp.class, - new Class[]{OkHttpClient.class, CapaObjectSerializer.class}, - new Object[]{OK_HTTP_CLIENT.get(), this.objectSerializer}); + new Class[]{OkHttpClient.class, + CapaObjectSerializer.class}, + new Object[]{OK_HTTP_CLIENT.get(), + this.objectSerializer}); } } diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/http/HttpResponse.java b/sdk-component/src/main/java/group/rxcloud/capa/component/http/HttpResponse.java index 82537e1..e0fc625 100644 --- a/sdk-component/src/main/java/group/rxcloud/capa/component/http/HttpResponse.java +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/http/HttpResponse.java @@ -45,6 +45,8 @@ public HttpResponse(T body, Map headers, int statusCode) { /** * Gets actual response data. + * + * @return */ public T getBody() { return body; @@ -52,6 +54,8 @@ public T getBody() { /** * Gets http headers. + * + * @return */ public Map getHeaders() { return headers; @@ -59,6 +63,8 @@ public Map getHeaders() { /** * Gets http invocation status code. + * + * @return */ public int getStatusCode() { return statusCode; diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/log/agent/CapaLog4jAppenderAgent.java b/sdk-component/src/main/java/group/rxcloud/capa/component/log/agent/CapaLog4jAppenderAgent.java new file mode 100644 index 0000000..e05cd68 --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/log/agent/CapaLog4jAppenderAgent.java @@ -0,0 +1,115 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.log.agent; + +import group.rxcloud.capa.infrastructure.CapaClassLoader; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.appender.AbstractAppender; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginAttribute; +import org.apache.logging.log4j.core.config.plugins.PluginElement; +import org.apache.logging.log4j.core.config.plugins.PluginFactory; + +import java.io.Serializable; + +/** + * The abstract log4j appender. Extend this and provide your specific impl. + */ +@Plugin(name = "CapaLog4jAppender", elementType = Appender.ELEMENT_TYPE, category = "Core") +public class CapaLog4jAppenderAgent extends AbstractAppender { + + /** + * The log component type. + */ + private static final String LOG_COMPONENT_TYPE = "log"; + /** + * Capa log4j appender instance. + */ + private static final CapaLog4jAppender logAppender; + + /** + * Init the logbackAppender impl. + */ + static { + logAppender = buildCapaLog4jAppender(); + } + + /** + * Instantiates a new Capa log4j appender. + * + * @param name The name of the appender. + * @param filter The filter of the appender. + * @param layout The layout of the appender. + * @param ignoreExceptions Whether to ignore exceptions. + */ + public CapaLog4jAppenderAgent(String name, + Filter filter, + Layout layout, + boolean ignoreExceptions) { + super(name, filter, layout, ignoreExceptions); + } + + /** + * Create a appender instance. + * + * @param name The name of the appender. + * @param filter The filter of the appender. + * @param layout The layout of the appender. + * @param ignoreExceptions Whether to ignore exceptions. + * @return CapaLog4jAppender instance. + */ + @PluginFactory + public static CapaLog4jAppenderAgent createAppender(@PluginAttribute("name") String name, + @PluginElement("Filter") final Filter filter, + @PluginElement("Layout") Layout layout, + @PluginAttribute("ignoreExceptions") boolean ignoreExceptions) { + return new CapaLog4jAppenderAgent(name, filter, layout, ignoreExceptions); + } + + /** + * Build a appender instance. + * + * @return CapaLog4jAppender instance. + */ + public static CapaLog4jAppender buildCapaLog4jAppender() { + // load spi capa Log4j appender impl + return CapaClassLoader.loadComponentClassObj( + LOG_COMPONENT_TYPE, + CapaLog4jAppender.class); + } + + @Override + public void append(LogEvent event) { + logAppender.appendLog(event); + } + + /** + * The abstract api of the log4j appender impl.Implement this and provide your specific impl. + */ + public interface CapaLog4jAppender { + + /** + * Deal with the log. + * + * @param event The log event. + */ + void appendLog(LogEvent event); + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/log/agent/CapaLogbackAppenderAgent.java b/sdk-component/src/main/java/group/rxcloud/capa/component/log/agent/CapaLogbackAppenderAgent.java new file mode 100644 index 0000000..c4c0d54 --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/log/agent/CapaLogbackAppenderAgent.java @@ -0,0 +1,77 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.log.agent; + +import ch.qos.logback.core.UnsynchronizedAppenderBase; +import group.rxcloud.capa.infrastructure.CapaClassLoader; + +/** + * The agent of the logback impl. + */ +public class CapaLogbackAppenderAgent extends UnsynchronizedAppenderBase { + + /** + * The log component type. + */ + private static final String LOG_COMPONENT_TYPE = "log"; + /** + * Capa logback appender instance. + */ + private static final CapaLogbackAppender logbackAppender; + + /** + * Init the logbackAppender impl. + */ + static { + logbackAppender = buildCapaLogbackAppender(); + } + + /** + * Build the logback appender impl. + * + * @return CapaLogbackAppender instance. + */ + public static CapaLogbackAppender buildCapaLogbackAppender() { + // load spi capa logback appender impl + return CapaClassLoader.loadComponentClassObj( + LOG_COMPONENT_TYPE, + CapaLogbackAppender.class); + } + + /** + * Deal with the log. + * + * @param event The log event. + */ + @Override + protected void append(EVENT event) { + logbackAppender.appendLog(event); + } + + /** + * The abstract api of the logback appender impl.Implement this and provide your specific impl. + */ + public interface CapaLogbackAppender { + + /** + * Deal with the log. + * + * @param event The log event. + */ + void appendLog(EVENT event); + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/pubsub/CapaPubSub.java b/sdk-component/src/main/java/group/rxcloud/capa/component/pubsub/CapaPubSub.java index fb86728..4ed01fd 100644 --- a/sdk-component/src/main/java/group/rxcloud/capa/component/pubsub/CapaPubSub.java +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/pubsub/CapaPubSub.java @@ -38,6 +38,8 @@ public abstract class CapaPubSub implements AutoCloseable { /** * Gets pubsub name. + * + * @return pubsubName */ public String getPubSubName() { return this.pubsubName; diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/pubsub/CapaPubSubBuilder.java b/sdk-component/src/main/java/group/rxcloud/capa/component/pubsub/CapaPubSubBuilder.java index 4f4e8cf..3ed6f04 100644 --- a/sdk-component/src/main/java/group/rxcloud/capa/component/pubsub/CapaPubSubBuilder.java +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/pubsub/CapaPubSubBuilder.java @@ -52,6 +52,7 @@ public CapaPubSub build() { * @return Instance of {@link CapaPubSub} implementor */ private CapaPubSub buildCapaPubSub() { + // TODO: 2021/11/30 build multi component return CapaClassLoader.loadComponentClassObj("pubsub", CapaPubSub.class); } } diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/SamplerConfig.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/SamplerConfig.java new file mode 100644 index 0000000..702962e --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/SamplerConfig.java @@ -0,0 +1,81 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry; + +import group.rxcloud.capa.infrastructure.utils.SpiUtils; + +import java.io.Serializable; +import java.util.Properties; + +/** + * Sampler config. + */ +public class SamplerConfig implements Serializable { + + public static final String FILE_PATH = "/capa-sample.properties"; + + /** + * Sample all data as default. + */ + public static final transient SamplerConfig DEFAULT_CONFIG = new SamplerConfig(); + + private static final long serialVersionUID = -2113523925814197551L; + + private boolean metricsSample = true; + + private boolean traceSample = true; + + private boolean logSample = true; + + public boolean isMetricsSample() { + return metricsSample; + } + + public void setMetricsSample(boolean metricsSample) { + this.metricsSample = metricsSample; + } + + public boolean isTraceSample() { + return traceSample; + } + + public void setTraceSample(boolean traceSample) { + this.traceSample = traceSample; + } + + public boolean isLogSample() { + return logSample; + } + + public void setLogSample(boolean logSample) { + this.logSample = logSample; + } + + public static SamplerConfig loadOrDefault() { + Properties properties = SpiUtils.loadPropertiesNullable(FILE_PATH); + if (properties == null) { + return DEFAULT_CONFIG; + } + + SamplerConfig result = new SamplerConfig(); + result.setMetricsSample(Boolean.valueOf(properties.getProperty("metricsSample", Boolean.TRUE.toString()))); + result.setTraceSample(Boolean.valueOf(properties.getProperty("traceSample", Boolean.TRUE.toString()))); + result.setLogSample(Boolean.valueOf(properties.getProperty("logSample", Boolean.TRUE.toString()))); + + return result; + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/CapaContext.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/CapaContext.java new file mode 100644 index 0000000..a00c310 --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/CapaContext.java @@ -0,0 +1,67 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.context; + +import group.rxcloud.capa.infrastructure.utils.SpiUtils; + +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; + +/** + * Method for async context. + */ +public final class CapaContext { + + private static final CapaContextAsyncWrapper WRAPPER = getAsyncWrapper(); + + private CapaContext() { + } + + public static Runnable taskWrapping(Runnable runnable) { + return WRAPPER.wrap(runnable); + } + + public static Callable taskWrapping(Callable callable) { + return WRAPPER.wrap(callable); + } + + public static Executor taskWrapping(Executor executor) { + return WRAPPER.wrap(executor); + } + + public static ExecutorService taskWrapping(ExecutorService executor) { + return WRAPPER.wrap(executor); + } + + public static ScheduledExecutorService taskWrapping(ScheduledExecutorService executor) { + return WRAPPER.wrap(executor); + } + + public static String getTraceId() { + return WRAPPER.getTraceId(); + } + + private static CapaContextAsyncWrapper getAsyncWrapper() { + CapaContextAsyncWrapper WRAPPER = SpiUtils.loadFromSpiComponentFileNullable(CapaContextAsyncWrapper.class, "telemetry"); + if (WRAPPER == null) { + return new CapaContextAsyncWrapper() {}; + } + return WRAPPER; + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/CapaContextAsyncWrapper.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/CapaContextAsyncWrapper.java new file mode 100644 index 0000000..94fc790 --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/CapaContextAsyncWrapper.java @@ -0,0 +1,54 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.context; + +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; + +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; + +/** + */ +public interface CapaContextAsyncWrapper { + + default Runnable wrap(Runnable runnable) { + return Context.current().wrap(runnable); + } + + default Callable wrap(Callable callable) { + return Context.current().wrap(callable); + } + + default Executor wrap(Executor executor) { + return Context.current().wrap(executor); + } + + default ExecutorService wrap(ExecutorService executor) { + return Context.current().wrap(executor); + } + + default ScheduledExecutorService wrap(ScheduledExecutorService executor) { + return Context.current().wrap(executor); + } + + default String getTraceId() { + return Span.fromContext(Context.current()).getSpanContext().getTraceId(); + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/CapaContextPropagatorBuilder.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/CapaContextPropagatorBuilder.java new file mode 100644 index 0000000..0f19fc0 --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/CapaContextPropagatorBuilder.java @@ -0,0 +1,93 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.context; + +import group.rxcloud.capa.infrastructure.utils.SpiUtils; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.context.propagation.TextMapPropagator; + +import javax.annotation.concurrent.NotThreadSafe; +import java.util.ArrayList; +import java.util.List; + +/** + * Builder for capa context propagator. + */ +@NotThreadSafe +public class CapaContextPropagatorBuilder implements CapaContextPropagatorSettings { + + /** + * Context config. + */ + private ContextConfig contextConfig; + + /** + * Context propagator instances. + */ + private List contextPropagatorsInstance; + + @Override + public CapaContextPropagatorBuilder setContextConfig(ContextConfig config) { + contextConfig = config; + return this; + } + + @Override + public CapaContextPropagatorBuilder addContextPropagators(TextMapPropagator processor) { + if (contextPropagatorsInstance == null) { + contextPropagatorsInstance = new ArrayList<>(); + } + contextPropagatorsInstance.add(processor); + return this; + } + + /** + * Build context propagators. + * + * @return context propagators. + */ + public ContextPropagators buildContextPropagators() { + if (contextPropagatorsInstance != null && !contextPropagatorsInstance.isEmpty()) { + return ContextPropagators + .create(TextMapPropagator.composite(contextPropagatorsInstance.toArray(new TextMapPropagator[0]))); + } + + initContextConfig(); + if (contextConfig != null) { + List types = contextConfig.getContextPropagators(); + if (types != null && !types.isEmpty()) { + return ContextPropagators + .create(TextMapPropagator.composite(types.stream() + .map(path -> SpiUtils + .newInstanceWithConstructorCache(path, TextMapPropagator.class)) + .toArray(TextMapPropagator[]::new))); + } + } + + ContextPropagatorLoader loader = SpiUtils.loadFromSpiComponentFileNullable(ContextPropagatorLoader.class, "telemetry"); + if (loader == null) { + loader = ContextPropagatorLoader.DEFAULT; + } + return loader.load(); + } + + private void initContextConfig() { + if (contextConfig == null) { + contextConfig = SpiUtils.loadConfigNullable(FILE_PATH, ContextConfig.class);; + } + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/CapaContextPropagatorSettings.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/CapaContextPropagatorSettings.java new file mode 100644 index 0000000..bba38ab --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/CapaContextPropagatorSettings.java @@ -0,0 +1,44 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.context; + +import io.opentelemetry.context.propagation.TextMapPropagator; + +/** + * Settings for capa context propagator. + */ +public interface CapaContextPropagatorSettings { + + // FIXME: 2021/11/28 change to capa-component-telemetry-context.json + String FILE_PATH = "/capa-context.json"; + + /** + * Replace the whole context config. + * + * @param config context config + * @return current settings. + */ + CapaContextPropagatorSettings setContextConfig(ContextConfig config); + + /** + * Add one more processor to current context config. + * + * @param processor processor config + * @return current settings. + */ + CapaContextPropagatorSettings addContextPropagators(TextMapPropagator processor); +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/ContextConfig.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/ContextConfig.java new file mode 100644 index 0000000..5b17317 --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/ContextConfig.java @@ -0,0 +1,38 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.context; + +import java.io.Serializable; +import java.util.List; + +/** + * Config for context propagators. + */ +public class ContextConfig implements Serializable { + + private static final long serialVersionUID = 6587103489345563395L; + + private List contextPropagators; + + public List getContextPropagators() { + return contextPropagators; + } + + public void setContextPropagators(List contextPropagators) { + this.contextPropagators = contextPropagators; + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/ContextPropagatorLoader.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/ContextPropagatorLoader.java new file mode 100644 index 0000000..dff7460 --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/context/ContextPropagatorLoader.java @@ -0,0 +1,37 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.context; + +import io.opentelemetry.context.propagation.ContextPropagators; + +/** + * Load default context propagator. + */ +public interface ContextPropagatorLoader { + + ContextPropagatorLoader DEFAULT = new ContextPropagatorLoader() { + }; + + /** + * Load default context propagator. + * + * @return default context propagator. + */ + default ContextPropagators load() { + return ContextPropagators.noop(); + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/metrics/CapaMeterProviderBuilder.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/metrics/CapaMeterProviderBuilder.java new file mode 100644 index 0000000..044eb92 --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/metrics/CapaMeterProviderBuilder.java @@ -0,0 +1,158 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.metrics; + +import group.rxcloud.capa.component.telemetry.SamplerConfig; +import group.rxcloud.capa.infrastructure.utils.SpiUtils; +import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.sdk.metrics.SdkMeterProvider; +import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; +import io.opentelemetry.sdk.metrics.export.MetricExporter; +import io.opentelemetry.sdk.metrics.export.MetricReaderFactory; +import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.concurrent.NotThreadSafe; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +/** + * Builder for capa metric provider. + */ +@NotThreadSafe +public class CapaMeterProviderBuilder implements CapaMeterProviderSettings { + + /** + * Config for capa metric provider. + */ + private MeterConfig meterConfigs; + + /** + * Sampler config. + */ + private SamplerConfig samplerConfig; + + /** + * Readers manually set. + */ + private List metricsReaderConfigs; + + /** + * Build the reader factories with reader configs. + * Each factory defined the export interval and exporter of the reader it will generate. + * + * @param readerConfigs metrics reader configs. + * @return metrics reader factories. + */ + private static List bulidReaderFactories(List readerConfigs) { + List factories = new ArrayList<>(); + for (MetricsReaderConfig config : readerConfigs) { + MetricExporter exporter = SpiUtils + .newInstanceWithConstructorCache(config.getExporterType(), MetricExporter.class); + if (exporter == null) { + throw new IllegalArgumentException( + "Metric Exporter is not configured. readerName = " + config.getName() + '.'); + } + + ScheduledThreadPoolExecutor worker = new ScheduledThreadPoolExecutor(1, new ThreadFactory() { + @Override + public Thread newThread(@NotNull Runnable r) { + Thread thread = new Thread(r); + thread.setDaemon(true); + thread.setName("capa-metric-reader-" + config.getName() + '-' + System + .currentTimeMillis()); + return thread; + } + }); + + factories.add(PeriodicMetricReader.builder(exporter) + .setInterval(config.getExportIntervalMillis(), TimeUnit.MILLISECONDS) + .setExecutor(worker) + .newMetricReaderFactory()); + } + return factories; + } + + @Override + public CapaMeterProviderBuilder setSamplerConfig(SamplerConfig samplerConfig) { + this.samplerConfig = samplerConfig; + return this; + } + + @Override + public CapaMeterProviderBuilder setMeterConfig(MeterConfig config) { + meterConfigs = config; + return this; + } + + @Override + public CapaMeterProviderBuilder addMetricReaderConfig(MetricsReaderConfig config) { + if (metricsReaderConfigs == null) { + metricsReaderConfigs = new ArrayList<>(); + } + metricsReaderConfigs.add(config); + return this; + } + + /** + * Build the meter provider with the config. + * In the following cases, a noop implementation will be returned and no new thread will be started. + * 1. No metrics reader was defined. + * + * @return the meter provider. + */ + public MeterProvider buildMeterProvider() { + List metricsReaderConfigs = this.metricsReaderConfigs; + if (metricsReaderConfigs == null || metricsReaderConfigs.isEmpty()) { + // if config was not explicitly set, try loading the config from the config loader. + initMeterConfig(); + + if (meterConfigs != null) { + metricsReaderConfigs = meterConfigs.getReaders(); + } + } + + if (metricsReaderConfigs == null || metricsReaderConfigs.isEmpty()) { + return MeterProvider.noop(); + } + + List factories = bulidReaderFactories(metricsReaderConfigs); + + initSampleConfig(); + + SdkMeterProviderBuilder builder = SdkMeterProvider.builder() + .setExemplarFilter(CapaMetricsSampler.getInstance() + .update(samplerConfig)); + factories.forEach(f -> builder.registerMetricReader(f)); + return builder.build(); + } + + private void initMeterConfig() { + if (meterConfigs == null) { + meterConfigs = SpiUtils.loadConfigNullable(FILE_PATH, MeterConfig.class); + } + } + + private void initSampleConfig() { + if (samplerConfig == null) { + samplerConfig = SamplerConfig.loadOrDefault(); + } + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/metrics/CapaMeterProviderSettings.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/metrics/CapaMeterProviderSettings.java new file mode 100644 index 0000000..01967a6 --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/metrics/CapaMeterProviderSettings.java @@ -0,0 +1,52 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.metrics; + +import group.rxcloud.capa.component.telemetry.SamplerConfig; + +/** + * Settings for capa meter provider. + */ +public interface CapaMeterProviderSettings { + + // FIXME: 2021/11/28 change to capa-component-telemetry-meter.json + String FILE_PATH ="/capa-meter.json"; + + /** + * Replace the whole config for the meter. + * + * @param config meter config. + * @return current settings. + */ + CapaMeterProviderSettings setMeterConfig(MeterConfig config); + + /** + * Add one more reader to current meter config. + * + * @param config metrics reader config. + * @return current settings. + */ + CapaMeterProviderSettings addMetricReaderConfig(MetricsReaderConfig config); + + /** + * Set sample config. + * + * @param samplerConfig sample config. + * @return current settings. + */ + CapaMeterProviderSettings setSamplerConfig(SamplerConfig samplerConfig); +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/metrics/CapaMetricsSampler.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/metrics/CapaMetricsSampler.java new file mode 100644 index 0000000..049a7a0 --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/metrics/CapaMetricsSampler.java @@ -0,0 +1,81 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.metrics; + +import group.rxcloud.capa.component.telemetry.SamplerConfig; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.metrics.exemplar.ExemplarFilter; + +/** + * Sampler for metrics data. + * Choose to sample all or none data according to the config file. + */ +public class CapaMetricsSampler implements ExemplarFilter { + + /** + * Sampler instance, which samples all the data if no config was explicitly set. + */ + private static final CapaMetricsSampler INSTANCE = new CapaMetricsSampler(SamplerConfig.DEFAULT_CONFIG); + + /** + * Inner instance. + */ + private ExemplarFilter inner; + + /** + * Get the sampler instance. + * + * @return the sampler instance. + */ + public static CapaMetricsSampler getInstance() { + return INSTANCE; + } + + private CapaMetricsSampler(SamplerConfig config) { + update(config); + } + + /** + * Update the sample policy. + * + * @param config new sample config. + * @return the updated sampler instance. + */ + public CapaMetricsSampler update(SamplerConfig config) { + if (config == null) { + return this; + } + + if (config.isMetricsSample()) { + inner = ExemplarFilter.alwaysSample(); + } else { + inner = ExemplarFilter.neverSample(); + } + return this; + } + + @Override + public boolean shouldSampleMeasurement(long value, Attributes attributes, Context context) { + return inner.shouldSampleMeasurement(value, attributes, context); + } + + @Override + public boolean shouldSampleMeasurement(double value, Attributes attributes, Context context) { + return inner.shouldSampleMeasurement(value, attributes, context); + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/metrics/MeterConfig.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/metrics/MeterConfig.java new file mode 100644 index 0000000..aa91b1f --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/metrics/MeterConfig.java @@ -0,0 +1,43 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.metrics; + +import java.io.Serializable; +import java.util.Collections; +import java.util.List; + +/** + * Config for meters. + */ +public class MeterConfig implements Serializable { + + private static final long serialVersionUID = 7090415828392034412L; + + /** + * Configs for metrics readers. + * Each reader related with a scheduled thread. + */ + private List readers = Collections.emptyList(); + + public List getReaders() { + return readers; + } + + public void setReaders(List readers) { + this.readers = readers; + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/metrics/MetricsReaderConfig.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/metrics/MetricsReaderConfig.java new file mode 100644 index 0000000..aff868b --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/metrics/MetricsReaderConfig.java @@ -0,0 +1,73 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.metrics; + +import java.io.Serializable; +import java.util.concurrent.TimeUnit; + +/** + * Config for metrics reader. + * Control the export interval and target exporter. + */ +public class MetricsReaderConfig implements Serializable { + + private static final long serialVersionUID = 5186270483151262376L; + + /** + * Reader name, used to find the related reader thread. + */ + private String name = "_DEFAULT_METRIC_READER"; + + /** + * Exporter interval. + * default 1min. + */ + private long exportIntervalMillis = TimeUnit.MINUTES.toMillis(1L); + + /** + * Exporter class name. Must have a no-args constructor. + */ + private String exporterType; + + public String getExporterType() { + return exporterType; + } + + public void setExporterType(String exporterType) { + this.exporterType = exporterType; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getExportIntervalMillis() { + return exportIntervalMillis; + } + + public void setExportIntervalMillis(long exportIntervalMillis) { + this.exportIntervalMillis = exportIntervalMillis; + } + + public void setExportInterval(long export, TimeUnit timeUnit) { + setExportIntervalMillis(timeUnit.toMillis(export)); + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaReadWriteSpan.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaReadWriteSpan.java new file mode 100644 index 0000000..5a9f137 --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaReadWriteSpan.java @@ -0,0 +1,160 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; +import io.opentelemetry.sdk.trace.ReadWriteSpan; +import io.opentelemetry.sdk.trace.data.SpanData; +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.TimeUnit; + +/** + * Read write span proxy. + */ +public class CapaReadWriteSpan implements ReadWriteSpan { + + protected final ReadWriteSpan span; + + protected final String tracerName; + + protected final String version; + + protected final String schemaUrl; + + public CapaReadWriteSpan(String tracerName, String version, String schemaUrl, ReadWriteSpan span) { + this.span = span; + this.tracerName = tracerName; + this.version = version; + this.schemaUrl = schemaUrl; + } + + public String getTracerName() { + return tracerName == null ? getInstrumentationLibraryInfo().getName() : tracerName; + } + + public String getVersion() { + return version == null ? getInstrumentationLibraryInfo().getVersion() : version; + } + + public String getSchemaUrl() { + return schemaUrl == null ? getInstrumentationLibraryInfo().getSchemaUrl() : schemaUrl; + } + + @Override + public Span setAttribute(AttributeKey key, T value) { + span.setAttribute(key, value); + return this; + } + + @Override + public Span addEvent(String name, Attributes attributes) { + span.addEvent(name, attributes); + return this; + } + + @Override + public Span addEvent(String name, Attributes attributes, long timestamp, TimeUnit unit) { + span.addEvent(name, attributes, timestamp, unit); + return this; + } + + @Override + public Span setStatus(StatusCode statusCode, String description) { + span.setStatus(statusCode, description); + return this; + } + + @Override + public Span recordException(Throwable exception, Attributes additionalAttributes) { + span.recordException(exception, additionalAttributes); + return this; + } + + @Override + public Span updateName(String name) { + span.updateName(name); + return this; + } + + @Override + public void end() { + span.end(); + } + + @Override + public void end(long timestamp, TimeUnit unit) { + span.end(timestamp, unit); + } + + @Override + public SpanContext getSpanContext() { + return span.getSpanContext(); + } + + @Override + public SpanContext getParentSpanContext() { + return span.getParentSpanContext(); + } + + @Override + public String getName() { + return span.getName(); + } + + @Override + public SpanData toSpanData() { + return span.toSpanData(); + } + + @Override + public InstrumentationLibraryInfo getInstrumentationLibraryInfo() { + return span.getInstrumentationLibraryInfo(); + } + + @Override + public boolean hasEnded() { + return span.hasEnded(); + } + + @Override + public long getLatencyNanos() { + return span.getLatencyNanos(); + } + + @Override + public SpanKind getKind() { + return span.getKind(); + } + + @Nullable + @Override + public T getAttribute(AttributeKey key) { + return span.getAttribute(key); + } + + @Override + public boolean isRecording() { + return span.isRecording(); + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaSpanBuilder.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaSpanBuilder.java new file mode 100644 index 0000000..2979570 --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaSpanBuilder.java @@ -0,0 +1,136 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.trace.ReadWriteSpan; + +import java.util.concurrent.TimeUnit; + +/** + * Span builder proxy. + */ +public class CapaSpanBuilder implements SpanBuilder { + + protected final String tracerName; + + protected String version; + + protected String schemaUrl; + + protected final String spanName; + + protected final SpanBuilder spanBuilder; + + public CapaSpanBuilder(String tracerName, String version, String schemaUrl, String spanName, + SpanBuilder spanBuilder) { + this.tracerName = tracerName; + this.version = version; + this.schemaUrl = schemaUrl; + this.spanName = spanName; + this.spanBuilder = spanBuilder; + } + + public String getSchemaUrl() { + return schemaUrl; + } + + public String getVersion() { + return version; + } + + @Override + public SpanBuilder setParent(Context context) { + spanBuilder.setParent(context); + return this; + } + + @Override + public SpanBuilder setNoParent() { + spanBuilder.setNoParent(); + return this; + } + + @Override + public SpanBuilder addLink(SpanContext spanContext) { + spanBuilder.addLink(spanContext); + return this; + } + + @Override + public SpanBuilder addLink(SpanContext spanContext, Attributes attributes) { + spanBuilder.addLink(spanContext, attributes); + return this; + } + + @Override + public SpanBuilder setAttribute(String key, String value) { + spanBuilder.setAttribute(key, value); + return this; + } + + @Override + public SpanBuilder setAttribute(String key, long value) { + spanBuilder.setAttribute(key, value); + return this; + } + + @Override + public SpanBuilder setAttribute(String key, double value) { + spanBuilder.setAttribute(key, value); + return this; + } + + @Override + public SpanBuilder setAttribute(String key, boolean value) { + spanBuilder.setAttribute(key, value); + return this; + } + + @Override + public SpanBuilder setAttribute(AttributeKey key, T value) { + spanBuilder.setAttribute(key, value); + return this; + } + + @Override + public SpanBuilder setSpanKind(SpanKind spanKind) { + spanBuilder.setSpanKind(spanKind); + return this; + } + + @Override + public SpanBuilder setStartTimestamp(long startTimestamp, TimeUnit unit) { + spanBuilder.setStartTimestamp(startTimestamp, unit); + return this; + } + + @Override + public Span startSpan() { + Span span = spanBuilder.startSpan(); + if (span instanceof ReadWriteSpan) { + return CapaWrapper.wrap(tracerName, version, schemaUrl, (ReadWriteSpan) span); + } + return span; + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTraceSampler.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTraceSampler.java new file mode 100644 index 0000000..4c1873b --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTraceSampler.java @@ -0,0 +1,70 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import group.rxcloud.capa.component.telemetry.SamplerConfig; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.trace.data.LinkData; +import io.opentelemetry.sdk.trace.samplers.Sampler; +import io.opentelemetry.sdk.trace.samplers.SamplingResult; + +import java.util.List; + +/** + * Sampler for trace data. + * Choose to sample all or none data according to the config file. + */ +public class CapaTraceSampler implements Sampler { + + private static final CapaTraceSampler INSTANCE = new CapaTraceSampler(SamplerConfig.DEFAULT_CONFIG); + + private Sampler inner; + + public static CapaTraceSampler getInstance() { + return INSTANCE; + } + + private CapaTraceSampler(SamplerConfig config) { + update(config); + } + + public CapaTraceSampler update(SamplerConfig config) { + if (config == null) { + return this; + } + + if (config.isTraceSample()) { + inner = Sampler.alwaysOn(); + } else { + inner = Sampler.alwaysOff(); + } + return this; + } + + @Override + public SamplingResult shouldSample(Context context, String traceId, String name, SpanKind kind, + Attributes attributes, List list) { + return inner.shouldSample(context, traceId, name, kind, attributes, list); + } + + @Override + public String getDescription() { + return "Always or never sample the telemetry data."; + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTracer.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTracer.java new file mode 100644 index 0000000..15d0a6b --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTracer.java @@ -0,0 +1,52 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.Tracer; + +/** + * Tracer proxy. + */ +public class CapaTracer implements Tracer { + + protected final String tracerName; + protected final String version; + protected final String schemaUrl; + protected final Tracer tracer; + + public CapaTracer(String tracerName, String version, String schemaUrl, Tracer tracer) { + this.tracerName = tracerName; + this.version = version; + this.schemaUrl = schemaUrl; + this.tracer = tracer; + } + + @Override + public SpanBuilder spanBuilder(String spanName) { + SpanBuilder builder = tracer.spanBuilder(spanName); + return CapaWrapper.wrap(tracerName, version, schemaUrl, spanName, builder); + } + + public String getVersion() { + return version; + } + + public String getSchemaUrl() { + return schemaUrl; + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerBuilder.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerBuilder.java new file mode 100644 index 0000000..06708c6 --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerBuilder.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.api.trace.TracerBuilder; + +/** + * Tracer builder proxy. + */ +public class CapaTracerBuilder implements TracerBuilder { + + protected final TracerBuilder tracerBuilder; + + protected final String tracerName; + + protected String version; + + protected String schemaUrl; + + public CapaTracerBuilder(String tracerName, TracerBuilder tracerBuilder) { + this.tracerName = tracerName; + this.tracerBuilder = tracerBuilder; + } + + @Override + public TracerBuilder setSchemaUrl(String schemaUrl) { + tracerBuilder.setSchemaUrl(schemaUrl); + this.schemaUrl = schemaUrl; + return this; + } + + @Override + public TracerBuilder setInstrumentationVersion(String instrumentationVersion) { + tracerBuilder.setInstrumentationVersion(instrumentationVersion); + this.version = instrumentationVersion; + return this; + } + + @Override + public Tracer build() { + return CapaWrapper.wrap(tracerName, version, schemaUrl, tracerBuilder.build()); + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerProvider.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerProvider.java new file mode 100644 index 0000000..3b102ae --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerProvider.java @@ -0,0 +1,49 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.api.trace.TracerBuilder; +import io.opentelemetry.api.trace.TracerProvider; + +/** + * Capa tracer provider proxy. + */ +public class CapaTracerProvider implements TracerProvider { + + private final TracerProvider provider; + + public CapaTracerProvider(TracerProvider provider) { + this.provider = provider; + } + + @Override + public Tracer get(String instrumentationName) { + return tracerBuilder(instrumentationName).build(); + } + + @Override + public Tracer get(String instrumentationName, String instrumentationVersion) { + return tracerBuilder(instrumentationName).setInstrumentationVersion(instrumentationVersion).build(); + } + + @Override + public TracerBuilder tracerBuilder(String instrumentationName) { + TracerBuilder tracerBuilder = provider.tracerBuilder(instrumentationName); + return CapaWrapper.wrap(instrumentationName, tracerBuilder); + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerProviderBuilder.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerProviderBuilder.java new file mode 100644 index 0000000..60f1bba --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerProviderBuilder.java @@ -0,0 +1,237 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import group.rxcloud.capa.component.telemetry.SamplerConfig; +import group.rxcloud.capa.infrastructure.exceptions.CapaErrorContext; +import group.rxcloud.capa.infrastructure.exceptions.CapaException; +import group.rxcloud.capa.infrastructure.utils.SpiUtils; +import io.opentelemetry.api.trace.TracerProvider; +import io.opentelemetry.sdk.trace.IdGenerator; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; +import io.opentelemetry.sdk.trace.SpanLimits; +import io.opentelemetry.sdk.trace.SpanLimitsBuilder; +import io.opentelemetry.sdk.trace.SpanProcessor; +import io.opentelemetry.sdk.trace.samplers.Sampler; + +import javax.annotation.concurrent.NotThreadSafe; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +/** + * Builder for capa tracer provider. + */ +@NotThreadSafe +public class CapaTracerProviderBuilder implements CapaTracerProviderSettings { + + /** + * Config for capa tracer provider. + */ + private TracerConfig tracerConfig; + + /** + * Id generator instance. + */ + private IdGenerator idGenerator; + + /** + * Span processor instances. + */ + private List processors; + + /** + * Span limits. + */ + private SpanLimitsConfig spanLimitsConfig; + + /** + * Sampler config. + */ + private SamplerConfig samplerConfig; + + private static boolean addSpanLimits(SpanLimitsConfig spanLimits, SpanLimitsBuilder limits) { + if (spanLimits == null) { + return false; + } + boolean added = false; + if (spanLimits.getMaxAttributeValueLength() != null) { + limits.setMaxAttributeValueLength(spanLimits.getMaxAttributeValueLength()); + added = true; + } + if (spanLimits.getMaxNumAttributes() != null) { + limits.setMaxNumberOfAttributes(spanLimits.getMaxNumAttributes()); + added = true; + } + if (spanLimits.getMaxNumEvents() != null) { + limits.setMaxNumberOfEvents(spanLimits.getMaxNumEvents()); + added = true; + } + if (spanLimits.getMaxNumLinks() != null) { + limits.setMaxNumberOfLinks(spanLimits.getMaxNumLinks()); + added = true; + } + if (spanLimits.getMaxNumAttributesPerLink() != null) { + limits.setMaxNumberOfAttributesPerLink(spanLimits.getMaxNumAttributesPerLink()); + added = true; + } + if (spanLimits.getMaxNumAttributesPerEvent() != null) { + limits.setMaxNumberOfAttributesPerEvent(spanLimits.getMaxNumAttributesPerEvent()); + added = true; + } + return added; + } + + private static void skipIdValidate(SdkTracerProvider provider) { + try { + Field fieldTracerSharedState = SdkTracerProvider.class.getDeclaredField("sharedState"); + fieldTracerSharedState.setAccessible(true); + Object sharedStatus = fieldTracerSharedState.get(provider); + Class sharedStatusType = sharedStatus.getClass(); + Field fieldFlag = sharedStatusType.getDeclaredField("idGeneratorSafeToSkipIdValidation"); + fieldFlag.setAccessible(true); + fieldFlag.set(sharedStatus, true); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new CapaException(CapaErrorContext.SYSTEM_ERROR, "Fail to skip id validation.", e); + } + } + + @Override + public CapaTracerProviderBuilder setSamplerConfig(SamplerConfig samplerConfig) { + this.samplerConfig = samplerConfig; + return this; + } + + @Override + public CapaTracerProviderBuilder setTracerConfig(TracerConfig tracerConfig) { + this.tracerConfig = tracerConfig; + return this; + } + + @Override + public CapaTracerProviderBuilder setSpanLimits(SpanLimitsConfig spanLimits) { + spanLimitsConfig = spanLimits; + return this; + } + + @Override + public CapaTracerProviderBuilder setIdGenerator(IdGenerator idGenerator) { + this.idGenerator = idGenerator; + return this; + } + + @Override + public CapaTracerProviderBuilder addProcessor(SpanProcessor processor) { + if (processors == null) { + processors = new ArrayList<>(); + } + processors.add(processor); + return this; + } + + private void initTracerConfig() { + if (tracerConfig == null) { + tracerConfig = SpiUtils.loadConfigNullable(CapaTracerProviderSettings.FILE_PATH, TracerConfig.class); + } + } + + /** + * Build the tracer provider with the config. + * In the following cases, a noop implementation will be returned. + * 1. No processor config was defined. + * + * @return the meter provider. + */ + public CapaTracerProvider buildTracerProvider() { + // if config was not explicitly set, try loading the config from the config loader. + initTracerConfig(); + + if ((processors == null || processors.isEmpty()) && (tracerConfig == null + || tracerConfig.getProcessors() == null + || tracerConfig.getProcessors().isEmpty())) { + return new CapaTracerProvider(TracerProvider.noop()); + } + + SdkTracerProviderBuilder builder = SdkTracerProvider.builder(); + addSpanLimits(builder); + addIdGenerator(builder); + addSampler(builder); + addProcessors(builder); + + SdkTracerProvider provider = builder.build(); + + if (tracerConfig != null && !tracerConfig.isEnableIdValidate()) { + skipIdValidate(provider); + } + + return new CapaTracerProvider(provider); + } + + private void addIdGenerator(SdkTracerProviderBuilder builder) { + if (idGenerator != null) { + builder.setIdGenerator(idGenerator); + } else if (tracerConfig != null) { + IdGenerator generator = SpiUtils + .newInstanceWithConstructorCache(tracerConfig.getIdGenerator(), IdGenerator.class); + if (generator != null) { + builder.setIdGenerator(generator); + } + } + } + + private void addSpanLimits(SdkTracerProviderBuilder builder) { + SpanLimitsBuilder limits = SpanLimits.builder(); + boolean added = false; + if (tracerConfig != null && tracerConfig.getSpanLimits() != null) { + added |= addSpanLimits(tracerConfig.getSpanLimits(), limits); + } + if (spanLimitsConfig != null) { + added |= addSpanLimits(spanLimitsConfig, limits); + } + + if (added) { + builder.setSpanLimits(limits.build()); + } + } + + private void addSampler(SdkTracerProviderBuilder builder) { + initSampleConfig(); + builder.setSampler(Sampler.parentBased(CapaTraceSampler.getInstance().update(samplerConfig))); + } + + private void initSampleConfig() { + if (samplerConfig == null) { + samplerConfig = SamplerConfig.loadOrDefault(); + } + } + + private void addProcessors(SdkTracerProviderBuilder builder) { + List processors = this.processors; + if (processors != null && !processors.isEmpty()) { + processors.forEach(p -> builder.addSpanProcessor(p)); + } else if (tracerConfig != null && tracerConfig.getProcessors() != null) { + tracerConfig.getProcessors().forEach(p -> { + SpanProcessor processor = SpiUtils.newInstanceWithConstructorCache(p, SpanProcessor.class); + if (processor != null) { + builder.addSpanProcessor(processor); + } + }); + } + } +} + diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerProviderSettings.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerProviderSettings.java new file mode 100644 index 0000000..f1ac0da --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerProviderSettings.java @@ -0,0 +1,71 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import group.rxcloud.capa.component.telemetry.SamplerConfig; +import io.opentelemetry.sdk.trace.IdGenerator; +import io.opentelemetry.sdk.trace.SpanProcessor; + +/** + * Settings for capa trace provider. + */ +public interface CapaTracerProviderSettings { + + // FIXME: 2021/11/28 change to capa-component-telemetry-tracer.json + String FILE_PATH = "/capa-tracer.json"; + + /** + * Replace the whole config for the meter. + * + * @param tracerConfig tracer config + * @return current settings. + */ + CapaTracerProviderSettings setTracerConfig(TracerConfig tracerConfig); + + /** + * Set the span limits. + * + * @param spanLimits span limits config. + * @return current settings. + */ + CapaTracerProviderSettings setSpanLimits(SpanLimitsConfig spanLimits); + + /** + * Set the trace/span id generator. + * + * @param idGenerator trace/span id generator. + * @return current settings. + */ + CapaTracerProviderSettings setIdGenerator(IdGenerator idGenerator); + + /** + * Add one more span processor to current meter config. + * + * @param processor span processor. + * @return current settings. + */ + CapaTracerProviderSettings addProcessor(SpanProcessor processor); + + /** + * Set sample config. + * + * @param samplerConfig sample config. + * @return current settings. + */ + CapaTracerProviderSettings setSamplerConfig(SamplerConfig samplerConfig); + +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaWrapper.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaWrapper.java new file mode 100644 index 0000000..fec1d7c --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/CapaWrapper.java @@ -0,0 +1,94 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import group.rxcloud.capa.infrastructure.utils.SpiUtils; +import io.opentelemetry.api.trace.SpanBuilder; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.api.trace.TracerBuilder; +import io.opentelemetry.sdk.trace.ReadWriteSpan; + +import javax.annotation.Nullable; + +/** + * Load capa implementation. + */ +final class CapaWrapper { + + static final String FILE_SUFFIX = "telemetry"; + + static final boolean CACHE = true; + + private CapaWrapper() { + } + + @Nullable + static CapaSpanBuilder wrap(String tracerName, String version, String schemaUrl, String spanName, SpanBuilder builder) { + if (builder instanceof CapaSpanBuilder) { + return (CapaSpanBuilder) builder; + } + CapaSpanBuilder result = SpiUtils + .loadFromSpiComponentFileNullable(CapaSpanBuilder.class, new Class[]{String.class, String.class, String.class, String.class, SpanBuilder.class}, + new Object[]{tracerName, version, schemaUrl, spanName, builder}, FILE_SUFFIX, CACHE); + if (result == null) { + result = new CapaSpanBuilder(tracerName, version, schemaUrl, spanName, builder); + } + return result; + } + + @Nullable + static CapaReadWriteSpan wrap(String tracerName, String version, String schemaUrl, ReadWriteSpan span) { + if (span instanceof CapaReadWriteSpan) { + return (CapaReadWriteSpan) span; + } + CapaReadWriteSpan result = SpiUtils + .loadFromSpiComponentFileNullable(CapaReadWriteSpan.class, new Class[]{String.class, String.class, String.class, ReadWriteSpan.class}, new Object[]{tracerName, version, schemaUrl, span}, + FILE_SUFFIX, CACHE); + if (result == null) { + result = new CapaReadWriteSpan(tracerName, version, schemaUrl, span); + } + return result; + } + + @Nullable + static CapaTracer wrap(String tracerName, String version, String schemaUrl, Tracer tracer) { + if (tracer instanceof CapaTracer) { + return (CapaTracer) tracer; + } + CapaTracer result = SpiUtils.loadFromSpiComponentFileNullable(CapaTracer.class, new Class[]{String.class, String.class, String.class, Tracer.class}, + new Object[]{tracerName, version, schemaUrl, tracer}, FILE_SUFFIX, CACHE); + if (result == null) { + result = new CapaTracer(tracerName, version, schemaUrl, tracer); + } + return result; + } + + @Nullable + static CapaTracerBuilder wrap(String tracerName, TracerBuilder tracerBuilder) { + if (tracerBuilder instanceof CapaTracerBuilder) { + return (CapaTracerBuilder) tracerBuilder; + } + CapaTracerBuilder result = SpiUtils + .loadFromSpiComponentFileNullable(CapaTracerBuilder.class, new Class[]{String.class, TracerBuilder.class}, + new Object[]{tracerName, tracerBuilder}, FILE_SUFFIX, CACHE); + if (result == null) { + result = new CapaTracerBuilder(tracerName, tracerBuilder); + } + return result; + } + +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/EventAttributeKey.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/EventAttributeKey.java new file mode 100644 index 0000000..057896a --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/EventAttributeKey.java @@ -0,0 +1,63 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.AttributeType; + + +/** + * Attribute key for event params. + */ +public final class EventAttributeKey implements AttributeKey { + + public static EventAttributeKey SIZE = new EventAttributeKey(AttributeKey.longKey("_capa_event_size")); + + public static EventAttributeKey COUNT = new EventAttributeKey(AttributeKey.longKey("_capa_event_count")); + + public static EventAttributeKey FAIL = new EventAttributeKey(AttributeKey.longKey("_capa_event_fail")); + + private final AttributeKey key; + + private EventAttributeKey(AttributeKey key) { + this.key = key; + } + + public Integer getNum(Object value) { + if (!(value instanceof Long)) { + return null; + } + + Long l = (Long) value; + // overflow + if (l.compareTo((long)Integer.MAX_VALUE) > 0 || l.compareTo((long)Integer.MIN_VALUE) < 0 ) { + return null; + } + + return ((Long) value).intValue(); + } + + @Override + public String getKey() { + return key.getKey(); + } + + @Override + public AttributeType getType() { + return key.getType(); + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/SpanLimitsConfig.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/SpanLimitsConfig.java new file mode 100644 index 0000000..5f3c010 --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/SpanLimitsConfig.java @@ -0,0 +1,87 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import java.io.Serializable; + +/** + * Span limits. + */ +public class SpanLimitsConfig implements Serializable { + + private static final long serialVersionUID = 6918786580143929155L; + + private Integer maxNumAttributes; + + private Integer maxNumEvents; + + private Integer maxNumLinks; + + private Integer maxNumAttributesPerEvent; + + private Integer maxNumAttributesPerLink; + + private Integer maxAttributeValueLength; + + public Integer getMaxNumAttributes() { + return maxNumAttributes; + } + + public void setMaxNumAttributes(Integer maxNumAttributes) { + this.maxNumAttributes = maxNumAttributes; + } + + public Integer getMaxNumEvents() { + return maxNumEvents; + } + + public void setMaxNumEvents(Integer maxNumEvents) { + this.maxNumEvents = maxNumEvents; + } + + public Integer getMaxNumLinks() { + return maxNumLinks; + } + + public void setMaxNumLinks(Integer maxNumLinks) { + this.maxNumLinks = maxNumLinks; + } + + public Integer getMaxNumAttributesPerEvent() { + return maxNumAttributesPerEvent; + } + + public void setMaxNumAttributesPerEvent(Integer maxNumAttributesPerEvent) { + this.maxNumAttributesPerEvent = maxNumAttributesPerEvent; + } + + public Integer getMaxNumAttributesPerLink() { + return maxNumAttributesPerLink; + } + + public void setMaxNumAttributesPerLink(Integer maxNumAttributesPerLink) { + this.maxNumAttributesPerLink = maxNumAttributesPerLink; + } + + public Integer getMaxAttributeValueLength() { + return maxAttributeValueLength; + } + + public void setMaxAttributeValueLength(Integer maxAttributeValueLength) { + this.maxAttributeValueLength = maxAttributeValueLength; + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/StatusAttributeKey.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/StatusAttributeKey.java new file mode 100644 index 0000000..2730207 --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/StatusAttributeKey.java @@ -0,0 +1,49 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.AttributeType; + +/** + * Attribute key for status params. + */ +public final class StatusAttributeKey implements AttributeKey { + + public static StatusAttributeKey MESSAGE = new StatusAttributeKey(AttributeKey.stringKey("_capa_error_message")); + + public static StatusAttributeKey STATUS = new StatusAttributeKey(AttributeKey.stringKey("_capa_status")); + + public static StatusAttributeKey LINK = new StatusAttributeKey(AttributeKey.stringKey("_capa_link")); + + private final AttributeKey key; + + private StatusAttributeKey(AttributeKey key) { + this.key = key; + } + + + @Override + public String getKey() { + return key.getKey(); + } + + @Override + public AttributeType getType() { + return key.getType(); + } +} diff --git a/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/TracerConfig.java b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/TracerConfig.java new file mode 100644 index 0000000..5f8edb1 --- /dev/null +++ b/sdk-component/src/main/java/group/rxcloud/capa/component/telemetry/trace/TracerConfig.java @@ -0,0 +1,81 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import java.io.Serializable; +import java.util.List; + +/** + * Trace config. + */ +public class TracerConfig implements Serializable { + + private static final long serialVersionUID = 6587103489345563395L; + + /** + * Id generator class. + */ + private String idGenerator; + + /** + * Will trace/span id be validated with open telemetry restriction. + */ + private boolean enableIdValidate; + + /** + * Span limits. + */ + private SpanLimitsConfig spanLimits; + + /** + * Span processor classes. + */ + private List processors; + + public String getIdGenerator() { + return idGenerator; + } + + public void setIdGenerator(String className) { + this.idGenerator = className; + } + + public boolean isEnableIdValidate() { + return enableIdValidate; + } + + public void setEnableIdValidate(boolean enableIdValidate) { + this.enableIdValidate = enableIdValidate; + } + + public SpanLimitsConfig getSpanLimits() { + return spanLimits; + } + + public void setSpanLimits(SpanLimitsConfig spanLimits) { + this.spanLimits = spanLimits; + } + + public List getProcessors() { + return processors; + } + + public void setProcessors(List processors) { + this.processors = processors; + } + +} diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/http/CapaHttpBuilderTest.java b/sdk-component/src/test/java/group/rxcloud/capa/component/http/CapaHttpBuilderTest.java index 2f60a08..b1beb44 100644 --- a/sdk-component/src/test/java/group/rxcloud/capa/component/http/CapaHttpBuilderTest.java +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/http/CapaHttpBuilderTest.java @@ -1,66 +1,66 @@ -/* - * 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. - */ -package group.rxcloud.capa.component.http; - -import group.rxcloud.capa.infrastructure.serializer.CapaObjectSerializer; -import group.rxcloud.capa.infrastructure.serializer.DefaultObjectSerializer; -import group.rxcloud.capa.infrastructure.serializer.ObjectSerializer; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class CapaHttpBuilderTest { - - @Test - public void testWithObjectSerializer_FailWhenCapaObjectSerializerIsNull() { - Assertions.assertThrows(IllegalArgumentException.class, () -> { - new CapaHttpBuilder().withObjectSerializer(null); - }); - } - - @Test - public void testWithObjectSerializer_FailWhenContentTypeIsNull() { - Assertions.assertThrows(IllegalArgumentException.class, () -> { - new CapaHttpBuilder().withObjectSerializer(new TestObjectSerializer()); - }); - } - - @Test - public void testWithObjectSerializer_SuccessWhenDefaultObjectSerializerIsUsed() { - CapaHttpBuilder capaHttpBuilder = new CapaHttpBuilder().withObjectSerializer(new DefaultObjectSerializer()); - Assertions.assertNotNull(capaHttpBuilder); - } - - @Test - public void testBuild_Success() { - CapaHttpBuilder capaHttpBuilder = new CapaHttpBuilder(); - capaHttpBuilder.build(); - } - - /** - * serializer/deserializer for request/response objects used in tests only - */ - private class TestObjectSerializer extends ObjectSerializer implements CapaObjectSerializer { - - /** - * {@inheritDoc} - */ - @Override - public String getContentType() { - return ""; - } - } -} +/* + * 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. + */ +package group.rxcloud.capa.component.http; + +import group.rxcloud.capa.infrastructure.serializer.CapaObjectSerializer; +import group.rxcloud.capa.infrastructure.serializer.DefaultObjectSerializer; +import group.rxcloud.capa.infrastructure.serializer.ObjectSerializer; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class CapaHttpBuilderTest { + + @Test + public void testWithObjectSerializer_FailWhenCapaObjectSerializerIsNull() { + Assertions.assertThrows(IllegalArgumentException.class, () -> { + new CapaHttpBuilder().withObjectSerializer(null); + }); + } + + @Test + public void testWithObjectSerializer_FailWhenContentTypeIsNull() { + Assertions.assertThrows(IllegalArgumentException.class, () -> { + new CapaHttpBuilder().withObjectSerializer(new TestObjectSerializer()); + }); + } + + @Test + public void testWithObjectSerializer_SuccessWhenDefaultObjectSerializerIsUsed() { + CapaHttpBuilder capaHttpBuilder = new CapaHttpBuilder().withObjectSerializer(new DefaultObjectSerializer()); + Assertions.assertNotNull(capaHttpBuilder); + } + + @Test + public void testBuild_Success() { + CapaHttpBuilder capaHttpBuilder = new CapaHttpBuilder(); + capaHttpBuilder.build(); + } + + /** + * serializer/deserializer for request/response objects used in tests only + */ + private class TestObjectSerializer extends ObjectSerializer implements CapaObjectSerializer { + + /** + * {@inheritDoc} + */ + @Override + public String getContentType() { + return ""; + } + } +} diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/http/CapaHttpTest.java b/sdk-component/src/test/java/group/rxcloud/capa/component/http/CapaHttpTest.java index 443daf5..bcc67ad 100644 --- a/sdk-component/src/test/java/group/rxcloud/capa/component/http/CapaHttpTest.java +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/http/CapaHttpTest.java @@ -1,63 +1,63 @@ -/* - * 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. - */ -package group.rxcloud.capa.component.http; - -import group.rxcloud.capa.infrastructure.serializer.DefaultObjectSerializer; -import group.rxcloud.cloudruntimes.utils.TypeRef; -import okhttp3.OkHttpClient; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Mono; - -import java.util.HashMap; -import java.util.Map; - -/** - * @author huijing xu - * @date 2021/10/18 - */ -public class CapaHttpTest { - - @Test - public void testInvokeApi_Success() { - Map headers = new HashMap<>(); - headers.put("Content-Type", "application/json"); - - OkHttpClient.Builder builder = new OkHttpClient.Builder(); - TestCapaHttp capaHttp = new TestCapaHttp(builder.build(), new DefaultObjectSerializer()); - Mono> responseMono = capaHttp.invokeApi("post", - null, - null, - null, - headers, - null, - TypeRef.STRING); - - HttpResponse block = responseMono.block(); - int statusCode = block.getStatusCode(); - - Assertions.assertEquals(200, statusCode); - } - - @Test - public void testClose_Success() throws Exception { - OkHttpClient.Builder builder = new OkHttpClient.Builder(); - TestCapaHttp capaHttp = new TestCapaHttp(builder.build(), new DefaultObjectSerializer()); - - capaHttp.close(); - } -} +/* + * 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. + */ +package group.rxcloud.capa.component.http; + +import group.rxcloud.capa.infrastructure.serializer.DefaultObjectSerializer; +import group.rxcloud.cloudruntimes.utils.TypeRef; +import okhttp3.OkHttpClient; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import reactor.core.publisher.Mono; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author huijing xu + * @date 2021/10/18 + */ +public class CapaHttpTest { + + @Test + public void testInvokeApi_Success() { + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + TestCapaHttp capaHttp = new TestCapaHttp(builder.build(), new DefaultObjectSerializer()); + Mono> responseMono = capaHttp.invokeApi("post", + null, + null, + null, + headers, + null, + TypeRef.STRING); + + HttpResponse block = responseMono.block(); + int statusCode = block.getStatusCode(); + + Assertions.assertEquals(200, statusCode); + } + + @Test + public void testClose_Success() throws Exception { + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + TestCapaHttp capaHttp = new TestCapaHttp(builder.build(), new DefaultObjectSerializer()); + + capaHttp.close(); + } +} diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/http/HttpResponseTest.java b/sdk-component/src/test/java/group/rxcloud/capa/component/http/HttpResponseTest.java index b61aae4..b4aabb5 100644 --- a/sdk-component/src/test/java/group/rxcloud/capa/component/http/HttpResponseTest.java +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/http/HttpResponseTest.java @@ -1,46 +1,46 @@ -/* - * 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. - */ -package group.rxcloud.capa.component.http; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.util.HashMap; -import java.util.Map; - -public class HttpResponseTest { - - @Test - public void testGet_Success() { - Map headers = new HashMap<>(); - headers.put("Content-Type", "application/json"); - - HttpResponse httpResponse = new HttpResponse("body", headers, 200); - - Assertions.assertEquals("body", httpResponse.getBody()); - - Map resultMap = headers; - if (httpResponse.getHeaders() != null) { - resultMap = httpResponse.getHeaders(); - } - Assertions.assertEquals("application/json", resultMap.get("Content-Type")); - - Assertions.assertEquals(200, httpResponse.getStatusCode()); - } - - -} +/* + * 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. + */ +package group.rxcloud.capa.component.http; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +public class HttpResponseTest { + + @Test + public void testGet_Success() { + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + + HttpResponse httpResponse = new HttpResponse("body", headers, 200); + + Assertions.assertEquals("body", httpResponse.getBody()); + + Map resultMap = headers; + if (httpResponse.getHeaders() != null) { + resultMap = httpResponse.getHeaders(); + } + Assertions.assertEquals("application/json", resultMap.get("Content-Type")); + + Assertions.assertEquals(200, httpResponse.getStatusCode()); + } + + +} diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/http/TestCapaHttp.java b/sdk-component/src/test/java/group/rxcloud/capa/component/http/TestCapaHttp.java index e5dc9de..fa69654 100644 --- a/sdk-component/src/test/java/group/rxcloud/capa/component/http/TestCapaHttp.java +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/http/TestCapaHttp.java @@ -1,51 +1,51 @@ -/* - * 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. - */ -package group.rxcloud.capa.component.http; - -import group.rxcloud.capa.infrastructure.serializer.CapaObjectSerializer; -import group.rxcloud.cloudruntimes.utils.TypeRef; -import okhttp3.OkHttpClient; -import reactor.util.context.Context; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; - -/** - * The capa http invoker used in tests only. - */ -public class TestCapaHttp extends CapaHttp { - - public TestCapaHttp(OkHttpClient httpClient, CapaObjectSerializer objectSerializer) { - super(httpClient, objectSerializer); - } - - @Override - protected CompletableFuture> doInvokeApi(String httpMethod, - String[] pathSegments, - Map> urlParameters, - Object requestData, - Map headers, - Context context, - TypeRef type) { - return CompletableFuture.supplyAsync( - () -> { - return new HttpResponse<>(null, null, 200); - }, - Runnable::run); - } -} +/* + * 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. + */ +package group.rxcloud.capa.component.http; + +import group.rxcloud.capa.infrastructure.serializer.CapaObjectSerializer; +import group.rxcloud.cloudruntimes.utils.TypeRef; +import okhttp3.OkHttpClient; +import reactor.util.context.Context; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +/** + * The capa http invoker used in tests only. + */ +public class TestCapaHttp extends CapaHttp { + + public TestCapaHttp(OkHttpClient httpClient, CapaObjectSerializer objectSerializer) { + super(httpClient, objectSerializer); + } + + @Override + protected CompletableFuture> doInvokeApi(String httpMethod, + String[] pathSegments, + Map> urlParameters, + Object requestData, + Map headers, + Context context, + TypeRef type) { + return CompletableFuture.supplyAsync( + () -> { + return new HttpResponse<>(null, null, 200); + }, + Runnable::run); + } +} diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/log/agent/CapaLog4jAppenderAgentTest.java b/sdk-component/src/test/java/group/rxcloud/capa/component/log/agent/CapaLog4jAppenderAgentTest.java new file mode 100644 index 0000000..2b1ab7d --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/log/agent/CapaLog4jAppenderAgentTest.java @@ -0,0 +1,53 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.log.agent; + +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.message.Message; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class CapaLog4jAppenderAgentTest { + + @Test + void testCreateAppender() { + Filter filter = Mockito.mock(Filter.class); + Layout layout = Mockito.mock(Layout.class); + new CapaLog4jAppenderAgent("CapaLog4jAppender", filter, layout, true); + } + + @Test + void testBuildCapaLog4jAppender() { + Filter filter = Mockito.mock(Filter.class); + Layout layout = Mockito.mock(Layout.class); + CapaLog4jAppenderAgent.createAppender("CapaLog4jAppender", filter, layout, true); + } + + @Test + void testAppend() { + Filter filter = Mockito.mock(Filter.class); + Layout layout = Mockito.mock(Layout.class); + CapaLog4jAppenderAgent capaLog4jAppender = CapaLog4jAppenderAgent.createAppender("CapaLog4jAppender", filter, layout, true); + LogEvent logEvent = Mockito.mock(LogEvent.class); + Message message = Mockito.mock(Message.class); + Mockito.when(logEvent.getMessage()).thenReturn(Mockito.mock(Message.class)); + Mockito.when(message.getFormattedMessage()).thenReturn("TEST"); + capaLog4jAppender.append(logEvent); + } +} \ No newline at end of file diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/log/agent/CapaLogbackAppenderAgentTest.java b/sdk-component/src/test/java/group/rxcloud/capa/component/log/agent/CapaLogbackAppenderAgentTest.java new file mode 100644 index 0000000..16b61fc --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/log/agent/CapaLogbackAppenderAgentTest.java @@ -0,0 +1,42 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.log.agent; + +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.message.Message; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class CapaLogbackAppenderAgentTest { + + @Test + void testBuildCapaLogbackAppender() { + CapaLogbackAppenderAgent.CapaLogbackAppender capaLogbackAppender = CapaLogbackAppenderAgent.buildCapaLogbackAppender(); + Assertions.assertNotNull(capaLogbackAppender); + } + + @Test + void testAppend() { + CapaLogbackAppenderAgent.CapaLogbackAppender capaLogbackAppender = CapaLogbackAppenderAgent.buildCapaLogbackAppender(); + LogEvent logEvent = Mockito.mock(LogEvent.class); + Message message = Mockito.mock(Message.class); + Mockito.when(logEvent.getMessage()).thenReturn(Mockito.mock(Message.class)); + Mockito.when(message.getFormattedMessage()).thenReturn("TEST"); + capaLogbackAppender.appendLog(logEvent); + } +} \ No newline at end of file diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/log/agent/TestCapaLog4jAppender.java b/sdk-component/src/test/java/group/rxcloud/capa/component/log/agent/TestCapaLog4jAppender.java new file mode 100644 index 0000000..4dbdca6 --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/log/agent/TestCapaLog4jAppender.java @@ -0,0 +1,30 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.log.agent; + +import org.apache.logging.log4j.core.LogEvent; + +/** + * The capa log4j appender used in tests only. + */ +public class TestCapaLog4jAppender implements CapaLog4jAppenderAgent.CapaLog4jAppender { + + @Override + public void appendLog(LogEvent event) { + System.out.println("test log log4j and content is " + event.getMessage().getFormattedMessage()); + } +} \ No newline at end of file diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/log/agent/TestCapaLogbackAppender.java b/sdk-component/src/test/java/group/rxcloud/capa/component/log/agent/TestCapaLogbackAppender.java new file mode 100644 index 0000000..af58bcd --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/log/agent/TestCapaLogbackAppender.java @@ -0,0 +1,34 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.log.agent; + +import org.apache.logging.log4j.core.LogEvent; + +/** + * The capa logback appender used in tests only. + */ +public class TestCapaLogbackAppender implements CapaLogbackAppenderAgent.CapaLogbackAppender { + + public TestCapaLogbackAppender() { + } + + @Override + public void appendLog(LogEvent event) { + System.out.println("test logback log and content is " + event.getMessage().getFormattedMessage()); + } +} + diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/context/CapaContextPropagatorBuilderTest.java b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/context/CapaContextPropagatorBuilderTest.java new file mode 100644 index 0000000..8256824 --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/context/CapaContextPropagatorBuilderTest.java @@ -0,0 +1,145 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.context; + +import com.google.common.collect.Lists; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.ContextKey; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.context.propagation.TextMapSetter; +import org.jetbrains.annotations.Nullable; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * @author: chenyijiang + * @date: 2021/11/25 21:03 + */ +public class CapaContextPropagatorBuilderTest { + + @Test + public void setContextConfig() { + TestPropagator.clean(); + ContextConfig config = new ContextConfig(); + config.setContextPropagators( + Lists.newArrayList("group.rxcloud.capa.component.telemetry.context.TestPropagator")); + ContextPropagators propagators = new CapaContextPropagatorBuilder().setContextConfig(config) + .buildContextPropagators(); + propagators.getTextMapPropagator().inject(new Context() { + @Nullable + @Override + public V get(ContextKey key) { + return null; + } + + @Override + public Context with(ContextKey k1, V v1) { + return null; + } + }, null, new TextMapSetter() { + @Override + public void set(@Nullable Object carrier, String key, String value) { + + } + }); + assertEquals(1, TestPropagator.getCalled()); + } + + @Test + public void addContextPropagators() { + TestPropagator.clean(); + ContextPropagators propagators = new CapaContextPropagatorBuilder().addContextPropagators(new TestPropagator()) + .addContextPropagators(new TestPropagator()) + .buildContextPropagators(); + + propagators.getTextMapPropagator().inject(new Context() { + @Nullable + @Override + public V get(ContextKey key) { + return null; + } + + @Override + public Context with(ContextKey k1, V v1) { + return null; + } + }, null, new TextMapSetter() { + @Override + public void set(@Nullable Object carrier, String key, String value) { + + } + }); + + assertEquals(2, TestPropagator.getCalled()); + } + + + @Test + public void buildFromContextConfig() { + TestPropagator.clean(); + ContextPropagators propagators = new CapaContextPropagatorBuilder() + .buildContextPropagators(); + propagators.getTextMapPropagator().inject(new Context() { + @Nullable + @Override + public V get(ContextKey key) { + return null; + } + + @Override + public Context with(ContextKey k1, V v1) { + return null; + } + }, null, new TextMapSetter() { + @Override + public void set(@Nullable Object carrier, String key, String value) { + + } + }); + assertEquals(3, TestPropagator.getCalled()); + } + + @Test + public void buildFromLoader() { + TestPropagator.clean(); + ContextPropagators propagators = new CapaContextPropagatorBuilder() + .setContextConfig(new ContextConfig()) + .buildContextPropagators(); + propagators.getTextMapPropagator().inject(new Context() { + @Nullable + @Override + public V get(ContextKey key) { + return null; + } + + @Override + public Context with(ContextKey k1, V v1) { + return null; + } + }, null, new TextMapSetter() { + @Override + public void set(@Nullable Object carrier, String key, String value) { + + } + }); + assertNotNull(propagators); + assertEquals(0, TestPropagator.getCalled()); + } + +} \ No newline at end of file diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/context/CapaContextTest.java b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/context/CapaContextTest.java new file mode 100644 index 0000000..b1493b4 --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/context/CapaContextTest.java @@ -0,0 +1,68 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.context; + +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @author: chenyijiang + * @date: 2021/11/25 20:53 + */ +public class CapaContextTest { + + @Test + public void taskWrapping() { + CapaContext.taskWrapping(new Runnable() { + @Override + public void run() { + + } + }); + assertTrue(TestCapaContextAsyncWrapper.called(Runnable.class)); + CapaContext.taskWrapping(new Callable() { + + @Override + public Boolean call() throws Exception { + return true; + } + }); + assertTrue(TestCapaContextAsyncWrapper.called(Callable.class)); + CapaContext.taskWrapping(Executors.newSingleThreadExecutor()); + assertTrue(TestCapaContextAsyncWrapper.called(ExecutorService.class)); + CapaContext.taskWrapping(new Executor() { + @Override + public void execute(@NotNull Runnable command) { + + } + }); + assertTrue(TestCapaContextAsyncWrapper.called(Executor.class)); + CapaContext.taskWrapping(Executors.newScheduledThreadPool(1)); + assertTrue(TestCapaContextAsyncWrapper.called(ScheduledExecutorService.class)); + + assertNotNull(CapaContext.getTraceId()); + } +} \ No newline at end of file diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/context/TestCapaContextAsyncWrapper.java b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/context/TestCapaContextAsyncWrapper.java new file mode 100644 index 0000000..8c114e1 --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/context/TestCapaContextAsyncWrapper.java @@ -0,0 +1,72 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.context; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; + +/** + * @author: chenyijiang + * @date: 2021/11/25 20:55 + */ +public class TestCapaContextAsyncWrapper implements CapaContextAsyncWrapper { + + private static Set called = new HashSet<>(); + + @Override + public Runnable wrap(Runnable runnable) { + called.add(Runnable.class); + return CapaContextAsyncWrapper.super.wrap(runnable); + } + + @Override + public Callable wrap(Callable callable) { + called.add(Callable.class); + return CapaContextAsyncWrapper.super.wrap(callable); + } + + @Override + public Executor wrap(Executor executor) { + called.add(Executor.class); + return CapaContextAsyncWrapper.super.wrap(executor); + } + + @Override + public ExecutorService wrap(ExecutorService executor) { + called.add(ExecutorService.class); + return CapaContextAsyncWrapper.super.wrap(executor); + } + + @Override + public ScheduledExecutorService wrap(ScheduledExecutorService executor) { + called.add(ScheduledExecutorService.class); + return CapaContextAsyncWrapper.super.wrap(executor); + } + + @Override + public String getTraceId() { + return CapaContextAsyncWrapper.super.getTraceId(); + } + + public static boolean called(Class type) { + return called.contains(type); + } +} diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/context/TestPropagator.java b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/context/TestPropagator.java new file mode 100644 index 0000000..605ecfc --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/context/TestPropagator.java @@ -0,0 +1,59 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.context; + +import com.google.common.collect.Lists; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.propagation.TextMapGetter; +import io.opentelemetry.context.propagation.TextMapPropagator; +import io.opentelemetry.context.propagation.TextMapSetter; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author: chenyijiang + * @date: 2021/11/25 21:07 + */ +public class TestPropagator implements TextMapPropagator { + + private static AtomicInteger called = new AtomicInteger(); + + @Override + public Collection fields() { + return Lists.newArrayList("a"); + } + + @Override + public void inject(Context context, @Nullable C carrier, TextMapSetter setter) { + called.incrementAndGet(); + } + + @Override + public Context extract(Context context, @Nullable C carrier, TextMapGetter getter) { + return null; + } + + public static int getCalled() { + return called.get(); + } + + public static void clean() { + called.set(0); + } +} diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/metrics/CapaMeterProviderBuilderTest.java b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/metrics/CapaMeterProviderBuilderTest.java new file mode 100644 index 0000000..f12879e --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/metrics/CapaMeterProviderBuilderTest.java @@ -0,0 +1,147 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.metrics; + +import com.google.common.collect.Lists; +import group.rxcloud.capa.component.telemetry.SamplerConfig; +import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.api.metrics.internal.NoopMeterProvider; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @author: chenyijiang + * @date: 2021/11/25 17:31 + */ +public class CapaMeterProviderBuilderTest { + + + @Test + public void buildWithConfigFile() { + + MeterProvider meterProvider = new CapaMeterProviderBuilder() + .buildMeterProvider(); + + ThreadGroup currentGroup = + Thread.currentThread().getThreadGroup(); + int noThreads = currentGroup.activeCount(); + Thread[] lstThreads = new Thread[noThreads]; + currentGroup.enumerate(lstThreads); + + assertTrue(Arrays.stream(lstThreads).anyMatch(t -> t.getName().contains("my-reader"))); + assertTrue(CapaMetricsSampler.getInstance().shouldSampleMeasurement(1L, null, null)); + assertTrue(CapaMetricsSampler.getInstance().shouldSampleMeasurement(1.0, null, null)); + } + + + @Test + public void buildWithEmptyConfig() { + + MeterProvider meterProvider = new CapaMeterProviderBuilder() + .setMeterConfig(new MeterConfig()) + .buildMeterProvider(); + + assertTrue(meterProvider instanceof NoopMeterProvider); + } + + @Test + public void buildWithUnknownExporterConfig() { + Throwable throwable = null; + try { + new CapaMeterProviderBuilder() + .addMetricReaderConfig(new MetricsReaderConfig() {{ + setExporterType("aaaaa"); + }}) + .buildMeterProvider(); + } catch (Throwable throwable1) { + throwable = throwable1; + } + + assertTrue(throwable instanceof IllegalArgumentException); + } + + @Test + public void addReaderConfig() { + MetricsReaderConfig readerConfigByInstance = new MetricsReaderConfig(); + readerConfigByInstance.setName("reader_a2"); + readerConfigByInstance.setExportInterval(2, TimeUnit.SECONDS); + readerConfigByInstance.setExporterType(TestMetricsExporter.class.getName()); + MetricsReaderConfig readerConfigByPath = new MetricsReaderConfig(); + readerConfigByPath.setName("reader_b2"); + readerConfigByPath.setExportInterval(4, TimeUnit.SECONDS); + readerConfigByPath.setExporterType("group.rxcloud.capa.component.telemetry.metrics.TestMetricsExporter"); + + MeterProvider meterProvider = new CapaMeterProviderBuilder() + .addMetricReaderConfig(readerConfigByInstance) + .addMetricReaderConfig(readerConfigByPath) + .buildMeterProvider(); + + ThreadGroup currentGroup = + Thread.currentThread().getThreadGroup(); + int noThreads = currentGroup.activeCount(); + Thread[] lstThreads = new Thread[noThreads]; + currentGroup.enumerate(lstThreads); + + assertTrue(Arrays.stream(lstThreads).anyMatch(t -> t.getName().contains(readerConfigByInstance.getName()))); + assertTrue(Arrays.stream(lstThreads).anyMatch(t -> t.getName().contains(readerConfigByPath.getName()))); + + assertTrue(CapaMetricsSampler.getInstance().shouldSampleMeasurement(1L, null, null)); + assertTrue(CapaMetricsSampler.getInstance().shouldSampleMeasurement(1.0, null, null)); + } + + + @Test + public void setMeterConfig() { + MeterConfig meterConfig = new MeterConfig(); + MetricsReaderConfig readerConfigByInstance = new MetricsReaderConfig(); + readerConfigByInstance.setName("reader_a3"); + readerConfigByInstance.setExportInterval(2, TimeUnit.SECONDS); + readerConfigByInstance.setExporterType(TestMetricsExporter.class.getName()); + meterConfig.setReaders(Lists.newArrayList(readerConfigByInstance)); + + MetricsReaderConfig readerConfigByPath = new MetricsReaderConfig(); + readerConfigByPath.setName("reader_b3"); + readerConfigByPath.setExportInterval(4, TimeUnit.SECONDS); + readerConfigByPath.setExporterType("group.rxcloud.capa.component.telemetry.metrics.TestMetricsExporter"); + + SamplerConfig samplerConfig = new SamplerConfig(); + samplerConfig.setMetricsSample(false); + + MeterProvider meterProvider = new CapaMeterProviderBuilder() + .addMetricReaderConfig(readerConfigByPath) + .setMeterConfig(meterConfig) + .setSamplerConfig(samplerConfig) + .buildMeterProvider(); + + ThreadGroup currentGroup = + Thread.currentThread().getThreadGroup(); + int noThreads = currentGroup.activeCount(); + Thread[] lstThreads = new Thread[noThreads]; + currentGroup.enumerate(lstThreads); + + assertTrue(Arrays.stream(lstThreads).noneMatch(t -> t.getName().contains(readerConfigByInstance.getName()))); + assertTrue(Arrays.stream(lstThreads).anyMatch(t -> t.getName().contains(readerConfigByPath.getName()))); + + assertFalse(CapaMetricsSampler.getInstance().shouldSampleMeasurement(1L, null, null)); + assertFalse(CapaMetricsSampler.getInstance().shouldSampleMeasurement(1.0, null, null)); + } +} \ No newline at end of file diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/metrics/CapaMetricsSamplerTest.java b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/metrics/CapaMetricsSamplerTest.java new file mode 100644 index 0000000..d05d7e1 --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/metrics/CapaMetricsSamplerTest.java @@ -0,0 +1,60 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.metrics; + +import group.rxcloud.capa.component.telemetry.SamplerConfig; +import group.rxcloud.capa.component.telemetry.trace.CapaTraceSampler; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @author: chenyijiang + * @date: 2021/11/25 17:16 + */ +public class CapaMetricsSamplerTest { + + @Test + public void getInstance() { + assertNotNull(CapaMetricsSampler.getInstance()); + CapaMetricsSampler.getInstance().update(SamplerConfig.DEFAULT_CONFIG); + assertTrue(CapaMetricsSampler.getInstance().shouldSampleMeasurement(1L, null, null)); + assertTrue(CapaMetricsSampler.getInstance().shouldSampleMeasurement(1.0, null, null)); + + CapaMetricsSampler.getInstance().update(null); + assertTrue(CapaMetricsSampler.getInstance().shouldSampleMeasurement(1L, null, null)); + assertTrue(CapaMetricsSampler.getInstance().shouldSampleMeasurement(1.0, null, null)); + + SamplerConfig samplerConfig = new SamplerConfig(); + samplerConfig.setMetricsSample(false); + CapaMetricsSampler.getInstance().update(samplerConfig); + assertFalse(CapaMetricsSampler.getInstance().shouldSampleMeasurement(1L, null, null)); + assertFalse(CapaMetricsSampler.getInstance().shouldSampleMeasurement(1.0, null, null)); + + + samplerConfig.setMetricsSample(true); + CapaMetricsSampler.getInstance().update(samplerConfig); + assertTrue(CapaMetricsSampler.getInstance().shouldSampleMeasurement(1L, null, null)); + assertTrue(CapaMetricsSampler.getInstance().shouldSampleMeasurement(1.0, null, null)); + + CapaMetricsSampler.getInstance().update(SamplerConfig.DEFAULT_CONFIG); + + assertNotNull(CapaTraceSampler.getInstance().getDescription()); + } +} \ No newline at end of file diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/metrics/TestMetricsExporter.java b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/metrics/TestMetricsExporter.java new file mode 100644 index 0000000..ede215b --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/metrics/TestMetricsExporter.java @@ -0,0 +1,46 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.metrics; + +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.export.MetricExporter; + +import java.util.Collection; + +/** + * @author: chenyijiang + * @date: 2021/11/25 17:04 + */ +public class TestMetricsExporter implements MetricExporter { + + @Override + public CompletableResultCode export(Collection metrics) { + metrics.forEach(System.out::println); + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode flush() { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode shutdown() { + return CompletableResultCode.ofSuccess(); + } +} diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/CapaReadWriteSpanTest.java b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/CapaReadWriteSpanTest.java new file mode 100644 index 0000000..3b74075 --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/CapaReadWriteSpanTest.java @@ -0,0 +1,88 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import io.opentelemetry.sdk.trace.ReadWriteSpan; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +/** + * @author: chenyijiang + * @date: 2021/11/25 22:48 + */ +public class CapaReadWriteSpanTest { + + @Test + public void getTracerName() { + ReadWriteSpan span = Mockito.mock(ReadWriteSpan.class); + CapaReadWriteSpan readWriteSpan = new CapaReadWriteSpan("aaa", "1.1", "url", span); + + readWriteSpan.getName(); + verify(span).getName(); + + readWriteSpan.getKind(); + verify(span).getKind(); + + readWriteSpan.getParentSpanContext(); + verify(span).getParentSpanContext(); + + assertEquals("aaa", readWriteSpan.getTracerName()); + verify(span, never()).getInstrumentationLibraryInfo(); + + assertEquals("1.1", readWriteSpan.getVersion()); + verify(span, never()).getInstrumentationLibraryInfo(); + + assertEquals("url", readWriteSpan.getSchemaUrl()); + verify(span, never()).getInstrumentationLibraryInfo(); + + long mills = System.currentTimeMillis(); + readWriteSpan.addEvent("aaa", null, mills, TimeUnit.MILLISECONDS); + verify(span).addEvent("aaa", null, mills, TimeUnit.MILLISECONDS); + + readWriteSpan.updateName("lll"); + verify(span).updateName("lll"); + + readWriteSpan.toSpanData(); + verify(span).toSpanData(); + + readWriteSpan.getInstrumentationLibraryInfo(); + verify(span).getInstrumentationLibraryInfo(); + + doReturn(true).when(span).hasEnded(); + assertTrue(readWriteSpan.hasEnded()); + + doReturn(System.nanoTime()).when(span).getLatencyNanos(); + readWriteSpan.getLatencyNanos(); + verify(span).getLatencyNanos(); + + readWriteSpan.getAttribute(StatusAttributeKey.STATUS); + verify(span).getAttribute(StatusAttributeKey.STATUS); + + + doReturn(true).when(span).isRecording(); + assertTrue(readWriteSpan.isRecording()); + + } +} \ No newline at end of file diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/CapaTraceSamplerTest.java b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/CapaTraceSamplerTest.java new file mode 100644 index 0000000..9bff803 --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/CapaTraceSamplerTest.java @@ -0,0 +1,55 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import group.rxcloud.capa.component.telemetry.SamplerConfig; +import io.opentelemetry.sdk.trace.samplers.SamplingResult; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * @author: chenyijiang + * @date: 2021/11/25 21:41 + */ +public class CapaTraceSamplerTest { + + @Test + public void getInstance() { + assertNotNull(CapaTraceSampler.getInstance()); + CapaTraceSampler.getInstance().update(SamplerConfig.DEFAULT_CONFIG); + assertEquals(SamplingResult.recordAndSample(), CapaTraceSampler.getInstance().shouldSample(null, null, null, null, null, null)); + + CapaTraceSampler.getInstance().update(null); + assertEquals(SamplingResult.recordAndSample(), CapaTraceSampler.getInstance().shouldSample(null, null, null, null, null, null)); + + SamplerConfig samplerConfig = new SamplerConfig(); + samplerConfig.setTraceSample(false); + CapaTraceSampler.getInstance().update(samplerConfig); + assertEquals(SamplingResult.drop(), CapaTraceSampler.getInstance().shouldSample(null, null, null, null, null, null)); + + + samplerConfig.setTraceSample(true); + CapaTraceSampler.getInstance().update(samplerConfig); + assertEquals(SamplingResult.recordAndSample(), CapaTraceSampler.getInstance().shouldSample(null, null, null, null, null, null)); + + CapaTraceSampler.getInstance().update(SamplerConfig.DEFAULT_CONFIG); + + assertNotNull(CapaTraceSampler.getInstance().getDescription()); + } +} \ No newline at end of file diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerProviderBuilderTest.java b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerProviderBuilderTest.java new file mode 100644 index 0000000..c3a49a6 --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerProviderBuilderTest.java @@ -0,0 +1,136 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import group.rxcloud.capa.component.telemetry.SamplerConfig; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.sdk.trace.IdGenerator; +import io.opentelemetry.sdk.trace.ReadableSpan; +import io.opentelemetry.sdk.trace.SpanProcessor; +import io.opentelemetry.sdk.trace.data.SpanData; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatcher; + +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +/** + * @author: chenyijiang + * @date: 2021/11/25 21:45 + */ +public class CapaTracerProviderBuilderTest { + + @Test + public void buildFromTraceConfg() { + TracerConfig config = new TracerConfig(); + config.setEnableIdValidate(false); + config.setSpanLimits(new SpanLimitsConfig()); + config.getSpanLimits().setMaxAttributeValueLength(1); + config.getSpanLimits().setMaxNumAttributes(5); + config.getSpanLimits().setMaxNumAttributesPerEvent(2); + config.getSpanLimits().setMaxNumAttributesPerLink(2); + config.getSpanLimits().setMaxNumEvents(2); + config.getSpanLimits().setMaxNumLinks(2); + + SpanLimitsConfig outter = new SpanLimitsConfig(); + outter.setMaxAttributeValueLength(5); + + SpanProcessor processor = mock(SpanProcessor.class); + CapaTracerProvider provider = new CapaTracerProviderBuilder() + .setTracerConfig(config) + .addProcessor(processor) + .setSpanLimits(outter) + .setIdGenerator(IdGenerator.random()) + .setSamplerConfig(SamplerConfig.DEFAULT_CONFIG) + .buildTracerProvider(); + Span spanAnother = provider.tracerBuilder("otherTracer").build().spanBuilder("otherSpan").startSpan(); + spanAnother.end(System.currentTimeMillis(), TimeUnit.MILLISECONDS); + + + Span span = provider.tracerBuilder("test") + .build() + .spanBuilder("???") + .setSpanKind(SpanKind.SERVER) + .setNoParent() + .setAttribute("len", "aaaaaaaa") + .setAttribute("aaa", 1L) + .setAttribute("bbb", 2.0) + .setAttribute("ccc", true) + .setAttribute(AttributeKey.stringKey("ssss"), "str") + .addLink(spanAnother.getSpanContext()) + .addLink(spanAnother.getSpanContext(), Attributes.builder().put(StatusAttributeKey.MESSAGE, "testing").build()) + .startSpan(); + + span.updateName("span").recordException(new RuntimeException(), Attributes.builder().put(StatusAttributeKey.MESSAGE, "fail").build()); + + span.setStatus(StatusCode.OK); + span.setAttribute("lalala", "hahaha"); + span.addEvent("countEvent", Attributes.builder().put(EventAttributeKey.COUNT, 1L).build()); + + span.end(); + + verify(processor).onEnd(argThat(new ArgumentMatcher() { + @Override + public boolean matches(ReadableSpan span) { + if ("span".equals(span.getName())) { + assertEquals("test", span.getInstrumentationLibraryInfo().getName()); + assertEquals("span", span.getName()); + assertEquals(SpanKind.SERVER, span.getKind()); + assertEquals(SpanContext.getInvalid(), span.getParentSpanContext()); + SpanData spanData = span.toSpanData(); + assertEquals(2, spanData.getEvents().size()); + assertEquals(2, spanData.getLinks().size()); + assertEquals(5, spanData.getAttributes().size()); + assertEquals(StatusCode.OK, spanData.getStatus().getStatusCode()); + return span.getAttribute(AttributeKey.stringKey("len")).length() == 5; + } + return false; + } + })); + } + + @Test + public void buildFromTraceConfig() { + CapaTracerProvider provider = new CapaTracerProviderBuilder() + .buildTracerProvider(); + + Span span = provider.tracerBuilder("test") + .setSchemaUrl("url") + .setInstrumentationVersion("1.1.1") + .build() + .spanBuilder("span2") + .setSpanKind(SpanKind.SERVER) + .setAttribute("len", "aaaaaaaa") + .startSpan(); + + span.recordException(new RuntimeException(), Attributes.builder().put(StatusAttributeKey.MESSAGE, "fail").build()); + + span.end(); + + assertTrue(TestSpanProcessor.called("span2")); + } +} \ No newline at end of file diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerProviderTest.java b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerProviderTest.java new file mode 100644 index 0000000..c29f2d6 --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/CapaTracerProviderTest.java @@ -0,0 +1,49 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import io.opentelemetry.api.trace.Tracer; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @author: chenyijiang + * @date: 2021/11/25 22:35 + */ +public class CapaTracerProviderTest { + + @Test + public void get() { + Tracer tracer = new CapaTracerProviderBuilder().buildTracerProvider().get("aaa"); + assertTrue(tracer instanceof CapaTracer); + assertEquals("aaa", ((CapaTracer) tracer).tracerName); + + tracer = new CapaTracerProviderBuilder().buildTracerProvider().get("aaa", "1.1"); + assertTrue(tracer instanceof CapaTracer); + assertEquals("aaa", ((CapaTracer) tracer).tracerName); + assertEquals("1.1", ((CapaTracer) tracer).getVersion()); + + + tracer = new CapaTracerProviderBuilder().buildTracerProvider().tracerBuilder("aaa").setSchemaUrl("url").setInstrumentationVersion("1.1").build(); + assertTrue(tracer instanceof CapaTracer); + assertEquals("aaa", ((CapaTracer) tracer).tracerName); + assertEquals("1.1", ((CapaTracer) tracer).getVersion()); + assertEquals("url", ((CapaTracer) tracer).getSchemaUrl()); + } +} \ No newline at end of file diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/EventAttributeKeyTest.java b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/EventAttributeKeyTest.java new file mode 100644 index 0000000..5faf1a1 --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/EventAttributeKeyTest.java @@ -0,0 +1,38 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * @author: chenyijiang + * @date: 2021/11/25 23:00 + */ +public class EventAttributeKeyTest { + + @Test + public void getNum() { + assertNull(EventAttributeKey.COUNT.getNum("aaa")); + + assertNull(EventAttributeKey.COUNT.getNum(Long.MAX_VALUE)); + assertNull(EventAttributeKey.COUNT.getNum(Long.MIN_VALUE)); + assertEquals(22, EventAttributeKey.COUNT.getNum(22L).intValue()); + } +} \ No newline at end of file diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/TestIdGenerator.java b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/TestIdGenerator.java new file mode 100644 index 0000000..8ab6d0d --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/TestIdGenerator.java @@ -0,0 +1,36 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import io.opentelemetry.sdk.trace.IdGenerator; + +/** + * @author: chenyijiang + * @date: 2021/11/25 22:20 + */ +public class TestIdGenerator implements IdGenerator { + + @Override + public String generateSpanId() { + return String.valueOf(System.nanoTime()); + } + + @Override + public String generateTraceId() { + return String.valueOf(System.nanoTime()); + } +} diff --git a/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/TestSpanProcessor.java b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/TestSpanProcessor.java new file mode 100644 index 0000000..2fd98bb --- /dev/null +++ b/sdk-component/src/test/java/group/rxcloud/capa/component/telemetry/trace/TestSpanProcessor.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package group.rxcloud.capa.component.telemetry.trace; + +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.trace.ReadWriteSpan; +import io.opentelemetry.sdk.trace.ReadableSpan; +import io.opentelemetry.sdk.trace.SpanProcessor; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author: chenyijiang + * @date: 2021/11/25 21:52 + */ +public class TestSpanProcessor implements SpanProcessor { + + static Set spanNames = new HashSet<>(); + + @Override + public void onStart(Context context, ReadWriteSpan span) { + + } + + @Override + public boolean isStartRequired() { + return false; + } + + @Override + public void onEnd(ReadableSpan span) { + spanNames.add(span.getName()); + } + + @Override + public boolean isEndRequired() { + return false; + } + + public static boolean called(String name) { + return spanNames.contains(name); + } +} diff --git a/sdk-component/src/test/resources/capa-component-configuration.properties b/sdk-component/src/test/resources/capa-component-configuration.properties index 2e1217f..4b98d3f 100644 --- a/sdk-component/src/test/resources/capa-component-configuration.properties +++ b/sdk-component/src/test/resources/capa-component-configuration.properties @@ -1 +1 @@ -group.rxcloud.capa.component.configstore.CapaConfigStore=group.rxcloud.capa.component.configstore.TestCapaConfigStore +group.rxcloud.capa.component.configstore.CapaConfigStore=group.rxcloud.capa.component.configstore.TestCapaConfigStore diff --git a/sdk-component/src/test/resources/capa-component-log.properties b/sdk-component/src/test/resources/capa-component-log.properties new file mode 100644 index 0000000..17fc340 --- /dev/null +++ b/sdk-component/src/test/resources/capa-component-log.properties @@ -0,0 +1,2 @@ +group.rxcloud.capa.component.log.agent.CapaLog4jAppenderAgent$CapaLog4jAppender=group.rxcloud.capa.component.log.agent.TestCapaLog4jAppender +group.rxcloud.capa.component.log.agent.CapaLogbackAppenderAgent$CapaLogbackAppender=group.rxcloud.capa.component.log.agent.TestCapaLogbackAppender \ No newline at end of file diff --git a/sdk-component/src/test/resources/capa-component-telemetry.properties b/sdk-component/src/test/resources/capa-component-telemetry.properties new file mode 100644 index 0000000..33bbdf7 --- /dev/null +++ b/sdk-component/src/test/resources/capa-component-telemetry.properties @@ -0,0 +1 @@ +group.rxcloud.capa.component.telemetry.context.CapaContextAsyncWrapper=group.rxcloud.capa.component.telemetry.context.TestCapaContextAsyncWrapper \ No newline at end of file diff --git a/sdk-component/src/test/resources/capa-context.json b/sdk-component/src/test/resources/capa-context.json new file mode 100644 index 0000000..e9c202c --- /dev/null +++ b/sdk-component/src/test/resources/capa-context.json @@ -0,0 +1,3 @@ +{ + "contextPropagators": ["group.rxcloud.capa.component.telemetry.context.TestPropagator","group.rxcloud.capa.component.telemetry.context.TestPropagator","group.rxcloud.capa.component.telemetry.context.TestPropagator"] +} \ No newline at end of file diff --git a/sdk-component/src/test/resources/capa-meter.json b/sdk-component/src/test/resources/capa-meter.json new file mode 100644 index 0000000..2e10339 --- /dev/null +++ b/sdk-component/src/test/resources/capa-meter.json @@ -0,0 +1,6 @@ +{ + "readers": [{ + "name": "my-reader", + "exporterType": "group.rxcloud.capa.component.telemetry.metrics.TestMetricsExporter" + }] +} \ No newline at end of file diff --git a/sdk-component/src/test/resources/capa-sample.properties b/sdk-component/src/test/resources/capa-sample.properties new file mode 100644 index 0000000..d22c308 --- /dev/null +++ b/sdk-component/src/test/resources/capa-sample.properties @@ -0,0 +1,2 @@ +metricsSample=true +traceSample=true \ No newline at end of file diff --git a/sdk-component/src/test/resources/capa-tracer.json b/sdk-component/src/test/resources/capa-tracer.json new file mode 100644 index 0000000..3d12acc --- /dev/null +++ b/sdk-component/src/test/resources/capa-tracer.json @@ -0,0 +1,7 @@ +{ + "enableIdValidate" : false, + "idGenerator": "group.rxcloud.capa.component.telemetry.trace.TestIdGenerator", + "processors" : [ + "group.rxcloud.capa.component.telemetry.trace.TestSpanProcessor" + ] +} \ No newline at end of file diff --git a/sdk-infrastructure/pom.xml b/sdk-infrastructure/pom.xml index 9ff9834..17a1891 100644 --- a/sdk-infrastructure/pom.xml +++ b/sdk-infrastructure/pom.xml @@ -23,7 +23,7 @@ capa-parent group.rxcloud - 1.0.6.RELEASE + 1.0.7.RELEASE capa-sdk-infrastructure @@ -31,10 +31,9 @@ SDK infrastructure for Capa - 1.0.0 + 1.0.1-RELEASE 1.39.0 2.12.4 - 1.7.32 @@ -50,6 +49,22 @@ reactor-core + + + org.slf4j + slf4j-api + + + + + io.opentelemetry + opentelemetry-api + + + io.opentelemetry + opentelemetry-api-metrics + + com.kevinten @@ -57,13 +72,6 @@ ${vrml.version} - - - org.slf4j - slf4j-api - ${slf4j-api.version} - - io.grpc diff --git a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaConstants.java b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaConstants.java index 04fb156..752ea46 100644 --- a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaConstants.java +++ b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaConstants.java @@ -30,15 +30,18 @@ interface Properties { * The {@code infrastructure} properties prefix. */ String CAPA_INFRASTRUCTURE_PROPERTIES_PREFIX = "/capa-infrastructure-"; - /** * The {@code component} properties prefix. */ String CAPA_COMPONENT_PROPERTIES_PREFIX = "/capa-component-"; /** - * The constant SUFFIX. + * The properties suffix. */ String CAPA_PROPERTIES_SUFFIX = ".properties"; + /** + * The json suffix. + */ + String CAPA_JSON_SUFFIX = ".json"; } } diff --git a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaProperties.java b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaProperties.java index ce0ddfd..c47bdc0 100644 --- a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaProperties.java +++ b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/CapaProperties.java @@ -16,6 +16,12 @@ */ package group.rxcloud.capa.infrastructure; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; + import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -30,6 +36,7 @@ import static group.rxcloud.capa.infrastructure.CapaConstants.Properties.CAPA_COMPONENT_PROPERTIES_PREFIX; import static group.rxcloud.capa.infrastructure.CapaConstants.Properties.CAPA_INFRASTRUCTURE_PROPERTIES_PREFIX; import static group.rxcloud.capa.infrastructure.CapaConstants.Properties.CAPA_PROPERTIES_SUFFIX; +import static group.rxcloud.capa.infrastructure.Module.OBJECT_MAPPER; /** * Global properties for Capa's SDK, using Supplier so they are dynamically resolved. @@ -60,13 +67,13 @@ public abstract class CapaProperties { /** * Capa's properties cache map. */ - private static final Map PROPERTIES_MAP = new ConcurrentHashMap<>(); + private static final Map PROPERTIES_MAP = new ConcurrentHashMap<>(); /** * Capa's infrastructure properties. */ public static final Function INFRASTRUCTURE_PROPERTIES_SUPPLIER - = (infrastructureDomain) -> PROPERTIES_MAP.computeIfAbsent(infrastructureDomain, + = (infrastructureDomain) -> (Properties) PROPERTIES_MAP.computeIfAbsent(infrastructureDomain, s -> { final String fileName = CAPA_INFRASTRUCTURE_PROPERTIES_PREFIX + infrastructureDomain.toLowerCase() @@ -78,7 +85,7 @@ public abstract class CapaProperties { * Capa's component properties. */ public static final Function COMPONENT_PROPERTIES_SUPPLIER - = (componentDomain) -> PROPERTIES_MAP.computeIfAbsent(componentDomain, + = (componentDomain) -> (Properties) PROPERTIES_MAP.computeIfAbsent(componentDomain, s -> { final String fileName = CAPA_COMPONENT_PROPERTIES_PREFIX + componentDomain.toLowerCase() @@ -97,4 +104,23 @@ private static Properties loadCapaProperties(final String fileName) { throw new IllegalArgumentException(fileName + " file not found."); } } + + public static T loadCapaConfig(final String fileName, Class configClazz) { + Objects.requireNonNull(fileName, "fileName not found."); + try (InputStream in = configClazz.getResourceAsStream(fileName)) { + InputStreamReader inputStreamReader = new InputStreamReader(in, StandardCharsets.UTF_8); + return OBJECT_MAPPER.readValue(inputStreamReader, configClazz); + } catch (JsonParseException | JsonMappingException e) { + throw new IllegalArgumentException(fileName + " file not load."); + } catch (IOException e) { + throw new IllegalArgumentException(fileName + " file not found."); + } + } +} + +interface Module { + + ObjectMapper OBJECT_MAPPER = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .setSerializationInclusion(JsonInclude.Include.NON_NULL); } diff --git a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/hook/ConfigurationHooks.java b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/hook/ConfigurationHooks.java new file mode 100644 index 0000000..8845bba --- /dev/null +++ b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/hook/ConfigurationHooks.java @@ -0,0 +1,95 @@ +/* + * 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. + */ +package group.rxcloud.capa.infrastructure.hook; + +import group.rxcloud.cloudruntimes.domain.core.ConfigurationRuntimes; +import group.rxcloud.cloudruntimes.domain.core.configuration.ConfigurationItem; +import group.rxcloud.cloudruntimes.domain.core.configuration.ConfigurationRequestItem; +import group.rxcloud.cloudruntimes.domain.core.configuration.SaveConfigurationRequest; +import group.rxcloud.cloudruntimes.domain.core.configuration.SubConfigurationResp; +import group.rxcloud.cloudruntimes.utils.TypeRef; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.Map; + +/** + * The Mixer configuration hooks. + */ +public interface ConfigurationHooks extends ConfigurationRuntimes { + + /** + * Registry Store Names. + */ + List registryStoreNames(); + + /** + * Default configuration appI. + */ + String defaultConfigurationAppId(); + + @Override + default Mono>> getConfiguration(String storeName, String appId, List keys, Map metadata, TypeRef type) { + throw new UnsupportedOperationException("If you want to use this operate, please impl this."); + } + + @Override + default Mono>> getConfiguration(String storeName, String appId, List keys, Map metadata, String group, TypeRef type) { + throw new UnsupportedOperationException("If you want to use this operate, please impl this."); + } + + @Override + default Mono>> getConfiguration(String storeName, String appId, List keys, Map metadata, String group, String label, TypeRef type) { + throw new UnsupportedOperationException("If you want to use this operate, please impl this."); + } + + @Override + default Mono>> getConfiguration(ConfigurationRequestItem configurationRequestItem, TypeRef type) { + throw new UnsupportedOperationException("If you want to use this operate, please impl this."); + } + + @Override + default Mono saveConfiguration(SaveConfigurationRequest saveConfigurationRequest) { + throw new UnsupportedOperationException("If you want to use this operate, please impl this."); + } + + @Override + default Mono deleteConfiguration(ConfigurationRequestItem configurationRequestItem) { + throw new UnsupportedOperationException("If you want to use this operate, please impl this."); + } + + @Override + default Flux> subscribeConfiguration(String storeName, String appId, List keys, Map metadata, TypeRef type) { + throw new UnsupportedOperationException("If you want to use this operate, please impl this."); + } + + @Override + default Flux> subscribeConfiguration(String storeName, String appId, List keys, Map metadata, String group, TypeRef type) { + throw new UnsupportedOperationException("If you want to use this operate, please impl this."); + } + + @Override + default Flux> subscribeConfiguration(String storeName, String appId, List keys, Map metadata, String group, String label, TypeRef type) { + throw new UnsupportedOperationException("If you want to use this operate, please impl this."); + } + + @Override + default Flux> subscribeConfiguration(ConfigurationRequestItem configurationRequestItem, TypeRef type) { + throw new UnsupportedOperationException("If you want to use this operate, please impl this."); + } +} diff --git a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/hook/Mixer.java b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/hook/Mixer.java new file mode 100644 index 0000000..3a28b05 --- /dev/null +++ b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/hook/Mixer.java @@ -0,0 +1,123 @@ +/* + * 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. + */ +package group.rxcloud.capa.infrastructure.hook; + +import group.rxcloud.capa.infrastructure.CapaClassLoader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nullable; +import java.util.Optional; + +/** + * The Inner Runtimes Mixer. + */ +public abstract class Mixer { + + private static final Logger logger = LoggerFactory.getLogger(Mixer.class); + + private static ConfigurationHooks configurationHooks; + private static TelemetryHooks telemetryHooks; + + static { + try { + MixerProvider mixerProvider = CapaClassLoader.loadInfrastructureClassObj("mixer", MixerProvider.class); + if (mixerProvider != null) { + registerConfigurationHooks(mixerProvider.provideConfigurationHooks()); + registerTelemetryHooks(mixerProvider.provideTelemetryHooks()); + } + } catch (Exception e) { + logger.info("[CapaMixer] load empty mixer. expected error: ", e); + } + } + + /** + * The SPI Mixer provider. + */ + public interface MixerProvider { + + /** + * Provide global configuration hooks. + * + * @return the configuration hooks + */ + ConfigurationHooks provideConfigurationHooks(); + + /** + * Provide global telemetry hooks. + * + * @return the telemetry hooks + */ + TelemetryHooks provideTelemetryHooks(); + } + + /** + * Register configuration hooks. + * + * @param configurationHooks the configuration hooks + */ + private static void registerConfigurationHooks(ConfigurationHooks configurationHooks) { + Mixer.configurationHooks = configurationHooks; + } + + /** + * Register telemetry hooks. + * + * @param telemetryHooks the telemetry hooks + */ + private static void registerTelemetryHooks(TelemetryHooks telemetryHooks) { + Mixer.telemetryHooks = telemetryHooks; + } + + /** + * Gets configuration hooks. + * + * @return the configuration hooks + */ + @Nullable + public static ConfigurationHooks configurationHooks() { + return configurationHooks; + } + + /** + * Gets configuration hooks. + * + * @return the configuration hooks + */ + public static Optional configurationHooksNullable() { + return Optional.ofNullable(configurationHooks); + } + + /** + * Gets telemetry hooks. + * + * @return the telemetry hooks + */ + @Nullable + public static TelemetryHooks telemetryHooks() { + return telemetryHooks; + } + + /** + * Gets telemetry hooks. + * + * @return the telemetry hooks + */ + public static Optional telemetryHooksNullable() { + return Optional.ofNullable(telemetryHooks); + } +} diff --git a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/hook/TelemetryHooks.java b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/hook/TelemetryHooks.java new file mode 100644 index 0000000..b48fbf9 --- /dev/null +++ b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/hook/TelemetryHooks.java @@ -0,0 +1,64 @@ +/* + * 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. + */ +package group.rxcloud.capa.infrastructure.hook; + +import group.rxcloud.cloudruntimes.domain.enhanced.TelemetryRuntimes; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.propagation.ContextPropagators; +import reactor.core.publisher.Mono; + +/** + * The Mixer telemetry hooks. + */ +public interface TelemetryHooks extends TelemetryRuntimes { + + @Override + default Mono buildTracer(String tracerName) { + throw new UnsupportedOperationException("If you want to use this operate, please impl this."); + } + + @Override + default Mono buildTracer(String tracerName, String version) { + throw new UnsupportedOperationException("If you want to use this operate, please impl this."); + } + + @Override + default Mono buildTracer(String tracerName, String version, String schemaUrl) { + throw new UnsupportedOperationException("If you want to use this operate, please impl this."); + } + + @Override + default Mono getContextPropagators() { + throw new UnsupportedOperationException("If you want to use this operate, please impl this."); + } + + @Override + default Mono buildMeter(String meterName) { + throw new UnsupportedOperationException("If you want to use this operate, please impl this."); + } + + @Override + default Mono buildMeter(String meterName, String version) { + throw new UnsupportedOperationException("If you want to use this operate, please impl this."); + } + + @Override + default Mono buildMeter(String meterName, String version, String schemaUrl) { + throw new UnsupportedOperationException("If you want to use this operate, please impl this."); + } +} diff --git a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/hook/package-info.java b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/hook/package-info.java new file mode 100644 index 0000000..1aba000 --- /dev/null +++ b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/hook/package-info.java @@ -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. + */ +/** + * Hooks design: + * TODO + */ +package group.rxcloud.capa.infrastructure.hook; diff --git a/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/utils/SpiUtils.java b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/utils/SpiUtils.java new file mode 100644 index 0000000..89b02ac --- /dev/null +++ b/sdk-infrastructure/src/main/java/group/rxcloud/capa/infrastructure/utils/SpiUtils.java @@ -0,0 +1,165 @@ +/* + * 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. + */ + +package group.rxcloud.capa.infrastructure.utils; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import group.rxcloud.capa.infrastructure.CapaProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Load class and create instance from config file. + */ +public final class SpiUtils { + + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .setSerializationInclusion(JsonInclude.Include.NON_NULL); + + private static final Map CACHE = new ConcurrentHashMap<>(); + + private static final Logger log = LoggerFactory.getLogger(SpiUtils.class); + + private SpiUtils() { + } + + public static T loadConfigNullable(String path, Class configType) { + try (InputStream in = configType.getResourceAsStream(path)) { + if (in != null) { + InputStreamReader inputStreamReader = new InputStreamReader(in, StandardCharsets.UTF_8); + return OBJECT_MAPPER.readValue(inputStreamReader, configType); + } else { + log.warn(path + " file not found."); + } + } catch (IOException e) { + log.warn(path + " config file not found.", e); + } + return null; + } + + public static Properties loadPropertiesNullable(String path) { + try (InputStream in = SpiUtils.class.getResourceAsStream(path)) { + if (in != null) { + InputStreamReader inputStreamReader = new InputStreamReader(in, StandardCharsets.UTF_8); + Properties properties = new Properties(); + properties.load(inputStreamReader); + return properties; + } else { + log.warn(path + " file not found."); + } + } catch (IOException e) { + log.warn(path + " file not found.", e); + } + return null; + } + + public static Properties loadProperties(String path) { + try (InputStream in = SpiUtils.class.getResourceAsStream(path)) { + if (in != null) { + InputStreamReader inputStreamReader = new InputStreamReader(in, StandardCharsets.UTF_8); + Properties properties = new Properties(); + properties.load(inputStreamReader); + return properties; + } else { + throw new IllegalArgumentException(path + " file not found."); + } + } catch (IOException e) { + throw new IllegalArgumentException(path + " file not found.", e); + } + } + + @Nullable + public static T loadFromSpiComponentFileNullable(Class type, String fileSuffix) { + return loadFromSpiComponentFileNullable(type, null, null, fileSuffix, false); + } + + @Nullable + public static T loadFromSpiComponentFileNullable(Class type, Class[] argTypes, Object[] args, + String fileSuffix, boolean cache) { + try { + Properties properties = CapaProperties.COMPONENT_PROPERTIES_SUPPLIER.apply(fileSuffix); + String path = properties.getProperty(type.getName()); + if (path != null) { + return doNewInstance(path, type, argTypes, args, cache); + } + return null; + } catch (Throwable e) { + log.warn("Fail to load " + type.getName() + " instance from spi config file.", e); + } + return null; + } + + @Nullable + public static T newInstanceWithConstructorCache(String path, Class type) { + return newInstance(path, type, null, null, true); + } + + @Nullable + public static T newInstance(String path, Class type, Class[] argTypes, Object[] args, boolean cache) { + if (path == null) { + return null; + } + return doNewInstance(path, type, argTypes, args, cache); + } + + private static String keyOf(String path, Class type, Class[] argTypes) { + StringBuilder builder = new StringBuilder(type.getName()).append('=').append(path); + if (argTypes != null) { + for (Class arg : argTypes) { + builder.append('_').append(arg.getName()); + } + } + return builder.toString(); + } + + @Nonnull + private static T doNewInstance(String path, Class type, Class[] argTypes, Object[] args, boolean cache) { + String key = keyOf(path, type, argTypes); + Constructor targetCons = cache + ? CACHE.computeIfAbsent(key, k -> findConstructor(path, type, argTypes)) + : findConstructor(path, type, argTypes); + try { + return targetCons.getParameterCount() == 0 ? targetCons.newInstance() : targetCons.newInstance(args); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new IllegalArgumentException("Fail to create component. targetType = " + type.getName(), e); + } + } + + private static Constructor findConstructor(String path, Class type, Class[] argTypes) { + try { + Class aClass = path == null ? type : (Class) Class.forName(path); + return aClass.getConstructor(argTypes); + } catch (ClassNotFoundException | NoSuchMethodException e) { + throw new IllegalArgumentException("Fail to find the constructor. path = " + path, e); + } + } +} diff --git a/sdk-infrastructure/src/main/resources/sample/capa-infrastructure-mixer.properties b/sdk-infrastructure/src/main/resources/sample/capa-infrastructure-mixer.properties new file mode 100644 index 0000000..105ef32 --- /dev/null +++ b/sdk-infrastructure/src/main/resources/sample/capa-infrastructure-mixer.properties @@ -0,0 +1 @@ +# optional \ No newline at end of file diff --git a/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/MyImpl.java b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/MyImpl.java new file mode 100644 index 0000000..1791222 --- /dev/null +++ b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/MyImpl.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package group.rxcloud.capa.infrastructure.utils; + +public class MyImpl implements MyInterface{ + +} diff --git a/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/MyImplWithArgs.java b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/MyImplWithArgs.java new file mode 100644 index 0000000..5232dca --- /dev/null +++ b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/MyImplWithArgs.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package group.rxcloud.capa.infrastructure.utils; + +public class MyImplWithArgs implements MyInterfaceWithArgs{ + + private MyImplWithArgs(Integer a) { + + } + public MyImplWithArgs(String a) { + + } + public MyImplWithArgs(Integer a, String b) { + + } + + public MyImplWithArgs(boolean a, short b, int c, long d, float e, double f, byte g, char h, String i) { + + } +} diff --git a/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/MyInterface.java b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/MyInterface.java new file mode 100644 index 0000000..70fb329 --- /dev/null +++ b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/MyInterface.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package group.rxcloud.capa.infrastructure.utils; + +public interface MyInterface { + +} diff --git a/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/MyInterfaceWithArgs.java b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/MyInterfaceWithArgs.java new file mode 100644 index 0000000..fe69c4c --- /dev/null +++ b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/MyInterfaceWithArgs.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package group.rxcloud.capa.infrastructure.utils; + +public interface MyInterfaceWithArgs { + +} diff --git a/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/SpiUtilsTest.java b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/SpiUtilsTest.java new file mode 100644 index 0000000..ddefc30 --- /dev/null +++ b/sdk-infrastructure/src/test/java/group/rxcloud/capa/infrastructure/utils/SpiUtilsTest.java @@ -0,0 +1,144 @@ +/* + * 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. + */ +package group.rxcloud.capa.infrastructure.utils; + +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Properties; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class SpiUtilsTest { + + @Test + public void loadConfigNullable() { + Config config = SpiUtils.loadConfigNullable("/config.json", Config.class); + assertEquals("aaa", config.str); + assertEquals(2, config.getList().size()); + assertEquals("zzz", config.getList().get(0)); + + assertNull(SpiUtils.loadConfigNullable("aaa", Config.class)); + assertNull(SpiUtils.loadConfigNullable("/config.json", Integer.class)); + } + + @Test + public void loadPropertiesNullable() { + Properties properties = SpiUtils.loadPropertiesNullable("/config.properties"); + assertEquals("aaa", properties.getProperty("str")); + + assertNull(SpiUtils.loadPropertiesNullable("lalala")); + } + + @Test + public void loadProperties() { + Properties properties = SpiUtils.loadProperties("/config.properties"); + assertEquals("aaa", properties.getProperty("str")); + } + + @Test + public void loadPropertiesFail() { + Throwable t = null; + try { + Properties properties = SpiUtils.loadProperties("aaaa"); + } catch (Throwable throwable) { + t = throwable; + } + assertNotNull(t); + } + @Test + public void loadFromSpiComponentFileNullable() { + MyInterface myInterface = SpiUtils.loadFromSpiComponentFileNullable(MyInterface.class, "test"); + assertTrue(myInterface instanceof MyImpl); + } + + @Test + public void loadFromSpiComponentFileNullable2() { + MyInterfaceWithArgs myInterfaceWithArgs = SpiUtils.loadFromSpiComponentFileNullable(MyInterfaceWithArgs.class, new Class[] {boolean.class, short.class, int.class, long.class, float.class, double.class, byte.class, char.class, String.class}, new Object[] {true, (short)1, 2, 3L, 4.0f, 5.0, (byte)0x1, 'x', "a"}, "test", true); + + assertTrue(myInterfaceWithArgs instanceof MyImplWithArgs); + + + } + + @Test + public void loadFromSpiComponentFileNullable2Fail() { + MyInterfaceWithArgs myInterfaceWithArgs = SpiUtils.loadFromSpiComponentFileNullable(MyInterfaceWithArgs.class, "test"); + assertNull(myInterfaceWithArgs); + + + assertNull(SpiUtils.loadFromSpiComponentFileNullable(MyImplWithArgs.class, new Class[] {String.class}, new Object[] {"a"}, "test", true)); + + assertNull(SpiUtils.loadFromSpiComponentFileNullable(MyInterfaceWithArgs.class, new Class[] {Long.class}, new Object[] {1L}, "test", false)); + + assertNull(SpiUtils.loadFromSpiComponentFileNullable(MyInterfaceWithArgs.class, new Class[] {Integer.class}, new Object[] {1}, "test", false)); + + assertNull(SpiUtils.loadFromSpiComponentFileNullable(MyInterfaceWithArgs.class, new Class[] {boolean.class, short.class, int.class, long.class, float.class, double.class, byte.class, char.class, String.class}, new Object[] {true, (short)1, 2, 3L, 4.0f, 5.0, null, 'x', "a"}, "test", true)); + + + } + + @Test + public void newInstance() { + assertNull(SpiUtils.newInstance(null, Config.class, null, null, false)); + + MyImpl my = SpiUtils.newInstanceWithConstructorCache(MyImpl.class.getCanonicalName(), MyImpl.class); + assertNotNull(my); + + MyImplWithArgs myImplWithArgs = SpiUtils.newInstance(MyImplWithArgs.class.getCanonicalName(),MyImplWithArgs.class, new Class[] {String.class}, new Object[] {"a"}, false); + assertNotNull(myImplWithArgs); + } + + @Test + public void newInstanceFail() { + Throwable t = null; + try { + Config my = SpiUtils.newInstanceWithConstructorCache(Config.class.getCanonicalName(), Config.class); + } catch (Throwable throwable) { + t = throwable; + } + assertNotNull(t); + } + + static class Config { + + private String str; + + private List list; + + public String getStr() { + return str; + } + + public Config setStr(String str) { + this.str = str; + return this; + } + + public List getList() { + return list; + } + + public Config setList(List list) { + this.list = list; + return this; + } + } +} \ No newline at end of file diff --git a/sdk-infrastructure/src/test/resources/capa-component-test.properties b/sdk-infrastructure/src/test/resources/capa-component-test.properties new file mode 100644 index 0000000..dafd0e8 --- /dev/null +++ b/sdk-infrastructure/src/test/resources/capa-component-test.properties @@ -0,0 +1,2 @@ +group.rxcloud.capa.infrastructure.utils.MyInterface=group.rxcloud.capa.infrastructure.utils.MyImpl +group.rxcloud.capa.infrastructure.utils.MyInterfaceWithArgs=group.rxcloud.capa.infrastructure.utils.MyImplWithArgs \ No newline at end of file diff --git a/sdk-infrastructure/src/test/resources/config.json b/sdk-infrastructure/src/test/resources/config.json new file mode 100644 index 0000000..0de38f1 --- /dev/null +++ b/sdk-infrastructure/src/test/resources/config.json @@ -0,0 +1,4 @@ +{ + "str": "aaa", + "list": ["zzz", "yyy"] +} \ No newline at end of file diff --git a/sdk-infrastructure/src/test/resources/config.properties b/sdk-infrastructure/src/test/resources/config.properties new file mode 100644 index 0000000..2b9c2c9 --- /dev/null +++ b/sdk-infrastructure/src/test/resources/config.properties @@ -0,0 +1 @@ +str=aaa \ No newline at end of file diff --git a/sdk-spi-demo/pom.xml b/sdk-spi-demo/pom.xml index 1081e97..4256367 100644 --- a/sdk-spi-demo/pom.xml +++ b/sdk-spi-demo/pom.xml @@ -23,13 +23,18 @@ capa-parent group.rxcloud - 1.0.6.RELEASE + 1.0.7.RELEASE capa-sdk-spi-demo jar capa-sdk-spi-demo + + 2.8.2 + 1.1.7 + + @@ -37,6 +42,37 @@ capa-sdk-spi + + + org.slf4j + slf4j-api + + + + + ch.qos.logback + logback-classic + ${logback.version} + + true + + + ch.qos.logback + logback-core + ${logback.version} + + + + org.apache.logging.log4j + log4j-core + ${log4j.version} + + + org.apache.logging.log4j + log4j-api + ${log4j.version} + + org.junit.jupiter diff --git a/sdk-spi-demo/src/main/java/group/rxcloud/capa/spi/demo/http/DemoCapaHttp.java b/sdk-spi-demo/src/main/java/group/rxcloud/capa/spi/demo/http/DemoCapaHttp.java index 921ac11..0f93d72 100644 --- a/sdk-spi-demo/src/main/java/group/rxcloud/capa/spi/demo/http/DemoCapaHttp.java +++ b/sdk-spi-demo/src/main/java/group/rxcloud/capa/spi/demo/http/DemoCapaHttp.java @@ -18,14 +18,15 @@ import group.rxcloud.capa.component.http.HttpResponse; import group.rxcloud.capa.infrastructure.serializer.CapaObjectSerializer; -import group.rxcloud.capa.spi.http.config.RpcServiceOptions; import group.rxcloud.capa.spi.demo.http.config.DemoRpcServiceOptions; import group.rxcloud.capa.spi.http.CapaSerializeHttpSpi; +import group.rxcloud.capa.spi.http.config.RpcServiceOptions; import group.rxcloud.cloudruntimes.utils.TypeRef; import okhttp3.OkHttpClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -47,12 +48,15 @@ public DemoCapaHttp(OkHttpClient httpClient, CapaObjectSerializer objectSerializ } @Override - protected CompletableFuture> invokeSpiApi(String appId, - String method, - Object requestData, - Map headers, - TypeRef type, - RpcServiceOptions rpcServiceOptions) { + protected CompletableFuture> invokeSpiApi( + String appId, + String method, + Object requestData, + String httpMethod, + Map headers, + Map> urlParameters, + TypeRef type, + RpcServiceOptions rpcServiceOptions) { DemoRpcServiceOptions demoRpcServiceOptions = (DemoRpcServiceOptions) rpcServiceOptions; logger.info("[DemoCapaHttp.invokeSpiApi] rpcServiceOptions[{}]", demoRpcServiceOptions); diff --git a/sdk-spi-demo/src/main/java/group/rxcloud/capa/spi/demo/log/DemoLog4jAppender.java b/sdk-spi-demo/src/main/java/group/rxcloud/capa/spi/demo/log/DemoLog4jAppender.java new file mode 100644 index 0000000..ccf07cc --- /dev/null +++ b/sdk-spi-demo/src/main/java/group/rxcloud/capa/spi/demo/log/DemoLog4jAppender.java @@ -0,0 +1,28 @@ +/* + * 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. + */ +package group.rxcloud.capa.spi.demo.log; + +import group.rxcloud.capa.component.log.agent.CapaLog4jAppenderAgent; +import org.apache.logging.log4j.core.LogEvent; + +public class DemoLog4jAppender implements CapaLog4jAppenderAgent.CapaLog4jAppender { + + @Override + public void appendLog(LogEvent event) { + System.out.println("test log log4j and content is " + event.getMessage().getFormattedMessage()); + } +} diff --git a/sdk-spi-demo/src/main/java/group/rxcloud/capa/spi/demo/log/DemoLogbackAppender.java b/sdk-spi-demo/src/main/java/group/rxcloud/capa/spi/demo/log/DemoLogbackAppender.java new file mode 100644 index 0000000..c6029cd --- /dev/null +++ b/sdk-spi-demo/src/main/java/group/rxcloud/capa/spi/demo/log/DemoLogbackAppender.java @@ -0,0 +1,31 @@ +/* + * 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. + */ +package group.rxcloud.capa.spi.demo.log; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import group.rxcloud.capa.component.log.agent.CapaLogbackAppenderAgent; + +public class DemoLogbackAppender implements CapaLogbackAppenderAgent.CapaLogbackAppender { + + public DemoLogbackAppender() { + } + + @Override + public void appendLog(ILoggingEvent event) { + System.out.println("test logback log and content is " + event.getFormattedMessage()); + } +} diff --git a/sdk-spi-demo/src/main/resources/capa-component-log.properties b/sdk-spi-demo/src/main/resources/capa-component-log.properties new file mode 100644 index 0000000..2b10f8d --- /dev/null +++ b/sdk-spi-demo/src/main/resources/capa-component-log.properties @@ -0,0 +1,2 @@ +group.rxcloud.capa.component.log.agent.CapaLog4jAppenderAgent$CapaLog4jAppender=group.rxcloud.capa.spi.demo.log.DemoLog4jAppender +group.rxcloud.capa.component.log.agent.CapaLogbackAppenderAgent$CapaLogbackAppender=group.rxcloud.capa.spi.demo.log.DemoLogbackAppender \ No newline at end of file diff --git a/sdk-spi/pom.xml b/sdk-spi/pom.xml index 78521df..dc3077f 100644 --- a/sdk-spi/pom.xml +++ b/sdk-spi/pom.xml @@ -23,7 +23,7 @@ capa-parent group.rxcloud - 1.0.6.RELEASE + 1.0.7.RELEASE capa-sdk-spi diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/http/CapaHttpSpi.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/http/CapaHttpSpi.java index f0d07c3..711b514 100644 --- a/sdk-spi/src/main/java/group/rxcloud/capa/spi/http/CapaHttpSpi.java +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/http/CapaHttpSpi.java @@ -22,7 +22,6 @@ import group.rxcloud.capa.spi.http.config.CapaSpiOptionsLoader; import group.rxcloud.capa.spi.http.config.CapaSpiProperties; import group.rxcloud.capa.spi.http.config.RpcServiceOptions; -import group.rxcloud.cloudruntimes.domain.core.invocation.HttpExtension; import group.rxcloud.cloudruntimes.utils.TypeRef; import okhttp3.OkHttpClient; import org.slf4j.Logger; @@ -41,15 +40,18 @@ public abstract class CapaHttpSpi extends CapaHttp { private static final Logger logger = LoggerFactory.getLogger(CapaHttpSpi.class); + /** + * Instantiates a new Capa http spi. + * + * @param httpClient the http client + * @param objectSerializer the object serializer + */ public CapaHttpSpi(OkHttpClient httpClient, CapaObjectSerializer objectSerializer) { super(httpClient, objectSerializer); } /** * Templates, delegate to specific http invoker. - * - * @param httpMethod Ignore, fix to POST. FIXME - * @param urlParameters Ignore, fix to EMPTY. FIXME */ @Override protected CompletableFuture> doInvokeApi(String httpMethod, @@ -73,22 +75,6 @@ protected CompletableFuture> doInvokeApi(String httpMethod, logger.debug("[CapaHttpSpi] invoke rpc context[{}]", context); } } - // FIXME Ignore, fix to POST. - if (!HttpExtension.POST.getMethod().toString().equalsIgnoreCase(httpMethod)) { - if (logger.isWarnEnabled()) { - logger.warn("[CapaHttpSpi] invoke rpc httpMethod[{}] only support POST now.", - httpMethod); - } - httpMethod = HttpExtension.POST.getMethod().toString(); - } - // FIXME Ignore, fix to EMPTY. - if (urlParameters != null && !urlParameters.isEmpty()) { - if (logger.isWarnEnabled()) { - logger.warn("[CapaHttpSpi] invoke rpc urlParameters[{}] not supported now.", - urlParameters); - } - urlParameters = null; - } // parse url path segments Objects.requireNonNull(pathSegments, "pathSegments"); @@ -112,7 +98,7 @@ protected CompletableFuture> doInvokeApi(String httpMethod, // spi invoke CompletableFuture> invokeSpiApi = - invokeSpiApi(appId, method, requestData, headers, type, rpcServiceOptions); + invokeSpiApi(appId, method, requestData, httpMethod, headers, urlParameters, type, rpcServiceOptions); invokeSpiApi.whenComplete((tHttpResponse, throwable) -> { if (throwable != null) { if (logger.isWarnEnabled()) { @@ -141,6 +127,9 @@ protected CompletableFuture> doInvokeApi(String httpMethod, /** * Override to get the configuration of the corresponding appId. + * + * @param appId the app id + * @return the rpc service options */ protected RpcServiceOptions getRpcServiceOptions(String appId) { CapaSpiOptionsLoader capaSpiOptionsLoader = CapaSpiProperties.getSpiOptionsLoader(); @@ -154,15 +143,20 @@ protected RpcServiceOptions getRpcServiceOptions(String appId) { * @param appId the app id * @param method the invoke method * @param requestData the request data + * @param httpMethod the http method * @param headers the headers + * @param urlParameters the url parameters * @param type the response type * @param rpcServiceOptions the rpc service options * @return the async completable future */ - protected abstract CompletableFuture> invokeSpiApi(String appId, - String method, - Object requestData, - Map headers, - TypeRef type, - RpcServiceOptions rpcServiceOptions); + protected abstract CompletableFuture> invokeSpiApi( + String appId, + String method, + Object requestData, + String httpMethod, + Map headers, + Map> urlParameters, + TypeRef type, + RpcServiceOptions rpcServiceOptions); } diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaContextAsyncWrapperSpi.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaContextAsyncWrapperSpi.java new file mode 100644 index 0000000..8062b67 --- /dev/null +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaContextAsyncWrapperSpi.java @@ -0,0 +1,26 @@ +/* + * 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. + */ +package group.rxcloud.capa.spi.telemetry; + +import group.rxcloud.capa.component.telemetry.context.CapaContextAsyncWrapper; + +/** + * SPI Capa context async wrapper. + */ +public abstract class CapaContextAsyncWrapperSpi implements CapaContextAsyncWrapper { + +} diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaReadWriteSpanSpi.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaReadWriteSpanSpi.java new file mode 100644 index 0000000..a317306 --- /dev/null +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaReadWriteSpanSpi.java @@ -0,0 +1,31 @@ +/* + * 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. + */ +package group.rxcloud.capa.spi.telemetry; + +import group.rxcloud.capa.component.telemetry.trace.CapaReadWriteSpan; +import io.opentelemetry.sdk.trace.ReadWriteSpan; + +/** + * SPI Capa read write span. + */ +public abstract class CapaReadWriteSpanSpi extends CapaReadWriteSpan { + + public CapaReadWriteSpanSpi(String tracerName, String version, String schemaUrl, + ReadWriteSpan span) { + super(tracerName, version, schemaUrl, span); + } +} diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaSpanBuilderSpi.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaSpanBuilderSpi.java new file mode 100644 index 0000000..f9c3686 --- /dev/null +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaSpanBuilderSpi.java @@ -0,0 +1,31 @@ +/* + * 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. + */ +package group.rxcloud.capa.spi.telemetry; + +import group.rxcloud.capa.component.telemetry.trace.CapaSpanBuilder; +import io.opentelemetry.api.trace.SpanBuilder; + +/** + * SPI Capa span builder. + */ +public abstract class CapaSpanBuilderSpi extends CapaSpanBuilder { + + public CapaSpanBuilderSpi(String tracerName, String version, String schemaUrl, String spanName, + SpanBuilder spanBuilder) { + super(tracerName, version, schemaUrl, spanName, spanBuilder); + } +} diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaTracerBuilderSpi.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaTracerBuilderSpi.java new file mode 100644 index 0000000..3599480 --- /dev/null +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaTracerBuilderSpi.java @@ -0,0 +1,30 @@ +/* + * 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. + */ +package group.rxcloud.capa.spi.telemetry; + +import group.rxcloud.capa.component.telemetry.trace.CapaTracerBuilder; +import io.opentelemetry.api.trace.TracerBuilder; + +/** + * SPI Capa tracer builder. + */ +public abstract class CapaTracerBuilderSpi extends CapaTracerBuilder { + + public CapaTracerBuilderSpi(String tracerName, TracerBuilder builder) { + super(tracerName, builder); + } +} diff --git a/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaTracerSpi.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaTracerSpi.java new file mode 100644 index 0000000..53239a5 --- /dev/null +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/CapaTracerSpi.java @@ -0,0 +1,30 @@ +/* + * 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. + */ +package group.rxcloud.capa.spi.telemetry; + +import group.rxcloud.capa.component.telemetry.trace.CapaTracer; +import io.opentelemetry.api.trace.Tracer; + +/** + * SPI Capa tracer. + */ +public abstract class CapaTracerSpi extends CapaTracer { + + public CapaTracerSpi(String tracerName, String version, String schemaUrl, Tracer tracer) { + super(tracerName, version, schemaUrl, tracer); + } +} diff --git a/sdk/src/main/java/group/rxcloud/capa/metrics/CapaMetricsClient.java b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/ContextPropagatorLoaderSpi.java similarity index 70% rename from sdk/src/main/java/group/rxcloud/capa/metrics/CapaMetricsClient.java rename to sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/ContextPropagatorLoaderSpi.java index c062ab3..148165d 100644 --- a/sdk/src/main/java/group/rxcloud/capa/metrics/CapaMetricsClient.java +++ b/sdk-spi/src/main/java/group/rxcloud/capa/spi/telemetry/ContextPropagatorLoaderSpi.java @@ -14,18 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package group.rxcloud.capa.metrics; +package group.rxcloud.capa.spi.telemetry; -import group.rxcloud.cloudruntimes.client.DefaultCloudRuntimesClient; -import reactor.core.publisher.Mono; +import group.rxcloud.capa.component.telemetry.context.ContextPropagatorLoader; -public interface CapaMetricsClient extends DefaultCloudRuntimesClient { - @Override - default Mono shutdown() { - return Mono.empty(); - } +/** + * SPI context propagator loader. + */ +public abstract class ContextPropagatorLoaderSpi implements ContextPropagatorLoader { - @Override - void close(); } diff --git a/sdk-spi/src/test/java/group/rxcloud/capa/spi/configstore/CapaConfigStoreSpiTest.java b/sdk-spi/src/test/java/group/rxcloud/capa/spi/configstore/CapaConfigStoreSpiTest.java index c32c34a..b747a87 100644 --- a/sdk-spi/src/test/java/group/rxcloud/capa/spi/configstore/CapaConfigStoreSpiTest.java +++ b/sdk-spi/src/test/java/group/rxcloud/capa/spi/configstore/CapaConfigStoreSpiTest.java @@ -67,15 +67,15 @@ public void testSubscribe_Success() { Flux> subscribeFlux = configStoreSpiImpl.subscribe(constructSubscribeReq(), TypeRef.STRING); SubscribeResp resp = subscribeFlux.blockFirst(); Assertions.assertNotNull(resp); - Assertions.assertEquals("12345",resp.getAppId()); + Assertions.assertEquals("12345", resp.getAppId()); - Assertions.assertEquals(2,resp.getItems().size()); + Assertions.assertEquals(2, resp.getItems().size()); ConfigurationItem firstConfigurationItem = resp.getItems().get(0); - Assertions.assertEquals("testKey1",firstConfigurationItem.getKey()); + Assertions.assertEquals("testKey1", firstConfigurationItem.getKey()); Assertions.assertNull(firstConfigurationItem.getContent()); - Assertions.assertEquals("testGroup",firstConfigurationItem.getGroup()); - Assertions.assertEquals("testLabel",firstConfigurationItem.getLabel()); + Assertions.assertEquals("testGroup", firstConfigurationItem.getGroup()); + Assertions.assertEquals("testLabel", firstConfigurationItem.getLabel()); Assertions.assertNotNull(firstConfigurationItem.getLabel()); Assertions.assertEquals(2, firstConfigurationItem.getTags().size()); @@ -114,12 +114,12 @@ private GetRequest constructGetRequest() { return getRequest; } - private SubscribeReq constructSubscribeReq(){ + private SubscribeReq constructSubscribeReq() { SubscribeReq req = new SubscribeReq(); req.setAppId("12345"); req.setGroup("testGroup"); req.setLabel("testLabel"); - req.setKeys(Lists.newArrayList("testKey1","testKey2")); + req.setKeys(Lists.newArrayList("testKey1", "testKey2")); Map metaDataMap = new HashMap<>(); metaDataMap.put("cluster", "default"); diff --git a/sdk-spi/src/test/java/group/rxcloud/capa/spi/http/CapaSerializeHttpSpiTest.java b/sdk-spi/src/test/java/group/rxcloud/capa/spi/http/CapaSerializeHttpSpiTest.java index 351a9a4..b8dafe3 100644 --- a/sdk-spi/src/test/java/group/rxcloud/capa/spi/http/CapaSerializeHttpSpiTest.java +++ b/sdk-spi/src/test/java/group/rxcloud/capa/spi/http/CapaSerializeHttpSpiTest.java @@ -1,301 +1,311 @@ -/* - * 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. - */ -package group.rxcloud.capa.spi.http; - -import group.rxcloud.capa.component.http.CapaHttp; -import group.rxcloud.capa.component.http.HttpResponse; -import group.rxcloud.capa.infrastructure.exceptions.CapaException; -import group.rxcloud.capa.infrastructure.serializer.CapaObjectSerializer; -import group.rxcloud.capa.infrastructure.serializer.DefaultObjectSerializer; -import group.rxcloud.capa.infrastructure.serializer.ObjectSerializer; -import group.rxcloud.capa.spi.http.config.RpcServiceOptions; -import group.rxcloud.cloudruntimes.utils.TypeRef; -import okhttp3.*; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import reactor.util.context.Context; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -public class CapaSerializeHttpSpiTest { - - private OkHttpClient okHttpClient; - - private TestCapaSerializeHttpSpi capaSerializeHttpSpi; - - private CapaObjectSerializer defaultObjectSerializer; - - @BeforeEach - public void setUp() { - okHttpClient = new OkHttpClient.Builder().build(); - defaultObjectSerializer = new DefaultObjectSerializer(); - capaSerializeHttpSpi = new TestCapaSerializeHttpSpi(okHttpClient, defaultObjectSerializer); - } - - @Test - public void testGetRequestWithSerialize_Success() throws IOException { - byte[] serializerRequest = capaSerializeHttpSpi.getRequestWithSerialize("Object"); - String request = defaultObjectSerializer.deserialize(serializerRequest, TypeRef.STRING); - - Assertions.assertEquals("Object", request); - } - - @Test - public void testGetRequestWithSerialize_FailWhenThrowException() { - capaSerializeHttpSpi = new TestCapaSerializeHttpSpi(okHttpClient, new TestIOExceptionObjectSerializer()); - Assertions.assertThrows(CapaException.class, () -> { - capaSerializeHttpSpi.getRequestWithSerialize("Object"); - }); - - capaSerializeHttpSpi = new TestCapaSerializeHttpSpi(okHttpClient, new TestRuntimeExceptionObjectSerializer()); - Assertions.assertThrows(CapaException.class, () -> { - capaSerializeHttpSpi.getRequestWithSerialize("Object"); - }); - } - - @Test - public void testGetRequestBodyWithSerialize_SuccessWhenHeaderHasValue() { - Map headers = new HashMap<>(); - headers.put("content-type", "application/json"); - - RequestBody requestBody = capaSerializeHttpSpi.getRequestBodyWithSerialize("Object", headers); - String type = requestBody.contentType().type(); - String subtype = requestBody.contentType().subtype(); - Assertions.assertEquals("application", type); - Assertions.assertEquals("json", subtype); - } - - @Test - public void testGetRequestBodyWithSerialize_SuccessWhenHeaderIsNull() { - RequestBody requestBody = capaSerializeHttpSpi.getRequestBodyWithSerialize(null, null); - String type = requestBody.contentType().type(); - String subtype = requestBody.contentType().subtype(); - Assertions.assertEquals("application", type); - Assertions.assertEquals("json", subtype); - } - - @Test - public void testGetRequestHeaderWithParams_SuccessWhenHeaderHasValue() { - Map headersParams = new HashMap<>(); - headersParams.put("key", "value"); - Headers requestHeaderWithParams = capaSerializeHttpSpi.getRequestHeaderWithParams(headersParams); - String value = requestHeaderWithParams.get("key"); - Assertions.assertEquals("value", value); - } - - @Test - public void testGetRequestHeaderWithParams_SuccessWhenHeaderIsNull() { - Headers requestHeaderWithParams = capaSerializeHttpSpi.getRequestHeaderWithParams(null); - String value = requestHeaderWithParams.get("key"); - Assertions.assertNull(value); - } - - @Test - public void testDoAsyncInvoke0_Success() { - Request request = new Request.Builder().url("https://www.url/").build(); - - CompletableFuture> responseFuture = capaSerializeHttpSpi.doAsyncInvoke0( - request, - TypeRef.STRING); - responseFuture.cancel(true); - } - - @Test - public void testGetResponseBodyWithDeserialize_Success() { - HttpResponse httpResponse = new HttpResponse<>(null, null, 200); - HttpResponse deserializeHttpResponse = capaSerializeHttpSpi.getResponseBodyWithDeserialize( - TypeRef.STRING, - httpResponse); - - int statusCode = deserializeHttpResponse.getStatusCode(); - Assertions.assertEquals(200, statusCode); - } - - @Test - public void testGetResponseBodyWithDeserialize_FailWhenThrowException() { - HttpResponse httpResponse = new HttpResponse<>(null, null, 200); - capaSerializeHttpSpi = new TestCapaSerializeHttpSpi(okHttpClient, new TestIOExceptionObjectSerializer()); - Assertions.assertThrows(CapaException.class, () -> { - capaSerializeHttpSpi.getResponseBodyWithDeserialize(TypeRef.STRING, httpResponse); - }); - - capaSerializeHttpSpi = new TestCapaSerializeHttpSpi(okHttpClient, new TestRuntimeExceptionObjectSerializer()); - Assertions.assertThrows(CapaException.class, () -> { - capaSerializeHttpSpi.getResponseBodyWithDeserialize(TypeRef.STRING, httpResponse); - }); - } - - @Test - public void testOnResponseInSerializationResponseFutureCallback_Success() throws IOException { - CompletableFuture> future = new CompletableFuture<>(); - CapaSerializeHttpSpi.SerializationResponseFutureCallback responseFutureCallback = - new CapaSerializeHttpSpi.SerializationResponseFutureCallback(future); - - Request request = new Request.Builder().url("https://www.url/").build(); - ResponseBody responseBody = ResponseBody.create(new byte[1], - MediaType.get("application/json; charset=utf-8")); - - Response response = new Response.Builder() - .request(request) - .protocol(Protocol.HTTP_1_1) - .message("message") - .code(200) - .build(); - responseFutureCallback.onResponse(null, response); - future.cancel(true); - - response = new Response.Builder() - .request(request) - .protocol(Protocol.HTTP_1_1) - .message("message") - .code(200) - .body(responseBody) - .build(); - responseFutureCallback.onResponse(null, response); - future.cancel(true); - } - - - @Test - public void testGetRpcServiceOptions_Success() { - RpcServiceOptions rpcServiceOptions = capaSerializeHttpSpi.getRpcServiceOptions("appId"); - String className = rpcServiceOptions.getClass().getName(); - Assertions.assertEquals("group.rxcloud.capa.spi.http.config.TestRpcServiceOptions", className); - } - - @Test - public void testDoInvokeApi_Success() throws ExecutionException, InterruptedException { - String[] pathSegments = new String[]{ - CapaHttp.API_VERSION, - "invoke", "appId", - "method", "method"}; - - Map> urlParameters = new HashMap<>(); - urlParameters.put("key", new ArrayList<>()); - - Map headers = new HashMap<>(); - headers.put("content-type", "application/json"); - - Context context = Context.of("content", "value"); - - CompletableFuture> responseCompletableFuture = capaSerializeHttpSpi.doInvokeApi( - "httpMethod", - pathSegments, - urlParameters, - "requestData", - headers, - context, - TypeRef.STRING); - - HttpResponse httpResponse = responseCompletableFuture.get(); - int statusCode = httpResponse.getStatusCode(); - Assertions.assertEquals(200, statusCode); - } - - /** - * serializer/deserializer for request/response objects used in tests only - */ - private class TestRuntimeExceptionObjectSerializer extends ObjectSerializer implements CapaObjectSerializer { - - /** - * {@inheritDoc} - */ - @Override - public byte[] serialize(Object o) { - throw new RuntimeException("test serialize exception"); - } - - /** - * {@inheritDoc} - */ - @Override - public T deserialize(byte[] data, TypeRef type) { - throw new RuntimeException("test deserialize exception"); - } - - /** - * {@inheritDoc} - */ - @Override - public String getContentType() { - return ""; - } - } - - - /** - * serializer/deserializer for request/response objects used in tests only - */ - private class TestIOExceptionObjectSerializer extends ObjectSerializer implements CapaObjectSerializer { - - /** - * {@inheritDoc} - */ - @Override - public byte[] serialize(Object o) throws IOException { - throw new IOException("test serialize ioexception"); - } - - /** - * {@inheritDoc} - */ - @Override - public T deserialize(byte[] data, TypeRef type) throws IOException { - throw new IOException("test deserialize ioexception"); - } - - /** - * {@inheritDoc} - */ - @Override - public String getContentType() { - return ""; - } - } - - - /** - * The test capa http invoker. - */ - private class TestCapaSerializeHttpSpi extends CapaSerializeHttpSpi { - - public TestCapaSerializeHttpSpi(OkHttpClient httpClient, CapaObjectSerializer objectSerializer) { - super(httpClient, objectSerializer); - } - - @Override - protected CompletableFuture> invokeSpiApi(String appId, - String method, - Object requestData, - Map headers, - TypeRef type, - RpcServiceOptions rpcServiceOptions) { - return CompletableFuture.supplyAsync( - () -> { - return new HttpResponse<>(null, null, 200); - }, - Runnable::run); - } - } -} +/* + * 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. + */ +package group.rxcloud.capa.spi.http; + +import group.rxcloud.capa.component.http.CapaHttp; +import group.rxcloud.capa.component.http.HttpResponse; +import group.rxcloud.capa.infrastructure.exceptions.CapaException; +import group.rxcloud.capa.infrastructure.serializer.CapaObjectSerializer; +import group.rxcloud.capa.infrastructure.serializer.DefaultObjectSerializer; +import group.rxcloud.capa.infrastructure.serializer.ObjectSerializer; +import group.rxcloud.capa.spi.http.config.RpcServiceOptions; +import group.rxcloud.cloudruntimes.utils.TypeRef; +import okhttp3.Headers; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import reactor.util.context.Context; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +public class CapaSerializeHttpSpiTest { + + private OkHttpClient okHttpClient; + + private TestCapaSerializeHttpSpi capaSerializeHttpSpi; + + private CapaObjectSerializer defaultObjectSerializer; + + @BeforeEach + public void setUp() { + okHttpClient = new OkHttpClient.Builder().build(); + defaultObjectSerializer = new DefaultObjectSerializer(); + capaSerializeHttpSpi = new TestCapaSerializeHttpSpi(okHttpClient, defaultObjectSerializer); + } + + @Test + public void testGetRequestWithSerialize_Success() throws IOException { + byte[] serializerRequest = capaSerializeHttpSpi.getRequestWithSerialize("Object"); + String request = defaultObjectSerializer.deserialize(serializerRequest, TypeRef.STRING); + + Assertions.assertEquals("Object", request); + } + + @Test + public void testGetRequestWithSerialize_FailWhenThrowException() { + capaSerializeHttpSpi = new TestCapaSerializeHttpSpi(okHttpClient, new TestIOExceptionObjectSerializer()); + Assertions.assertThrows(CapaException.class, () -> { + capaSerializeHttpSpi.getRequestWithSerialize("Object"); + }); + + capaSerializeHttpSpi = new TestCapaSerializeHttpSpi(okHttpClient, new TestRuntimeExceptionObjectSerializer()); + Assertions.assertThrows(CapaException.class, () -> { + capaSerializeHttpSpi.getRequestWithSerialize("Object"); + }); + } + + @Test + public void testGetRequestBodyWithSerialize_SuccessWhenHeaderHasValue() { + Map headers = new HashMap<>(); + headers.put("content-type", "application/json"); + + RequestBody requestBody = capaSerializeHttpSpi.getRequestBodyWithSerialize("Object", headers); + String type = requestBody.contentType().type(); + String subtype = requestBody.contentType().subtype(); + Assertions.assertEquals("application", type); + Assertions.assertEquals("json", subtype); + } + + @Test + public void testGetRequestBodyWithSerialize_SuccessWhenHeaderIsNull() { + RequestBody requestBody = capaSerializeHttpSpi.getRequestBodyWithSerialize(null, null); + String type = requestBody.contentType().type(); + String subtype = requestBody.contentType().subtype(); + Assertions.assertEquals("application", type); + Assertions.assertEquals("json", subtype); + } + + @Test + public void testGetRequestHeaderWithParams_SuccessWhenHeaderHasValue() { + Map headersParams = new HashMap<>(); + headersParams.put("key", "value"); + Headers requestHeaderWithParams = capaSerializeHttpSpi.getRequestHeaderWithParams(headersParams); + String value = requestHeaderWithParams.get("key"); + Assertions.assertEquals("value", value); + } + + @Test + public void testGetRequestHeaderWithParams_SuccessWhenHeaderIsNull() { + Headers requestHeaderWithParams = capaSerializeHttpSpi.getRequestHeaderWithParams(null); + String value = requestHeaderWithParams.get("key"); + Assertions.assertNull(value); + } + + @Test + public void testDoAsyncInvoke0_Success() { + Request request = new Request.Builder().url("https://www.url/").build(); + + CompletableFuture> responseFuture = capaSerializeHttpSpi.doAsyncInvoke0( + request, + TypeRef.STRING); + responseFuture.cancel(true); + } + + @Test + public void testGetResponseBodyWithDeserialize_Success() { + HttpResponse httpResponse = new HttpResponse<>(null, null, 200); + HttpResponse deserializeHttpResponse = capaSerializeHttpSpi.getResponseBodyWithDeserialize( + TypeRef.STRING, + httpResponse); + + int statusCode = deserializeHttpResponse.getStatusCode(); + Assertions.assertEquals(200, statusCode); + } + + @Test + public void testGetResponseBodyWithDeserialize_FailWhenThrowException() { + HttpResponse httpResponse = new HttpResponse<>(null, null, 200); + capaSerializeHttpSpi = new TestCapaSerializeHttpSpi(okHttpClient, new TestIOExceptionObjectSerializer()); + Assertions.assertThrows(CapaException.class, () -> { + capaSerializeHttpSpi.getResponseBodyWithDeserialize(TypeRef.STRING, httpResponse); + }); + + capaSerializeHttpSpi = new TestCapaSerializeHttpSpi(okHttpClient, new TestRuntimeExceptionObjectSerializer()); + Assertions.assertThrows(CapaException.class, () -> { + capaSerializeHttpSpi.getResponseBodyWithDeserialize(TypeRef.STRING, httpResponse); + }); + } + + @Test + public void testOnResponseInSerializationResponseFutureCallback_Success() throws IOException { + CompletableFuture> future = new CompletableFuture<>(); + CapaSerializeHttpSpi.SerializationResponseFutureCallback responseFutureCallback = + new CapaSerializeHttpSpi.SerializationResponseFutureCallback(future); + + Request request = new Request.Builder().url("https://www.url/").build(); + ResponseBody responseBody = ResponseBody.create(new byte[1], + MediaType.get("application/json; charset=utf-8")); + + Response response = new Response.Builder() + .request(request) + .protocol(Protocol.HTTP_1_1) + .message("message") + .code(200) + .build(); + responseFutureCallback.onResponse(null, response); + future.cancel(true); + + response = new Response.Builder() + .request(request) + .protocol(Protocol.HTTP_1_1) + .message("message") + .code(200) + .body(responseBody) + .build(); + responseFutureCallback.onResponse(null, response); + future.cancel(true); + } + + + @Test + public void testGetRpcServiceOptions_Success() { + RpcServiceOptions rpcServiceOptions = capaSerializeHttpSpi.getRpcServiceOptions("appId"); + String className = rpcServiceOptions.getClass().getName(); + Assertions.assertEquals("group.rxcloud.capa.spi.http.config.TestRpcServiceOptions", className); + } + + @Test + public void testDoInvokeApi_Success() throws ExecutionException, InterruptedException { + String[] pathSegments = new String[]{ + CapaHttp.API_VERSION, + "invoke", "appId", + "method", "method"}; + + Map> urlParameters = new HashMap<>(); + urlParameters.put("key", new ArrayList<>()); + + Map headers = new HashMap<>(); + headers.put("content-type", "application/json"); + + Context context = Context.of("content", "value"); + + CompletableFuture> responseCompletableFuture = capaSerializeHttpSpi.doInvokeApi( + "httpMethod", + pathSegments, + urlParameters, + "requestData", + headers, + context, + TypeRef.STRING); + + HttpResponse httpResponse = responseCompletableFuture.get(); + int statusCode = httpResponse.getStatusCode(); + Assertions.assertEquals(200, statusCode); + } + + /** + * serializer/deserializer for request/response objects used in tests only + */ + private class TestRuntimeExceptionObjectSerializer extends ObjectSerializer implements CapaObjectSerializer { + + /** + * {@inheritDoc} + */ + @Override + public byte[] serialize(Object o) { + throw new RuntimeException("test serialize exception"); + } + + /** + * {@inheritDoc} + */ + @Override + public T deserialize(byte[] data, TypeRef type) { + throw new RuntimeException("test deserialize exception"); + } + + /** + * {@inheritDoc} + */ + @Override + public String getContentType() { + return ""; + } + } + + + /** + * serializer/deserializer for request/response objects used in tests only + */ + private class TestIOExceptionObjectSerializer extends ObjectSerializer implements CapaObjectSerializer { + + /** + * {@inheritDoc} + */ + @Override + public byte[] serialize(Object o) throws IOException { + throw new IOException("test serialize ioexception"); + } + + /** + * {@inheritDoc} + */ + @Override + public T deserialize(byte[] data, TypeRef type) throws IOException { + throw new IOException("test deserialize ioexception"); + } + + /** + * {@inheritDoc} + */ + @Override + public String getContentType() { + return ""; + } + } + + + /** + * The test capa http invoker. + */ + private class TestCapaSerializeHttpSpi extends CapaSerializeHttpSpi { + + public TestCapaSerializeHttpSpi(OkHttpClient httpClient, CapaObjectSerializer objectSerializer) { + super(httpClient, objectSerializer); + } + + @Override + protected CompletableFuture> invokeSpiApi( + String appId, + String method, + Object requestData, + String httpMethod, + Map headers, + Map> urlParameters, + TypeRef type, + RpcServiceOptions rpcServiceOptions) { + return CompletableFuture.supplyAsync( + () -> { + return new HttpResponse<>(null, null, 200); + }, + Runnable::run); + } + } +} diff --git a/sdk-springboot/pom.xml b/sdk-springboot/pom.xml index a6790d7..8febac5 100644 --- a/sdk-springboot/pom.xml +++ b/sdk-springboot/pom.xml @@ -23,7 +23,7 @@ capa-parent group.rxcloud - 1.0.6.RELEASE + 1.0.7.RELEASE sdk-springboot diff --git a/sdk/pom.xml b/sdk/pom.xml index 62a8172..b1e9a06 100644 --- a/sdk/pom.xml +++ b/sdk/pom.xml @@ -23,7 +23,7 @@ group.rxcloud capa-parent - 1.0.6.RELEASE + 1.0.7.RELEASE capa-sdk diff --git a/sdk/src/main/java/group/rxcloud/capa/configuration/AbstractCapaConfigurationClient.java b/sdk/src/main/java/group/rxcloud/capa/configuration/AbstractCapaConfigurationClient.java index b43d6d5..e11cbaa 100644 --- a/sdk/src/main/java/group/rxcloud/capa/configuration/AbstractCapaConfigurationClient.java +++ b/sdk/src/main/java/group/rxcloud/capa/configuration/AbstractCapaConfigurationClient.java @@ -34,6 +34,13 @@ */ public abstract class AbstractCapaConfigurationClient implements CapaConfigurationClient { + protected List registryNames; + + @Override + public List registryNames() { + return registryNames; + } + @Override public Mono saveConfiguration(SaveConfigurationRequest saveConfigurationRequest) { return Mono.error(new UnsupportedOperationException("unsupported save configuration")); diff --git a/sdk/src/main/java/group/rxcloud/capa/configuration/CapaConfigurationClient.java b/sdk/src/main/java/group/rxcloud/capa/configuration/CapaConfigurationClient.java index edd780f..aa213e1 100644 --- a/sdk/src/main/java/group/rxcloud/capa/configuration/CapaConfigurationClient.java +++ b/sdk/src/main/java/group/rxcloud/capa/configuration/CapaConfigurationClient.java @@ -63,7 +63,6 @@ public interface CapaConfigurationClient extends DefaultCloudRuntimesClient { @Override Mono deleteConfiguration(ConfigurationRequestItem configurationRequestItem); - @Override default Mono shutdown() { return Mono.empty(); diff --git a/sdk/src/main/java/group/rxcloud/capa/configuration/CapaConfigurationClientStore.java b/sdk/src/main/java/group/rxcloud/capa/configuration/CapaConfigurationClientStore.java index 67454d9..2a143e4 100644 --- a/sdk/src/main/java/group/rxcloud/capa/configuration/CapaConfigurationClientStore.java +++ b/sdk/src/main/java/group/rxcloud/capa/configuration/CapaConfigurationClientStore.java @@ -28,6 +28,7 @@ import reactor.core.publisher.Mono; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -50,11 +51,13 @@ public class CapaConfigurationClientStore extends AbstractCapaConfigurationClien public CapaConfigurationClientStore(List stores) { if (stores == null || stores.isEmpty()) { this.configStores = new HashMap<>(2, 1); + this.registryNames = Collections.emptyList(); } else { this.configStores = stores.stream() .collect(Collectors.toMap( CapaConfigStore::getStoreName, Function.identity())); + this.registryNames = new ArrayList<>(this.configStores.keySet()); } } diff --git a/sdk/src/main/java/group/rxcloud/capa/pubsub/AbstractCapaPubSubClient.java b/sdk/src/main/java/group/rxcloud/capa/pubsub/AbstractCapaPubSubClient.java index d91d0bd..1c051ec 100644 --- a/sdk/src/main/java/group/rxcloud/capa/pubsub/AbstractCapaPubSubClient.java +++ b/sdk/src/main/java/group/rxcloud/capa/pubsub/AbstractCapaPubSubClient.java @@ -19,6 +19,7 @@ import group.rxcloud.cloudruntimes.domain.core.pubsub.PublishEventRequest; import reactor.core.publisher.Mono; +import java.util.List; import java.util.Map; /** @@ -28,6 +29,13 @@ */ public abstract class AbstractCapaPubSubClient implements CapaPubSubClient { + protected List registryNames; + + @Override + public List registryNames() { + return registryNames; + } + @Override public Mono publishEvent(String pubsubName, String topicName, Object data) { PublishEventRequest publishEventRequest = new PublishEventRequest(pubsubName, topicName, data); diff --git a/sdk/src/main/java/group/rxcloud/capa/pubsub/CapaPubSubClientPubSub.java b/sdk/src/main/java/group/rxcloud/capa/pubsub/CapaPubSubClientPubSub.java index f7d089f..2816c5b 100644 --- a/sdk/src/main/java/group/rxcloud/capa/pubsub/CapaPubSubClientPubSub.java +++ b/sdk/src/main/java/group/rxcloud/capa/pubsub/CapaPubSubClientPubSub.java @@ -22,6 +22,8 @@ import group.rxcloud.cloudruntimes.domain.core.pubsub.PublishEventRequest; import reactor.core.publisher.Mono; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -44,11 +46,13 @@ public class CapaPubSubClientPubSub extends AbstractCapaPubSubClient { public CapaPubSubClientPubSub(List pubSubs) { if (pubSubs == null || pubSubs.isEmpty()) { this.pubSubs = new HashMap<>(2, 1); + this.registryNames = Collections.emptyList(); } else { this.pubSubs = pubSubs.stream() .collect(Collectors.toMap( CapaPubSub::getPubSubName, Function.identity())); + this.registryNames = new ArrayList<>(this.pubSubs.keySet()); } } diff --git a/sdk/src/main/java/group/rxcloud/capa/rpc/AbstractCapaRpcClient.java b/sdk/src/main/java/group/rxcloud/capa/rpc/AbstractCapaRpcClient.java index 38bbd27..ebaf8ef 100644 --- a/sdk/src/main/java/group/rxcloud/capa/rpc/AbstractCapaRpcClient.java +++ b/sdk/src/main/java/group/rxcloud/capa/rpc/AbstractCapaRpcClient.java @@ -22,6 +22,7 @@ import group.rxcloud.cloudruntimes.utils.TypeRef; import reactor.core.publisher.Mono; +import java.util.List; import java.util.Map; /** @@ -31,6 +32,13 @@ */ public abstract class AbstractCapaRpcClient implements CapaRpcClient { + protected List registryNames; + + @Override + public List registryNames() { + return registryNames; + } + @Override public Mono invokeMethod(String appId, String methodName, Object request, HttpExtension httpExtension, Map metadata, TypeRef type) { InvokeMethodRequestBuilder builder = new InvokeMethodRequestBuilder(appId, methodName); diff --git a/sdk/src/main/java/group/rxcloud/capa/rpc/CapaRpcClientHttp.java b/sdk/src/main/java/group/rxcloud/capa/rpc/CapaRpcClientHttp.java index 6c7ebe8..6e7ea9c 100644 --- a/sdk/src/main/java/group/rxcloud/capa/rpc/CapaRpcClientHttp.java +++ b/sdk/src/main/java/group/rxcloud/capa/rpc/CapaRpcClientHttp.java @@ -23,6 +23,7 @@ import group.rxcloud.cloudruntimes.utils.TypeRef; import reactor.core.publisher.Mono; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -41,6 +42,9 @@ public class CapaRpcClientHttp extends AbstractCapaRpcClient { public CapaRpcClientHttp(CapaHttp client) { this.client = client; + + this.registryNames = new ArrayList<>(1); + this.registryNames.add("http"); } @Override diff --git a/sdk/src/main/java/group/rxcloud/capa/state/CapaStateClient.java b/sdk/src/main/java/group/rxcloud/capa/state/CapaStateClient.java index 73f19c8..d884c39 100644 --- a/sdk/src/main/java/group/rxcloud/capa/state/CapaStateClient.java +++ b/sdk/src/main/java/group/rxcloud/capa/state/CapaStateClient.java @@ -17,14 +17,14 @@ package group.rxcloud.capa.state; import group.rxcloud.cloudruntimes.client.DefaultCloudRuntimesClient; -import group.rxcloud.cloudruntimes.domain.core.state.State; import group.rxcloud.cloudruntimes.domain.core.state.DeleteStateRequest; +import group.rxcloud.cloudruntimes.domain.core.state.ExecuteStateTransactionRequest; import group.rxcloud.cloudruntimes.domain.core.state.GetBulkStateRequest; import group.rxcloud.cloudruntimes.domain.core.state.GetStateRequest; -import group.rxcloud.cloudruntimes.domain.core.state.ExecuteStateTransactionRequest; -import group.rxcloud.cloudruntimes.domain.core.state.TransactionalStateOperation; -import group.rxcloud.cloudruntimes.domain.core.state.StateOptions; import group.rxcloud.cloudruntimes.domain.core.state.SaveStateRequest; +import group.rxcloud.cloudruntimes.domain.core.state.State; +import group.rxcloud.cloudruntimes.domain.core.state.StateOptions; +import group.rxcloud.cloudruntimes.domain.core.state.TransactionalStateOperation; import group.rxcloud.cloudruntimes.utils.TypeRef; import reactor.core.publisher.Mono; diff --git a/sdk/src/main/java/group/rxcloud/capa/telemetry/CapaTelemetryClient.java b/sdk/src/main/java/group/rxcloud/capa/telemetry/CapaTelemetryClient.java new file mode 100644 index 0000000..b7f06ff --- /dev/null +++ b/sdk/src/main/java/group/rxcloud/capa/telemetry/CapaTelemetryClient.java @@ -0,0 +1,50 @@ +/* + * 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. + */ +package group.rxcloud.capa.telemetry; + +import group.rxcloud.cloudruntimes.client.DefaultCloudRuntimesClient; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.propagation.ContextPropagators; +import reactor.core.publisher.Mono; + +public interface CapaTelemetryClient extends DefaultCloudRuntimesClient { + + @Override + Mono buildTracer(String tracerName); + + @Override + Mono getContextPropagators(); + + @Override + Mono buildTracer(String tracerName, String version); + + @Override + Mono buildTracer(String tracerName, String version, String schemaUrl); + + @Override + Mono buildMeter(String meterName); + + @Override + Mono buildMeter(String meterName, String version); + + @Override + Mono buildMeter(String meterName, String version, String schemaUrl); + + @Override + void close(); +} diff --git a/sdk/src/main/java/group/rxcloud/capa/telemetry/CapaTelemetryClientBuilder.java b/sdk/src/main/java/group/rxcloud/capa/telemetry/CapaTelemetryClientBuilder.java new file mode 100644 index 0000000..9b5023a --- /dev/null +++ b/sdk/src/main/java/group/rxcloud/capa/telemetry/CapaTelemetryClientBuilder.java @@ -0,0 +1,117 @@ +/* + * 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. + */ +package group.rxcloud.capa.telemetry; + +import group.rxcloud.capa.component.telemetry.SamplerConfig; +import group.rxcloud.capa.component.telemetry.context.CapaContextPropagatorBuilder; +import group.rxcloud.capa.component.telemetry.context.CapaContextPropagatorSettings; +import group.rxcloud.capa.component.telemetry.context.ContextConfig; +import group.rxcloud.capa.component.telemetry.metrics.CapaMeterProviderBuilder; +import group.rxcloud.capa.component.telemetry.metrics.CapaMeterProviderSettings; +import group.rxcloud.capa.component.telemetry.metrics.MeterConfig; +import group.rxcloud.capa.component.telemetry.metrics.MetricsReaderConfig; +import group.rxcloud.capa.component.telemetry.trace.CapaTracerProviderBuilder; +import group.rxcloud.capa.component.telemetry.trace.CapaTracerProviderSettings; +import group.rxcloud.capa.component.telemetry.trace.SpanLimitsConfig; +import group.rxcloud.capa.component.telemetry.trace.TracerConfig; +import io.opentelemetry.context.propagation.TextMapPropagator; +import io.opentelemetry.sdk.trace.IdGenerator; +import io.opentelemetry.sdk.trace.SpanProcessor; + +/** + * A builder for the {@link CapaTelemetryClient} + */ +public class CapaTelemetryClientBuilder implements CapaContextPropagatorSettings, CapaTracerProviderSettings, CapaMeterProviderSettings { + + private final CapaTracerProviderBuilder tracerProviderBuilder = new CapaTracerProviderBuilder(); + + private final CapaMeterProviderBuilder meterProviderBuilder = new CapaMeterProviderBuilder(); + + private final CapaContextPropagatorBuilder contextPropagatorBuilder = new CapaContextPropagatorBuilder(); + + @Override + public CapaTelemetryClientBuilder setTracerConfig(TracerConfig tracerConfig) { + tracerProviderBuilder.setTracerConfig(tracerConfig); + return this; + } + + @Override + public CapaTelemetryClientBuilder setSpanLimits(SpanLimitsConfig spanLimits) { + tracerProviderBuilder.setSpanLimits(spanLimits); + return this; + } + + @Override + public CapaTelemetryClientBuilder setIdGenerator(IdGenerator idGenerator) { + tracerProviderBuilder.setIdGenerator(idGenerator); + return this; + } + + @Override + public CapaTelemetryClientBuilder addProcessor(SpanProcessor processor) { + tracerProviderBuilder.addProcessor(processor); + return this; + } + + @Override + public CapaTelemetryClientBuilder setContextConfig(ContextConfig config) { + contextPropagatorBuilder.setContextConfig(config); + return this; + } + + @Override + public CapaTelemetryClientBuilder addContextPropagators(TextMapPropagator processor) { + contextPropagatorBuilder.addContextPropagators(processor); + return this; + } + + + @Override + public CapaTelemetryClientBuilder setMeterConfig(MeterConfig config) { + meterProviderBuilder.setMeterConfig(config); + return this; + } + + @Override + public CapaTelemetryClientBuilder addMetricReaderConfig(MetricsReaderConfig config) { + meterProviderBuilder.addMetricReaderConfig(config); + return this; + } + + @Override + public CapaTelemetryClientBuilder setSamplerConfig(SamplerConfig samplerConfig) { + meterProviderBuilder.setSamplerConfig(samplerConfig); + tracerProviderBuilder.setSamplerConfig(samplerConfig); + return this; + } + + public CapaTelemetryClient build() { + CapaTelemetryClientGlobal client = new CapaTelemetryClientGlobal(); + + // context + client.setContextPropagators(contextPropagatorBuilder.buildContextPropagators()); + + // tracer + client.setTracerProvider(tracerProviderBuilder.buildTracerProvider()); + + // meter + client.setMeterProvider(meterProviderBuilder.buildMeterProvider()); + + return client; + } + +} diff --git a/sdk/src/main/java/group/rxcloud/capa/telemetry/CapaTelemetryClientGlobal.java b/sdk/src/main/java/group/rxcloud/capa/telemetry/CapaTelemetryClientGlobal.java new file mode 100644 index 0000000..5755b13 --- /dev/null +++ b/sdk/src/main/java/group/rxcloud/capa/telemetry/CapaTelemetryClientGlobal.java @@ -0,0 +1,152 @@ +/* + * 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. + */ +package group.rxcloud.capa.telemetry; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.api.trace.TracerProvider; +import io.opentelemetry.context.propagation.ContextPropagators; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; +import java.util.List; + +public class CapaTelemetryClientGlobal implements CapaTelemetryClient, OpenTelemetry { + + // noop as default. + private static volatile CapaTelemetryClientGlobal instance; + + private TracerProvider tracerProvider = TracerProvider.noop(); + + private MeterProvider meterProvider = MeterProvider.noop(); + + private ContextPropagators contextPropagators = ContextPropagators.noop(); + + public static CapaTelemetryClientGlobal getOrCreate() { + if (instance == null) { + synchronized (CapaTelemetryClientGlobal.class) { + if (instance == null) { + instance = (CapaTelemetryClientGlobal) new CapaTelemetryClientBuilder().build(); + GlobalOpenTelemetry.set(instance); + } + } + } + return instance; + } + + static void set(CapaTelemetryClientGlobal capaTelemetryClient) { + instance = capaTelemetryClient; + } + + protected List registryNames; + + @Override + public List registryNames() { + return registryNames; + } + + CapaTelemetryClientGlobal() { + this.registryNames = new ArrayList<>(1); + this.registryNames.add("opentelemetry"); + } + + @Override + public TracerProvider getTracerProvider() { + return tracerProvider; + } + + void setTracerProvider(TracerProvider tracerProvider) { + this.tracerProvider = tracerProvider; + } + + public MeterProvider getMeterProvider() { + return meterProvider; + } + + void setMeterProvider(MeterProvider meterProvider) { + this.meterProvider = meterProvider; + } + + @Override + public ContextPropagators getPropagators() { + return contextPropagators; + } + + @Override + public Mono buildTracer(String tracerName) { + return Mono.fromSupplier(() -> { + return tracerProvider.tracerBuilder(tracerName).build(); + }); + } + + @Override + public Mono getContextPropagators() { + return Mono.fromSupplier(() -> { + return contextPropagators; + }); + } + + void setContextPropagators(ContextPropagators contextPropagators) { + this.contextPropagators = contextPropagators; + } + + @Override + public Mono buildTracer(String tracerName, String version) { + return Mono.fromSupplier(() -> { + return tracerProvider.tracerBuilder(tracerName).setInstrumentationVersion(version).build(); + }); + } + + @Override + public Mono buildTracer(String tracerName, String version, String schemaUrl) { + return Mono.fromSupplier(() -> { + return tracerProvider.tracerBuilder(tracerName).setInstrumentationVersion(version).setSchemaUrl(schemaUrl) + .build(); + }); + } + + @Override + public Mono buildMeter(String meterName) { + return Mono.fromSupplier(() -> { + return meterProvider.meterBuilder(meterName) + .build(); + }); + } + + @Override + public Mono buildMeter(String meterName, String version) { + return Mono.fromSupplier(() -> { + return meterProvider.meterBuilder(meterName).setInstrumentationVersion(version) + .build(); + }); + } + + @Override + public Mono buildMeter(String meterName, String version, String schemaUrl) { + return Mono.fromSupplier(() -> { + return meterProvider.meterBuilder(meterName).setInstrumentationVersion(version).setSchemaUrl(schemaUrl) + .build(); + }); + } + + @Override + public void close() { + } +} diff --git a/sdk/src/test/java/group/rxcloud/capa/configuration/TestCapaConfigStore.java b/sdk/src/test/java/group/rxcloud/capa/configuration/TestCapaConfigStore.java index 868837c..c9b0374 100644 --- a/sdk/src/test/java/group/rxcloud/capa/configuration/TestCapaConfigStore.java +++ b/sdk/src/test/java/group/rxcloud/capa/configuration/TestCapaConfigStore.java @@ -16,7 +16,13 @@ */ package group.rxcloud.capa.configuration; -import group.rxcloud.capa.component.configstore.*; +import group.rxcloud.capa.component.configstore.CapaConfigStore; +import group.rxcloud.capa.component.configstore.ConfigurationItem; +import group.rxcloud.capa.component.configstore.GetRequest; +import group.rxcloud.capa.component.configstore.StoreConfig; +import group.rxcloud.capa.component.configstore.SubscribeReq; +import group.rxcloud.capa.component.configstore.SubscribeResp; +import group.rxcloud.capa.infrastructure.hook.TelemetryHooks; import group.rxcloud.capa.infrastructure.serializer.CapaObjectSerializer; import group.rxcloud.cloudruntimes.utils.TypeRef; import reactor.core.publisher.Flux; @@ -37,7 +43,7 @@ public class TestCapaConfigStore extends CapaConfigStore { * * @param objectSerializer Serializer for transient request/response objects. */ - public TestCapaConfigStore(CapaObjectSerializer objectSerializer) { + public TestCapaConfigStore(CapaObjectSerializer objectSerializer, TelemetryHooks telemetryHooks) { super(objectSerializer); } diff --git a/sdk/src/test/java/group/rxcloud/capa/rpc/CapaRpcClientBuilderTest.java b/sdk/src/test/java/group/rxcloud/capa/rpc/CapaRpcClientBuilderTest.java index 2d10759..178176d 100644 --- a/sdk/src/test/java/group/rxcloud/capa/rpc/CapaRpcClientBuilderTest.java +++ b/sdk/src/test/java/group/rxcloud/capa/rpc/CapaRpcClientBuilderTest.java @@ -1,229 +1,232 @@ -/* - * 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. - */ -package group.rxcloud.capa.rpc; - -import group.rxcloud.capa.component.http.CapaHttp; -import group.rxcloud.capa.component.http.HttpResponse; -import group.rxcloud.capa.infrastructure.exceptions.CapaException; -import group.rxcloud.capa.infrastructure.serializer.CapaObjectSerializer; -import group.rxcloud.capa.infrastructure.serializer.DefaultObjectSerializer; -import group.rxcloud.capa.rpc.domain.InvokeMethodRequestBuilder; -import group.rxcloud.cloudruntimes.domain.core.invocation.HttpExtension; -import group.rxcloud.cloudruntimes.domain.core.invocation.InvokeMethodRequest; -import group.rxcloud.cloudruntimes.utils.TypeRef; -import okhttp3.OkHttpClient; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Mono; -import reactor.util.context.Context; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; - - -public class CapaRpcClientBuilderTest { - - private CapaRpcClientHttp capaRpcClientHttp; - - private OkHttpClient okHttpClient; - - private DefaultObjectSerializer defaultObjectSerializer; - - @BeforeEach - public void setUp() { - okHttpClient = new OkHttpClient.Builder().build(); - defaultObjectSerializer = new DefaultObjectSerializer(); - capaRpcClientHttp = new CapaRpcClientHttp(new TestCapaHttp(okHttpClient, defaultObjectSerializer)); - } - - @Test - public void testInvokeMethod_FailWhenAppIdIsEmpty() { - InvokeMethodRequest methodRequest = new InvokeMethodRequestBuilder("", "method").build(); - - Mono stringMono = capaRpcClientHttp.invokeMethod(methodRequest, TypeRef.STRING); - - Assertions.assertThrows(IllegalArgumentException.class, () -> { - stringMono.block(); - }); - } - - @Test - public void testInvokeMethod_FailWhenMethodIsEmpty() { - InvokeMethodRequest methodRequest = new InvokeMethodRequestBuilder("appId", "").build(); - - Mono stringMono = capaRpcClientHttp.invokeMethod(methodRequest, TypeRef.STRING); - - Assertions.assertThrows(IllegalArgumentException.class, () -> { - stringMono.block(); - }); - } - - @Test - public void testInvokeMethod_FailWhenHttpExtensionIsNull() { - InvokeMethodRequest methodRequest = new InvokeMethodRequestBuilder("appId", "method") - .withHttpExtension(null) - .build(); - - Mono stringMono = capaRpcClientHttp.invokeMethod(methodRequest, TypeRef.STRING); - - Assertions.assertThrows(IllegalArgumentException.class, () -> { - stringMono.block(); - }); - } - - @Test - public void testInvokeMethod_Success() { - Map metadata = new HashMap<>(); - metadata.put("key", "value"); - - InvokeMethodRequest methodRequest = new InvokeMethodRequestBuilder("appId", "method") - .withHttpExtension(HttpExtension.POST) - .withMetadata(metadata) - .build(); - - Mono responseMono = capaRpcClientHttp.invokeMethod(methodRequest, TypeRef.STRING); - String response = responseMono.block(); - - Assertions.assertNull(response); - } - - @Test - public void testAbstractInvokeMethod_Success() { - Map metadata = new HashMap<>(); - metadata.put("key", "value"); - - Mono responseMono = capaRpcClientHttp.invokeMethod("appId", - "method", - "request", - HttpExtension.POST, - metadata, - String.class); - String response = responseMono.block(); - Assertions.assertNull(response); - - responseMono = capaRpcClientHttp.invokeMethod("appId", - "method", - "request", - HttpExtension.POST, - TypeRef.STRING); - response = responseMono.block(); - Assertions.assertNull(response); - - responseMono = capaRpcClientHttp.invokeMethod("appId", - "method", - "request", - HttpExtension.POST, - String.class); - response = responseMono.block(); - Assertions.assertNull(response); - - responseMono = capaRpcClientHttp.invokeMethod("appId", - "method", - HttpExtension.POST, - metadata, - String.class); - response = responseMono.block(); - Assertions.assertNull(response); - - responseMono = capaRpcClientHttp.invokeMethod("appId", - "method", - HttpExtension.POST, - metadata, - TypeRef.STRING); - response = responseMono.block(); - Assertions.assertNull(response); - - Mono voidResponseMono = capaRpcClientHttp.invokeMethod("appId", - "method", - "request", - HttpExtension.POST, - metadata); - voidResponseMono.block(); - - voidResponseMono = capaRpcClientHttp.invokeMethod("appId", - "method", - "request", - HttpExtension.POST); - voidResponseMono.block(); - - voidResponseMono = capaRpcClientHttp.invokeMethod("appId", - "method", - HttpExtension.POST, - metadata); - voidResponseMono.block(); - - Mono byteResponseMono = capaRpcClientHttp.invokeMethod("appId", - "method", - new byte[1], - HttpExtension.POST, - metadata); - byte[] byteResponse = byteResponseMono.block(); - Assertions.assertNull(byteResponse); - - } - - @Test - public void testShutdown_Success() { - Mono shutdown = capaRpcClientHttp.shutdown(); - shutdown.block(); - } - - @Test - public void testClose_Success() { - capaRpcClientHttp.close(); - } - - @Test - public void testClose_FailWhenThrowException() { - - capaRpcClientHttp = new CapaRpcClientHttp(new ExceptionCapaHttp(okHttpClient, defaultObjectSerializer)); - - Assertions.assertThrows(CapaException.class, () -> { - capaRpcClientHttp.close(); - }); - } - - /** - * The capa http invoker used in tests only. - */ - private class ExceptionCapaHttp extends CapaHttp { - - public ExceptionCapaHttp(OkHttpClient httpClient, CapaObjectSerializer objectSerializer) { - super(httpClient, objectSerializer); - } - - @Override - protected CompletableFuture> doInvokeApi(String httpMethod, - String[] pathSegments, - Map> urlParameters, - Object requestData, - Map headers, - Context context, - TypeRef type) { - return null; - } - - @Override - public void close() { - throw new RuntimeException() { - }; - } - } -} +/* + * 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. + */ +package group.rxcloud.capa.rpc; + +import group.rxcloud.capa.component.http.CapaHttp; +import group.rxcloud.capa.component.http.HttpResponse; +import group.rxcloud.capa.infrastructure.exceptions.CapaException; +import group.rxcloud.capa.infrastructure.hook.ConfigurationHooks; +import group.rxcloud.capa.infrastructure.hook.TelemetryHooks; +import group.rxcloud.capa.infrastructure.serializer.CapaObjectSerializer; +import group.rxcloud.capa.infrastructure.serializer.DefaultObjectSerializer; +import group.rxcloud.capa.rpc.domain.InvokeMethodRequestBuilder; +import group.rxcloud.cloudruntimes.domain.core.invocation.HttpExtension; +import group.rxcloud.cloudruntimes.domain.core.invocation.InvokeMethodRequest; +import group.rxcloud.cloudruntimes.utils.TypeRef; +import okhttp3.OkHttpClient; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import reactor.core.publisher.Mono; +import reactor.util.context.Context; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + + +public class CapaRpcClientBuilderTest { + + private CapaRpcClientHttp capaRpcClientHttp; + + private OkHttpClient okHttpClient; + + private DefaultObjectSerializer defaultObjectSerializer; + + @BeforeEach + public void setUp() { + okHttpClient = new OkHttpClient.Builder().build(); + defaultObjectSerializer = new DefaultObjectSerializer(); + capaRpcClientHttp = new CapaRpcClientHttp(new TestCapaHttp(okHttpClient, defaultObjectSerializer)); + } + + @Test + public void testInvokeMethod_FailWhenAppIdIsEmpty() { + InvokeMethodRequest methodRequest = new InvokeMethodRequestBuilder("", "method").build(); + + Mono stringMono = capaRpcClientHttp.invokeMethod(methodRequest, TypeRef.STRING); + + Assertions.assertThrows(IllegalArgumentException.class, () -> { + stringMono.block(); + }); + } + + @Test + public void testInvokeMethod_FailWhenMethodIsEmpty() { + InvokeMethodRequest methodRequest = new InvokeMethodRequestBuilder("appId", "").build(); + + Mono stringMono = capaRpcClientHttp.invokeMethod(methodRequest, TypeRef.STRING); + + Assertions.assertThrows(IllegalArgumentException.class, () -> { + stringMono.block(); + }); + } + + @Test + public void testInvokeMethod_FailWhenHttpExtensionIsNull() { + InvokeMethodRequest methodRequest = new InvokeMethodRequestBuilder("appId", "method") + .withHttpExtension(null) + .build(); + + Mono stringMono = capaRpcClientHttp.invokeMethod(methodRequest, TypeRef.STRING); + + Assertions.assertThrows(IllegalArgumentException.class, () -> { + stringMono.block(); + }); + } + + @Test + public void testInvokeMethod_Success() { + Map metadata = new HashMap<>(); + metadata.put("key", "value"); + + InvokeMethodRequest methodRequest = new InvokeMethodRequestBuilder("appId", "method") + .withHttpExtension(HttpExtension.POST) + .withMetadata(metadata) + .build(); + + Mono responseMono = capaRpcClientHttp.invokeMethod(methodRequest, TypeRef.STRING); + String response = responseMono.block(); + + Assertions.assertNull(response); + } + + @Test + public void testAbstractInvokeMethod_Success() { + Map metadata = new HashMap<>(); + metadata.put("key", "value"); + + Mono responseMono = capaRpcClientHttp.invokeMethod("appId", + "method", + "request", + HttpExtension.POST, + metadata, + String.class); + String response = responseMono.block(); + Assertions.assertNull(response); + + responseMono = capaRpcClientHttp.invokeMethod("appId", + "method", + "request", + HttpExtension.POST, + TypeRef.STRING); + response = responseMono.block(); + Assertions.assertNull(response); + + responseMono = capaRpcClientHttp.invokeMethod("appId", + "method", + "request", + HttpExtension.POST, + String.class); + response = responseMono.block(); + Assertions.assertNull(response); + + responseMono = capaRpcClientHttp.invokeMethod("appId", + "method", + HttpExtension.POST, + metadata, + String.class); + response = responseMono.block(); + Assertions.assertNull(response); + + responseMono = capaRpcClientHttp.invokeMethod("appId", + "method", + HttpExtension.POST, + metadata, + TypeRef.STRING); + response = responseMono.block(); + Assertions.assertNull(response); + + Mono voidResponseMono = capaRpcClientHttp.invokeMethod("appId", + "method", + "request", + HttpExtension.POST, + metadata); + voidResponseMono.block(); + + voidResponseMono = capaRpcClientHttp.invokeMethod("appId", + "method", + "request", + HttpExtension.POST); + voidResponseMono.block(); + + voidResponseMono = capaRpcClientHttp.invokeMethod("appId", + "method", + HttpExtension.POST, + metadata); + voidResponseMono.block(); + + Mono byteResponseMono = capaRpcClientHttp.invokeMethod("appId", + "method", + new byte[1], + HttpExtension.POST, + metadata); + byte[] byteResponse = byteResponseMono.block(); + Assertions.assertNull(byteResponse); + + } + + @Test + public void testShutdown_Success() { + Mono shutdown = capaRpcClientHttp.shutdown(); + shutdown.block(); + } + + @Test + public void testClose_Success() { + capaRpcClientHttp.close(); + } + + @Test + public void testClose_FailWhenThrowException() { + + capaRpcClientHttp = new CapaRpcClientHttp(new ExceptionCapaHttp(okHttpClient, defaultObjectSerializer, null, null)); + + Assertions.assertThrows(CapaException.class, () -> { + capaRpcClientHttp.close(); + }); + } + + /** + * The capa http invoker used in tests only. + */ + private class ExceptionCapaHttp extends CapaHttp { + + public ExceptionCapaHttp(OkHttpClient httpClient, CapaObjectSerializer objectSerializer, + TelemetryHooks telemetryHooks, ConfigurationHooks configurationHooks) { + super(httpClient, objectSerializer); + } + + @Override + protected CompletableFuture> doInvokeApi(String httpMethod, + String[] pathSegments, + Map> urlParameters, + Object requestData, + Map headers, + Context context, + TypeRef type) { + return null; + } + + @Override + public void close() { + throw new RuntimeException() { + }; + } + } +} diff --git a/sdk/src/test/java/group/rxcloud/capa/rpc/CapaRpcClientHttpTest.java b/sdk/src/test/java/group/rxcloud/capa/rpc/CapaRpcClientHttpTest.java index c78ce02..68640a6 100644 --- a/sdk/src/test/java/group/rxcloud/capa/rpc/CapaRpcClientHttpTest.java +++ b/sdk/src/test/java/group/rxcloud/capa/rpc/CapaRpcClientHttpTest.java @@ -1,44 +1,44 @@ -/* - * 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. - */ -package group.rxcloud.capa.rpc; - -import group.rxcloud.capa.component.http.CapaHttpBuilder; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.util.function.Supplier; - -public class CapaRpcClientHttpTest { - - @Test - public void testStructure_Success() { - CapaRpcClientBuilder capaRpcClientBuilder = new CapaRpcClientBuilder(); - Assertions.assertNotNull(capaRpcClientBuilder); - - Supplier capaHttpBuilderSupplier = () -> new CapaHttpBuilder(); - CapaRpcClientBuilder rpcClientBuilder = new CapaRpcClientBuilder(capaHttpBuilderSupplier); - Assertions.assertNotNull(rpcClientBuilder); - } - - @Test - public void testBuild_Success() { - CapaRpcClientBuilder capaRpcClientBuilder = new CapaRpcClientBuilder(); - CapaRpcClient client = capaRpcClientBuilder.build(); - - Assertions.assertNotNull(client); - } -} +/* + * 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. + */ +package group.rxcloud.capa.rpc; + +import group.rxcloud.capa.component.http.CapaHttpBuilder; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.function.Supplier; + +public class CapaRpcClientHttpTest { + + @Test + public void testStructure_Success() { + CapaRpcClientBuilder capaRpcClientBuilder = new CapaRpcClientBuilder(); + Assertions.assertNotNull(capaRpcClientBuilder); + + Supplier capaHttpBuilderSupplier = () -> new CapaHttpBuilder(); + CapaRpcClientBuilder rpcClientBuilder = new CapaRpcClientBuilder(capaHttpBuilderSupplier); + Assertions.assertNotNull(rpcClientBuilder); + } + + @Test + public void testBuild_Success() { + CapaRpcClientBuilder capaRpcClientBuilder = new CapaRpcClientBuilder(); + CapaRpcClient client = capaRpcClientBuilder.build(); + + Assertions.assertNotNull(client); + } +} diff --git a/sdk/src/test/java/group/rxcloud/capa/rpc/TestCapaHttp.java b/sdk/src/test/java/group/rxcloud/capa/rpc/TestCapaHttp.java index dbd32df..823e31f 100644 --- a/sdk/src/test/java/group/rxcloud/capa/rpc/TestCapaHttp.java +++ b/sdk/src/test/java/group/rxcloud/capa/rpc/TestCapaHttp.java @@ -1,53 +1,53 @@ -/* - * 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. - */ -package group.rxcloud.capa.rpc; - -import group.rxcloud.capa.component.http.CapaHttp; -import group.rxcloud.capa.component.http.HttpResponse; -import group.rxcloud.capa.infrastructure.serializer.CapaObjectSerializer; -import group.rxcloud.cloudruntimes.utils.TypeRef; -import okhttp3.OkHttpClient; -import reactor.util.context.Context; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; - -/** - * The capa http invoker used in tests only. - */ -public class TestCapaHttp extends CapaHttp { - - public TestCapaHttp(OkHttpClient httpClient, CapaObjectSerializer objectSerializer) { - super(httpClient, objectSerializer); - } - - @Override - protected CompletableFuture> doInvokeApi(String httpMethod, - String[] pathSegments, - Map> urlParameters, - Object requestData, - Map headers, - Context context, - TypeRef type) { - return CompletableFuture.supplyAsync( - () -> { - return new HttpResponse<>(null, null, 200); - }, - Runnable::run); - } -} +/* + * 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. + */ +package group.rxcloud.capa.rpc; + +import group.rxcloud.capa.component.http.CapaHttp; +import group.rxcloud.capa.component.http.HttpResponse; +import group.rxcloud.capa.infrastructure.serializer.CapaObjectSerializer; +import group.rxcloud.cloudruntimes.utils.TypeRef; +import okhttp3.OkHttpClient; +import reactor.util.context.Context; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +/** + * The capa http invoker used in tests only. + */ +public class TestCapaHttp extends CapaHttp { + + public TestCapaHttp(OkHttpClient httpClient, CapaObjectSerializer objectSerializer) { + super(httpClient, objectSerializer); + } + + @Override + protected CompletableFuture> doInvokeApi(String httpMethod, + String[] pathSegments, + Map> urlParameters, + Object requestData, + Map headers, + Context context, + TypeRef type) { + return CompletableFuture.supplyAsync( + () -> { + return new HttpResponse<>(null, null, 200); + }, + Runnable::run); + } +} diff --git a/sdk/src/test/java/group/rxcloud/capa/rpc/domain/InvokeMethodRequestBuilderTest.java b/sdk/src/test/java/group/rxcloud/capa/rpc/domain/InvokeMethodRequestBuilderTest.java index cdd9b5d..a17b102 100644 --- a/sdk/src/test/java/group/rxcloud/capa/rpc/domain/InvokeMethodRequestBuilderTest.java +++ b/sdk/src/test/java/group/rxcloud/capa/rpc/domain/InvokeMethodRequestBuilderTest.java @@ -1,86 +1,86 @@ -/* - * 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. - */ -package group.rxcloud.capa.rpc.domain; - -import group.rxcloud.cloudruntimes.domain.core.invocation.HttpExtension; -import group.rxcloud.cloudruntimes.domain.core.invocation.InvokeMethodRequest; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.HashMap; -import java.util.Map; - - -public class InvokeMethodRequestBuilderTest { - - private InvokeMethodRequestBuilder invokeMethodRequestBuilder; - - @BeforeEach - public void setUp() { - invokeMethodRequestBuilder = new InvokeMethodRequestBuilder("appId", "method"); - } - - @Test - public void testWithContentType_Success() { - InvokeMethodRequestBuilder requestBuilder = invokeMethodRequestBuilder.withContentType("application/json"); - Assertions.assertNotNull(requestBuilder); - } - - @Test - public void testWithBody_Success() { - InvokeMethodRequestBuilder requestBuilder = invokeMethodRequestBuilder.withBody("body"); - Assertions.assertNotNull(requestBuilder); - } - - @Test - public void testWithHttpExtension_Success() { - InvokeMethodRequestBuilder requestBuilder = invokeMethodRequestBuilder.withHttpExtension(HttpExtension.POST); - Assertions.assertNotNull(requestBuilder); - } - - @Test - public void testWithMetadata_Success() { - Map metadata = new HashMap<>(); - metadata.put("key", "value"); - - InvokeMethodRequestBuilder requestBuilder = invokeMethodRequestBuilder.withMetadata(metadata); - Assertions.assertNotNull(requestBuilder); - } - - @Test - public void testBuild_Success() { - Map metadata = new HashMap<>(); - metadata.put("key", "value"); - - InvokeMethodRequest invokeMethodRequest = invokeMethodRequestBuilder - .withContentType("application/json") - .withBody("body") - .withHttpExtension(HttpExtension.POST) - .withMetadata(metadata) - .build(); - - Assertions.assertEquals("appId", invokeMethodRequest.getAppId()); - Assertions.assertEquals("method", invokeMethodRequest.getMethod()); - Assertions.assertEquals("application/json", invokeMethodRequest.getContentType()); - Assertions.assertEquals("body", invokeMethodRequest.getBody()); - Assertions.assertEquals(HttpExtension.POST, invokeMethodRequest.getHttpExtension()); - - Map requestMetadata = invokeMethodRequest.getMetadata(); - Assertions.assertEquals("value", requestMetadata.get("key")); - } -} +/* + * 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. + */ +package group.rxcloud.capa.rpc.domain; + +import group.rxcloud.cloudruntimes.domain.core.invocation.HttpExtension; +import group.rxcloud.cloudruntimes.domain.core.invocation.InvokeMethodRequest; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + + +public class InvokeMethodRequestBuilderTest { + + private InvokeMethodRequestBuilder invokeMethodRequestBuilder; + + @BeforeEach + public void setUp() { + invokeMethodRequestBuilder = new InvokeMethodRequestBuilder("appId", "method"); + } + + @Test + public void testWithContentType_Success() { + InvokeMethodRequestBuilder requestBuilder = invokeMethodRequestBuilder.withContentType("application/json"); + Assertions.assertNotNull(requestBuilder); + } + + @Test + public void testWithBody_Success() { + InvokeMethodRequestBuilder requestBuilder = invokeMethodRequestBuilder.withBody("body"); + Assertions.assertNotNull(requestBuilder); + } + + @Test + public void testWithHttpExtension_Success() { + InvokeMethodRequestBuilder requestBuilder = invokeMethodRequestBuilder.withHttpExtension(HttpExtension.POST); + Assertions.assertNotNull(requestBuilder); + } + + @Test + public void testWithMetadata_Success() { + Map metadata = new HashMap<>(); + metadata.put("key", "value"); + + InvokeMethodRequestBuilder requestBuilder = invokeMethodRequestBuilder.withMetadata(metadata); + Assertions.assertNotNull(requestBuilder); + } + + @Test + public void testBuild_Success() { + Map metadata = new HashMap<>(); + metadata.put("key", "value"); + + InvokeMethodRequest invokeMethodRequest = invokeMethodRequestBuilder + .withContentType("application/json") + .withBody("body") + .withHttpExtension(HttpExtension.POST) + .withMetadata(metadata) + .build(); + + Assertions.assertEquals("appId", invokeMethodRequest.getAppId()); + Assertions.assertEquals("method", invokeMethodRequest.getMethod()); + Assertions.assertEquals("application/json", invokeMethodRequest.getContentType()); + Assertions.assertEquals("body", invokeMethodRequest.getBody()); + Assertions.assertEquals(HttpExtension.POST, invokeMethodRequest.getHttpExtension()); + + Map requestMetadata = invokeMethodRequest.getMetadata(); + Assertions.assertEquals("value", requestMetadata.get("key")); + } +} diff --git a/sdk/src/test/java/group/rxcloud/capa/telemetry/CapaTelemetryClientBuilderTest.java b/sdk/src/test/java/group/rxcloud/capa/telemetry/CapaTelemetryClientBuilderTest.java new file mode 100644 index 0000000..d79bf17 --- /dev/null +++ b/sdk/src/test/java/group/rxcloud/capa/telemetry/CapaTelemetryClientBuilderTest.java @@ -0,0 +1,93 @@ +/* + * 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. + */ +package group.rxcloud.capa.telemetry; + +import group.rxcloud.capa.component.telemetry.SamplerConfig; +import group.rxcloud.capa.component.telemetry.context.ContextConfig; +import group.rxcloud.capa.component.telemetry.metrics.MeterConfig; +import group.rxcloud.capa.component.telemetry.metrics.MetricsReaderConfig; +import group.rxcloud.capa.component.telemetry.trace.SpanLimitsConfig; +import group.rxcloud.capa.component.telemetry.trace.TracerConfig; +import io.opentelemetry.api.metrics.LongCounter; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.sdk.trace.IdGenerator; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * @author: chenyijiang + * @date: 2021/11/26 13:33 + */ +public class CapaTelemetryClientBuilderTest { + + @Test + public void build() { + CapaTelemetryClient client = new CapaTelemetryClientBuilder().build(); + assertNotNull(client.getContextPropagators().block()); + assertNotNull(client.buildTracer("aaa").block()); + assertNotNull(client.buildTracer("aaa", "ccc", "fff").block()); + assertNotNull(client.buildTracer("aaa", "sss").block()); + assertNotNull(client.buildMeter("bbb").block()); + assertNotNull(client.buildMeter("bbb", "shdas", "dasoi").block()); + assertNotNull(client.buildMeter("bbb", "dhasiug").block()); + } + + @Test + public void buildManual() throws InterruptedException { + MetricsReaderConfig readerConfig = new MetricsReaderConfig(); + readerConfig.setExporterType(MetricTestExporter.class.getName()); + readerConfig.setName("metric-reader"); + readerConfig.setExportInterval(1, TimeUnit.SECONDS); + CapaTelemetryClient capaTelemetryClient = new CapaTelemetryClientBuilder() + .addProcessor(new TraceProcessor()) + .setSamplerConfig(SamplerConfig.DEFAULT_CONFIG) + .setSpanLimits(new SpanLimitsConfig()) + .setIdGenerator(IdGenerator.random()) + .setTracerConfig(new TracerConfig()) + .setMeterConfig(new MeterConfig()) + .addMetricReaderConfig(readerConfig) + .setContextConfig(new ContextConfig()) + .addContextPropagators(W3CTraceContextPropagator.getInstance()) + .build(); + + // tracer + Tracer tracer = capaTelemetryClient.buildTracer("tracer-test") + .block(); + + LongCounter counter = capaTelemetryClient.buildMeter("meter-test") + .block() + .counterBuilder("counter-test") + .build(); + + Span span = tracer.spanBuilder("span-test") + .setAttribute("key1", 1) + .setAttribute("key2", 2) + .startSpan(); + // working + for (int i = 0; i < 10; i++) { + Thread.sleep(200); + counter.add(i); + } + + span.end(); + } +} \ No newline at end of file diff --git a/sdk/src/test/java/group/rxcloud/capa/telemetry/CapaTelemetryClientGlobalTest.java b/sdk/src/test/java/group/rxcloud/capa/telemetry/CapaTelemetryClientGlobalTest.java new file mode 100644 index 0000000..579d125 --- /dev/null +++ b/sdk/src/test/java/group/rxcloud/capa/telemetry/CapaTelemetryClientGlobalTest.java @@ -0,0 +1,43 @@ +/* + * 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. + */ +package group.rxcloud.capa.telemetry; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @author: chenyijiang + * @date: 2021/11/26 14:12 + */ +public class CapaTelemetryClientGlobalTest { + + @Test + public void getOrCreate() { + CapaTelemetryClient client = CapaTelemetryClientGlobal.getOrCreate(); + assertTrue(client instanceof CapaTelemetryClientGlobal); + assertNotNull(client.getContextPropagators()); + assertNotNull(((CapaTelemetryClientGlobal) client).getPropagators()); + assertNotNull(((CapaTelemetryClientGlobal) client).getMeterProvider()); + assertNotNull(((CapaTelemetryClientGlobal) client).getTracerProvider()); + assertNotNull(GlobalOpenTelemetry.get()); + assertEquals(client, CapaTelemetryClientGlobal.getOrCreate()); + } +} \ No newline at end of file diff --git a/sdk/src/test/java/group/rxcloud/capa/telemetry/MetricTestExporter.java b/sdk/src/test/java/group/rxcloud/capa/telemetry/MetricTestExporter.java new file mode 100644 index 0000000..6149cf5 --- /dev/null +++ b/sdk/src/test/java/group/rxcloud/capa/telemetry/MetricTestExporter.java @@ -0,0 +1,42 @@ +/* + * 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. + */ +package group.rxcloud.capa.telemetry; + +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.export.MetricExporter; + +import java.util.Collection; + +public class MetricTestExporter implements MetricExporter { + + @Override + public CompletableResultCode export(Collection metrics) { + metrics.forEach(System.out::println); + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode flush() { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode shutdown() { + return CompletableResultCode.ofSuccess(); + } +} \ No newline at end of file diff --git a/sdk/src/test/java/group/rxcloud/capa/telemetry/TraceProcessor.java b/sdk/src/test/java/group/rxcloud/capa/telemetry/TraceProcessor.java new file mode 100644 index 0000000..ab579b0 --- /dev/null +++ b/sdk/src/test/java/group/rxcloud/capa/telemetry/TraceProcessor.java @@ -0,0 +1,45 @@ +/* + * 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. + */ +package group.rxcloud.capa.telemetry; + +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.trace.ReadWriteSpan; +import io.opentelemetry.sdk.trace.ReadableSpan; +import io.opentelemetry.sdk.trace.SpanProcessor; + +public class TraceProcessor implements SpanProcessor { + + @Override + public void onStart(Context context, ReadWriteSpan span) { + + } + + @Override + public boolean isStartRequired() { + return false; + } + + @Override + public void onEnd(ReadableSpan span) { + System.out.println(span.toSpanData()); + } + + @Override + public boolean isEndRequired() { + return true; + } +} \ No newline at end of file