diff --git a/quine/src/main/scala/com/thatdot/quine/app/ImproveQuine.scala b/quine/src/main/scala/com/thatdot/quine/app/ImproveQuine.scala index 9d25f4e0..1baf8679 100644 --- a/quine/src/main/scala/com/thatdot/quine/app/ImproveQuine.scala +++ b/quine/src/main/scala/com/thatdot/quine/app/ImproveQuine.scala @@ -18,36 +18,33 @@ import org.apache.pekko.http.scaladsl.model.{HttpEntity, HttpMethods, HttpReques import org.apache.pekko.pattern.retry import com.typesafe.scalalogging.StrictLogging - -trait ImproveQuine { - def started(): Future[Unit] -} +import io.circe.syntax.EncoderOps object ImproveQuine { - object Noop extends ImproveQuine { - def started(): Future[Unit] = Future.successful(()) - } - case class Enabled( - quineVersion: String, + val eventUri: Uri = Uri("https://improve.quine.io/event") + case class TelemetryRequest( + service: String, + version: String, hostHash: String, - eventUri: Uri, - system: ActorSystem - ) extends ImproveQuine - with StrictLogging { - implicit private val actorSystem: ActorSystem = system + extraArgs: Map[String, String] + )(implicit system: ActorSystem) + extends StrictLogging { implicit private val executionContext: ExecutionContext = system.dispatcher implicit private val scheduler: Scheduler = system.scheduler - def started(): Future[Unit] = { + def run(): Future[Unit] = { val now = java.time.OffsetDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME) - val body: String = s"""{ - | "service": "Quine", - | "version": "$quineVersion", - | "host_hash": "$hostHash", - | "event": "instance.started", - | "time": "$now" - |}""".stripMargin + + val telemetryData = Map[String, String]( + "service" -> service, + "version" -> version, + "host_hash" -> hostHash, + "event" -> "instance.started", + "time" -> now + ) ++ extraArgs + + val body = telemetryData.asJson.noSpaces val send = () => Http() @@ -83,7 +80,7 @@ object ImproveQuine { private val prefixBytes = "Quine_".getBytes(StandardCharsets.UTF_8) - private def hostHash(): String = { + private def hostHash(): String = Try { val mac = hostMac() val encoder = Base64.getEncoder // Salt the input to prevent a SHA256 of a MAC address from matching another system using a SHA256 of a MAC @@ -91,14 +88,14 @@ object ImproveQuine { val prefixedBytes = Array.concat(prefixBytes, mac) val hash = MessageDigest.getInstance("SHA-256").digest(prefixedBytes) encoder.encodeToString(hash) - } + }.getOrElse("host_unavailable") - def apply( - enabled: Boolean, + def reportTelemetry( + service: String, quineVersion: String, - eventUri: Uri, - system: ActorSystem - ): ImproveQuine = if (enabled) { - Try(Enabled(quineVersion, hostHash(), eventUri, system)).getOrElse(Noop) - } else Noop + /* extra values some callers may wish to add to telemetry.*/ + extraArgs: Map[String, String] = Map.empty[String, String] + )(implicit system: ActorSystem): Future[Unit] = + TelemetryRequest(service, quineVersion, hostHash(), extraArgs).run() + } diff --git a/quine/src/main/scala/com/thatdot/quine/app/Main.scala b/quine/src/main/scala/com/thatdot/quine/app/Main.scala index 57af8a43..969e8f66 100644 --- a/quine/src/main/scala/com/thatdot/quine/app/Main.scala +++ b/quine/src/main/scala/com/thatdot/quine/app/Main.scala @@ -195,13 +195,13 @@ object Main extends App with LazyLogging { interpreter.run(quineApp.thisMemberIdx) interpreter } - private val improveQuine = ImproveQuine( - config.helpMakeQuineBetter, - BuildInfo.version, - Uri("https://improve.quine.io/event"), - system - ) - improveQuine.started() + + // report telemetry only if the user has opted in. + if (config.helpMakeQuineBetter) + ImproveQuine.reportTelemetry( + "Quine", + BuildInfo.version + ) bindAndResolvableAddresses foreach { case (bindAddress, resolvableUrl) => new QuineAppRoutes(graph, quineApp, config.loadedConfigJson, resolvableUrl, timeout)