aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/xyz/driver/core/app/init.scala
blob: d505f0ffd2a15513ae459104d5ea9f4a88717037 (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
125
126
127
128
129
130
131
132
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
  }
  object ApplicationContext {
    def apply(config: Config, clock: Clock, log0: Logger): ApplicationContext = {
      val reporter = new NoTraceReporter with ScalaLoggingCompat {
        val logger = log0
      }
      ApplicationContext(config, clock, reporter)
    }
    def apply(config: Config, time: TimeProvider, log0: Logger): ApplicationContext =
      ApplicationContext(config, time.toClock, log0)
  }

  /** 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(),
      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)
  }

}