diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad6c520cb..a57ba1374 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,4 +15,4 @@ jobs: with: java-version: adopt@1.8.0-292 - name: Test - run: sbt -v ";+instrumentation/publishLocal;+core/test;+instrumentation/test;+reporters/test" + run: sbt -v ";+core/test;+instrumentation/test;+reporters/test" diff --git a/README.md b/README.md index 97bd8d829..93b52fa38 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,17 @@ -# Kamon +# Kamon Telemetry [![Discord](https://img.shields.io/discord/866301994074243132?label=Join%20the%20Comunity%20on%20Discord)](https://discord.gg/5JuYsDJ7au) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.kamon/kamon-core_2.13/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.kamon/kamon-core_2.13) -Kamon is a set of tools for instrumenting applications running on the JVM. The best way to get started is to go to our -official [Get Started Page](https://kamon.io/get-started/) and start instrumenting your applications right away! There -you will also find guides and reference documentation for the core APIs, instrumentation and reporting modules. - -# Importing the project into Intellij IDEA -This project has a library dependency on a subproject of itself (`kamon-tapir`). -As a result of that, if you just clone this project and open it in IDEA, it will fail to import it. -First, run `sbt +kamon-tapir/publishLocal` from the console, and then IDEA will be able to import the project. - -## Why is this necessary? -Among our instrumented libraries is `Tapir`, which is also the only library we instrument that does not have a scala 2.11 version. -In order to be able to cross publish `kamon-bundle` to all scala versions, while excluding `kamon-tapir` from the 2.11 bundle, -we had to define `kamon-tapir` as a library dependency of `kamon-bundle` (instead of as a subproject). +Kamon Telemetry is a set of libraries for instrumenting applications running on the JVM. With Kamon Telemetry you can +collect metrics, propagate context across threads and services, and get distributed traces automatically. The best way +to get started is following our [installation guides](https://kamon.io/get-started/) and taking it from there. Have fun +with Kamon! ## License This software is licensed under the Apache 2 license, quoted below. -Copyright © 2013-2019 the kamon project +Copyright © 2013-2022 the kamon project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of diff --git a/build.sbt b/build.sbt index f55a0c518..0496973d1 100644 --- a/build.sbt +++ b/build.sbt @@ -36,7 +36,7 @@ lazy val `kamon-core` = (project in file("core/kamon-core")) .settings( buildInfoKeys := Seq[BuildInfoKey](version), buildInfoPackage := "kamon.status", - crossScalaVersions += scala3Version, + crossScalaVersions += `scala_3_version`, scalacOptions ++= { if(scalaBinaryVersion.value == "2.11") Seq("-Ydelambdafy:method") else Seq.empty }, assembly / assemblyShadeRules := Seq( ShadeRule.rename("org.jctools.**" -> "kamon.lib.@0").inAll, @@ -71,7 +71,7 @@ lazy val `kamon-core` = (project in file("core/kamon-core")) lazy val `kamon-status-page` = (project in file("core/kamon-status-page")) .enablePlugins(AssemblyPlugin) .settings( - crossScalaVersions += scala3Version, + crossScalaVersions += `scala_3_version`, assembly / assemblyShadeRules := Seq( ShadeRule.rename("com.grack.nanojson.**" -> "kamon.lib.@0").inAll, ShadeRule.rename("fi.iki.elonen.**" -> "kamon.lib.@0").inAll, @@ -86,7 +86,7 @@ lazy val `kamon-status-page` = (project in file("core/kamon-status-page")) lazy val `kamon-testkit` = (project in file("core/kamon-testkit")) .disablePlugins(AssemblyPlugin) .settings( - crossScalaVersions += scala3Version, + crossScalaVersions += `scala_3_version`, libraryDependencies += scalatest % "provided,test" ).dependsOn(`kamon-core`) @@ -95,7 +95,7 @@ lazy val `kamon-core-tests` = (project in file("core/kamon-core-tests")) .disablePlugins(AssemblyPlugin) .settings(noPublishing: _*) .settings( - crossScalaVersions += scala3Version, + crossScalaVersions += `scala_3_version`, libraryDependencies ++= Seq( scalatest % "test", logbackClassic % "test" @@ -106,7 +106,7 @@ lazy val `kamon-core-tests` = (project in file("core/kamon-core-tests")) lazy val `kamon-core-bench` = (project in file("core/kamon-core-bench")) .disablePlugins(AssemblyPlugin) .enablePlugins(JmhPlugin) - .settings(crossScalaVersions += scala3Version) + .settings(crossScalaVersions += `scala_3_version`) .settings(noPublishing: _*) .dependsOn(`kamon-core`) @@ -559,7 +559,7 @@ lazy val `kamon-finagle` = (project in file("instrumentation/kamon-finagle")) .enablePlugins(JavaAgent) .settings(instrumentationSettings) .settings( - crossScalaVersions := Seq("2.12.11", "2.13.1"), + crossScalaVersions := Seq(`scala_2.12_version`, `scala_2.13_version`), libraryDependencies ++= Seq( kanelaAgent % "provided", "com.twitter" %% "finagle-http" % "21.12.0" % "provided", @@ -595,7 +595,7 @@ lazy val reporters = (project in file("reporters")) lazy val `kamon-datadog` = (project in file("reporters/kamon-datadog")) .enablePlugins(AssemblyPlugin) .settings( - crossScalaVersions += scala3Version, + crossScalaVersions += `scala_3_version`, assembly / assemblyMergeStrategy := { case PathList("META-INF", xs @ _*) => MergeStrategy.discard case _ => MergeStrategy.first @@ -620,7 +620,7 @@ lazy val `kamon-datadog` = (project in file("reporters/kamon-datadog")) lazy val `kamon-apm-reporter` = (project in file("reporters/kamon-apm-reporter")) .enablePlugins(AssemblyPlugin) .settings( - crossScalaVersions += scala3Version, + crossScalaVersions += `scala_3_version`, assembly / test := {}, assembly / assemblyMergeStrategy := { case PathList("META-INF", xs @ _*) => MergeStrategy.discard @@ -653,7 +653,7 @@ lazy val `kamon-apm-reporter` = (project in file("reporters/kamon-apm-reporter") lazy val `kamon-statsd` = (project in file("reporters/kamon-statsd")) .disablePlugins(AssemblyPlugin) .settings( - crossScalaVersions += scala3Version, + crossScalaVersions += `scala_3_version`, libraryDependencies += scalatest % Test, ).dependsOn(`kamon-core`) @@ -661,7 +661,7 @@ lazy val `kamon-statsd` = (project in file("reporters/kamon-statsd")) lazy val `kamon-zipkin` = (project in file("reporters/kamon-zipkin")) .disablePlugins(AssemblyPlugin) .settings( - crossScalaVersions += scala3Version, + crossScalaVersions += `scala_3_version`, libraryDependencies ++= Seq( "io.zipkin.reporter2" % "zipkin-reporter" % "2.7.15", "io.zipkin.reporter2" % "zipkin-sender-okhttp3" % "2.7.15", @@ -673,7 +673,7 @@ lazy val `kamon-zipkin` = (project in file("reporters/kamon-zipkin")) lazy val `kamon-jaeger` = (project in file("reporters/kamon-jaeger")) .disablePlugins(AssemblyPlugin) .settings( - crossScalaVersions += scala3Version, + crossScalaVersions += `scala_3_version`, libraryDependencies ++= Seq( "io.jaegertracing" % "jaeger-thrift" % "1.1.0", scalatest % "test" @@ -684,7 +684,7 @@ lazy val `kamon-jaeger` = (project in file("reporters/kamon-jaeger")) lazy val `kamon-influxdb` = (project in file("reporters/kamon-influxdb")) .disablePlugins(AssemblyPlugin) .settings( - crossScalaVersions += scala3Version, + crossScalaVersions += `scala_3_version`, libraryDependencies ++= Seq( okHttp, okHttpMockServer % "test", @@ -696,7 +696,7 @@ lazy val `kamon-influxdb` = (project in file("reporters/kamon-influxdb")) lazy val `kamon-graphite` = (project in file("reporters/kamon-graphite")) .disablePlugins(AssemblyPlugin) .settings( - crossScalaVersions += scala3Version, + crossScalaVersions += `scala_3_version`, libraryDependencies ++= Seq( scalatest % "test", logbackClassic % "test" @@ -707,7 +707,7 @@ lazy val `kamon-graphite` = (project in file("reporters/kamon-graphite")) lazy val `kamon-newrelic` = (project in file("reporters/kamon-newrelic")) .disablePlugins(AssemblyPlugin) .settings( - crossScalaVersions += scala3Version, + crossScalaVersions += `scala_3_version`, libraryDependencies ++= Seq( "com.newrelic.telemetry" % "telemetry-core" % "0.12.0", "com.newrelic.telemetry" % "telemetry-http-okhttp" % "0.12.0", @@ -719,7 +719,7 @@ lazy val `kamon-newrelic` = (project in file("reporters/kamon-newrelic")) lazy val `kamon-opentelemetry` = (project in file("reporters/kamon-opentelemetry")) .disablePlugins(AssemblyPlugin) .settings( - crossScalaVersions += scala3Version, + crossScalaVersions += `scala_3_version`, libraryDependencies ++= Seq( "io.opentelemetry" % "opentelemetry-proto" % "0.17.1", "io.grpc" % "grpc-netty" % "1.36.0", @@ -732,7 +732,7 @@ lazy val `kamon-opentelemetry` = (project in file("reporters/kamon-opentelemetry lazy val `kamon-prometheus` = (project in file("reporters/kamon-prometheus")) .disablePlugins(AssemblyPlugin) .settings( - crossScalaVersions += scala3Version, + crossScalaVersions += `scala_3_version`, libraryDependencies ++= Seq( okHttp, scalatest % "test", @@ -741,98 +741,163 @@ lazy val `kamon-prometheus` = (project in file("reporters/kamon-prometheus")) ).dependsOn(`kamon-core`, `kamon-testkit` % "test") +/** + * Bundle Projects + */ lazy val bundle = (project in file("bundle")) .disablePlugins(AssemblyPlugin) .settings(noPublishing: _*) .settings(crossScalaVersions := Nil) .aggregate( - `kamon-bundle` + `kamon-bundle`, + `kamon-bundle_2_11`, + `kamon-runtime-attacher` ) - import com.lightbend.sbt.javaagent.Modules import BundleKeys._ -val `kamon-bundle` = (project in file("bundle/kamon-bundle")) +lazy val commonBundleSettings = Seq( + moduleName := "kamon-bundle", + assembly / fullClasspath ++= (Shaded / internalDependencyClasspath).value, + assembly / assemblyShadeRules := Seq( + ShadeRule.zap("**module-info").inAll, + ShadeRule.rename("net.bytebuddy.agent.**" -> "kamon.lib.@0").inAll + ), + assembly / assemblyExcludedJars := { + (assembly / fullClasspath).value.filter(f => { + val fileName = f.data.getName() + fileName.contains("kamon-core") || fileName.contains("oshi-core") + }) + }, + assembly / assemblyOption := (assembly / assemblyOption).value.copy( + includeBin = true, + includeScala = false, + includeDependency = false, + cacheOutput = false + ), + assembly / assemblyMergeStrategy := { + case "reference.conf" => MergeStrategy.concat + case anyOther => (assembly / assemblyMergeStrategy).value(anyOther) + }, + libraryDependencies ++= Seq( + oshiCore + ) +) + +lazy val `kamon-runtime-attacher` = (project in file("bundle/kamon-runtime-attacher")) .enablePlugins(BuildInfoPlugin) .enablePlugins(AssemblyPlugin) .settings( - moduleName := "kamon-bundle", - buildInfoPackage := "kamon.bundle", + moduleName := "kamon-runtime-attacher", + buildInfoPackage := "kamon.runtime.attacher", buildInfoKeys := Seq[BuildInfoKey](kanelaAgentJarName), kanelaAgentJar := update.value.matching(Modules.exactFilter(kanelaAgent)).head, kanelaAgentJarName := kanelaAgentJar.value.getName, Compile / resourceGenerators += Def.task(Seq(kanelaAgentJar.value)).taskValue, - assembly / fullClasspath ++= (Shaded / internalDependencyClasspath).value, assembly / assemblyShadeRules := Seq( ShadeRule.zap("**module-info").inAll, ShadeRule.rename("net.bytebuddy.agent.**" -> "kamon.lib.@0").inAll ), - assembly / assemblyExcludedJars := { - (assembly / fullClasspath).value.filter(f => { - val fileName = f.data.getName() - fileName.contains("kamon-core") || fileName.contains("oshi-core") - }) - }, - assembly / assemblyOption := (assembly / assemblyOption).value.copy( - includeBin = true, - includeScala = false, - includeDependency = false, - cacheOutput = false - ), - assembly / assemblyMergeStrategy := { - case "reference.conf" => MergeStrategy.concat - case anyOther => (assembly / assemblyMergeStrategy).value(anyOther) - }, libraryDependencies ++= Seq( - oshiCore, + slf4jApi % "compile", kanelaAgent % "provided", - "net.bytebuddy" % "byte-buddy-agent" % "1.9.12" % "provided,shaded", + "net.bytebuddy" % "byte-buddy-agent" % "1.12.7" % "provided,shaded" + ) + ) + + +/** + * Add a reference here to all the project dependencies that can be built + * for Scala 2.11, 2.12, and 2.13. + */ +lazy val `kamon-bundle-dependencies-all` = (project in file("bundle/kamon-bundle-dependencies-all")) + .disablePlugins(AssemblyPlugin) + .settings(noPublishing: _*) + .settings(ideSkipProject: _*) + .dependsOn( + `kamon-runtime-attacher`, + `kamon-status-page`, + `kamon-instrumentation-common`, + `kamon-executors`, + `kamon-scala-future`, + `kamon-twitter-future`, + `kamon-scalaz-future`, + `kamon-cats-io`, + `kamon-logback`, + `kamon-jdbc`, + `kamon-kafka`, + `kamon-mongo`, + `kamon-mongo-legacy`, + `kamon-cassandra`, + `kamon-elasticsearch`, + `kamon-spring`, + `kamon-annotation`, + `kamon-annotation-api`, + `kamon-system-metrics`, + `kamon-akka`, + `kamon-akka-http`, + `kamon-play`, + `kamon-redis`, + `kamon-okhttp`, + `kamon-caffeine`, + `kamon-lagom` + ) + +/** + * Add a reference here to all the project dependencies that can be built + * from 2.12. Currently only Scala 2.12 and 2.13. + */ +lazy val `kamon-bundle-dependencies-2-12-and-up` = (project in file("bundle/kamon-bundle-dependencies-2-12-and-up")) + .disablePlugins(AssemblyPlugin) + .settings(noPublishing: _*) + .settings(ideSkipProject: _*) + .settings( + crossScalaVersions := Seq( + `scala_2.12_version`, + `scala_2.13_version` + ) + ) + .dependsOn( + `kamon-bundle-dependencies-all`, + `kamon-finagle`, + `kamon-tapir` + ) + +lazy val `kamon-bundle` = (project in file("bundle/kamon-bundle")) + .enablePlugins(AssemblyPlugin) + .settings(commonBundleSettings) + .settings(ideSkipProject: _*) + .settings( + crossScalaVersions := Seq( + `scala_2.12_version`, + `scala_2.13_version` + ) + ) + .dependsOn( + `kamon-core`, + `kamon-bundle-dependencies-2-12-and-up` % "shaded" + ) + +lazy val `kamon-bundle_2_11` = (project in file("bundle/kamon-bundle_2.11")) + .enablePlugins(AssemblyPlugin) + .settings(commonBundleSettings) + .settings(ideSkipProject: _*) + .settings( + scalaVersion := `scala_2.11_version`, + crossScalaVersions := Seq( + `scala_2.11_version` ), - libraryDependencies ++= { - // We are adding the Tapir instrumentation as library dependency (instead as a project dependency - // via .dependsOn(...) as all other projects below) because it is not published for Scala 2.11 and - // any proper solution requires major changes in the build. We might need to start using - // sbt-projectmatrix in the future. - // - // Since the bundle dependencies are only important when publishing we can force a run of - // publishLocal to get Tapir deployed on the local Ivy and then publish on the bundle as usual. - if(scalaBinaryVersion.value == "2.11") Seq.empty else Seq( - "io.kamon" %% "kamon-tapir" % version.value % "shaded" - ) - }, - ).dependsOn( + ) + .dependsOn( `kamon-core`, - `kamon-status-page` % "shaded", - `kamon-instrumentation-common` % "shaded", - `kamon-executors` % "shaded", - `kamon-scala-future` % "shaded", - `kamon-twitter-future` % "shaded", - `kamon-scalaz-future` % "shaded", - `kamon-cats-io` % "shaded", - `kamon-logback` % "shaded", - `kamon-jdbc` % "shaded", - `kamon-kafka` % "shaded", - `kamon-mongo` % "shaded", - `kamon-mongo-legacy` % "shaded", - `kamon-cassandra` % "shaded", - `kamon-elasticsearch` % "shaded", - `kamon-spring` % "shaded", - `kamon-annotation` % "shaded", - `kamon-annotation-api` % "shaded", - `kamon-system-metrics` % "shaded", - `kamon-akka` % "shaded", - `kamon-akka-http` % "shaded", - `kamon-play` % "shaded", - `kamon-redis` % "shaded", - `kamon-okhttp` % "shaded", - `kamon-caffeine` % "shaded", - `kamon-lagom` % "shaded", - `kamon-finagle` % "shaded", + `kamon-bundle-dependencies-all` % "shaded" ) + lazy val `bill-of-materials` = (project in file("bill-of-materials")) .enablePlugins(BillOfMaterialsPlugin) + .settings(ideSkipProject: _*) .settings( name := "kamon-bom", crossVersion := CrossVersion.disabled, diff --git a/bundle/kamon-bundle/src/main/scala/kamon/bundle/Bundle.scala b/bundle/kamon-runtime-attacher/src/main/scala/kamon/runtime/Attacher.scala similarity index 81% rename from bundle/kamon-bundle/src/main/scala/kamon/bundle/Bundle.scala rename to bundle/kamon-runtime-attacher/src/main/scala/kamon/runtime/Attacher.scala index cac93692d..d98739eb8 100644 --- a/bundle/kamon-bundle/src/main/scala/kamon/bundle/Bundle.scala +++ b/bundle/kamon-runtime-attacher/src/main/scala/kamon/runtime/Attacher.scala @@ -1,29 +1,14 @@ -/* - * Copyright 2013-2020 The Kamon Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package kamon.bundle +package kamon.runtime -import java.lang.management.ManagementFactory -import java.nio.file.{Files, StandardCopyOption} +import kamon.runtime.attacher.BuildInfo import net.bytebuddy.agent.ByteBuddyAgent import org.slf4j.LoggerFactory +import java.lang.management.ManagementFactory +import java.nio.file.{Files, StandardCopyOption} import scala.util.control.NonFatal -object Bundle { +object Attacher { private val _instrumentationClassLoaderProp = "kanela.instrumentation.classLoader" @@ -34,7 +19,7 @@ object Bundle { def attach(): Unit = { val springBootClassLoader = findSpringBootJarLauncherClassLoader() - if(isKanelaLoaded) { + if (isKanelaLoaded) { // If Kanela has already been loaded and we are running on a Spring Boot application, we might need to reload // Kanela to ensure it will use the proper ClassLoader for loading the instrumentations. @@ -44,7 +29,7 @@ object Bundle { } else { - val embeddedAgentFile = Bundle.getClass.getClassLoader.getResourceAsStream(BuildInfo.kanelaAgentJarName) + val embeddedAgentFile = Attacher.getClass.getClassLoader.getResourceAsStream(BuildInfo.kanelaAgentJarName) val temporaryAgentFile = Files.createTempFile(BuildInfo.kanelaAgentJarName, ".jar") Files.copy(embeddedAgentFile, temporaryAgentFile, StandardCopyOption.REPLACE_EXISTING) @@ -58,7 +43,7 @@ object Bundle { case NonFatal(t) => // We initialize the logger here instead of as a static member to avoid loading // Logger-related classes before attaching Kanela to the current JVM. - LoggerFactory.getLogger(Bundle.getClass) + LoggerFactory.getLogger(Attacher.getClass) .warn("Failed to mark the temporary Kanela Agent file for deletion after exiting the JVM", t) } } @@ -75,7 +60,9 @@ object Bundle { val isLoadedProperty = java.lang.Boolean.parseBoolean(System.getProperty("kanela.loaded")) val hasKanelaClasses = try { Class.forName("kanela.agent.Kanela", false, ClassLoader.getSystemClassLoader) != null - } catch { case _: Throwable => false } + } catch { + case _: Throwable => false + } hasKanelaClasses && isLoadedProperty } @@ -111,7 +98,7 @@ object Bundle { def withInstrumentationClassLoader[T](classLoader: ClassLoader)(thunk: => T): T = { try { - if(classLoader != null) + if (classLoader != null) System.getProperties.put(_instrumentationClassLoaderProp, classLoader) thunk } finally { diff --git a/core/kamon-core/src/main/scala/kamon/Init.scala b/core/kamon-core/src/main/scala/kamon/Init.scala index ccd007011..96b7560cc 100644 --- a/core/kamon-core/src/main/scala/kamon/Init.scala +++ b/core/kamon-core/src/main/scala/kamon/Init.scala @@ -89,7 +89,7 @@ trait Init { self: ModuleManagement with Configuration with CurrentStatus with M def attachInstrumentation(): Unit = { if(!InstrumentationStatus.create(warnIfFailed = false).present) { try { - val attacherClass = Class.forName("kamon.bundle.Bundle") + val attacherClass = Class.forName("kamon.runtime.Attacher") val attachMethod = attacherClass.getDeclaredMethod("attach") attachMethod.invoke(null) } catch { diff --git a/project/Build.scala b/project/Build.scala index ba2679c35..a669ab906 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -52,7 +52,14 @@ object BaseProject extends AutoPlugin { javaAgents := Seq("io.kamon" % "kanela-agent" % kanelaAgentVersion.value % "runtime;test") ) - val scala3Version = "3.0.2" + val ideSkipProject = Seq( + SettingKey[Boolean]("ideSkipProject") := true + ) + + val `scala_2.11_version` = "2.11.12" + val `scala_2.12_version` = "2.12.15" + val `scala_2.13_version` = "2.13.8" + val scala_3_version = "3.0.2" // This installs the GPG signing key from the setupGpg() @@ -128,8 +135,12 @@ object BaseProject extends AutoPlugin { private lazy val compilationSettings = Seq( crossPaths := true, - scalaVersion := "2.12.11", - crossScalaVersions := Seq("2.11.12", "2.12.11", "2.13.6"), + scalaVersion := autoImport.`scala_2.12_version`, + crossScalaVersions := Seq( + autoImport.`scala_2.11_version`, + autoImport.`scala_2.12_version`, + autoImport.`scala_2.13_version` + ), javacOptions := Seq( "-source", "1.8", "-target", "1.8", diff --git a/project/build.properties b/project/build.properties index 10fd9eee0..3161d2146 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.5.5 +sbt.version=1.6.1