-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Support part of Metrics API (#9)
- Loading branch information
Showing
16 changed files
with
413 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
integrationTests/src/test/scala/scaladog/MetricsAPIIntegrationTest.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package scaladog | ||
|
||
import java.time.Instant | ||
import java.time.temporal.ChronoUnit | ||
|
||
import org.scalatest.Inside | ||
|
||
import scala.util.Random | ||
|
||
class MetricsAPIIntegrationTest extends ClientITSpec with Inside { | ||
|
||
test("GET /metrics") { | ||
val from = Instant.now().minus(1, ChronoUnit.DAYS).truncatedTo(ChronoUnit.SECONDS) | ||
val host = "myhost" | ||
val response = client.getMetrics(from, host) | ||
inside(response) { case GetMetricsResponse(_, actualFrom, actualHost) => | ||
assert(actualFrom == from) | ||
assert(Some(host) == actualHost) | ||
} | ||
} | ||
|
||
test("POST /series") { | ||
val response = client.postMetrics( | ||
Seq( | ||
Series( | ||
metric = "test.metric", | ||
points = Seq(Point(Instant.now(), Random.nextInt(1000))), | ||
host = "myhost", | ||
tags = Seq(Tag("project:scaladog")), | ||
MetricType.Gauge | ||
) | ||
) | ||
) | ||
assert(response.isOk) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package scaladog | ||
|
||
import java.time.Instant | ||
|
||
import DDPickle._ | ||
|
||
case class GetMetricsResponse( | ||
metrics: Seq[String], | ||
from: Instant, | ||
private val host: Option[String] = None | ||
) | ||
|
||
object GetMetricsResponse { | ||
implicit val reader: Reader[GetMetricsResponse] = macroR | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package scaladog | ||
|
||
sealed abstract class MetricType(val name: String) { | ||
def asMetricType: MetricType = this | ||
} | ||
|
||
object MetricType { | ||
case object Gauge extends MetricType("gauge") | ||
case object Rate extends MetricType("rate") | ||
case object Count extends MetricType("count") | ||
|
||
val all: Set[MetricType] = Set(Gauge, Rate, Count) | ||
|
||
def fromString(str: String): Option[MetricType] = all.find(_.name == str) | ||
|
||
implicit def readwriter: DDPickle.ReadWriter[MetricType] = | ||
DDPickle | ||
.readwriter[String] | ||
.bimap( | ||
_.name, | ||
s => fromString(s).getOrElse(throw new IllegalArgumentException(s"Invalid MetricType: $s")) | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package scaladog | ||
|
||
private[scaladog] case class PostMetricsRequest(series: Seq[Series]) | ||
|
||
private[scaladog] object PostMetricsRequest { | ||
implicit val writer: DDPickle.Writer[PostMetricsRequest] = DDPickle.macroW | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package scaladog | ||
|
||
import java.time.Instant | ||
|
||
case class Series( | ||
metric: String, | ||
points: Seq[Point], | ||
host: String = "", | ||
tags: Seq[Tag] = Seq.empty, | ||
@upickle.implicits.key("type") metricType: MetricType = MetricType.Gauge | ||
) | ||
|
||
object Series { | ||
implicit val writer: DDPickle.Writer[Series] = DDPickle.macroW | ||
} | ||
|
||
case class Point(timestamp: Instant, value: BigDecimal) | ||
|
||
object Point { | ||
implicit val writer: DDPickle.Writer[Point] = | ||
DDPickle.writer[ujson.Arr].comap(p => ujson.Arr(p.timestamp.getEpochSecond, p.value.toString())) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package scaladog | ||
|
||
case class StatusResponse(status: String) { | ||
val isOk: Boolean = status.toLowerCase == "ok" | ||
} | ||
|
||
object StatusResponse { | ||
implicit val reader: DDPickle.Reader[StatusResponse] = DDPickle.macroR | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package scaladog | ||
|
||
sealed trait Tag { | ||
def asString: String | ||
def asTag: Tag = this | ||
} | ||
|
||
object Tag { | ||
|
||
case class Value(value: String) extends Tag { | ||
val asString: String = value | ||
} | ||
|
||
case class KeyValue(key: String, value: String) extends Tag { | ||
val asString: String = s"$key:$value" | ||
} | ||
|
||
def apply(str: String): Tag = { | ||
val (left, right) = str.span(_ != ':') | ||
if (right.isEmpty) Value(left) | ||
else KeyValue(left, right.drop(1)) | ||
} | ||
|
||
implicit val readwriter: DDPickle.ReadWriter[Tag] = | ||
DDPickle.readwriter[String].bimap(_.asString, apply) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import java.time.Instant | ||
|
||
package object scaladog { | ||
|
||
/** | ||
* http://www.lihaoyi.com/upickle/#CustomConfiguration | ||
*/ | ||
private[scaladog] object DDPickle extends upickle.AttributeTagged { | ||
private def camelToSnake(s: String) = { | ||
s.split("(?=[A-Z])", -1).map(_.toLowerCase).mkString("_") | ||
} | ||
private def snakeToCamel(s: String) = { | ||
val res = s.split("_", -1).map(x => x(0).toUpper + x.drop(1)).mkString | ||
s(0).toLower + res.drop(1) | ||
} | ||
|
||
override def objectAttributeKeyReadMap(s: CharSequence): String = | ||
snakeToCamel(s.toString) | ||
override def objectAttributeKeyWriteMap(s: CharSequence): String = | ||
camelToSnake(s.toString) | ||
|
||
override def objectTypeKeyReadMap(s: CharSequence): String = | ||
snakeToCamel(s.toString) | ||
override def objectTypeKeyWriteMap(s: CharSequence): String = | ||
camelToSnake(s.toString) | ||
|
||
override implicit def OptionWriter[T: Writer]: Writer[Option[T]] = | ||
implicitly[Writer[T]].comap[Option[T]] { | ||
case None => null.asInstanceOf[T] | ||
case Some(x) => x | ||
} | ||
|
||
override implicit def OptionReader[T: Reader]: Reader[Option[T]] = | ||
implicitly[Reader[T]].mapNulls { | ||
case null => None | ||
case x => Some(x) | ||
} | ||
} | ||
|
||
import DDPickle._ | ||
|
||
private[scaladog] implicit val instantR: Reader[Instant] = | ||
reader[String].map(s => Instant.ofEpochSecond(s.toInt)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package scaladog | ||
|
||
import org.scalatest.FunSpec | ||
|
||
class MetricTypeTest extends FunSpec { | ||
|
||
describe("readwriter") { | ||
|
||
it("should read a string") { | ||
assert(DDPickle.read[MetricType]("\"rate\"") == MetricType.Rate) | ||
} | ||
|
||
it("should throw an IllegalArgumentException when read an invalid string") { | ||
assertThrows[IllegalArgumentException](DDPickle.read[MetricType]("\"invalid\"") == null) | ||
} | ||
|
||
it("should write JSON from a string") { | ||
assert(DDPickle.write(MetricType.Gauge.asMetricType) == "\"gauge\"") | ||
} | ||
} | ||
} |
Oops, something went wrong.