diff --git a/README.md b/README.md index f8b50ba2..070245bf 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,10 @@ This repository contains Solarwinds APM implementation that works with OpenTelem Here is the summary of the sub-projects: - agent : Builds the full OT auto agent with extra Solarwinds APM components. This is simply a repackaging build script that pull OT agent and our sub-projects to construct a new auto agent -- appoptics-opentelemetry-sdk : (Archived as we have decided not to maintain backward-compatibility with AppOptics) Builds the SDK artifact which has exactly the same interface as our existing AppOptics java agent SDK https://github.com/librato/joboe/tree/master/api . This is to be used as a base for `appoptics-opentelemetry-sdk-shaded` -- appoptics-opentelemetry-sdk-shaded : (Archived as we have decided not to maintain backward-compatibility with AppOptics) Same as appoptics-opentelemetry-sdk but can be used with the OT agent with shaded class names +- appoptics-opentelemetry-sdk : (most of which are archived as we have decided not to maintain backward-compatibility with AppOptics) Current it has only one API: the agent checker. - custom : Extra Solarwinds APM components, contains all custom functionality, SPI and other extensions (for example Sampler, Tracer Provider etc) to be loaded by OT's agent classloader - core-bootstrap : Core Solarwinds APM components that need to be made available to bootstrap classloader. This is important for `appoptics-opentelemetry-sdk` as the classes from `appoptics-opentelemetry-sdk` are loaded by app loader, which has no access to OT's agent classloader which loads `custom` - instrumentation : Additional instrumentation provided by us using the OT instrumentation framework (ByteBuddy) -- sdk-extensions : Builds the AO extension jar which runs with the original OT agent (vs the agent built from `agent` sub-project) -- sdk-extensions-bootstrap : Builds the AO extension jar dependencies that should be made available to bootstrap loader. It basically package the `core` and `metrics` from joboe More details for each of the sub-projects are listed in [Sub-Projects](#sub-projects) section @@ -19,68 +16,31 @@ More details for each of the sub-projects are listed in [Sub-Projects](#sub-proj #### Preparations Since this project has dependencies on various internal artifacts from [joboe](https://github.com/librato/joboe), the build machine would need access to those artifacts. Currently the Joboe core libraries for the OpenTelemetry custom distro are in the `otel` branch of the `Joboe` repo and are published to the Github Packages. -#### Agent/Extensions Jars -Simply run `gradle build` at the root folder. +#### Agent Jars +Simply run `gradle build` at the root folder. (or run `gradle publishToMavenLocal` to publish to local maven repo) -The agent should be built at `agent\build\libs\solarwinds-apm-agent-all.jar`. -The sdk-extensions jar should be built at `sdk-extensions\build\libs\sdk-extensions-1.0-SNAPSHOT-all.jar`. - -#### SDK artifacts -To build the `appoptics-opentelemetry-sdk` and `appoptics-opentelemetry-sdk-shaded` artifacts, use -`gradle :appoptics-opentelemetry-sdk:publishToMavenLocal` and -`gradle :appoptics-opentelemetry-sdk-shaded:publishToMavenLocal` - -The artifacts will be published to local maven repo. (Use the Github Actions workflow `Release` to build and publish the custom distro to Github Packages.) +The agent should be built at `agent\build\libs\solarwinds-apm-agent.jar`. ## Usage #### Agent Jar Attach the agent to jvm process arg such as: `-javaagent:"_the_path_to_the_jar_file" -Dotel.solarwinds.service.key=` -Upon successful initialization, the log should print such as: -``` -[otel.javaagent 2021-06-30 13:04:07:759 -0700] [main] INFO com.appoptics.opentelemetry.extensions.AppOpticsTracerProviderConfigurer - Successfully initialized Solarwinds APM OpenTelemetry extensions with service key ec3d********************************************************5468:ot -``` -#### Extension Jar -1. Either download the auto agent directly from https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent-all.jar or build from source. To build from source: - - Checkout https://github.com/open-telemetry/opentelemetry-java-instrumentation -Navigate to the project directory, then gradlew build -x test (-x test is for skipping tests, remove the option if tests are to be run). Use java 9 or above => export JAVA_HOME=. - - The java agent jar can be found in ...\git\opentelemetry-java-instrumentation\javaagent\build\libs -2. Attach the OT agent and our AO extension to the jvm process arg such as: -``` --javaagent:"C:\Users\patson.luk\Downloads\opentelemetry-javaagent-all-1.3.1.jar" --Dotel.javaagent.experimental.initializer.jar="C:\Users\patson.luk\git\opentelemetry-custom-distro\sdk-extensions\build\libs\sdk-extensions-1.0-SNAPSHOT-all.jar" --Dotel.traces.exporter=appoptics --Dotel.traces.sampler=appoptics --Dotel.metrics.exporter=none --Dotel.propagators=tracecontext,baggage,appoptics --Dotel.appoptics.service.key= --Xbootclasspath/a:"C:\Users\patson.luk\git\opentelemetry-custom-distro\sdk-extensions-bootstrap\build\libs\sdk-extensions-bootstrap-1.0-SNAPSHOT.jar" -``` +The service key can also be defined via the environment variable `SW_APM_SERVICE_KEY` or in the config file. Upon successful initialization, the log should print such as: ``` -[otel.javaagent 2021-07-08 10:41:16:650 -0700] [main] INFO io.opentelemetry.javaagent.tooling.VersionLogger - opentelemetry-javaagent - version: 1.3.1 -[otel.javaagent 2021-07-08 10:41:19:141 -0700] [main] INFO com.appoptics.opentelemetry.extensions.AppOpticsTracerProviderConfigurer - Successfully initialized AppOptics OpenTelemetry extensions with service key ec3d********************************************************5468:ot +[otel.javaagent 2021-06-30 13:04:07:759 -0700] [main] INFO com.appoptics.opentelemetry.extensions.AppOpticsTracerProviderConfigurer - Successfully initialized Solarwinds APM OpenTelemetry extensions with service key ec3d********************************************************5468:ot ``` -**There are certain challenges for classloading with extension jar, more details in https://github.com/open-telemetry/opentelemetry-java-instrumentation/discussions/3350** +#### SDK +The custom distro supports the standard OpenTelemetry APIs/SDKs. In addition to that, it also has an API to check if the agent is ready to use (and wait for a specified duration before it is ready). This is useful when you need to create traces manually. -#### SDK artifact -After the artifact `appoptics-opentelemetry-sdk-shaded` is built and published to local maven, it can be used by any java maven projects by adding `dependency` to `pom.xml` such as: -``` - - com.appoptics.agent.java - appoptics-opentelemetry-sdk-shaded - 1.0-SNAPSHOT - - ``` +The API can be called as below, which waits for at most 10 seconds before the agent is ready. +```AgentChecker.waitUntilAgentReady(10, TimeUnit.SECONDS))``` ## Debug -Various flags can be enabled to enable debugging - -#### Solarwinds APM core logs -(WIP) +Various flags can be enabled to enable debugging. You can define the environment variable `SW_APM_DEBUG_LEVEL` to `debug` to print verbose logs. The OpenTelemetry core agent also provides an JVM argument `-Dotel.javaagent.debug=true` to enable detailed logs. #### Muzzling OT provides Muzzling which matches classes/fields/methods used by instrumentation vs the ones available on the running JVM. If there are any mismatch, the instrumentation will be silently disabled unless debugging flag such as below is provided in the JVM args: @@ -94,10 +54,6 @@ Repackages the OT original agent with our custom compoenents (such as Sampler, T This produces a new agent, that contains both the OT agent and our changes. -This approach is a middleground of the other 2 approaches: -1. AO as a pure OT extension, isolated from the OT agent - https://github.com/appoptics/appoptics-opentelemetry-java#opentelemetry-auto-agent -2. AO as a fork of OT java instrumentation agent - https://github.com/open-telemetry/opentelemetry-java-instrumentation - The advantage of this approach: 1. More control over the OT agent logic, for example we can have another layer of agent and modify the OT agent entry point by [changing the MANIFEST file](https://github.com/appoptics/opentelemetry-custom-distro/blob/master/agent/build.gradle#L48) 2. Since this is a separate repo from the OT java instrumentation, we have loose coupling here. Updates from OT java instrumentation and changes in this repo are less likely to have conflicts with eachother. @@ -110,16 +66,7 @@ The disadvantage of this approach: 1. Whenever OT provides a newer version of agent, we will need to rebuild the agent on this repo too if we want the updates. #### appoptics-opentelemetry-sdk -An SDK artifact that has the same interfaces as our existing appoptics SDK (https://librato.github.io/java-agent-sdk-javadoc/com/appoptics/api/ext/package-summary.html), under the hood, this translates SDK calls into OT operations (spans), therefore it can work with application that has existing manual OT SDK instrumentation. - -In fact this artifact is currently not working on its own (missing dependency on `custom` and `core-bootstrap` in the built artifact). There is no strong use case for this artifact, the more useful case is addressed by `appoptics-opentelemetry-sdk-shaded` which is built on top of this artifact. - -#### appoptics-opentelemetry-sdk-shaded -Repackage `appoptics-opentelemetry-sdk` to [shaded name space](https://github.com/appoptics/opentelemetry-custom-distro/blob/master/gradle/shadow.gradle), for example `io.opentelemetry.api` -> `io.opentelemetry.javaagent.shaded.io.opentelemetry.api` so SDK calls works with the shaded classes in OT auto agent. - -This is expected to be used with the enhanced OT auto agent repackaged by our sub-project `agent` or the pure OT agent with our extension jar from sub-projec `sdk-extension`. - -The use case would be someone using our existing AppOptics agent with SDK calls can migrate to use our enhanced OT agent with this `appoptics-opentelemetry-sdk-shaded` artifact. There should be no code change except changes to build process to reference this new artifact instead of the existing appoptics SDK +Currently it has only one API: the agent ready checker. #### custom Our main implementation for OT SPI - which scans implementation using Java service loader. We provide our "implementation" to various OT services such as Sampler, Tracer to enable various AO specific features - AO sampling, profiling, detailed trace reporting/export etc. This also contains various intiailization code and resource files such as default config, SSL cert for gRPC to collector etc. @@ -148,21 +95,6 @@ so the muzzle plugin will inject our `Tracer` to the application classloader A very good description of instrumentation with bytebuddy/OT can be found in [here](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/contributing/writing-instrumentation-module.md#advice-classes) -#### sdk-extensions -Repackages and builds the AO extension jar which runs with the original OT agent (vs the agent built from `agent` sub-project). Take note that since classes from this jar are appended via `-Dotel.javaagent.experimental.initializer.jar` which is loaded by application classloader (instead of OT agent classloader), no custom shadowing is performed (no putting in `inst` and renaming extension from `class` to `classdata`). Regular shadowing/shading is still applied (`io.opentelemetry.xyz` -> `io.opentelemetry.javaagent.shaded.io.opentelemetry.xyz`) as this is run with the OT original agent which some OT class references are still shaded. Take note that in order ot use this extension, it has to be augmented with `-Xbootclasspath` to append `sdk-extensions-bootstrap` jar to bootstrap class path (see [sdk-extensions-bootstrap](sdk-extensions-bootstrap) for details) - -#### sdk-extensions-bootstrap -Repackages `core` and `metric` from joboe and append these classes to the bootstrap classpath. This is necessary as sdk-extension's instrumentation classes are injected into application classloader, these instrumentations reference our classes in joboe `core` and `metrics`. If the `core` classes are included in the sdk-extension via `-Dotel.javaagent.experimental.initializer.jar`, then they are unavailable to such classloader. - -More details are documented in https://github.com/appoptics/appoptics-opentelemetry-java/pull/5 . Take note that since the instrumentations are now "muzzled", it no longer triggers the same exception as seen in the PR, but the instrumentation would still fail with similar classloading failure: -``` -[otel.javaagent 2021-07-08 11:25:46:278 -0700] [http-nio-8080-exec-1] WARN muzzleMatcher - -- com.appoptics.opentelemetry.instrumentation.AoStatementTracer:22 Missing class com.tracelytics.util.BackTraceUtil -``` - -As discussed in https://github.com/open-telemetry/opentelemetry-java-instrumentation/discussions/3350, one approach is to append the `core` and `metrics` classes to bootstrap classloader by using a separate jar, which is produced by this sub-project - - - diff --git a/agent/build.gradle b/agent/build.gradle index cf4634eb..ba1b0a44 100644 --- a/agent/build.gradle +++ b/agent/build.gradle @@ -17,6 +17,7 @@ dependencies { customShadow project(path: ":custom", configuration: "shadow") customShadow project(path: ":instrumentation", configuration: "shadow") implementation project(path: ":core-bootstrap") + implementation project(path: ":appoptics-opentelemetry-sdk") implementation "io.opentelemetry.javaagent:opentelemetry-javaagent:${versions.opentelemetryJavaagent}" implementation "com.appoptics.agent.java:core:${versions.appopticsCore}" implementation "com.appoptics.agent.java:metrics:${versions.appopticsMetrics}" @@ -34,7 +35,7 @@ CopySpec isolateSpec() { } shadowJar { - classifier = null + archiveClassifier.set(null) } tasks { diff --git a/appoptics-opentelemetry-sdk-shaded/build.gradle b/appoptics-opentelemetry-sdk-shaded/build.gradle deleted file mode 100644 index 8af37106..00000000 --- a/appoptics-opentelemetry-sdk-shaded/build.gradle +++ /dev/null @@ -1,50 +0,0 @@ -plugins { - id("com.github.johnrengelman.shadow") version "6.0.0" - id("maven-publish") - id("java") -} - -//apply plugin: "maven" -apply from: "$rootDir/gradle/shadow.gradle" - -group = "com.appoptics.agent.java" - -def relocatePackages = ext.relocatePackages - -configurations { - customShadow -} - -dependencies { - customShadow project(path: ":appoptics-opentelemetry-sdk", configuration: "shadow") - implementation project(path: ":appoptics-opentelemetry-sdk") -} - -shadowJar { - archiveClassifier = '' -} - -publishing { - publications { - shadow(MavenPublication) { publication -> - from project.shadow.component(publication) - } - } -} - - -tasks { - shadowJar { - relocatePackages(it) - } - - assemble { - dependsOn(shadowJar) - } - -// install { -// dependsOn(shadowJar) -// dependsOn(publish) -// } -} - diff --git a/appoptics-opentelemetry-sdk/build.gradle b/appoptics-opentelemetry-sdk/build.gradle index 8a7b4c1d..aef771e5 100644 --- a/appoptics-opentelemetry-sdk/build.gradle +++ b/appoptics-opentelemetry-sdk/build.gradle @@ -1,7 +1,7 @@ apply plugin: 'java' apply plugin: "maven-publish" -group = "com.appoptics.agent.java" +group = "com.solarwinds.agent" dependencies { compileOnly("io.opentelemetry:opentelemetry-sdk:${versions.opentelemetry}") diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/AgentChecker.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/AgentChecker.java index c36b1b32..c6f8711d 100644 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/AgentChecker.java +++ b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/AgentChecker.java @@ -1,9 +1,8 @@ package com.appoptics.api.ext; -import com.appoptics.opentelemetry.extensions.initialize.Initializer; +import com.appoptics.opentelemetry.core.AgentState; import io.opentelemetry.javaagent.bootstrap.AgentInitializer; -import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; @@ -14,37 +13,29 @@ * @author pluk */ public class AgentChecker { - private static final Logger LOGGER = Logger.getLogger("appoptics-sdk"); - private static final String APPOPTICS_SERVICE_KEY = "otel.appoptics.service.key"; + private static final Logger LOGGER = Logger.getLogger("solarwinds-sdk"); private static boolean IS_EXTENSION_AVAILABLE = false; - private static final String SERVICE_KEY; static { String readServiceKey = null; try { - Class.forName("com.appoptics.opentelemetry.extensions.initialize.Initializer"); + Class.forName("com.appoptics.opentelemetry.core.AgentState"); setIsExtensionAvailable(true); //TODO version check? - readServiceKey = System.getProperty(APPOPTICS_SERVICE_KEY); } catch (ClassNotFoundException e) { //perhaps running in OT agent environment, try agent classloader instead try { - AgentInitializer.getAgentClassLoader().loadClass("com.appoptics.opentelemetry.extensions.initialize.Initializer"); + AgentInitializer.getExtensionsClassLoader().loadClass("com.appoptics.opentelemetry.core.AgentState"); setIsExtensionAvailable(true); //TODO version check? - readServiceKey = System.getProperty(APPOPTICS_SERVICE_KEY); } catch (Throwable e2) { - LOGGER.log(Level.INFO, "AppOptics extensions not available"); + LOGGER.log(Level.INFO, "Solarwinds APM extensions not available"); } } catch (NoClassDefFoundError e) { /* This is not so expected as ClassLoader is supposed to throw ClassNotFoundException, but some loaders might throw NoClassDefFoundError instead */ - LOGGER.log(Level.INFO, "AppOptics extensions not available"); + LOGGER.log(Level.INFO, "Solarwinds APM extensions not available"); } - finally { - SERVICE_KEY = readServiceKey; - } - } @@ -60,24 +51,8 @@ public class AgentChecker { * @return whether the agent is ready */ public static boolean waitUntilAgentReady(long timeout, TimeUnit unit) { - if (isExtensionAvailable() && SERVICE_KEY != null) { - try { - //Future future = Initializer.initialize(serviceKey); - final Future future = Initializer.getStartupTasksFuture(); - if (future != null) { - future.get(timeout, unit); - return true; - } - else { - LOGGER.warning("AppOptics can only be used with javaagent"); - return false; - } - - } - catch (Exception e) { - LOGGER.warning("Agent is still not ready after waiting for " + timeout + " " + unit); - return false; - } + if (isExtensionAvailable()) { + return AgentState.waitForReady(timeout, unit); } return false; } diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/HandlerFactory.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/HandlerFactory.java deleted file mode 100644 index 96e06f1a..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/HandlerFactory.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.appoptics.api.ext; - -import com.appoptics.api.ext.impl.IRumHandler; -import com.appoptics.api.ext.impl.ITraceContextHandler; -import com.appoptics.api.ext.impl.ITraceHandler; -import com.appoptics.api.ext.impl.RUMHandlerNoOp; -import com.appoptics.api.ext.impl.TraceContextHandler; -import com.appoptics.api.ext.impl.TraceContextHandlerNoOp; -import com.appoptics.api.ext.impl.TraceHandler; -import com.appoptics.api.ext.impl.TraceHandlerNoOp; - -/** - * Creates handler for various existing sdk classes that provide static methods. Depending on whether the java - * agent is available and up-to-date, no ops handlers or normal handler would be returned. - * - * - * @author Patson Luk - * - */ -class HandlerFactory { - private HandlerFactory() { - } - - static ITraceHandler getTraceHandler() { - return AgentChecker.isExtensionAvailable() ? new TraceHandler() : new TraceHandlerNoOp(); - } - - public static ITraceContextHandler getTraceContextHandler() { - return AgentChecker.isExtensionAvailable() ? new TraceContextHandler() : new TraceContextHandlerNoOp(); - } - - public static IRumHandler getRumHandler() { - return new RUMHandlerNoOp(); //always returns noop as manual RUM is no longer supported in T2 - } -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/LogMethod.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/LogMethod.java deleted file mode 100644 index 7b668632..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/LogMethod.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.appoptics.api.ext; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Logs execution of a method call using annotation. To add custom spans with annotation: - *

- *

    - *
  1. - * Import the {@code com.appoptics.api.ext.LogMethod} annotation - *
  2. - *
  3. - * Annotate your method by adding {@code @LogMethod(layer="yourLayerName")} above it. - *
  4. - *
- *

- * @see Java Agent - Instrumentation SDK - */ -@Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) -@Retention(RetentionPolicy.RUNTIME) -public @interface LogMethod { - /** - * Sets the layer name for the custom span, this is optional - * @return - */ - String layer() default ""; - /** - * Flags whether method stack trace should be included in the event - * @return - */ - boolean backTrace() default false; - /** - * Flags whether method result will be converted to string and stored in the event - * @return - */ - boolean storeReturn() default false; - /** - * Flags whether exceptions thrown by this method would be reported - * @return - */ - boolean reportExceptions() default true; -} - diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/Metrics.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/Metrics.java deleted file mode 100644 index b2e86cff..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/Metrics.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.appoptics.api.ext; - -import java.util.HashMap; -import java.util.Map; - -import com.tracelytics.monitor.metrics.CustomMetricsCollector; - -/** - * API for recording custom metrics. Recorded metrics will be aggregated and submitted periodically - * - */ -public class Metrics { - public static final String HOST_TAG_KEY = "HostTag"; - - /** - * Records a Summary Metric which consists of a single value. - * - * Summary metrics will be aggregated by the key- combination of metric name and tags, - * with a sum (sum of value from each call with same key), and a count (sum of count from each call with same key, with by default is 1 per call). - * - * @param name a custom name for this Summary Metric - * @param value a double value for this Summary Metric - * @param tags a Map of custom tags for this Summary Metric - */ - public static void summaryMetric(String name, double value, Map tags) { - summaryMetric(name, value, 1, false, tags); - } - - /** - * Records a Summary Metric which consists of a single value and a count. - * - * Summary metrics will be aggregated by the key- combination of metric name and tags, - * with a sum (sum of value from each call with same key), and a count (sum of count from each call with same key). - * - * This is a more efficient method to record metrics with same key. - * - * For example, if a Summary Metric is to be recorded for an operation performed repeatedly, - * then a total duration can be first accumulated with a count and passed to this method once instead of calling this repeatedly for each operation. - * - * @param name a custom name for this Summary Metric - * @param value a double value for this Summary Metric, take note that this should be an accumulative value if count is greater than 1 - * @param count a count of measured operations that produce the accumulative value - * @param addHostTag whether tag the Summary Metric with host information - * @param tags a Map of custom tags for this Summary Metric - */ - public static void summaryMetric(String name, double value, int count, boolean addHostTag, Map tags) { - if (AgentChecker.isExtensionAvailable()) { - if (addHostTag) { - tags = tags != null ? new HashMap(tags) : new HashMap(); //input tags might not be mutable, use clone - tags.put(HOST_TAG_KEY, "true"); - } - CustomMetricsCollector.INSTANCE.recordSummaryMetric(name, value, count, tags); - } - } - - /** - * Records a Count Metrics that increments by 1 - * - * Count metrics will be aggregated by the key- combination of metric name and tags, - * with a count (sum of count from each call with same key, default as 1). - * - * @param name a custom name for this Count Metric - * @param tags a Map of custom tags for Count Metric - */ - public static void incrementMetric(String name, Map tags) { - incrementMetric(name, 1, false, tags); - } - - /** - * Records a Count metrics that increments by the count parameter - * - * Count metrics will be aggregated by the key- combination of metric name and tags, - * with a count (sum of count from each call with same key). - * - * This is a more efficient method to record metrics with same key. - * - * For example, if a Count Metric is to be recorded for an operation performed repeatedly, - * then an accumulated count can be passed to this method once instead of calling this repeatedly for each operation. - * - * @param name a custom name for this Count Metric - * @param count a accumulative count of operations - * @param addHostTag whether tag the Count Metric with host information - * @param tags a Map of custom tags for Count Metric - */ - public static void incrementMetric(String name, int count, boolean addHostTag, Map tags) { - if (AgentChecker.isExtensionAvailable()) { - if (addHostTag) { - tags = tags != null ? new HashMap(tags) : new HashMap(); //input tags might not be mutable, use clone - tags.put(HOST_TAG_KEY, "true"); - } - CustomMetricsCollector.INSTANCE.recordIncrementMetrics(name, count, tags); - } - } -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/ProfileMethod.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/ProfileMethod.java deleted file mode 100644 index a373a25a..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/ProfileMethod.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.appoptics.api.ext; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** -* Profiles execution of a method call using annotation. Will be deprecated soon. Please use {@link LogMethod} instead -*/ -@Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) -@Retention(RetentionPolicy.RUNTIME) -public @interface ProfileMethod { - /** - * Sets the name of the profile reported - * @return - */ - String profileName(); - /** - * Flags whether method stack trace should be included in the event - * @return - */ - boolean backTrace() default false; - /** - * Flags whether method result will be converted to string and stored in the event - * @return - */ - boolean storeReturn() default false; -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/RUM.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/RUM.java deleted file mode 100644 index ca4ad0f4..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/RUM.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.appoptics.api.ext; - -import com.appoptics.api.ext.impl.IRumHandler; - -/** - * RUM (real user monitoring) is no longer supported in this SDK - * - * @author pluk - * - */ -@Deprecated -public class RUM { - private static final IRumHandler HANDLER = HandlerFactory.getRumHandler(); - - /** - * @deprecated Manual RUM is no longer supported - */ - public static String getHeader() { - return HANDLER.getHeader(); - } - - /** - * @deprecated Manual RUM is no longer supported - */ - public static String getFooter() { - return HANDLER.getFooter(); - } -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/Trace.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/Trace.java deleted file mode 100644 index 36eef945..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/Trace.java +++ /dev/null @@ -1,290 +0,0 @@ -package com.appoptics.api.ext; - -import java.util.Map; - -import com.appoptics.api.ext.impl.ITraceHandler; - -/** - * API for initiating traces and creating events, for use by non-web / background apps, etc. - *

- * A Trace is a unit of instrumented work, usually mapped to a web request. - *

- * Each trace consists of exactly one top span, more spans can be added below and each of those spans can contain - * multiple "spans" which are marked by exactly one entry and exit event and optionally info events in between. - * A span usually represents duration of an operation. - * - * @see Java Agent - Instrumentation SDK - */ -public class Trace { - private static final ITraceHandler HANDLER = HandlerFactory.getTraceHandler(); - - private Trace() { } // do not allow instantiation of this class - - /** - * Starts a trace, respecting the sampling rate. - *

- * To start a trace, you must call the startTrace method with your span name. This would typically be done when a new request enters your system. - * You can then add key / value pairs to the event containing information about the request. - *

- * Take note that this method does not report the event. The {@code TraceEvent} must be reported by invoking {@link TraceEvent#report()}. - *

- * Example: - *

-     * {@code
-     * TraceEvent event = Trace.startTrace("my_layer");
-     * event.addInfo("my_key", "my_value");
-     * event.report();
-     * }
-     * 
- * Note that startTrace automatically takes into account sampling settings - for testing, set tracingMode to always and - * sampleRate to 1000000. (See Configuring Java Instrumentation.) - * - * @param layer The name of the top span - * @return TraceEvent: an entry {@link TraceEvent} that can be populated with name/value pairs and reported. This event - * is the entry of the top extent. - */ - public static TraceEvent startTrace(String layer) { - return HANDLER.startTrace(layer); - } - - /** - * Continues a trace from external span, respecting the sampling rate. - *

- * If your application receive requests through a higher layer, such as an instrumented web server, - * you will receive an identifier for that trace. This identifier, the X-Trace ID, should be provided to the continueTrace - * method along with the span name. - * If you are instrumenting a standalone application, you will not need to use this call. Note that you should not use - * startTrace in this case. - *

- * Take note that this method does not report the event. The {@code TraceEvent} must be reported by invoking - * {@link TraceEvent#report()}. - *

- * Example: - *

-     * {@code
-     * TraceEvent event= Trace.continueTrace("my_layer", xTraceID);
-     * event.addInfo("my_key", "my_value");
-     * event.report();
-     * }
-     * 
- * - * @param layer The name of the span added below the existing span above - * @param inXTraceID XTrace ID from incoming/previous span - * @return TraceEvent: an entry {@link TraceEvent} that can be populated with name/value pairs and reported. This event - * is the entry of the extent added below the external span - */ - public static TraceEvent continueTrace(String layer, String inXTraceID) { - return HANDLER.continueTrace(layer, inXTraceID); - } - - - /** - * Ends a trace by creating an exit event and reporting it for the named span. Metadata is then cleared and the - * XTrace ID is returned. This is just a convenience method, as createExitEvent could also be used. - *

- * To end a trace, you must call the endTrace method with your span name. This would typically be done when your request - * is done processing. - * The X-Trace ID of the reported event is returned. If you are returning control to a higher span (such as an instrumented - * web server), - * you will need to return that ID using the appropriate method (such as an HTTP response header). - * If you are tracing a standalone application, it can be ignored. - *

- * Example: - *

-     * {@code
-     * String xTraceID = Trace.endTrace("my_layer");
-     * }
-     * 
- * - * @param layer The name of the trace's top span - * @return XTrace ID that can be returned to calling span - */ - public static String endTrace(String layer) { - return HANDLER.endTrace(layer); - } - - - /** - * Ends a trace by creating an exit event and reporting it for the named span. Metadata is then cleared and the - * XTrace ID is returned. This is just a convenience method, as createExitEvent could also be used. - *

- * To end a trace, you must call the endTrace method with your span name. This would typically be done when your - * request is done processing. - * The X-Trace ID of the reported event is returned. If you are returning control to a higher span (such as an - * instrumented web server), - * you will need to return that ID using the appropriate method (such as an HTTP response header). - * If you are tracing a standalone application, it can be ignored. - *

- * Example: - *

-     * {@code
-     * String xTraceID = Trace.endTrace("my_layer");
-     * }
-     * 
- * - * @param layer The name of the trace's top span - * @param info name/value pairs reported with exit event - * @return XTrace ID that can be returned to calling span - */ - public static String endTrace(String layer, Map info) { - return HANDLER.endTrace(layer, info); - } - - /** - * Ends a trace by creating an exit event and reporting it for the named span. Metadata is then cleared and the - * XTrace ID is returned. This is just a convenience method, as createExitEvent could also be used. - *

- * To end a trace, you must call the endTrace method with your span name. This would typically be done when your - * request is done processing. - * The X-Trace ID of the reported event is returned. If you are returning control to a higher span (such as an - * instrumented web server), - * you will need to return that ID using the appropriate method (such as an HTTP response header). - * If you are tracing a standalone application, it can be ignored. - *

- * Example: - *

-     * {@code
-     * String xTraceID = Trace.endTrace("my_layer");
-     * }
-     * 
- * @param layer The name of the trace's top span - * @param info name/value pairs reported with exit event - * @return XTrace ID that can be returned to calling span - */ - public static String endTrace(String layer, Object... info) { - return HANDLER.endTrace(layer, info); - } - - /** - * Creates an entry event of a new span with the given name. The entry event indicates the start of the newly created span. - * - * It is up to you, the application developer, to decide how to segment your application's modules and subsystems into spans. - * The event must be created, populated with name/value pairs. - *

- * Take note that this method does not report the event. The {@code TraceEvent} must be reported by invoking - * {@link TraceEvent#report()}. - *

- * Example: - *

-     * {@code
-     * TraceEvent event = Trace.createEntryEvent("some_other_layer");
-     * event.addInfo("name2","value2");
-     * event.report();
-     * }
-     * 
- * - * @param layer The name of the new span to be created - * @return TraceEvent: an entry {@link TraceEvent} that can be populated with name/value pairs and reported later - */ - public static TraceEvent createEntryEvent(String layer) { - return HANDLER.createEntryEvent(layer); - } - - /** - * Creates an exit event of the current span with the given name. The exit event indicates the end of the current span. - * - * It can be populated with name/value pairs just like the entry event. There should be a matching exit event for - * each entry. - *

- * Take note that this method does not report the event. The {@code TraceEvent} must be reported by invoking - * {@link TraceEvent#report()}. - *

- * Example: - *

-     * {@code
-     * TraceEvent event = Trace.createExitEvent("some_other_layer");
-     * event.addInfo("name1", "value1");
-     * event.addInfo("name2", "value2");
-     * event.report();
-     * }
-     * 
- * - * @param layer The name of the current span to be ended - * @return TraceEvent: an exit {@link TraceEvent} that can be populated with name/value pairs and reported later - */ - public static TraceEvent createExitEvent(String layer) { - return HANDLER.createExitEvent(layer); - } - - /** - * Creates an info event for the named span. You may need to report various information as your application executes, - * in between the entry and exit events of a particular span. - * This can be done using info events. Note that the span name of the info event can be null if you wish to inherit - * the current span. - *

- * Take note that this method does not report the event. The {@code TraceEvent} must be reported by invoking - * {@link TraceEvent#report()}. - *

- * Example: - *

-     * {@code
-     * TraceEvent event = Trace.createInfoEvent("some_other_layer");
-     * event.addInfo("something", "interesting");
-     * event.report();
-     * }
-     * 
- * @param layer The name of the span which the info event is created for. null if the current span name is to be used. - * @return TraceEvent: an info event that can be populated with name/value pairs and reported - */ - public static TraceEvent createInfoEvent(String layer) { - return HANDLER.createInfoEvent(layer); - } - - /** - * Creates and sends an error event for an exception (throwable), including a back trace. - *

- * Example: - *

-     * {@code
-     * try {
-     *     // your code that might throw an exception goes here ...
-     * } catch(YourException exception) {
-     *     Trace.logException(exception);
-     *     // the rest of your exception handler ...
-     * }
-     * }
-     * 
- * @param error throwable to be logged - */ - public static void logException(Throwable error) { - HANDLER.logException(error); - } - - /** - * Sets a transaction name to the current active trace, the transaction name will be reported along with the - * corresponding trace and metrics. - * - * This overrides the transaction name provided by out-of-the-box instrumentation. - * - * If multiple transaction names are set on the same trace, then the last one would be used. - * - * Take note that transaction name might be truncated with invalid characters replaced. - * - * Empty string and null are considered invalid transaction name values and will be ignored - * - * @param transactionName transaction name to be used, should not be null or empty string. - * @return true if there is an active trace and transaction name is not null or empty string. - */ - public static boolean setTransactionName(String transactionName) { - return HANDLER.setTransactionName(transactionName); - } - - /** - * Returns XTraceID associated with current context's Metadata as a hex string - * This is suitable for propagating to other spans (HTTP -> App servers, etc.) - * - * Take note that in order to correlate logs with traces, please use {@link Trace#getCurrentLogTraceID()} - * - * @return a full id for current context - */ - public static String getCurrentXTraceID() { - return HANDLER.getCurrentXTraceID(); - } - /** - * Returns a compact form of current context's Metadata suitable for logging purpose - * @return a compact id for current context - */ - public static String getCurrentLogTraceID() { - return HANDLER.getCurrentLogTraceId(); - } -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/TraceContext.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/TraceContext.java deleted file mode 100644 index 2363c2b5..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/TraceContext.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.appoptics.api.ext; - -import com.appoptics.api.ext.impl.ITraceContextHandler; - -/** - * Allows explicit control on tracing context, which is used to manage the linkage of {@code TraceEvent}s. - *

- * This determines the current state/context of tracing, when {@code TraceEvent}s are reported, the context would be updated. - * The context then provides references such that new events created can link and point to previous events to form extents/trace. - *

- * Under most circumstances, context is set and managed automatically. - * This explicit control might only be necessary for trace that crosses multiple threads with top extent thread not being the - * parent thread of all the other events. - *

- * Example: - *

- * {@code
- * TraceContext currentContext = TraceContext.getDefault();
- * threadPoolExecutor.submit(new MyCallable(currentContext));
- * ...
- * private class MyCallable {
- *     private TraceContext traceContext;
- *     private MyCallable(TraceContext context) {
- *         this.traceContext = context;
- *     }
- *
- *     public call() {
- *         if (traceContext != null) {
- *             traceContext.setAsDefault();
- *             TraceEvent entryEvent = Trace.createEntryEvent("ThreadedJob");
- *             ...
- *         }
- *     }
- *
- * }
- *
- * }
- * 
- * - * @see com.tracelytics.joboe.Context - */ -public abstract class TraceContext { - private static final ITraceContextHandler HANDLER = HandlerFactory.getTraceContextHandler(); - - /** - * Returns the Context currently associated with this thread. - * - * Note that this context is Clone of the context: modifications will NOT affect the current - * thread unless setAsDefault is called. - * - * @return ITraceContextHandler - */ - public static TraceContext getDefault() { - return HANDLER.getDefault(); - } - - /** - * Resets the current thread's context - */ - public static void clearDefault() { - HANDLER.clearDefault(); - } - - /** - * Sets the current thread's context to this context - */ - public abstract void setAsDefault(); - - public static boolean isSampled(String xTraceID) { - return HANDLER.isSampled(xTraceID); - } -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/TraceEvent.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/TraceEvent.java deleted file mode 100644 index d0577123..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/TraceEvent.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.appoptics.api.ext; - -import java.util.Map; - -/** - * Interface for trace event which is the building block of traces. Each {@link TraceEvent} has its own type such as "entry", - * "exit", "info" and "error", which is determined when the event was created by methods in {@link Trace}. To add additional - * information key/value - * - * @see Java Agent - Instrumentation SDK - */ -public interface TraceEvent { - - /** - * Adds a key/value pair to an event - * @param key key - * @param value value - */ - void addInfo(String key, Object value); - - /** - * Adds key/value pairs to the event - * @param infoMap map of key/value pairs - */ - void addInfo(Map infoMap); - - /** - * Add all key/value pairs to event. This assumes that info contains alternating key/value pairs (String, Object). - * @param info - */ - void addInfo(Object... info); - - - /** - * Marks this event as asynchronous. - * While instrumenting your code, you may want to report events from background / child threads and associate them - * with the parent thread that spawned them. (This assumes that a trace was already started in the parent thread.) - * You must mark these events as "async" by calling this method on the entry event associated with that background thread. - *

- * You should then call Trace.endTrace() when that thread is done processing. - *

-     * {@code
-     * TraceEvent event = Trace.createEntryEvent(spanName);
-     * event.setAsync();
-     * event.report();
-     * // Your processing ...
-     * Trace.endTrace();
-     * }
-     * 
- */ - void setAsync(); - - /** - * Adds an additional edge to this event - */ - void addEdge(String xTraceID); - - /** - * Reports the event to the collector. - */ - void report(); - - /** - * To report the back traces of the certain time frame of the application. This adds the back trace of the current thread to the event. - *
-     * {@code
-     * TraceEvent event = Trace.createInfoEvent("some_other_layer");
-     * event.addBackTrace();
-     * event.report();
-     * }
-     * 
- */ - void addBackTrace(); -} - diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/IRumHandler.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/IRumHandler.java deleted file mode 100644 index 84a34d62..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/IRumHandler.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.appoptics.api.ext.impl; - -public interface IRumHandler { - String getHeader(); - String getFooter(); -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/ITraceContextHandler.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/ITraceContextHandler.java deleted file mode 100644 index 5f68d2c0..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/ITraceContextHandler.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.appoptics.api.ext.impl; - -import com.appoptics.api.ext.TraceContext; - -public interface ITraceContextHandler { - /** - * Returns the Context currently associated with this thread. - * - * Note that this context is a copy of the TLS context: modifications will NOT affect the current - * thread unless setAsDefault is called. - * - * @return ITraceContextHandler - */ - TraceContext getDefault(); - - /** - * Resets the current thread's context (updates TLS) - */ - void clearDefault(); - - /** - * Returns whether the xTraceID is from a sampled request - * @param xTraceID - * @return - */ - boolean isSampled(String xTraceID); -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/ITraceHandler.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/ITraceHandler.java deleted file mode 100644 index 172a7841..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/ITraceHandler.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.appoptics.api.ext.impl; - -import java.util.Map; - -import com.appoptics.api.ext.TraceEvent; - -public interface ITraceHandler { - /** - * Starts a trace, respecting the sampling rate and trace mode settings. - * - * @return TraceEvent: an entry event that can be populated with name/value pairs and reported - */ - TraceEvent startTrace(String layer); - - /** - * Continues a trace from external span, respecting the sampling rate and trace mode settings. - * - * @param inXTraceID XTrace ID from incoming/previous span - * @return TraceEvent: an entry event that can be populated with name/value pairs and reported - */ - TraceEvent continueTrace(String layer, String inXTraceID); - - - /** - * End trace: Creates an exit event and reports it for the named span. Metadata is then cleared and the - * XTrace ID is returned. This is just a convenience method, as createExitEvent could also be - * used. - * - * @param layer - * @return XTrace ID that can be returned to calling span - */ - String endTrace(String layer); - - - /** - * End trace: Creates an exit event and reports it for the named span. Metadata is then cleared and the - * XTrace ID is returned. This is just a convenience method, as createExitEvent could also be - * used. - * - * @param layer - * @param info name/value pairs reported with exit event - * @return XTrace ID that can be returned to calling span - */ - String endTrace(String layer, Map info); - - /** - * End trace: Creates an exit event and reports it for the named span. Metadata is then cleared and the - * XTrace ID is returned. This is just a convenience method, as createExitEvent could also be - * used. - * - * @param layer - * @param info name/value pairs reported with exit event - * @return XTrace ID that can be returned to calling span - */ - String endTrace(String layer, Object... info); - - /** - * Creates an entry event for the named span - * @param layer - * @return TraceEvent: an entry event that can be populated with name/value pairs and reported - */ - TraceEvent createEntryEvent(String layer); - - /** - * Creates an exit event for the named span - * @param layer - * @return TraceEvent: an exit event that can be populated with name/value pairs and reported - */ - TraceEvent createExitEvent(String layer); - - /** - * Creates an info event for the named span - * @param layer - * @return TraceEvent: an info event that can be populated with name/value pairs and reported - */ - TraceEvent createInfoEvent(String layer); - - /** - * Reports an error: creates and sends an error event for an exception (throwable), including a back trace. - * - * @param error throwable to be logged - */ - void logException(Throwable error); - - boolean setTransactionName(String transactionName); - - /** - * Returns XTraceID associated with current context's Metadata as a hex string - * This is suitable for propagating to other spans (HTTP -> App servers, etc.) - */ - String getCurrentXTraceID(); - - /** - * Returns a compact form of current context's Metadata suitable for logging purpose - * @return - */ - String getCurrentLogTraceId(); -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/RUMHandlerNoOp.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/RUMHandlerNoOp.java deleted file mode 100644 index a47ba975..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/RUMHandlerNoOp.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.appoptics.api.ext.impl; - -public class RUMHandlerNoOp implements IRumHandler { - - public String getHeader() { - return ""; - } - - public String getFooter() { - return ""; - } - -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/SdkUtil.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/SdkUtil.java deleted file mode 100644 index 7a1751c0..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/SdkUtil.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.appoptics.api.ext.impl; - -import java.util.logging.Logger; - -public class SdkUtil { - private static final Logger LOGGER = Logger.getLogger(SdkUtil.class.getName()); - - private SdkUtil() { - } -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/TraceContextHandler.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/TraceContextHandler.java deleted file mode 100644 index bb09d407..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/TraceContextHandler.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.appoptics.api.ext.impl; - -import com.appoptics.api.ext.TraceContext; -import com.tracelytics.joboe.Metadata; -import com.tracelytics.joboe.OboeException; -import com.tracelytics.logging.Logger; -import com.tracelytics.logging.LoggerFactory; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.context.Scope; - -public class TraceContextHandler implements ITraceContextHandler { - private final Logger logger = LoggerFactory.getLogger(); - private Scope currentScope; - /** - * Returns the Context currently associated with this thread. - * - * Note that this context is a copy of the TLS context: modifications will NOT affect the current - * thread unless setAsDefault is called. - * - * @return ITraceContextHandler - */ - public TraceContext getDefault() { - return new TraceContextConcrete(Span.current()); - } - - /** - * Resets the current thread's context (updates TLS) - */ - public void clearDefault() { - if (currentScope != null) { - currentScope.close(); - currentScope = null; - } - } - - @Override - public boolean isSampled(String xTraceID) { - try { - return new Metadata(xTraceID).isSampled(); - } - catch (OboeException e) { - logger.warn("X-Trace ID [" + xTraceID + "] is not valid"); - return false; - } - } - - - class TraceContextConcrete extends TraceContext { - private final Span span; - - /** - * Constructor: Currently, the only way public way to obtain a ITraceContextHandler is through getDefault - */ - protected TraceContextConcrete(Span span) { - this.span = span; - } - - @Override - /** - * Sets the current thread's context to this context (updates TLS) - * - * Take note that if current thread does not invoke {@link com.appoptics.api.ext.Trace#endTrace} to end the trace, - * then it is encouraged to invoke {@link TraceContext#clearDefault()} to clear up the context after the processing is done on current thread. - */ - public void setAsDefault() { - if (span != null) { - currentScope = io.opentelemetry.context.Context.current().with(span).makeCurrent(); - } - } - } -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/TraceContextHandlerNoOp.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/TraceContextHandlerNoOp.java deleted file mode 100644 index 8d824f04..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/TraceContextHandlerNoOp.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.appoptics.api.ext.impl; - -import com.appoptics.api.ext.TraceContext; - -public class TraceContextHandlerNoOp implements ITraceContextHandler { - - public TraceContext getDefault() { - return new TraceContextNoOp(); - } - - public void clearDefault() { - } - - @Override - public boolean isSampled(String xTraceID) { - return false; - } - - static class TraceContextNoOp extends TraceContext { - /** - * Sets the current thread's context to this context (updates TLS) - */ - public void setAsDefault() { - //Do nothing - } - } -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/TraceHandler.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/TraceHandler.java deleted file mode 100644 index 696b297c..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/TraceHandler.java +++ /dev/null @@ -1,262 +0,0 @@ -package com.appoptics.api.ext.impl; - -import com.appoptics.api.ext.TraceEvent; -import com.appoptics.api.ext.model.NoOpEvent; -import com.appoptics.api.ext.model.OpenTelemetryTraceEvent; -import com.appoptics.opentelemetry.core.RootSpan; -import com.appoptics.opentelemetry.core.Util; -import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanBuilder; -import io.opentelemetry.api.trace.Tracer; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.ContextKey; -import io.opentelemetry.context.Scope; -import io.opentelemetry.context.propagation.TextMapGetter; - -import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Map; -import java.util.WeakHashMap; -import java.util.logging.Logger; - -public class TraceHandler implements ITraceHandler { - private final Logger logger = Logger.getLogger(TraceHandler.class.getName()); - private static final ContextKey AO_SDK_SPAN_ID_CONTEXT_KEY = ContextKey.named("ao.sdk.spanId"); - private static final WeakHashMap SCOPE_LOOKUP = new WeakHashMap(); - private static final WeakHashMap REMOTE_SCOPE_LOOKUP = new WeakHashMap(); - - private static final Tracer TRACER; - - static { - TRACER = GlobalOpenTelemetry.getTracer("appoptics-sdk"); - } - - /** - * {@inheritDoc} - */ - public TraceEvent startTrace(String layer) { - return startOrContinueTrace(layer, null); - } - - /** - * {@inheritDoc} - */ - public TraceEvent continueTrace(String layer, String inXTraceID) { - return startOrContinueTrace(layer, inXTraceID); - } - - /** - * {@inheritDoc} - */ - public String endTrace(String layer) { - return endTrace(layer, (Map) null); - } - - - /** - * {@inheritDoc} - */ - public String endTrace(String layer, Map info) { - final Span currentSpan = Span.current(); - if (currentSpan == null) { - logger.warning("Attempt to end a Trace but there's no active span. Ignoring the operation"); - return ""; - } - - if (!validateSpanExit(currentSpan)) { - return ""; - } - - if (info != null) { - Util.setSpanAttributes(currentSpan, info); - } - currentSpan.end(); - - final Scope scope = SCOPE_LOOKUP.remove(currentSpan); - if (scope != null) { - scope.close(); - } - - final Scope remoteScope = REMOTE_SCOPE_LOOKUP.remove(Span.current()); - if (remoteScope != null) { - remoteScope.close(); - } - - return Util.buildSpanExitMetadata(currentSpan.getSpanContext()).toHexString(); - } - - private boolean validateSpanExit(Span currentSpan) { - // check if span is the expected SDK span - final String expectedSpanId = Context.current().get(AO_SDK_SPAN_ID_CONTEXT_KEY); - if (expectedSpanId == null) { - logger.warning("Attempt to end a SDK span but the active span was not created by SDK : " + - currentSpan.getSpanContext()); - return false; - } - else if (!expectedSpanId.equals(currentSpan.getSpanContext().getSpanId())) { - logger.warning("Attempt to end a SDK span but the active span has span ID " + - currentSpan.getSpanContext().getSpanId() + " which is not the same as the expected span ID " + - expectedSpanId); - return false; - } - else { - return true; - } - } - - /** - * {@inheritDoc} - */ - public String endTrace(String layer, Object... info) { - return endTrace(layer, Util.keyValuePairsToMap(info)); - } - - /** - * {@inheritDoc} - */ - public TraceEvent createEntryEvent(String layer) { - //to adhere to the original behavior, which metadata is captured when event is created - final Span currentSpan = Span.current(); - return new OpenTelemetryTraceEvent( - event -> { - try (Scope parentScope = currentSpan.makeCurrent()) { - final SpanBuilder spanBuilder = TRACER.spanBuilder(event.getOperationName()); - Util.setSpanAttributes(spanBuilder, event.getKeyValues()); - //TODO https://github.com/open-telemetry/opentelemetry-java/blob/main/QUICKSTART.md#create-spans-with-links, - // link is not exactly the same as edge. Might need to change this - for (String edge : event.getEdges()) { - spanBuilder.addLink(Util.toSpanContext(edge, false)); - } - final Span span = spanBuilder.startSpan(); - Context context = span.storeInContext(Context.current()); - context = context.with(AO_SDK_SPAN_ID_CONTEXT_KEY, span.getSpanContext().getSpanId()); - final Scope scope = context.makeCurrent(); - SCOPE_LOOKUP.put(span, scope); - } - }, - layer); - } - - /** - * {@inheritDoc} - */ - public TraceEvent createExitEvent(String layer) { - //to adhere to the original behavior, which metadata is captured when event is created - final Span span = Span.current(); - if (!validateSpanExit(span)) { - return new NoOpEvent(); - } - else { - return new OpenTelemetryTraceEvent( - event -> { - Util.setSpanAttributes(span, event.getKeyValues()); - span.end(); - final Scope scope = SCOPE_LOOKUP.remove(span); - if (scope != null) { - scope.close(); - } - }, - layer); - } - } - - /** - * {@inheritDoc} - */ - public TraceEvent createInfoEvent(String layer) { - //to adhere to the original behavior, which metadata is captured when event is created - final Span span = Span.current(); - return new OpenTelemetryTraceEvent( - event -> { - Util.setSpanAttributes(span, event.getKeyValues()); - }, - layer); - } - - - /** - * {@inheritDoc} - */ - public void logException(Throwable error) { - final Span span = Span.current(); - if (span.getSpanContext().isValid()) { - span.recordException(error); - } - } - - /** - * {@inheritDoc} - */ - public String getCurrentXTraceID() { - return Util.w3CContextToHexString(Span.current().getSpanContext()); - } - - @Override - public String getCurrentLogTraceId() { - return Util.buildMetadata(Span.current().getSpanContext()).getCompactTraceId(); - } - - private static final String TRACE_STATE_APPOPTICS_KEY = "appoptics"; - - private TraceEvent startOrContinueTrace(String layer, String inXTraceID) { - return new OpenTelemetryTraceEvent( - event -> { - Scope remoteScope = null; - if (inXTraceID != null) { - final Context extractedContext = GlobalOpenTelemetry.getPropagators().getTextMapPropagator() - .extract(Context.current(), Collections.singletonMap(TRACE_STATE_APPOPTICS_KEY, inXTraceID), - new TextMapGetter>() { - @Override - public Iterable keys(Map carrier) { - return new ArrayList(carrier.keySet()); - } - - @Nullable - @Override - public String get(@Nullable Map carrier, String key) { - return carrier != null ? carrier.get(key) : null; - } - }); - remoteScope = extractedContext.makeCurrent(); - } - - final SpanBuilder spanBuilder = TRACER.spanBuilder(event.getOperationName()); - Util.setSpanAttributes(spanBuilder, event.getKeyValues()); - //TODO https://github.com/open-telemetry/opentelemetry-java/blob/main/QUICKSTART.md#create-spans-with-links, - // link is not exactly the same as edge. Might need to change this - for (String edge : event.getEdges()) { - spanBuilder.addLink(Util.toSpanContext(edge, false)); - } - final Span span = spanBuilder.startSpan(); - - Context context = span.storeInContext(Context.current()); - context = context.with(AO_SDK_SPAN_ID_CONTEXT_KEY, span.getSpanContext().getSpanId()); - // this does not work as all child span (even made by non sdk call, will have this key - //context = Baggage.current().toBuilder().put(AO_SDK_KEY, Boolean.toString(true)).build().storeInContext(context); - SCOPE_LOOKUP.put(span, context.makeCurrent()); - if (remoteScope != null) { - REMOTE_SCOPE_LOOKUP.put(span, remoteScope); - } - }, layer); - } - - public boolean setTransactionName(String transactionName) { - if (transactionName == null || "".equals(transactionName)) { - return false; - } - if (!Span.current().getSpanContext().isValid()) { - return false; - } - - final Span rootSpan = RootSpan.fromTraceId(Span.current().getSpanContext().getTraceId()); - if (rootSpan == null) { - return false; - } - - Util.setSpanAttributes(rootSpan, Collections.singletonMap("TransactionName", transactionName)); - - return true; - } -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/TraceHandlerNoOp.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/TraceHandlerNoOp.java deleted file mode 100644 index cccbcef5..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/impl/TraceHandlerNoOp.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.appoptics.api.ext.impl; - -import java.util.Map; - -import com.appoptics.api.ext.TraceEvent; -import com.appoptics.api.ext.model.NoOpEvent; - -/** - * API for initiating traces and creating events, for use by non-web / background apps, etc. - */ -public class TraceHandlerNoOp implements ITraceHandler { - public TraceEvent startTrace(String layer) { - return NO_OP; - } - - public TraceEvent continueTrace(String layer, String inXTraceID) { - return NO_OP; - } - - public String endTrace(String layer) { - return ""; - } - - public String endTrace(String layer, Map info) { - return ""; - } - - public String endTrace(String layer, Object... info) { - return ""; - } - - public TraceEvent createEntryEvent(String layer) { - return NO_OP; - } - - public TraceEvent createExitEvent(String layer) { - return NO_OP; - } - - public TraceEvent createInfoEvent(String layer) { - return NO_OP; - } - - public void logException(Throwable error) { - } - - public String getCurrentXTraceID() { - return ""; - } - - @Override - public String getCurrentLogTraceId() { - return ""; - } - - private static final NoOpEvent NO_OP = new NoOpEvent(); - - public boolean setTransactionName(String transactionName) { - if (transactionName == null || "".equals(transactionName)) { - return false; - } - - return true; - } -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/model/NoOpEvent.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/model/NoOpEvent.java deleted file mode 100644 index 49f7dd2a..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/model/NoOpEvent.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.appoptics.api.ext.model; - -import java.util.Map; - -import com.appoptics.api.ext.TraceEvent; - -public class NoOpEvent implements TraceEvent { - public void addInfo(String key, Object value) { /* NoOp */ } - public void addInfo(Map infoMap) { /* NoOp */ } - public void addInfo(Object... info) { /* NoOp */ } - public void setAsync() { /* NoOp */ } - public void addEdge(String xTraceID) { /* NoOp */ } - public void report() { /*NoOp */ } - public void addBackTrace() { /*NoOp */ } -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/model/OpenTelemetryEventListener.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/model/OpenTelemetryEventListener.java deleted file mode 100644 index ec9a7db0..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/model/OpenTelemetryEventListener.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.appoptics.api.ext.model; - - -public interface OpenTelemetryEventListener { - void onReport(OpenTelemetryTraceEvent event); -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/model/OpenTelemetryTraceEvent.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/model/OpenTelemetryTraceEvent.java deleted file mode 100644 index 9d300216..00000000 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/model/OpenTelemetryTraceEvent.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.appoptics.api.ext.model; - -import com.appoptics.api.ext.TraceEvent; -import com.tracelytics.util.BackTraceUtil; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Logger; - -public class OpenTelemetryTraceEvent implements TraceEvent { - private final OpenTelemetryEventListener listener; - private final String operationName; - private final Map kvs = new ConcurrentHashMap(); - private final List edges = new ArrayList(); - private Logger logger = Logger.getLogger(OpenTelemetryTraceEvent.class.getName()); - - public OpenTelemetryTraceEvent(OpenTelemetryEventListener listener, String operationName) { - this.listener = listener; - this.operationName = operationName; - } - - @Override - public final void report() { - listener.onReport(this); - } - - public String getOperationName() { - return operationName; - } - - public void addInfo(String key, Object value) { - kvs.put(key, value); - } - - public void addInfo(Map infoMap) { - kvs.putAll(infoMap); - } - - public void addInfo(Object... info) { - if (info.length % 2 != 0) { - logger.warning("Expect even number of arguments for addInfo(Object...) call but found " + info.length); - } - for (int i = 0; i < info.length / 2; i++) { - final int keyIndex = i * 2; - final int valueIndex = keyIndex + 1; - if (!(info[keyIndex] instanceof String)) { - logger.warning( - "Expect String argument for odd n-th argument for addInfo(Object...) call but found " + - (info[keyIndex] != null ? info[keyIndex].getClass().getName() : "null")); - addInfo((String) info[keyIndex], info[valueIndex]); - } - } - } - - public void setAsync() { - kvs.put(com.tracelytics.joboe.Constants.XTR_ASYNC_KEY, true); - } - - public void addEdge(String xTraceID) { - edges.add(xTraceID); - } - - public void addBackTrace() { - kvs.put("Backtrace", BackTraceUtil.backTraceToString(BackTraceUtil.getBackTrace(1))); - } - - public Map getKeyValues() { - return kvs; - } - - public List getEdges() { - return edges; - } -} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/package-info.java b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/package-info.java index 1d791a45..a04149ab 100644 --- a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/package-info.java +++ b/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/package-info.java @@ -1,33 +1,5 @@ /** - * Enables custom instrumentation by providing SDK to initiate traces, send span entry, info, and exit events, and report errors. - *

- * There are 2 ways to insert custom instrumentation: - *

    - *
  1. - * Apply annotation to methods {@link com.appoptics.api.ext.LogMethod} - *
  2. - *
  3. - * Create and report traces/events explicitly using {@link com.appoptics.api.ext.Trace} and {@link com.appoptics.api.ext.TraceEvent} - *
  4. - *
- *

- * The SDK is based around event generation and reporting. Events are created, populated with key/value pairs and reported. - *

- * The SDK jar file appoptics-sdk.jar can be located in the agent installation directory and copied into your build project. - * It can also be downloaded from https://files.appoptics.com/java/latest/ - * or be included as a Maven Dependency with group ID com.appoptics.agent.java and artifact ID appoptics-sdk - *

- * The SDK jar file appoptics-sdk.jar must be used during the development and building phases. - * Please import or reference classes/interfaces from package {@code com.appoptics.api.ext} only and ensure the SDK jar - * file/classes is accessible in your runtime classpath/environment. - * Please take note that the java agent jar file appoptics-agent.jar should only be used via the javaagent JVM argument and - * not be included elsewhere in your runtime classpath/environment or you may encounter classloader errors. - *

- * All publicly accessible SDK classes are in this {@code com.appoptics.api.ext} package. - * Your application code should not import classes outside of this package. Even if they are marked as public, classes and - * interfaces outside of {@code com.appoptics.api.ext} are subject to change without notice. - * - * @see Java Agent - Instrumentation SDK + * The APIs offered by the Solarwinds Java agent. */ package com.appoptics.api.ext; diff --git a/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/BaseTest.java b/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/BaseTest.java deleted file mode 100644 index c2a731ee..00000000 --- a/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/BaseTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.appoptics.api.ext; - -import com.tracelytics.joboe.Context; -//import com.tracelytics.joboe.StartupManager; -import com.tracelytics.joboe.TestReporter; -import com.tracelytics.joboe.settings.TestSettingsReader; -import com.tracelytics.joboe.span.impl.ScopeManager; - -import junit.framework.TestCase; - -public abstract class BaseTest extends TestCase { - protected final TestReporter reporter; - protected final TestSettingsReader reader; - - protected BaseTest() throws Exception { - // StartupManager.flagTestingMode(); - - AgentChecker.setIsExtensionAvailable(true); //set to true for testing - //TestingEnv testingEnv = (TestingEnv) StartupManager.isAgentReady().get(10, TimeUnit.SECONDS); -// reporter = testingEnv.getTracingReporter(); -// reader = testingEnv.getSettingsReader(); - //TODO - reporter = null; - reader = null; - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - reader.reset(); - reporter.reset(); - Context.clearMetadata(); - ScopeManager.INSTANCE.removeAllScopes(); - super.tearDown(); - } -} diff --git a/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/MetricsTest.java b/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/MetricsTest.java deleted file mode 100644 index 4a3b6963..00000000 --- a/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/MetricsTest.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.appoptics.api.ext; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.junit.After; - -import com.appoptics.api.ext.Metrics; -import com.tracelytics.monitor.metrics.CustomMetricsCollector; - -public class MetricsTest extends BaseTest { - public MetricsTest() throws Exception { - super(); - } - -// @BeforeClass -// public void setupClass() throws OboeSettingsException { -// originalSettings = reader.getSettings(); -// Map quickRefreshSettings = Collections.singletonMap(SettingsFetcher.DEFAULT_LAYER, new TestSettingsReader.SettingsMockup((short) 0, 0, Collections.singletonMap(SettingsArg.METRIC_FLUSH_INTERVAL.getKey(), 2))); -// reader.setAll(quickRefreshSettings); -// ((SimpleSettingsFetcher) SettingsManager.getFetcher()).fetch(); //force interval update -// } -// -// @AfterClass -// public void tearDownClass() { -// reader.setAll(originalSettings); -// ((SimpleSettingsFetcher) SettingsManager.getFetcher()).fetch(); //force interval update -// } - - - @After - @Override - protected void tearDown() throws Exception { - CustomMetricsCollector.INSTANCE.reset(); - super.tearDown(); - } - - - public void testIncrementMetrics() throws Exception { - Metrics.incrementMetric("test-1", null); - Metrics.incrementMetric("test-1", 2, false, null); - - Metrics.incrementMetric("test-1", Collections.singletonMap("key-1", "1")); - Metrics.incrementMetric("test-1", 2, false, Collections.singletonMap("key-1", "1")); - Metrics.incrementMetric("test-1", 3, false, Collections.singletonMap("key-1", "1")); - - Metrics.incrementMetric("test-1", 2, false, Collections.singletonMap("key-1", "2")); - - Map tags = new HashMap(); - tags.put("key-1", "1"); - tags.put("key-2", "2"); - Metrics.incrementMetric("test-1", 3, false, tags); - - Metrics.incrementMetric("test-1", 4, true, tags); - - - Metrics.incrementMetric("test-2", null); - - CustomMetricsCollector collector = CustomMetricsCollector.INSTANCE; - assertEquals(3, (long) collector.getCount("test-1", null)); - assertEquals(6, (long) collector.getCount("test-1", Collections.singletonMap("key-1", "1"))); - assertEquals(2, (long) collector.getCount("test-1", Collections.singletonMap("key-1", "2"))); - assertEquals(3, (long) collector.getCount("test-1", tags)); - - Map tagsWithHost = new HashMap(tags); - tagsWithHost.put(Metrics.HOST_TAG_KEY, "true"); - assertEquals(4, (long) collector.getCount("test-1", tagsWithHost)); - - assertEquals(1, (long) collector.getCount("test-2", null)); - } - - public void testSummaryMetrics() throws Exception { - Metrics.summaryMetric("test-1", 1, null); - Metrics.summaryMetric("test-1", 1, 2, false, null); - - Metrics.summaryMetric("test-1", 1, Collections.singletonMap("key-1", "1")); - Metrics.summaryMetric("test-1", 1, 2, false, Collections.singletonMap("key-1", "1")); - Metrics.summaryMetric("test-1", 1, 3, false, Collections.singletonMap("key-1", "1")); - - Metrics.summaryMetric("test-1", 1, 2, false, Collections.singletonMap("key-1", "2")); - - Map tags = new HashMap(); - tags.put("key-1", "1"); - tags.put("key-2", "2"); - Metrics.summaryMetric("test-1", 3, tags); - Metrics.summaryMetric("test-1", 5.5, 2, true, tags); - - Metrics.summaryMetric("test-2", 4, null); - - CustomMetricsCollector collector = CustomMetricsCollector.INSTANCE; - assertEquals(2.0, collector.getSum("test-1", null)); - assertEquals(3, (long) collector.getCount("test-1", null)); - assertEquals(3.0, collector.getSum("test-1", Collections.singletonMap("key-1", "1"))); - assertEquals(6, (long) collector.getCount("test-1", Collections.singletonMap("key-1", "1"))); - assertEquals(1.0, collector.getSum("test-1", Collections.singletonMap("key-1", "2"))); - assertEquals(2, (long) collector.getCount("test-1", Collections.singletonMap("key-1", "2"))); - assertEquals(3.0, collector.getSum("test-1", tags)); - assertEquals(1, (long) collector.getCount("test-1", tags)); - Map tagsWithHost = new HashMap(tags); - tagsWithHost.put(Metrics.HOST_TAG_KEY, "true"); - assertEquals(5.5, collector.getSum("test-1", tagsWithHost)); - assertEquals(2, (long) collector.getCount("test-1", tagsWithHost)); - assertEquals(4.0, collector.getSum("test-2", null)); - assertEquals(1, (long) collector.getCount("test-2", null)); - } -} diff --git a/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/TraceContextTest.java b/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/TraceContextTest.java deleted file mode 100644 index 32d8ed1c..00000000 --- a/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/TraceContextTest.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.appoptics.api.ext; - -import com.appoptics.api.ext.Trace; -import com.appoptics.api.ext.TraceContext; -import com.tracelytics.joboe.Context; -import com.tracelytics.joboe.OboeException; -import com.tracelytics.joboe.TracingMode; -import com.tracelytics.joboe.settings.TestSettingsReader.SettingsMockupBuilder; - -public class TraceContextTest extends BaseTest { - - public TraceContextTest() throws Exception { - super(); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - - } - - public void testEmpty() throws OboeException { - TraceContext emptyContext = TraceContext.getDefault(); //not valid, not sampled - - Context.getMetadata().randomize(); //randomize current context to a valid context - - emptyContext.setAsDefault(); //now set the emptyContext back - assertFalse(Context.getMetadata().isValid()); //empty context is not valid - assertFalse(Context.getMetadata().isSampled()); //empty context is not sampled - - assertFalse(TraceContext.isSampled(Trace.getCurrentXTraceID())); - } - - public void testSampled() { - reader.put(new SettingsMockupBuilder().withFlags(TracingMode.ALWAYS).withSampleRate(1000000).build()); //ALWAYS sample rate = 100% - Trace.startTrace("sampled").report(); - TraceContext sampledContext = TraceContext.getDefault(); - - TraceContext.clearDefault(); //clear the current context - assertFalse(Context.getMetadata().isValid()); - assertFalse(Context.getMetadata().isSampled()); - - sampledContext.setAsDefault(); //now set back to sampledContext - assertTrue(Context.getMetadata().isValid()); - assertTrue(Context.getMetadata().isSampled()); - - assertTrue(TraceContext.isSampled(Trace.getCurrentXTraceID())); - } - - - - public void testNotSampled() throws OboeException { - reader.put(new SettingsMockupBuilder().withFlags(TracingMode.NEVER).withSampleRate(0).build()); //NEVER sample rate = 0% - Trace.startTrace("not-sampled").report(); - TraceContext notSampledContext = TraceContext.getDefault(); - - TraceContext.clearDefault(); //clear the current context - assertFalse(Context.getMetadata().isValid()); - assertFalse(Context.getMetadata().isSampled()); - - notSampledContext.setAsDefault(); //now set back to notSampledContext - assertTrue(Context.getMetadata().isValid()); //it is valid as it has gone through the sampling deicison - assertFalse(Context.getMetadata().isSampled()); //it is not sampled - - assertFalse(TraceContext.isSampled(Trace.getCurrentXTraceID())); - } -} diff --git a/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/TraceEventTest.java b/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/TraceEventTest.java deleted file mode 100644 index bb9d20b4..00000000 --- a/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/TraceEventTest.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.appoptics.api.ext; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import com.appoptics.api.ext.Trace; -import com.appoptics.api.ext.TraceEvent; -import com.appoptics.api.ext.model.NoOpEvent; -import com.tracelytics.ext.ebson.MultiValList; -import com.tracelytics.joboe.Constants; -import com.tracelytics.joboe.Context; -import com.tracelytics.joboe.Metadata; -import com.tracelytics.joboe.OboeException; -import com.tracelytics.joboe.TracingMode; -import com.tracelytics.joboe.TestReporter.DeserializedEvent; -import com.tracelytics.joboe.settings.SettingsManager; -import com.tracelytics.joboe.settings.SimpleSettingsFetcher; -import com.tracelytics.joboe.settings.TestSettingsReader.SettingsMockup; -import com.tracelytics.joboe.settings.TestSettingsReader.SettingsMockupBuilder; - -public class TraceEventTest extends BaseTest { - - public TraceEventTest() throws Exception { - super(); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - - public void testSampledEvent() throws OboeException { - reader.put(new SettingsMockupBuilder().withFlags(TracingMode.ALWAYS).withSampleRate(1000000).build()); //ALWAYS sample rate = 100% - Trace.startTrace("sampled").report(); - Metadata startContext = Context.getMetadata(); - String startEdge = startContext.opHexString(); - reporter.reset(); - - TraceEvent tracedEvent; - tracedEvent = Trace.createEntryEvent("entry-event"); - tracedEvent.addBackTrace(); - - Metadata generatedContext = new Metadata(startContext); //create a clone so next operation would not modify the existing metadata - generatedContext.randomizeOpID(); - - tracedEvent.addEdge(generatedContext.toHexString()); - tracedEvent.addInfo(Collections.singletonMap("key1", 1)); - tracedEvent.addInfo("key2", "test", "key3", 3.0); - tracedEvent.addInfo("key4", 4L); - tracedEvent.setAsync(); - tracedEvent.report(); - - List sentEvents = reporter.getSentEvents(); - assertEquals(1, sentEvents.size()); - - Map sentEntries = sentEvents.get(0).getSentEntries(); - assertEquals("entry", sentEntries.get("Label")); - assertEquals("entry-event", sentEntries.get("Layer")); - assertTrue(sentEntries.containsKey("Backtrace")); - MultiValList expectedEdges = new MultiValList(); - expectedEdges.add(startEdge); - expectedEdges.add(generatedContext.opHexString()); - assertEquals(expectedEdges, sentEntries.get(Constants.XTR_EDGE_KEY)); - assertEquals(1, sentEntries.get("key1")); - assertEquals("test", sentEntries.get("key2")); - assertEquals(3.0, sentEntries.get("key3")); - assertEquals(4L, sentEntries.get("key4")); - assertEquals(true, sentEntries.get(Constants.XTR_ASYNC_KEY)); - } - - public void testNotSampledEvent() throws OboeException { - reader.put(new SettingsMockupBuilder().withFlags(TracingMode.NEVER).withSampleRate(0).build()); //NEVER sample rate = 0% - Trace.startTrace("not-sampled").report(); - TraceEvent noopEvent; - noopEvent = Trace.createEntryEvent("entry-event"); - - assertTrue("Unexpected event " + noopEvent.getClass().getName() + " test reader: " + System.identityHashCode(reader) + " settings fetcher " + SettingsManager.getFetcher() + " settings reader: " + System.identityHashCode(((SimpleSettingsFetcher) SettingsManager.getFetcher()).getReader()), noopEvent instanceof NoOpEvent); - assertEquals(0, reporter.getSentEvents().size()); - } -} diff --git a/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/TraceTest.java b/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/TraceTest.java deleted file mode 100644 index 6f402021..00000000 --- a/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/TraceTest.java +++ /dev/null @@ -1,257 +0,0 @@ -package com.appoptics.api.ext; - -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import com.tracelytics.joboe.Constants; -import com.tracelytics.joboe.Context; -import com.tracelytics.joboe.Metadata; -import com.tracelytics.joboe.OboeException; -import com.tracelytics.joboe.TracingMode; -import com.tracelytics.joboe.TestReporter.DeserializedEvent; -import com.tracelytics.joboe.settings.TestSettingsReader.SettingsMockupBuilder; -import com.tracelytics.joboe.settings.TestSettingsReader.SettingsMockup; -import com.tracelytics.joboe.span.impl.ScopeManager; -import com.tracelytics.joboe.span.impl.Span; -import com.tracelytics.joboe.span.impl.TransactionNameManager; - -public class TraceTest extends BaseTest { - - public TraceTest() throws Exception { - super(); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - - public void testSampledTrace() throws OboeException { - reader.put(new SettingsMockupBuilder().withFlags(TracingMode.ALWAYS).withSampleRate(1000000).build()); //ALWAYS sample rate = 100% - Trace.startTrace("sampled").report(); - //assert that there's an active span - Span currentSpan = ScopeManager.INSTANCE.activeSpan(); - assertEquals("sampled", currentSpan.getOperationName()); - assertEquals(true, currentSpan.isRoot()); - assertEquals(true, currentSpan.context().isSampled()); - - Trace.createEntryEvent("child").report(); - Trace.createExitEvent("child").report(); - Trace.createInfoEvent("sampled").report(); - Trace.logException(new Throwable() {}); - Metadata reportedMetadata = new Metadata(Trace.endTrace("sampled")); - assertTrue(reportedMetadata.isValid()); - assertTrue(reportedMetadata.isSampled()); - assertEquals(null, ScopeManager.INSTANCE.activeSpan()); - - List sentEvents = reporter.getSentEvents(); - - assertEquals(6, sentEvents.size()); - } - - public void testNotSampledTrace() throws OboeException { - reader.put(new SettingsMockupBuilder().withFlags(TracingMode.NEVER).withSampleRate(0).build()); //NEVER sample rate = 0% - Trace.startTrace("not-sampled").report(); - //assert that there's an active span (not sampled) - Span currentSpan = ScopeManager.INSTANCE.activeSpan(); - assertEquals("not-sampled", currentSpan.getOperationName()); - assertEquals(true, currentSpan.isRoot()); - assertEquals(false, currentSpan.context().isSampled()); - - Trace.createEntryEvent("child").report(); - Trace.createExitEvent("child").report(); - Trace.createInfoEvent("not-sampled").report(); - Trace.logException(new Throwable() {}); - Metadata reportedMetadata = new Metadata(Trace.endTrace("not-sampled")); - assertTrue(reportedMetadata.isValid()); - assertFalse(reportedMetadata.isSampled()); - assertEquals(null, ScopeManager.INSTANCE.activeSpan()); - - List sentEvents = reporter.getSentEvents(); - assertEquals(0, sentEvents.size()); - } - - public void testContinueTraceSampledId() throws OboeException { - reader.put(new SettingsMockupBuilder().withFlags(TracingMode.ALWAYS).withSampleRate(1000000).build()); //ALWAYS sample rate = 100% - Metadata testMetadata = getMetadata(true); - String sampledId = testMetadata.toHexString(); - Trace.continueTrace("simple", sampledId).report(); - //assert that there's an active span - Span currentSpan = ScopeManager.INSTANCE.activeSpan(); - assertEquals("simple", currentSpan.getOperationName()); - assertEquals(true, currentSpan.isRoot()); - assertEquals(true, currentSpan.context().isSampled()); - - List sentEvents = reporter.getSentEvents(); - assertEquals(1, sentEvents.size()); - DeserializedEvent continueEvent = sentEvents.get(0); - //make sure there's an edge pointing at the incoming x-trace ID - assertEquals(testMetadata.opHexString(), continueEvent.getSentEntries().get(Constants.XTR_EDGE_KEY)); - - Metadata metadata = Context.getMetadata(); - assertTrue(metadata.isTaskEqual(testMetadata)); - assertFalse(metadata.isOpEqual(testMetadata)); - assertTrue(metadata.isValid()); - assertTrue(metadata.isSampled()); - } - - public void testContinueTraceIncompatibleId() throws OboeException { - reader.put(new SettingsMockupBuilder().withFlags(TracingMode.ALWAYS).withSampleRate(1000000).build()); //ALWAYS sample rate = 100% - Metadata testMetadata = getMetadata(true); - String incompatibleId = testMetadata.toHexString(Metadata.CURRENT_VERSION + 1); //make this one version ahead, hence incompatible - Trace.continueTrace("simple", incompatibleId).report(); //it should just ignore this x-trace id and start a new trace - //assert that there's an active span - Span currentSpan = ScopeManager.INSTANCE.activeSpan(); - assertEquals("simple", currentSpan.getOperationName()); - assertEquals(true, currentSpan.isRoot()); - assertEquals(true, currentSpan.context().isSampled()); - - List sentEvents = reporter.getSentEvents(); - assertEquals(1, sentEvents.size()); - - Metadata metadata = Context.getMetadata(); - assertFalse(metadata.isTaskEqual(testMetadata)); //should not be the same task as the incoming x-trace id is ignored - assertFalse(metadata.isOpEqual(testMetadata)); - assertTrue(metadata.isValid()); - assertTrue(metadata.isSampled()); - } - - public void testContinueTraceNotSampledId() throws OboeException { - reader.put(new SettingsMockupBuilder().withFlags(TracingMode.ALWAYS).withSampleRate(1000000).build()); //ALWAYS sample rate = 100% - Metadata testMetadata = getMetadata(false); - String notSampledId = testMetadata.toHexString(); - Trace.continueTrace("simple", notSampledId).report(); //it should not continue trace as incoming x-trace is not-sampled - //assert that there's an active span - Span currentSpan = ScopeManager.INSTANCE.activeSpan(); - assertEquals("simple", currentSpan.getOperationName()); - assertEquals(true, currentSpan.isRoot()); - assertEquals(false, currentSpan.context().isSampled()); - - List sentEvents = reporter.getSentEvents(); - assertEquals(0, sentEvents.size()); - - Metadata metadata = Context.getMetadata(); - assertTrue(metadata.isTaskEqual(testMetadata)); //task id should be equal as it should be propagated - assertTrue(metadata.isValid()); //it is a valid metadata just not sampled - assertFalse(metadata.isSampled()); //not sampled - - assertEquals(notSampledId, Trace.getCurrentXTraceID()); - } - - public void testContinueTraceNeverMode() throws OboeException { - reader.put(new SettingsMockupBuilder().withFlags(TracingMode.NEVER).withSampleRate(0).build()); //NEVER sample rate = 0% - Metadata testMetadata = getMetadata(true); - String sampledId = testMetadata.toHexString(); - Trace.continueTrace("not-sampled", sampledId).report(); //it should not continue trace this layer has trace mode never - //assert that there's an active span - Span currentSpan = ScopeManager.INSTANCE.activeSpan(); - assertEquals("not-sampled", currentSpan.getOperationName()); - assertEquals(true, currentSpan.isRoot()); - assertEquals(false, currentSpan.context().isSampled()); - - List sentEvents = reporter.getSentEvents(); - assertEquals(0, sentEvents.size()); - - Metadata metadata = Context.getMetadata(); - assertTrue(metadata.isTaskEqual(testMetadata)); //task id should be equal as it should be propagated - assertTrue(metadata.isValid()); //it is a valid metadata just not sampled - assertFalse(metadata.isSampled()); //not sampled - } - - public void testEmptyContext() { - assertEquals("", Trace.endTrace("test")); //no valid context - } - - public void testSetTransactionName() throws Exception { - reader.put(new SettingsMockupBuilder().withFlags(TracingMode.ALWAYS).withSampleRate(1000000).build()); //ALWAYS sample rate = 100% - - assertEquals(false, Trace.setTransactionName("test-1")); //cannot set transaction name as there's no valid context - - reporter.reset(); - Trace.startTrace("test-layer").report(); - assertEquals(true, Trace.setTransactionName("test-2")); //ok, there's an active trace - Trace.endTrace("test-layer"); - assertEquals("test-2", reporter.getSentEvents().get(1).getSentEntries().get("TransactionName")); - - reporter.reset(); - Trace.startTrace("test-layer").report(); - assertEquals(true, Trace.setTransactionName("test@123#$%")); //ok, there's an active trace - Trace.endTrace("test-layer"); - assertEquals("test_123___", reporter.getSentEvents().get(1).getSentEntries().get("TransactionName")); //transformed transaction name with invalid characters replaced with _ - - reporter.reset(); - Trace.startTrace("test-layer").report(); - String longString = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"; - assertEquals(true, Trace.setTransactionName(longString)); //ok, there's an active trace - Trace.endTrace("test-layer"); - assertEquals(longString.substring(0, TransactionNameManager.MAX_TRANSACTION_NAME_LENGTH - TransactionNameManager.TRANSACTION_NAME_ELLIPSIS.length()) + TransactionNameManager.TRANSACTION_NAME_ELLIPSIS, reporter.getSentEvents().get(1).getSentEntries().get("TransactionName")); //truncated transaction name - - reporter.reset(); - Trace.startTrace("test-layer").report(); - assertEquals(true, Trace.setTransactionName(" space ")); //ok, there's an active trace - Trace.endTrace("test-layer"); - assertEquals(" space ", reporter.getSentEvents().get(1).getSentEntries().get("TransactionName")); //empty space should not be replaced - - reporter.reset(); - Trace.startTrace("test-layer").report(); - assertEquals(true, Trace.setTransactionName("-.:_\\\\/?")); //ok, there's an active trace - Trace.endTrace("test-layer"); - assertEquals("-.:_\\\\/?", reporter.getSentEvents().get(1).getSentEntries().get("TransactionName")); //no transformation as all those are valid characters - - reporter.reset(); - Trace.startTrace("test-layer").report(); - assertEquals(false, Trace.setTransactionName(null)); //not ok, transaction name should not be null - Trace.endTrace("test-layer"); - assertEquals(TransactionNameManager.DEFAULT_SDK_TRANSACTION_NAME_PREFIX + "test-layer", reporter.getSentEvents().get(1).getSentEntries().get("TransactionName")); //default name for SDK traces - - reporter.reset(); - Trace.startTrace("test-layer").report(); - assertEquals(false, Trace.setTransactionName("")); //not ok, transaction name should not be empty - Trace.endTrace("test-layer"); - assertEquals(TransactionNameManager.DEFAULT_SDK_TRANSACTION_NAME_PREFIX + "test-layer", reporter.getSentEvents().get(1).getSentEntries().get("TransactionName")); //default name for SDK traces - - reporter.reset(); - Trace.startTrace("test-layer").report(); - Future future = Executors.newSingleThreadExecutor().submit(new Runnable() { - @Override - public void run() { - assertEquals(true, Trace.setTransactionName("test-4")); //ok, there's an active trace, transaction name set in spawned thread should be reflected in the active trace - } - }); - future.get(); - Trace.endTrace("test-layer"); - assertEquals("test-4", reporter.getSentEvents().get(1).getSentEntries().get("TransactionName")); - - //test multiple transaction name on same trace - reporter.reset(); - Trace.startTrace("test-layer").report(); - assertEquals(true, Trace.setTransactionName("name-1")); - assertEquals(true, Trace.setTransactionName("name-2")); - Trace.endTrace("test-layer"); - assertEquals("name-2", reporter.getSentEvents().get(1).getSentEntries().get("TransactionName")); //should use the last value - - //test transaction name precedence - reporter.reset(); - Trace.startTrace("test-layer").report(); - ScopeManager.INSTANCE.activeSpan().setTag("URL", "/1/2/3"); //cheat a bit by calling core code directly...as we currently do not expose tags via SDK - Trace.endTrace("test-layer"); - assertEquals("/1/2", reporter.getSentEvents().get(1).getSentEntries().get("TransactionName")); //no custom transaction name, should just return the URL based transaction name - - reporter.reset(); - Trace.startTrace("test-layer").report(); - assertEquals(true, Trace.setTransactionName("my-transaction")); - ScopeManager.INSTANCE.activeSpan().setTag("URL", "/1/2/3"); //cheat a bit by calling core code directly...as we currently do not expose tags via SDK - Trace.endTrace("test-layer"); - assertEquals("my-transaction", reporter.getSentEvents().get(1).getSentEntries().get("TransactionName")); //custom transaction name should override the url based name - } - - - private static Metadata getMetadata(boolean sampled) { - Metadata metadata = new Metadata(); - metadata.randomize(sampled); - - return metadata; - } -} diff --git a/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/WrapperIntegrationTest.java b/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/WrapperIntegrationTest.java deleted file mode 100644 index ceb7316f..00000000 --- a/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/WrapperIntegrationTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.appoptics.api.ext; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.URL; -import java.util.logging.Logger; - -import junit.framework.TestCase; - -public class WrapperIntegrationTest extends TestCase { - private Logger logger = Logger.getAnonymousLogger(); - - public void testGet() throws IOException { - String result = getUrl(new URL("http://localhost:8080/test.jsp")); - -// assertTrue("Cannot find the RUM header in the response:[" + result + "]", result.contains("var b=this._tly")); -// assertTrue("Cannot find the RUM footer in the response:[" + result + "]", result.contains("this._tly&&this._tly.measure(\"domload\");")); - - //in T2, we no longer add RUM header, ensure the response does not contain the RUM header - assertFalse("Still found RUM header in the response:[" + result + "]", result.contains("var b=this._tly")); - assertFalse("Still found RUM footer in the response:[" + result + "]", result.contains("this._tly&&this._tly.measure(\"domload\");")); - } - - private static String getUrl(URL url) throws IOException { - BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream())); - - String inLine; - StringBuffer result = new StringBuffer(); - while ((inLine = in.readLine()) != null) { - result.append(inLine); - } - in.close(); - - return result.toString(); - } -} diff --git a/core-bootstrap/src/main/java/com/appoptics/opentelemetry/core/AgentState.java b/core-bootstrap/src/main/java/com/appoptics/opentelemetry/core/AgentState.java new file mode 100644 index 00000000..9727cf01 --- /dev/null +++ b/core-bootstrap/src/main/java/com/appoptics/opentelemetry/core/AgentState.java @@ -0,0 +1,30 @@ +package com.appoptics.opentelemetry.core; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicReference; + +public class AgentState { + public static boolean waitForReady(long timeout, TimeUnit unit) { + try { + if (startupTasksFuture.get() != null) { + startupTasksFuture.get().get(timeout, unit); + return true; + } else { + throw new IllegalStateException("startupTasksFuture is not yet initialized!"); + } + } catch (IllegalStateException | InterruptedException | ExecutionException | TimeoutException e) { + e.printStackTrace(); + } + return false; + } + + public static void setStartupTasksFuture(Future future) { + startupTasksFuture.set(future); + } + + private static final AtomicReference> startupTasksFuture = new AtomicReference<>(); + +} diff --git a/custom/src/main/java/com/appoptics/opentelemetry/extensions/initialize/Initializer.java b/custom/src/main/java/com/appoptics/opentelemetry/extensions/initialize/Initializer.java index 7ae31895..c7f34a4c 100644 --- a/custom/src/main/java/com/appoptics/opentelemetry/extensions/initialize/Initializer.java +++ b/custom/src/main/java/com/appoptics/opentelemetry/extensions/initialize/Initializer.java @@ -1,5 +1,6 @@ package com.appoptics.opentelemetry.extensions.initialize; +import com.appoptics.opentelemetry.core.AgentState; import com.appoptics.opentelemetry.extensions.AppOpticsInboundMetricsSpanProcessor; import com.appoptics.opentelemetry.extensions.initialize.config.*; import com.tracelytics.joboe.EventImpl; @@ -31,7 +32,6 @@ public class Initializer { private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(Initializer.class.getName()); - private static Future startupTasksFuture; private static final String CONFIG_FILE = "solarwinds-apm-config.json"; static { @@ -93,7 +93,7 @@ public void run() { public static void executeStartupTasks() { ExecutorService service = Executors.newSingleThreadExecutor(DaemonThreadFactory.newInstance("post-startup-tasks")); - startupTasksFuture = service.submit(new Runnable() { + AgentState.setStartupTasksFuture(service.submit(new Runnable() { public void run() { try { LOGGER.info("Starting startup task"); @@ -164,16 +164,12 @@ protected MetricsMonitor buildMetricsMonitor() { LOGGER.warn("Failed post system startup operations due to : " + e.getMessage(), e); } } - }); + })); LOGGER.info("Submitted startup task"); service.shutdown(); } - public static Future getStartupTasksFuture() { - return startupTasksFuture; - } - private static void initializeConfig(String serviceKey) throws InvalidConfigException { ConfigContainer configs = null; boolean hasReadConfigException = false; diff --git a/instrumentation/appoptics-annotation/build.gradle b/instrumentation/appoptics-annotation/build.gradle deleted file mode 100644 index e6c15de4..00000000 --- a/instrumentation/appoptics-annotation/build.gradle +++ /dev/null @@ -1,26 +0,0 @@ -apply from: "$rootDir/gradle/instrumentation.gradle" - -//apply plugin: "otel.javaagent-instrumentation" -//muzzle { -// -//} - -dependencies { - compileOnly "io.opentelemetry.javaagent:opentelemetry-javaagent-instrumentation-api:${versions.opentelemetryJavaagentAlpha}" - compileOnly "com.appoptics.agent.java:core:${versions.appopticsCore}" - compileOnly project(":appoptics-opentelemetry-sdk") - compileOnly project(":custom") - compileOnly project(":core-bootstrap") - toolingRuntime project(":custom") - -// implementation "io.opentelemetry.javaagent:opentelemetry-javaagent-api:1.1.0-alpha" -// implementation "io.opentelemetry.javaagent:opentelemetry-javaagent-tooling:1.1.0-alpha" -// implementation "io.opentelemetry.instrumentation:opentelemetry-instrumentation-api:1.1.0-alpha" -// implementation "com.google.guava:guava:30.1-jre" //why - -// compileOnly "com.appoptics.agent.java:appoptics-opentelemetry-sdk:6.23.0" -// implementation "com.appoptics.agent.java:appoptics-opentelemetry-java-extensions:6.23.0" -} - - - diff --git a/instrumentation/appoptics-annotation/src/main/java/com/appoptics/opentelemetry/instrumentation/annotation/AppOpticsAnnotationModule.java b/instrumentation/appoptics-annotation/src/main/java/com/appoptics/opentelemetry/instrumentation/annotation/AppOpticsAnnotationModule.java deleted file mode 100644 index e59036dc..00000000 --- a/instrumentation/appoptics-annotation/src/main/java/com/appoptics/opentelemetry/instrumentation/annotation/AppOpticsAnnotationModule.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.appoptics.opentelemetry.instrumentation.annotation; - -import com.google.auto.service.AutoService; -import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; -import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import net.bytebuddy.description.annotation.AnnotationSource; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; - -import java.util.Arrays; -import java.util.List; - -import static net.bytebuddy.matcher.ElementMatchers.*; - -/** - * Experimental instrumentation to process @LogMethod and @ProfileMethod usage from - * our AO/OT SDK - */ -@AutoService(InstrumentationModule.class) -public class AppOpticsAnnotationModule extends InstrumentationModule { - - public AppOpticsAnnotationModule() { - super("appoptics-annotations"); - } - - @Override - public List typeInstrumentations() { - return Arrays.asList(new AnnotatedLogMethodInstrumentation(), new AnnotatedProfileMethodInstrumentation()); - } - - - @Override - public boolean isHelperClass(String className) { - return className.startsWith("com.appoptics.opentelemetry."); - } - - public static class AnnotatedLogMethodInstrumentation implements TypeInstrumentation { - private final ElementMatcher.Junction annotatedMethodMatcher; - - AnnotatedLogMethodInstrumentation() { - annotatedMethodMatcher = - isAnnotatedWith(named("com.appoptics.api.ext.LogMethod")); - } - - @Override - public ElementMatcher typeMatcher() { - return declaresMethod(annotatedMethodMatcher); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - annotatedMethodMatcher, - "com.appoptics.opentelemetry.instrumentation.annotation.AppOpticsLogMethodAnnotationAdvice"); - } - } - - public static class AnnotatedProfileMethodInstrumentation implements TypeInstrumentation { - private final ElementMatcher.Junction annotatedMethodMatcher; - - AnnotatedProfileMethodInstrumentation() { - annotatedMethodMatcher = - isAnnotatedWith(named("com.appoptics.api.ext.ProfileMethod")); - } - - @Override - public ElementMatcher typeMatcher() { - return declaresMethod(annotatedMethodMatcher); - } - - @Override - public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - annotatedMethodMatcher, - "com.appoptics.opentelemetry.instrumentation.annotation.AppOpticsProfileMethodAnnotationAdvice"); - } - } -} diff --git a/instrumentation/appoptics-annotation/src/main/java/com/appoptics/opentelemetry/instrumentation/annotation/AppOpticsAnnotationTracer.java b/instrumentation/appoptics-annotation/src/main/java/com/appoptics/opentelemetry/instrumentation/annotation/AppOpticsAnnotationTracer.java deleted file mode 100644 index 61b9fc9d..00000000 --- a/instrumentation/appoptics-annotation/src/main/java/com/appoptics/opentelemetry/instrumentation/annotation/AppOpticsAnnotationTracer.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.appoptics.opentelemetry.instrumentation.annotation; - -import com.appoptics.api.ext.LogMethod; -import com.appoptics.api.ext.ProfileMethod; -import com.appoptics.opentelemetry.core.Constants; -import com.appoptics.opentelemetry.core.Util; -import com.tracelytics.joboe.EventValueConverter; -import com.tracelytics.joboe.config.ConfigManager; -import com.tracelytics.joboe.config.ConfigProperty; -import com.tracelytics.util.BackTraceUtil; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.context.Context; -import io.opentelemetry.instrumentation.api.tracer.BaseTracer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.lang.reflect.Method; -import java.net.URL; -import java.security.CodeSource; -import java.util.Collections; - -public class AppOpticsAnnotationTracer extends BaseTracer { - private static final AppOpticsAnnotationTracer TRACER = new AppOpticsAnnotationTracer(); - private static EventValueConverter converter = new EventValueConverter(); - - public static AppOpticsAnnotationTracer tracer() { - return TRACER; - } - - private static final Logger log = LoggerFactory.getLogger(AppOpticsAnnotationTracer.class); - - public Context startSpan(Context parentContext, LogMethod annotation, Method method, SpanKind kind) { - - String operationName = annotation.layer(); - if (operationName == null || operationName.equals("")) { - operationName = (String) ConfigManager.getConfig(ConfigProperty.AGENT_LAYER); - } - - operationName = operationName.replace("\"", "\\\""); - - Span span = spanBuilder(parentContext, operationName, kind).startSpan(); - - span.setAttribute(Constants.SW_KEY_PREFIX + "Class", method.getDeclaringClass().getName()); - span.setAttribute(Constants.SW_KEY_PREFIX + "Method", method.getName()); - - - if (annotation.backTrace()) { - span.setAttribute(Constants.SW_KEY_PREFIX + "Backtrace", BackTraceUtil.backTraceToString(BackTraceUtil.getBackTrace(1))); - } - return parentContext.with(span); - } - - public Context startSpan(Context parentContext, ProfileMethod annotation, Method method, SpanKind kind) { - String operationName = annotation.profileName(); - - operationName = operationName.replace("\"", "\\\""); - - Span span = spanBuilder(parentContext, operationName, kind).startSpan(); - - span.setAttribute(Constants.SW_KEY_PREFIX + "Class", method.getDeclaringClass().getName()); - span.setAttribute(Constants.SW_KEY_PREFIX + "FunctionName", method.getName()); - span.setAttribute(Constants.SW_KEY_PREFIX + "Signature", method.toGenericString()); //slightly different from the method signature before, but this is more readable - - if (method.getDeclaringClass().getProtectionDomain() != null) { - CodeSource codeSource = method.getDeclaringClass().getProtectionDomain().getCodeSource(); - if (codeSource != null) { - URL location = codeSource.getLocation(); - if (location != null) { - String file = location.getFile(); - if (file != null && !"".equals(file)) { - span.setAttribute(Constants.SW_KEY_PREFIX + "File", file); - } - } - } - } - - if (annotation.backTrace()) { - span.setAttribute(Constants.SW_KEY_PREFIX + "Backtrace", BackTraceUtil.backTraceToString(BackTraceUtil.getBackTrace(1))); - } - return parentContext.with(span); - } - - - @Override - protected String getInstrumentationName() { - return "com.appoptics.opentelemetry.annotations"; - } - - public void endMethod(Context context, boolean storeReturn, Object returnValue) { - if (storeReturn) { - Span span = Span.fromContext(context); - Util.setSpanAttributes(span, Collections.singletonMap("ReturnValue", converter.convertToEventValue(returnValue))); - } - } - - @Override - public void end(Context context) { - super.end(context); - } -} - diff --git a/instrumentation/appoptics-annotation/src/main/java/com/appoptics/opentelemetry/instrumentation/annotation/AppOpticsLogMethodAnnotationAdvice.java b/instrumentation/appoptics-annotation/src/main/java/com/appoptics/opentelemetry/instrumentation/annotation/AppOpticsLogMethodAnnotationAdvice.java deleted file mode 100644 index 305c4858..00000000 --- a/instrumentation/appoptics-annotation/src/main/java/com/appoptics/opentelemetry/instrumentation/annotation/AppOpticsLogMethodAnnotationAdvice.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.appoptics.opentelemetry.instrumentation.annotation; - -import com.appoptics.api.ext.LogMethod; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; -import net.bytebuddy.asm.Advice; - -import java.lang.reflect.Method; - -import static com.appoptics.opentelemetry.instrumentation.annotation.AppOpticsAnnotationTracer.tracer; - -public class AppOpticsLogMethodAnnotationAdvice { - - @Advice.OnMethodEnter() - public static void onEnter( - @Advice.Origin Method method, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("annotation") LogMethod annotation) { - annotation = method.getAnnotation(LogMethod.class); - SpanKind kind = SpanKind.INTERNAL; - Context current = Context.current(); - - context = tracer().startSpan(current, annotation, method, kind); - scope = context.makeCurrent(); - } -// - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - //@Advice.OnMethodExit - public static void stopSpan( - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("annotation") LogMethod annotation, - @Advice.Return Object returnValue, - @Advice.Thrown Throwable throwable) { - if (scope == null) { - return; - } - - tracer().endMethod(context, annotation.storeReturn(), returnValue); - - if (annotation.reportExceptions() && throwable != null) { - tracer().endExceptionally(context, throwable); - } else { - tracer().end(context); - } - scope.close(); - } -} diff --git a/instrumentation/appoptics-annotation/src/main/java/com/appoptics/opentelemetry/instrumentation/annotation/AppOpticsProfileMethodAnnotationAdvice.java b/instrumentation/appoptics-annotation/src/main/java/com/appoptics/opentelemetry/instrumentation/annotation/AppOpticsProfileMethodAnnotationAdvice.java deleted file mode 100644 index 22da06bb..00000000 --- a/instrumentation/appoptics-annotation/src/main/java/com/appoptics/opentelemetry/instrumentation/annotation/AppOpticsProfileMethodAnnotationAdvice.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.appoptics.opentelemetry.instrumentation.annotation; - -import com.appoptics.api.ext.ProfileMethod; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.Scope; -import net.bytebuddy.asm.Advice; - -import java.lang.reflect.Method; - -import static com.appoptics.opentelemetry.instrumentation.annotation.AppOpticsAnnotationTracer.tracer; - -public class AppOpticsProfileMethodAnnotationAdvice { - @Advice.OnMethodEnter() - public static void onEnter( - @Advice.Origin Method method, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("annotation") ProfileMethod annotation) { - annotation = method.getAnnotation(ProfileMethod.class); - SpanKind kind = SpanKind.INTERNAL; - Context current = Context.current(); - - context = tracer().startSpan(current, annotation, method, kind); - scope = context.makeCurrent(); - } - - @Advice.OnMethodExit(suppress = Throwable.class) - public static void stopSpan( - @Advice.Local("otelContext") Context context, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("annotation") ProfileMethod annotation, - @Advice.Return Object returnValue) { - if (scope == null) { - return; - } - - tracer().endMethod(context, annotation.storeReturn(), returnValue); - - tracer().end(context); - - scope.close(); - } -} diff --git a/sdk-extensions-bootstrap/build.gradle b/sdk-extensions-bootstrap/build.gradle deleted file mode 100644 index aa4b4c0f..00000000 --- a/sdk-extensions-bootstrap/build.gradle +++ /dev/null @@ -1,23 +0,0 @@ -plugins { - id "java" - id("com.github.johnrengelman.shadow") version "6.0.0" -} - -apply from: "$rootDir/gradle/shadow.gradle" - -dependencies { - runtimeOnly "com.appoptics.agent.java:core:${versions.appopticsCore}" - runtimeOnly "com.appoptics.agent.java:metrics:${versions.appopticsMetrics}" -} - - -tasks { - shadowJar { - classifier = "" //make it overwrite the original file instead of generating an extra one with `-all` suffix - relocatePackages(it) - } - - assemble { - dependsOn(shadowJar) - } -} diff --git a/sdk-extensions/build.gradle b/sdk-extensions/build.gradle deleted file mode 100644 index 364ee0b4..00000000 --- a/sdk-extensions/build.gradle +++ /dev/null @@ -1,38 +0,0 @@ -plugins { - id("com.github.johnrengelman.shadow") version "6.0.0" -} - -apply from: "$rootDir/gradle/shadow.gradle" - -def relocatePackages = ext.relocatePackages - -configurations { -} - -dependencies { -// customShadow project(path: ":custom", configuration: "shadow") -// customShadow project(path: ":instrumentation", configuration: "shadow") - implementation project(":instrumentation") - implementation project(":custom") - - //core and metrics will be made available in jar from sdk-extensions-bootstrap, appended to bootstrap via `-Xbootclasspath/a:` - compileOnly "com.appoptics.agent.java:core:${versions.appopticsCore}" - compileOnly "com.appoptics.agent.java:metrics:${versions.appopticsMetrics}" -} - -tasks { - shadowJar { - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - - mergeServiceFiles { - include("inst/META-INF/services/*") - } - exclude("**/module-info.class") - - relocatePackages(it) - } - - assemble { - dependsOn(shadowJar) - } -} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index f11c4698..513079a8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,16 +1,12 @@ rootProject.name = 'otel-custom-distro' include "agent" -//include "appoptics-opentelemetry-sdk" -//include "appoptics-opentelemetry-sdk-shaded" +include "appoptics-opentelemetry-sdk" include "core-bootstrap" include "custom" include "instrumentation" include "instrumentation:jdbc" -//include "instrumentation:appoptics-annotation" include "instrumentation:spring:spring-webmvc-3.1" include "instrumentation:servlet:servlet-5.0:javaagent" include "instrumentation:servlet:servlet-3.0:javaagent" include "instrumentation:servlet:servlet-common:javaagent" -//include "sdk-extensions" -//include "sdk-extensions-bootstrap"