akka-http not showing metrics in NewRelic - sbt

I'm trying to monitor my akka-http Rest web-service with NewRelic
The application has only one GET url (defined with akka-http)
I have the following configuration in the plugins.sbt
logLevel := Level.Warn
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.0.4")
addSbtPlugin("com.gilt.sbt" % "sbt-newrelic" % "0.1.4")
I have the following configuration in the build.sbt
scalaVersion := "2.11.7"
name := "recommender-api"
...blablabla...
libraryDependencies += "com.typesafe.akka" % "akka-actor_2.11" % "2.4.2"
libraryDependencies += "com.typesafe.akka" % "akka-http-experimental_2.11" % "2.4.2"
libraryDependencies += "com.typesafe.akka" % "akka-http-spray-json-experimental_2.11" % "2.4.2"
libraryDependencies += "com.typesafe.akka" % "akka-slf4j_2.11" % "2.4.2"
newrelicIncludeApi := true
newrelicAppName := name.toString
enablePlugins(JavaServerAppPackaging, UniversalDeployPlugin, NewRelic)
I compile (and deploy) the code with sbt universal:publish, it creates a .zip, inside the .zip there is an executable file.
I pass the newRelic licenceKey by enviroment (NEW_RELIC_LICENSE_KEY)
The program starts and all works fine, the newRelic key is found (because the log dosen't say that it didn't find the key)
The aplication apears in the newRelic monitor system with the correct name
BUT NewRelic dosen't show any metrics
what I have to do to see some metrics on NewRelic?

When you specify the value of newrelicAppName as name.toString, you are not doing what you expect.
name is a value of type sbt.SettingKey, this contains details of a setting's name, type, and a short description of what the key is used for.
The type that actually contains a value is an sbt.Setting. You can get a Setting from a SettingKey (in the current project and configuration) by calling the .value method.
So when you set the value like this:
newrelicAppName := name.toString
the value looks something like this:
$ show newrelicAppName
[info] sbt.SettingKey$$anon$4#54ec2887
Yes, that is actually a string containing lots of strange characters.
On the other hand, if you used the .value call:
newrelicAppName := name.value
the value then looks like:
$ show newrelicAppName
[info] my-project
My best guess is that New Relic doesn't like application names with strange characters (like dollar signs and ampersands). By setting a more normal string, you made it more likely that New Relic would accept such a name as input.
Note: the default value for newrelicAppName is the name for the containing project, so not setting the value at all in the first example would probably have "just worked" as you would have liked.

I realy don't know what I did to make it work, the changes I made were:
In the build.sbt
newrelicVersion := "3.26.1"
newrelicAppName := "recommenders-jobs-api-monitor"
In the plugin.sbt
addSbtPlugin("com.gilt.sbt" % "sbt-newrelic" % "0.1.5")
(I updated de sbt-newrelic version)
(I harcoded the name of the new relic app)
(I specified the version of the Java Agent)

Related

SBT dependencyOverrides in a scope doesn't seem to work as expected

I would like to have a different version of library in test scope.
I was hoping the simplified version of project descriptor could look like that.
Please mind it's a simplified view, in my real project it's more convoluted. I need to use dependencyOverrides to enforce certain library version.
import sbt._, Keys._
organization := "me"
name := "test"
version := "0.1"
libraryDependencies := Seq("ch.qos.logback" % "logback-classic" % "1.2.3")
dependencyOverrides := Seq(
"ch.qos.logback" % "logback-classic" % "1.2.2"
)
dependencyOverrides in Test := Seq(
"ch.qos.logback" % "logback-classic" % "1.2.1"
)
I'd be hoping to see logback-classic version 1.2.1 when I run:
show test:managedClasspath.
Instead I get logback-classic version 1.2.2 as if dependencyOverrides in Test was ignored.
At the same time when I run show Test/dependencyOverrides I get the expected result which is:
ch.qos.logback:logback-classic:1.2.1
Does anyone has a clue what am I missing in the relation between dependencyOverrides in Test scope and managedClasspath?
It appears the problem cannot be solve the way I imagined. The main reason is libraryDependencies and update are not scoped to configuration.
I think the best solution is in case I need a different version of library in some tests to extract those tests to a separate module with independent set of libraryDependencies.

What is the meaning of 4th `%` in `libraryDependencies`in sbt

In the following setting, I suppose the format is "groupId" % "artifactId" % "version"
libraryDependencies += "org.specs2" % "specs2_2.10" % "1.14" % "test"
What does test mean?
As described here
Declaring a dependency looks like this, where groupId, artifactId, and revision are strings:
libraryDependencies += groupID % artifactID % revision
or like this, where configuration can be a string or Configuration val:
libraryDependencies += groupID % artifactID % revision % configuration
So the 4th % meaning is to add a dependency only to a certain configuration. In your example it is "test", which could also be written as Test.
The meaning is that you don't usually need to keep in your runtime classpath classes for test framework which you only use in staging environment and never use in production.
To learn more about configurations you can read this.

Pass in version number when building in sbt

I have a semi-complicated SBT process because I need to conditionally include a different config file based on what kind of build is needed. I solved this problem through sub-projects:
lazy val app = project
.in(file("."))
.enablePlugins(JavaAppPackaging)
.settings(
commonSettings // Seq() of settings to be shared between projects
,sourceGenerators in Compile += (avroScalaGenerateSpecific in Compile).taskValue
,(avroSpecificSourceDirectory in Compile) := new java.io.File("src/main/resources/com/coolCompany/folderName/avro")
)
lazy val localPackage = project
.in(file("build/local"))
.enablePlugins(JavaAppPackaging)
.settings(
organization := "com.coolCompany",
version := "0.1.0-SNAPSHOT",
scalaVersion := "2.11.8",
name := "my-neat-project",
scalacOptions := compilerOptions, //Seq() of compiler flags
sourceDirectory in Compile := (sourceDirectory in (app, Compile)).value,
mappings in Universal += {
((sourceDirectory in Compile).value / "../../conf/local/config.properties") -> "lib/config.properties"
}
)
.dependsOn(app)
val buildNumber = inputKey[String]("The version number of the artifact.")
lazy val deployedPackage = project
.in(file("build/deployed"))
.enablePlugins(JavaAppPackaging)
.settings(
organization := "com.coolCompany",
buildNumber := {
val args : Seq[String] = spaceDelimited("<arg>").parsed
println(s"Input version number is ${args.head}")
args.head
},
version := buildNumber.inputTaskValue + "-SNAPSHOT", //"0.1.0-SNAPSHOT",
scalaVersion := "2.11.8",
name := "my-cool-project",
scalacOptions := compilerOptions,
sourceDirectory in Compile := (sourceDirectory in (app, Compile)).value,
mappings in Universal += {
((sourceDirectory in Compile).value / "../../conf/deployed/config.properties") -> "lib/config.properties"
}
)
.dependsOn(app)
Now I need to allow the version number to be passed in by a build tool when building. You can see what I've attempted to do already: I created an inputKey task called buildNumber, then tried to access that in the version := definition. I can run the buildNumber task itself just fine:
$ sbt 'deployedPackage/buildNumber 0.1.2'
Input version number is 0.1.2
So I can at least verify that my input task works as expected. The issue is that I can't figure out how I actually get to that input value when running the actual packageBin step that I want.
I've tried the following:
$ sbt 'deployedPackage/universal:packageBin 0.1.2'
[error] Expected key
[error] Expected '::'
[error] Expected end of input.
[error] deployedPackage/universal:packageBin 0.1.2
So it clearly doesn't understand what to do with the version number. I've tried a bunch of different input variations, such as [...]packageBin buildNumber::0.1.2, [...]packageBin -- buildNumber 0.1.2, or [...]packageBin -- 0.1.2, and all of them give that error or something similar indicating it doesn't understand what I'm trying to pass in.
Now, ultimately, these errors make sense. buildNumber, the task, is what knows what to do with the command line values, but packageBin does not. How do I set up this task or these set of tasks to allow the version number to be passed in?
I have seen this question but the answers link to an sbt plugin that seems to do about 100 more things than I want it to do, including quite a few that I would need to find a way to explicitly disable. I only want the version number to be able to be passed in & used in the artifact.
Edit/Update: I resolved this issue by switching back to Maven.
I think you're a bit confused about the way sbt settings work. Settings are set when sbt loads and then cannot be changed until you reload the session. So whatever you set version to, it will be fixed, it cannot be dynamic and depend on user input or a task (which on the contrast is dynamic and is evaluated every time you call it).
This is true. However you can still compute a SettingKey value in the first place. We use environment variables to set our build version.
version := "1." + sys.env.getOrElse("BUILD_NUMBER", "0-SNAPSHOT")
Explanation
1. is the major version. Increment this manually as you like
BUILD_NUMBER is an environment variable that is typically set by a CI, e.g. Jenkins. If not set, use 0-SNAPSHOT as a version suffix.
We use this in our company for our continuous deployment pipeline.
Hope that helps,
Muki
I think you're a bit confused about the way sbt settings work. Settings are set when sbt loads and then cannot be changed until you reload the session. So whatever you set version to, it will be fixed, it cannot be dynamic and depend on user input or a task (which on the contrast is dynamic and is evaluated every time you call it).
You have an input task buildNumber which depends on user input and is evaluated every time you call it:
> show buildNumber 123
Input version number is 123
[info] 123
[success] Total time: 0 s, completed Dec 24, 2017 3:41:43 PM
> show buildNumber 456
Input version number is 456
[info] 456
[success] Total time: 0 s, completed Dec 24, 2017 3:41:45 PM
It returns whatever you give it and doesn't do anything (besides println). More importantly, it doesn't affect version setting anyhow (and couldn't even in theory).
When you use buildNumber.inputTaskValue, you refer to the input task itself, not its value (which is unknown because it depends on the user input). You can see it by checking the version setting value:
> show version
[info] sbt.InputTask#6c996907-SNAPSHOT
So it's definitely not what you want.
I suggest you to review your approach in general and read a bit more sbt docs, for example about Task graph (and the whole Getting started chapter).
If you still really need to set version on sbt load according to your input, you can do it with a command. It would look like this:
commands += Command.single("pkg") { (state0, buildNumber) =>
val state1 = Project.extract(state0).append(Seq(version := buildNumber + "-SNAPSHOT"), state0)
val (state2, result) = Project.extract(state1).runTask(packageBin in (deployedPackage, universal), state1)
state2
}
But you should be really careful dealing with the state manually. Again, I recommend you to review your approach and change it to a more sbt-idiomatic one.
I suggest you just set the version setting only for the project deployedPackage just before you call the task needing the version. This is the simplest way of setting the version, and as settings keys have scopes, this should work as intended.
I used something like this for a big multi module project, where one of the projects had a separate versioning history than the other projects.

What does "provided->default" mean in an sbt build file?

An example of this comes from a sample github project:
libraryDependencies ++= Seq(
"javax.servlet" % "servlet-api" % "2.5" % "provided->default",
...
}
I'm only vaguely clear on what the 'fourth column' in these configurations mean, but this is the first time I've seen either provided or provided->default, and it's unclear how I can go about finding what should be expected here in the documentation. Can anyone help explain this construct?
It means that your provided configuration depends on the default configuration of "java.servlet" % "servlet-api" % "2.5".
Maven scopes describe what these configurations or scopes mean.
For instance, if you're using a library to write your tests, you've probably come across something like "org.scalacheck" %% "scalacheck" % "1.13.2" % "test" or similar. Here, the second part of the configuration is omitted and refers to the default configuration (usually compile). Equivalently, you could write "org.scalacheck" %% "scalacheck" % "1.13.2" % "test->compile". It means that your test configuration depends on the default configuration of ScalaCheck: your tests need ScalaCheck on the class path to compile and run.
You may find more details in the Ivy documentation.

Can SBT work with jMockit?

After many struggles I finally got a large project converted over from Maven to SBT. One of the remaining issues, however, is that some of the unit tests in the project use jMockit which can be a bit high-maintenance when it comes to configuring the environment.
Specifically the jmockit dependency/jar has two difficult requirements:
The jmockit jar must appear in the classpath before the junit jar
On many JVM's, such as the OpenJDK one I'm using, the JVM argument -javaagent:<path/to/jmockit.jar> is required
If both of these conditions are not met, I'm faced with the error:
[error] Test <mytestclass>.initializationError failed: java.lang.Exception: Method <mytestmethod> should have no parameters
[error] at mockit.integration.junit4.JMockit.<init>(JMockit.java:32)
I think I eventually managed to take care of #1 with SBT but I'm still having trouble with the second one. The debug SBT logs do not show enough detail about the forked process invocation to tell me if my settings are working or not. But the test output consistently indicates that it's not working. I have what I think are all the relevant settings:
lazy val myproj = Project(
...
settings = otherSettings ++ Seq(
libraryDependencies ++= Seq(
"com.googlecode.jmockit" % "jmockit" % "1.7" % "test",
"junit" % "junit" % "4.8.1" % "test"
),
fork in Test := true,
javaOptions in test += "-javaagent:<hardcode-path-to-jmockit.jar>"
)
I think the classpath is OK based on the output of the test:dependencyClasspath:
sbt> project <myproject>
sbt> show test:dependencyClasspath
[info] List(...., Attributed(/var/build/ivy2/cache/junit/junit/jars/junit-4.8.1.jar), ...
..., Attributed(/var/build/ivy2/cache/com.googlecode.jmockit/jmockit/jars/jmockit-1.7.jar), ...)
So I'm thinking that my javaagent setting is not having the intended result.
If I do happen to get this to work, my next question is how to get the hard-coded jmockit.jar path out of there but for now I'll settle for a passing test case.
So, how do I set the JVM options used for testing? How do I view/verify what options are actually used when the tests are launched?
You need to change your javaOptions to javaOptions in Test (note the T in Test is capitalized).
You can check your options by executing show test:javaOptions
> show test:javaOptions
[info] List(-javaagent:/home/lpiepiora/.ivy2/cache/com.googlecode.jmockit/jmockit/jars/jmockit-1.7.jar)
Additionally if you want to use dynamic path to the jmockit jar, you can set your javaOptions like this:
def jmockitPath(f: Seq[File]) = f.filter(_.name.endsWith("jmockit-1.7.jar")).head
javaOptions in Test += s"-javaagent:${jmockitPath((dependencyClasspath in Test).value.files)}"
build.sbt for reference
libraryDependencies += "com.novocode" % "junit-interface" % "0.9" % "test"
libraryDependencies ++= Seq(
"com.googlecode.jmockit" % "jmockit" % "1.7" % "test",
"junit" % "junit" % "4.8.1" % "test"
)
fork in Test := true
def jmockitPath(f: Seq[File]) = f.filter(_.name.endsWith("jmockit-1.7.jar")).head
javaOptions in Test += s"-javaagent:${jmockitPath((dependencyClasspath in Test).value.files)}"

Resources