diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ae1a4f2c..9664d364 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,6 +34,11 @@ jobs: GP_TOKEN: ${{ secrets.GP_TOKEN }} # GITHUB_TOKEN is used to publish the build artifacts (the NightHawk agent) to Github Packages. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # The secrets are for publishing the build artifacts to the Maven Central. + MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} + SIGNING_KEY: ${{ secrets.SIGNING_KEY }} + SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} - name: Set agent version env run: | echo "AGENT_VERSION=v$(cd agent/build/libs && unzip -p solarwinds-apm-agent.jar META-INF/MANIFEST.MF | grep Implementation-Version | awk '{ print $2 }')" >> $GITHUB_ENV diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..66cad6e1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,194 @@ +Librato Open License +Version 1.0, October, 2016 + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 11 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. Licensor can include Librato as an +original contributor to the Work as defined below. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and +configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object +code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice that is +included in or attached to the work (an example is provided in the Appendix +below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original +version of the Work and any modifications or additions to that Work or +Derivative Works thereof, that is intentionally submitted to Licensor for +inclusion in the Work by the copyright owner or by an individual or Legal +Entity authorized to submit on behalf of the copyright owner. For the purposes +of this definition, "submitted" means any form of electronic, verbal, or +written communication sent to the Licensor or its representatives, including +but not limited to communication on electronic mailing lists, source code +control systems, and issue tracking systems that are managed by, or on behalf +of, the Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise designated in +writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and +such Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +Each time You convey a covered Work, the recipient automatically receives a +license from the original Licensor(s), to run, modify and propagate that work, +subject to this License. You are not responsible for enforcing compliance by +third parties with this License. + +You may not impose any further restrictions on the exercise of the rights +granted or affirmed under this License. For example, you may not impose a +license fee, royalty, or other charge for exercise of rights granted under this +License, and you may not initiate litigation (including a cross-claim or +counterclaim in a lawsuit) alleging that any patent claim is infringed by +making, using, selling, offering for sale, or importing the Work or any portion +of it. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + + 1. You must give any other recipients of the Work or Derivative Works a copy +of this License; and + 2. You must cause any modified files to carry prominent notices stating that +You changed the files; and + 3. You must retain, in the Source form of any Derivative Works that You +distribute, all copyright, patent, trademark, and attribution notices from the +Source form of the Work, excluding those notices that do not pertain to any +part of the Derivative Works; and + 4. If the Work includes a "NOTICE" text file as part of its distribution, +then any Derivative Works that You distribute must include a readable copy of +the attribution notices contained within such NOTICE file, excluding those +notices that do not pertain to any part of the Derivative Works, in at least +one of the following places: within a NOTICE text file distributed as part of +the Derivative Works; within the Source form or documentation, if provided +along with the Derivative Works; or, within a display generated by the +Derivative Works, if and wherever such third-party notices normally appear. The +contents of the NOTICE file are for informational purposes only and do not +modify the License. You may add Your own attribution notices within Derivative +Works that You distribute, alongside or as an addendum to the NOTICE text from +the Work, provided that such additional attribution notices cannot be construed +as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a +whole, provided Your use, reproduction, and distribution of the Work otherwise +complies with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms +of any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides +the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License +or out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, +or any and all other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. +However, in accepting such obligations, You may act only on Your own behalf and +on Your sole responsibility, not on behalf of any other Contributor, and only +if You agree to indemnify, defend, and hold each Contributor harmless for any +liability incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +10. Noncompetition + +You may install and execute the Work only in conjunction with the direct use of +Librato software. This Work, any file or any derivative thereof shall not be +used in conjunction with any product that competes with any Librato software. + +11. Termination + +The License stated above is automatically terminated and revoked if you exceed +its scope or violate any of the terms of this License or any related License or +notice. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/agent/SOURCES_DOC_README b/agent/SOURCES_DOC_README new file mode 100644 index 00000000..dd9cf5de --- /dev/null +++ b/agent/SOURCES_DOC_README @@ -0,0 +1 @@ +The -sources.jar and the -javadoc.jar contains nothing. \ No newline at end of file diff --git a/agent/build.gradle b/agent/build.gradle index d794f37d..9595bcbd 100644 --- a/agent/build.gradle +++ b/agent/build.gradle @@ -1,6 +1,7 @@ plugins { id("com.github.johnrengelman.shadow") version "7.0.0" id 'maven-publish' + id 'signing' } apply from: "$rootDir/gradle/shadow.gradle" @@ -17,7 +18,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 project(path: ":solarwinds-otel-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}" @@ -69,16 +70,60 @@ tasks { } } +task sourcesJar(type: Jar) { + from('.') { + include 'SOURCES_DOC_README' + } + archiveClassifier.set("sources") +} + +task javadocJar(type: Jar) { + from('.') { + include 'SOURCES_DOC_README' + } + archiveClassifier.set("javadoc") +} + publishing { publications { - maven(MavenPublication) { - groupId = 'com.solarwinds.agent' - artifactId = "${archivesBaseName}" - version = "${versions.agent}" - from components.java + mavenJava(MavenPublication) { + pom { + name = "${archivesBaseName}" + description = "${archivesBaseName}" + url = "www.solarwinds.com" + scm { + url = 'https://www.solarwinds.com' + } + developers { + developer { + id = 'APM' + name = 'The APM Agent team' + } + } + licenses { + license { + name = 'Librato Open License' + } + } + groupId = 'io.github.appoptics' + artifactId = "${archivesBaseName}" + version = "${versions.agent}" + from components.java + artifact sourcesJar + artifact javadocJar + } } } repositories { +// -- uncomment the lines below to publish the agent artifact to the Maven central -- +// maven { +// name = "OSSRH" +// url = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" +// credentials { +// username = System.getenv("MAVEN_USERNAME") +// password = System.getenv("MAVEN_PASSWORD") +// } +// } maven { name = "GitHubPackages" url = "https://maven.pkg.github.com/appoptics/solarwinds-apm-java" @@ -89,3 +134,10 @@ publishing { } } } + +signing { + def signingKey = System.getenv("SIGNING_KEY") + def signingPassword = System.getenv("SIGNING_PASSWORD") + useInMemoryPgpKeys(signingKey, signingPassword) + sign publishing.publications.mavenJava +} diff --git a/appoptics-opentelemetry-sdk/build.gradle b/appoptics-opentelemetry-sdk/build.gradle deleted file mode 100644 index aef771e5..00000000 --- a/appoptics-opentelemetry-sdk/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -apply plugin: 'java' -apply plugin: "maven-publish" - -group = "com.solarwinds.agent" - -dependencies { - compileOnly("io.opentelemetry:opentelemetry-sdk:${versions.opentelemetry}") - compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-bootstrap:${versions.opentelemetryJavaagentAlpha}") - compileOnly "com.appoptics.agent.java:core:${versions.appopticsCore}" - compileOnly "com.appoptics.agent.java:metrics:${versions.appopticsMetrics}" - compileOnly project(":custom") - compileOnly project(":core-bootstrap") - testImplementation "junit:junit:4.10" - testImplementation "com.appoptics.agent.java:core:${versions.appopticsCore}" - testImplementation "com.appoptics.agent.java:metrics:${versions.appopticsMetrics}" -} - - diff --git a/build.gradle b/build.gradle index 2b740e45..fdb59bc8 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,4 @@ -group = "com.solarwinds.agent" +group = "io.github.appoptics" subprojects { apply plugin: "java" @@ -12,7 +12,7 @@ subprojects { bytebuddy : "1.12.6", guava : "30.1-jre", appopticsCore : "7.8.0", - agent : "0.13.0" // the custom distro agent version + agent : "0.14.0-alpha2" // the custom distro agent version ] versions.appopticsMetrics = "${versions.appopticsCore}" // they share the same version now versions.opentelemetryAlpha = "${versions.opentelemetry}-alpha" diff --git a/core-bootstrap/src/main/java/com/appoptics/opentelemetry/core/CustomTransactionNameDict.java b/core-bootstrap/src/main/java/com/appoptics/opentelemetry/core/CustomTransactionNameDict.java new file mode 100644 index 00000000..933b91a8 --- /dev/null +++ b/core-bootstrap/src/main/java/com/appoptics/opentelemetry/core/CustomTransactionNameDict.java @@ -0,0 +1,21 @@ +package com.appoptics.opentelemetry.core; + +import com.tracelytics.ext.google.common.cache.Cache; +import com.tracelytics.ext.google.common.cache.CacheBuilder; + +import java.util.concurrent.TimeUnit; + +public class CustomTransactionNameDict { + private static final Cache dict = CacheBuilder.newBuilder() + .maximumSize(1000) + .expireAfterAccess(1200, TimeUnit.SECONDS) + .build(); //20 mins cache + + public static void set(String id, String name) { + dict.put(id, name); + } + + public static String get(String id) { + return dict.getIfPresent(id); + } +} diff --git a/custom/src/main/java/com/appoptics/opentelemetry/extensions/TransactionNameManager.java b/custom/src/main/java/com/appoptics/opentelemetry/extensions/TransactionNameManager.java index 7989eeb7..6c609768 100644 --- a/custom/src/main/java/com/appoptics/opentelemetry/extensions/TransactionNameManager.java +++ b/custom/src/main/java/com/appoptics/opentelemetry/extensions/TransactionNameManager.java @@ -1,5 +1,6 @@ package com.appoptics.opentelemetry.extensions; +import com.appoptics.opentelemetry.core.CustomTransactionNameDict; import com.appoptics.opentelemetry.core.Util; import com.tracelytics.ext.google.common.cache.Cache; import com.tracelytics.ext.google.common.cache.CacheBuilder; @@ -161,6 +162,12 @@ static String transformTransactionName(String inputTransactionName) { * @return a transaction name built based on the span, null if no transaction name can be built */ static String buildTransactionName(SpanData spanData) { + String traceId = spanData.getTraceId(); + String customName = CustomTransactionNameDict.get(traceId); + if (customName != null) { + return customName; + } + String url = (String) spanData.getAttributes().get(SemanticAttributes.HTTP_URL); String path = Util.parsePath(url); diff --git a/settings.gradle b/settings.gradle index 513079a8..5fd641cc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,7 +1,7 @@ rootProject.name = 'otel-custom-distro' include "agent" -include "appoptics-opentelemetry-sdk" +include "solarwinds-otel-sdk" include "core-bootstrap" include "custom" include "instrumentation" diff --git a/solarwinds-otel-sdk/SOURCES_DOC_README b/solarwinds-otel-sdk/SOURCES_DOC_README new file mode 100644 index 00000000..dd9cf5de --- /dev/null +++ b/solarwinds-otel-sdk/SOURCES_DOC_README @@ -0,0 +1 @@ +The -sources.jar and the -javadoc.jar contains nothing. \ No newline at end of file diff --git a/solarwinds-otel-sdk/build.gradle b/solarwinds-otel-sdk/build.gradle new file mode 100644 index 00000000..45ba0954 --- /dev/null +++ b/solarwinds-otel-sdk/build.gradle @@ -0,0 +1,94 @@ +plugins { + id("java") + id("maven-publish") + id("com.github.johnrengelman.shadow") version "7.0.0" + id 'signing' +} + +apply from: "$rootDir/gradle/shadow.gradle" + +project.archivesBaseName = 'solarwinds-otel-sdk' + + +dependencies { + compileOnly("io.opentelemetry:opentelemetry-sdk:${versions.opentelemetry}") + compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-bootstrap:${versions.opentelemetryJavaagentAlpha}") + compileOnly "com.appoptics.agent.java:core:${versions.appopticsCore}" + compileOnly "com.appoptics.agent.java:metrics:${versions.appopticsMetrics}" + compileOnly project(":custom") + compileOnly project(":core-bootstrap") + testImplementation "junit:junit:4.10" + testImplementation "com.appoptics.agent.java:core:${versions.appopticsCore}" + testImplementation "com.appoptics.agent.java:metrics:${versions.appopticsMetrics}" +} + +task sourcesJar(type: Jar) { + from('.') { + include 'SOURCES_DOC_README' + } + archiveClassifier.set("sources") +} + +task javadocJar(type: Jar) { + from('.') { + include 'SOURCES_DOC_README' + } + archiveClassifier.set("javadoc") +} + +publishing { + publications { + mavenJava(MavenPublication) { + pom { + name = "${archivesBaseName}" + description = "${archivesBaseName}" + url = "www.solarwinds.com" + scm { + url = 'https://www.solarwinds.com' + } + developers { + developer { + id = 'APM' + name = 'The APM Agent team' + } + } + licenses { + license { + name = 'Librato Open License' + } + } + groupId = 'io.github.appoptics' + artifactId = "${archivesBaseName}" + version = "${versions.agent}" + from components.java + artifact sourcesJar + artifact javadocJar + } + } + } + repositories { + maven { + name = "OSSRH" + url = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" + credentials { + username = System.getenv("MAVEN_USERNAME") + password = System.getenv("MAVEN_PASSWORD") + } + } + maven { + name = "GitHubPackages" + url = "https://maven.pkg.github.com/appoptics/solarwinds-apm-java" + credentials { + username = System.getenv("GITHUB_ACTOR") + password = System.getenv("GITHUB_TOKEN") + } + } + } +} + +signing { + def signingKey = System.getenv("SIGNING_KEY") + def signingPassword = System.getenv("SIGNING_PASSWORD") + useInMemoryPgpKeys(signingKey, signingPassword) + sign publishing.publications.mavenJava +} \ No newline at end of file diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/AgentChecker.java b/solarwinds-otel-sdk/src/main/java/com/appoptics/api/ext/AgentChecker.java similarity index 100% rename from appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/AgentChecker.java rename to solarwinds-otel-sdk/src/main/java/com/appoptics/api/ext/AgentChecker.java diff --git a/solarwinds-otel-sdk/src/main/java/com/appoptics/api/ext/CustomTransactionName.java b/solarwinds-otel-sdk/src/main/java/com/appoptics/api/ext/CustomTransactionName.java new file mode 100644 index 00000000..067db5cd --- /dev/null +++ b/solarwinds-otel-sdk/src/main/java/com/appoptics/api/ext/CustomTransactionName.java @@ -0,0 +1,46 @@ +package com.appoptics.api.ext; + +import com.appoptics.opentelemetry.core.CustomTransactionNameDict; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.context.Context; + +import java.util.logging.Logger; + +/** + * The API to set the custom transaction name for the current trace. It returns false if the current trace is not valid + * or not sampled. + */ +public class CustomTransactionName { + private static final Logger logger = Logger.getLogger(CustomTransactionName.class.getName()); + private static boolean isAgentReady = false; + static { + try { + Class.forName("com.appoptics.opentelemetry.core.CustomTransactionNameDict"); + isAgentReady = true; + logger.info("The SolarWinds APM agent and the SDK is available."); + } catch (ClassNotFoundException | NoClassDefFoundError | NoSuchMethodError e) { + logger.warning("The SolarWinds APM Agent is not available. The SDK will be no-op."); + } + } + + /** Set the transaction name of the current trace. + * + * @param name the custom transaction name to be set to the current trace + * @return {@code true} if the transaction name is successfully set, or {@code false} if the transaction name is not set because the span is invalid or the not sampled. + */ + public static boolean set(String name) { + if (!isAgentReady) { + return false; + } + + Context context = Context.current(); + Span span = Span.fromContext(context); + SpanContext spanContext = span.getSpanContext(); + if (!(spanContext.isValid() && spanContext.isSampled())) { + return false; + } + CustomTransactionNameDict.set(spanContext.getTraceId(), name); + return true; + } +} diff --git a/appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/package-info.java b/solarwinds-otel-sdk/src/main/java/com/appoptics/api/ext/package-info.java similarity index 100% rename from appoptics-opentelemetry-sdk/src/main/java/com/appoptics/api/ext/package-info.java rename to solarwinds-otel-sdk/src/main/java/com/appoptics/api/ext/package-info.java diff --git a/appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/AgentCheckerTest.java b/solarwinds-otel-sdk/src/test/java/com/appoptics/api/ext/AgentCheckerTest.java similarity index 100% rename from appoptics-opentelemetry-sdk/src/test/java/com/appoptics/api/ext/AgentCheckerTest.java rename to solarwinds-otel-sdk/src/test/java/com/appoptics/api/ext/AgentCheckerTest.java