aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/xyz/driver/core/app/init.scala
blob: bb7a798b491884929f9cd9453b6027318ba14a55 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package xyz.driver.core.app

import java.nio.file.{Files, Paths}
import java.time.Clock
import java.util.concurrent.{Executor, Executors}

import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import com.typesafe.config.{Config, ConfigFactory}
import com.typesafe.scalalogging.Logger
import org.slf4j.LoggerFactory
import xyz.driver.core.logging.MdcExecutionContext
import xyz.driver.core.reporting.{ScalaLoggingCompat, NoTraceReporter}
import xyz.driver.core.time.provider.TimeProvider
import xyz.driver.tracing.{GoogleTracer, NoTracer, Tracer}

import scala.concurrent.ExecutionContext
import scala.util.Try
import scala.language.reflectiveCalls

object init {

  type RequiredBuildInfo = {
    val name: String
    val version: String
    val gitHeadCommit: scala.Option[String]
  }

  case class ApplicationContext(config: Config, clock: Clock, reporter: ScalaLoggingCompat) {
    val time: TimeProvider = clock
  }

  /** NOTE: This needs to be the first that is run when application starts.
    * Otherwise if another command causes the logger to be instantiated,
    * it will default to logback.xml, and not honor this configuration
    */
  def configureLogging(): Unit = {
    scala.sys.env.get("JSON_LOGGING") match {
      case Some("true") =>
        System.setProperty("logback.configurationFile", "deployed-logback.xml")
      case _ =>
        System.setProperty("logback.configurationFile", "logback.xml")
    }
  }

  def getEnvironmentSpecificConfig(): Config = {
    scala.sys.env.get("APPLICATION_CONFIG_TYPE") match {
      case Some("deployed") =>
        ConfigFactory.load(this.getClass.getClassLoader, "deployed-application.conf")
      case _ =>
        xyz.driver.core.config.loadDefaultConfig
    }
  }

  def configureTracer(actorSystem: ActorSystem, applicationContext: ApplicationContext): Tracer = {

    val serviceAccountKeyFile =
      Paths.get(applicationContext.config.getString("tracing.google.serviceAccountKeyfile"))

    if (Files.exists(serviceAccountKeyFile)) {
      val materializer = ActorMaterializer()(actorSystem)
      new GoogleTracer(
        projectId = applicationContext.config.getString("tracing.google.projectId"),
        serviceAccountFile = serviceAccountKeyFile
      )(actorSystem, materializer)
    } else {
      applicationContext.reporter.logger.warn(s"Tracing file $serviceAccountKeyFile was not found, using NoTracer!")
      NoTracer
    }
  }

  def serviceActorSystem(serviceName: String, executionContext: ExecutionContext, config: Config): ActorSystem = {
    val actorSystem =
      ActorSystem(s"$serviceName-actors", Option(config), Option.empty[ClassLoader], Option(executionContext))

    sys.addShutdownHook {
      Try(actorSystem.terminate())
    }

    actorSystem
  }

  def toMdcExecutionContext(executor: Executor) =
    new MdcExecutionContext(ExecutionContext.fromExecutor(executor))

  def newFixedMdcExecutionContext(capacity: Int): MdcExecutionContext =
    toMdcExecutionContext(Executors.newFixedThreadPool(capacity))

  def defaultApplicationContext(): ApplicationContext =
    ApplicationContext(
      config = getEnvironmentSpecificConfig(),
      clock = Clock.systemUTC(),
      new NoTraceReporter with ScalaLoggingCompat {
        val logger = Logger(LoggerFactory.getLogger(classOf[DriverApp]))
      }
    )

  def createDefaultApplication(
      modules: Seq[Module],
      buildInfo: RequiredBuildInfo,
      actorSystem: ActorSystem,
      tracer: Tracer,
      context: ApplicationContext): DriverApp = {
    val scheme  = context.config.getString("application.scheme")
    val baseUrl = context.config.getString("application.baseUrl")
    val port    = context.config.getInt("application.port")

    new DriverApp(
      buildInfo.name,
      buildInfo.version,
      buildInfo.gitHeadCommit.getOrElse("None"),
      modules = modules,
      context.time,
      context.reporter,
      context.config,
      interface = "0.0.0.0",
      baseUrl,
      scheme,
      port,
      tracer
    )(actorSystem, actorSystem.dispatcher)
  }

}