All Downloads are FREE. Search and download functionalities are using the official Maven repository.

events.alerts.scala Maven / Gradle / Ivy

package otoroshi.events

import java.util.concurrent.{Executors, TimeUnit}
import akka.actor.{Actor, Cancellable, OneForOneStrategy, PoisonPill, Props, SupervisorStrategy, Terminated}
import akka.actor.SupervisorStrategy._
import akka.http.scaladsl.util.FastFuture._
import akka.http.scaladsl.util.FastFuture
import akka.stream.scaladsl.{Keep, Sink, Source}
import akka.stream.{OverflowStrategy, QueueOfferResult, ThrottleMode}
import akka.util.ByteString
import otoroshi.env.Env
import otoroshi.models.{QuotasAlmostExceededSettings, _}
import org.joda.time.DateTime
import play.api.Logger
import play.api.libs.json.{
  Format,
  JsArray,
  JsError,
  JsNull,
  JsObject,
  JsResult,
  JsString,
  JsSuccess,
  JsValue,
  Json,
  Writes
}
import play.api.libs.ws.WSAuthScheme
import play.api.mvc.RequestHeader
import otoroshi.ssl.Cert

import scala.concurrent.duration.Duration
import scala.concurrent.{ExecutionContext, Future}
import scala.util.{Failure, Success, Try}
import scala.concurrent.duration.FiniteDuration
import otoroshi.utils.http.RequestImplicits._
import otoroshi.utils.mailer.EmailLocation
import otoroshi.utils.syntax.implicits._

trait AlertEvent extends AnalyticEvent {
  override def `@type`: String = "AlertEvent"
}

object AlertEvent {
  def generic(alert: String, `@service`: String = "Otoroshi", `@serviceId`: String = "")(
      additionalPayload: JsObject
  )(implicit env: Env): GenericAlert = {
    GenericAlert(alert, env, `@service`, `@serviceId`)(additionalPayload)
  }
}

case class GenericAlert(alert: String, env: Env, `@service`: String = "Otoroshi", `@serviceId`: String = "")(
    additionalPayload: JsObject
) extends AlertEvent {

  val `@id`: String                 = env.snowflakeGenerator.nextIdStr()
  val `@timestamp`: DateTime        = DateTime.now()
  val fromOrigin: Option[String]    = None
  val fromUserAgent: Option[String] = None

  override def toJson(implicit _env: Env): JsValue = {
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "@env"       -> env.env,
      "alert"      -> alert
    ) ++ additionalPayload
  }
}

case class ApiKeySecretWillRotate(
    `@id`: String,
    `@env`: String,
    apikey: ApiKey,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = None
  override def fromUserAgent: Option[String] = None

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "ApiKeySecretWillRotate",
      "inHoursOrLess" -> apikey.rotation.gracePeriod,
      "apikey"        -> apikey.toJson
    )
}

case class ApiKeySecretHasRotated(
    `@id`: String,
    `@env`: String,
    oldApikey: ApiKey,
    apikey: ApiKey,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = None
  override def fromUserAgent: Option[String] = None

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "@env"       -> `@env`,
      "alert"      -> "ApiKeySecretHasRotated",
      "oldApikey"  -> oldApikey.toJson,
      "apikey"     -> apikey.toJson
    )
}

case class MaxConcurrentRequestReachedAlert(
    `@id`: String,
    `@env`: String,
    limit: Long,
    current: Long,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = None
  override def fromUserAgent: Option[String] = None

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "@env"       -> `@env`,
      "alert"      -> "MaxConcurrentRequestReachedAlert",
      "limit"      -> limit,
      "current"    -> current
    )
}

case class HighOverheadAlert(
    `@id`: String,
    limitOverhead: Double,
    currentOverhead: Long,
    serviceDescriptor: Option[ServiceDescriptor],
    target: Location,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = serviceDescriptor.map(_.name).getOrElse("--")
  override def `@serviceId`: String = serviceDescriptor.map(_.id).getOrElse("--")

  override def fromOrigin: Option[String]    = None
  override def fromUserAgent: Option[String] = None

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "alert"      -> "HighOverheadAlert",
      "limit"      -> limitOverhead,
      "overhead"   -> currentOverhead,
      "target"     -> Location.format.writes(target),
      "service"    -> serviceDescriptor.map(_.toJson).getOrElse(JsNull).asValue
    )
}

case class CircuitBreakerOpenedAlert(
    `@id`: String,
    `@env`: String,
    target: Target,
    service: JsValue,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = service.select("id").asOpt[String].getOrElse("--")

  override def fromOrigin: Option[String]    = None
  override def fromUserAgent: Option[String] = None

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "@env"       -> `@env`,
      "alert"      -> "CircuitBreakerOpenedAlert",
      "target"     -> target.toJson,
      "service"    -> service
    )
}

case class CircuitBreakerClosedAlert(
    `@id`: String,
    `@env`: String,
    target: Target,
    service: JsValue,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = service.select("id").asOpt[String].getOrElse("--")

  override def fromOrigin: Option[String]    = None
  override def fromUserAgent: Option[String] = None

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "@env"       -> `@env`,
      "alert"      -> "CircuitBreakerClosedAlert",
      "target"     -> target.toJson,
      "service"    -> service
    )
}

case class SessionDiscardedAlert(
    `@id`: String,
    `@env`: String,
    user: BackOfficeUser,
    event: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = Some(from)
  override def fromUserAgent: Option[String] = Some(ua)

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "@env"       -> `@env`,
      "alert"      -> "SessionDiscardedAlert",
      "user"       -> user.profile
    )
}

case class SessionsDiscardedAlert(
    `@id`: String,
    `@env`: String,
    user: BackOfficeUser,
    event: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = Some(from)
  override def fromUserAgent: Option[String] = Some(ua)

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "@env"       -> `@env`,
      "alert"      -> "SessionsDiscardedAlert",
      "user"       -> user.profile
    )
}

case class PanicModeAlert(
    `@id`: String,
    `@env`: String,
    user: BackOfficeUser,
    event: BackOfficeEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = Some(from)
  override def fromUserAgent: Option[String] = Some(ua)

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "@env"       -> `@env`,
      "alert"      -> "PanicModeAlert",
      "user"       -> user.profile
    )
}

case class OtoroshiExportAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    event: AdminApiEvent,
    export: JsValue,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = Some(from)
  override def fromUserAgent: Option[String] = Some(ua)

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "@env"       -> `@env`,
      "alert"      -> "OtoroshiExportAlert",
      "user"       -> user,
      "event"      -> event.toJson,
      "export"     -> export
    )
}

case class SnowMonkeyStartedAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    audit: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = Some(from)
  override def fromUserAgent: Option[String]       = Some(ua)
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "SnowMonkeyStartedAlert",
      "adminApiAlert" -> true,
      "user"          -> user,
      "audit"         -> audit.toJson
    )
}
case class SnowMonkeyStoppedAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    audit: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = Some(from)
  override def fromUserAgent: Option[String]       = Some(ua)
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "SnowMonkeyStoppedAlert",
      "adminApiAlert" -> true,
      "user"          -> user,
      "audit"         -> audit.toJson
    )
}
case class SnowMonkeyConfigUpdatedAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    audit: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = Some(from)
  override def fromUserAgent: Option[String]       = Some(ua)
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "SnowMonkeyConfigUpdatedAlert",
      "adminApiAlert" -> true,
      "user"          -> user,
      "audit"         -> audit.toJson
    )
}
case class SnowMonkeyResetAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    audit: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = Some(from)
  override def fromUserAgent: Option[String]       = Some(ua)
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "SnowMonkeyResetAlert",
      "adminApiAlert" -> true,
      "user"          -> user,
      "audit"         -> audit.toJson
    )
}

case class CertCreatedAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    audit: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = Some(from)
  override def fromUserAgent: Option[String]       = Some(ua)
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "CertCreatedAlert",
      "adminApiAlert" -> true,
      "user"          -> user,
      "audit"         -> audit.toJson
    )
}

case class CertUpdatedAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    audit: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = Some(from)
  override def fromUserAgent: Option[String]       = Some(ua)
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "CertUpdatedAlert",
      "adminApiAlert" -> true,
      "user"          -> user,
      "audit"         -> audit.toJson
    )
}

case class CertDeleteAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    audit: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = Some(from)
  override def fromUserAgent: Option[String]       = Some(ua)
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "CertDeleteAlert",
      "adminApiAlert" -> true,
      "user"          -> user,
      "audit"         -> audit.toJson
    )
}

case class CertRenewalAlert(`@id`: String, `@env`: String, cert: Cert, `@timestamp`: DateTime = DateTime.now())
    extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = None
  override def fromUserAgent: Option[String] = None

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"         -> `@id`,
      "@timestamp"  -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"       -> `@type`,
      "@product"    -> _env.eventsName,
      "@serviceId"  -> `@serviceId`,
      "@service"    -> `@service`,
      "@env"        -> `@env`,
      "audit"       -> "CertRenewalAlert",
      "certificate" -> cert.toJson
    )
}

case class CertExpiredAlert(`@id`: String, `@env`: String, cert: Cert, `@timestamp`: DateTime = DateTime.now())
    extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = None
  override def fromUserAgent: Option[String] = None

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"         -> `@id`,
      "@timestamp"  -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"       -> `@type`,
      "@product"    -> _env.eventsName,
      "@serviceId"  -> `@serviceId`,
      "@service"    -> `@service`,
      "@env"        -> `@env`,
      "audit"       -> "CertExpiredAlert",
      "certificate" -> cert.toJson
    )
}

case class CertAlmostExpiredAlert(`@id`: String, `@env`: String, cert: Cert, `@timestamp`: DateTime = DateTime.now())
    extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = None
  override def fromUserAgent: Option[String] = None

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"         -> `@id`,
      "@timestamp"  -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"       -> `@type`,
      "@product"    -> _env.eventsName,
      "@serviceId"  -> `@serviceId`,
      "@service"    -> `@service`,
      "@env"        -> `@env`,
      "audit"       -> "CertAlmostExpiredAlert",
      "certificate" -> cert.toJson
    )
}

case class SnowMonkeyOutageRegisteredAlert(
    `@id`: String,
    `@env`: String,
    audit: AuditEvent,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = None
  override def fromUserAgent: Option[String]       = None
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "SnowMonkeyResetAlert",
      "adminApiAlert" -> true,
      "user"          -> "--",
      "audit"         -> audit.toJson
    )
}

case class U2FAdminDeletedAlert(
    `@id`: String,
    `@env`: String,
    user: BackOfficeUser,
    event: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = Some(from)
  override def fromUserAgent: Option[String] = Some(ua)

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "@env"       -> `@env`,
      "alert"      -> "U2FAdminDeletedAlert",
      "event"      -> event.toJson,
      "user"       -> user.profile
    )
}

case class WebAuthnAdminDeletedAlert(
    `@id`: String,
    `@env`: String,
    user: BackOfficeUser,
    event: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = Some(from)
  override def fromUserAgent: Option[String] = Some(ua)

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "@env"       -> `@env`,
      "alert"      -> "WebAuthnAdminDeletedAlert",
      "event"      -> event.toJson,
      "user"       -> user.profile
    )
}

case class BlackListedBackOfficeUserAlert(
    `@id`: String,
    `@env`: String,
    user: BackOfficeUser,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = Some(from)
  override def fromUserAgent: Option[String] = Some(ua)

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "@env"       -> `@env`,
      "alert"      -> "BlackListedBackOfficeUserAlert",
      "user"       -> user.profile
    )
}

case class AdminLoggedInAlert(
    `@id`: String,
    `@env`: String,
    user: BackOfficeUser,
    from: String,
    ua: String,
    provider: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = Some(from)
  override def fromUserAgent: Option[String] = Some(ua)

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"          -> `@id`,
      "@timestamp"   -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"        -> `@type`,
      "@product"     -> _env.eventsName,
      "@serviceId"   -> `@serviceId`,
      "@service"     -> `@service`,
      "@env"         -> `@env`,
      "alert"        -> "AdminLoggedInAlert",
      "userName"     -> user.name,
      "userEmail"    -> user.email,
      "user"         -> user.profile,
      "userRandomId" -> user.randomId,
      "provider"     -> provider
    )
}

case class UserLoggedInAlert(
    `@id`: String,
    `@env`: String,
    user: PrivateAppsUser,
    from: String,
    ua: String,
    provider: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = Some(from)
  override def fromUserAgent: Option[String] = Some(ua)

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"          -> `@id`,
      "@timestamp"   -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"        -> `@type`,
      "@product"     -> _env.eventsName,
      "@serviceId"   -> `@serviceId`,
      "@service"     -> `@service`,
      "@env"         -> `@env`,
      "alert"        -> "UserLoggedInAlert",
      "userName"     -> user.name,
      "userEmail"    -> user.email,
      "user"         -> user.profile,
      "userRandomId" -> user.randomId,
      "provider"     -> provider
    )
}

case class AdminFirstLogin(
    `@id`: String,
    `@env`: String,
    user: BackOfficeUser,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = Some(from)
  override def fromUserAgent: Option[String] = Some(ua)

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"          -> `@id`,
      "@timestamp"   -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"        -> `@type`,
      "@product"     -> _env.eventsName,
      "@serviceId"   -> `@serviceId`,
      "@service"     -> `@service`,
      "@env"         -> `@env`,
      "alert"        -> "AdminFirstLogin",
      "userName"     -> user.name,
      "userEmail"    -> user.email,
      "user"         -> user.profile,
      "userRandomId" -> user.randomId
    )
}

case class AdminLoggedOutAlert(
    `@id`: String,
    `@env`: String,
    user: BackOfficeUser,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = Some(from)
  override def fromUserAgent: Option[String] = Some(ua)

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"          -> `@id`,
      "@timestamp"   -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"        -> `@type`,
      "@product"     -> _env.eventsName,
      "@serviceId"   -> `@serviceId`,
      "@service"     -> `@service`,
      "@env"         -> `@env`,
      "alert"        -> "AdminLoggedOutAlert",
      "userName"     -> user.name,
      "userEmail"    -> user.email,
      "user"         -> user.profile,
      "userRandomId" -> user.randomId
    )
}

case class DbResetAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = Some(from)
  override def fromUserAgent: Option[String] = Some(ua)

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "@env"       -> `@env`,
      "alert"      -> "DbResetAlert",
      "user"       -> user
    )
}

case class DangerZoneAccessAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = Some(from)
  override def fromUserAgent: Option[String] = Some(ua)

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "@env"       -> `@env`,
      "alert"      -> "DangerZoneAccessAlert",
      "user"       -> user
    )
}

case class GlobalConfigModification(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    oldConfig: JsValue,
    newConfig: JsValue,
    audit: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {

  override def `@service`: String   = "Otoroshi"
  override def `@serviceId`: String = "--"

  override def fromOrigin: Option[String]    = Some(from)
  override def fromUserAgent: Option[String] = Some(ua)

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "GlobalConfigModification",
      "adminApiAlert" -> true,
      "oldConfig"     -> oldConfig,
      "newConfig"     -> newConfig,
      "user"          -> user,
      "audit"         -> audit.toJson
    )
}

trait ApiKeyQuotasAlmostExceededReason {
  def name: String
  def json: JsValue = JsString(name)
}

object ApiKeyQuotasAlmostExceededReason {
  case object DailyQuotasAlmostExceeded   extends ApiKeyQuotasAlmostExceededReason {
    def name: String = "daily_quotas_almost_exceeded"
  }
  case object MonthlyQuotasAlmostExceeded extends ApiKeyQuotasAlmostExceededReason {
    def name: String = "monthly_quotas_almost_exceeded"
  }
}

trait ApiKeyQuotasExceededReason {
  def name: String
  def json: JsValue = JsString(name)
}

object ApiKeyQuotasExceededReason {
  case object DailyQuotasExceeded   extends ApiKeyQuotasExceededReason { def name: String = "daily_quotas_exceeded"   }
  case object MonthlyQuotasExceeded extends ApiKeyQuotasExceededReason { def name: String = "monthly_quotas_exceeded" }
}

case class ApiKeyQuotasAlmostExceededAlert(
    `@id`: String,
    `@env`: String,
    apikey: ApiKey,
    remainingQuotas: RemainingQuotas,
    reason: ApiKeyQuotasAlmostExceededReason,
    settings: QuotasAlmostExceededSettings,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = None
  override def fromUserAgent: Option[String]       = None
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "@env"       -> `@env`,
      "alert"      -> "QuotasAlmostExceeded",
      "apikey"     -> apikey.toJson,
      "remaining"  -> remainingQuotas.toJson,
      "settings"   -> settings.json,
      "reason"     -> reason.json
    )
}

case class ApiKeyQuotasExceededAlert(
    `@id`: String,
    `@env`: String,
    apikey: ApiKey,
    remainingQuotas: RemainingQuotas,
    reason: ApiKeyQuotasExceededReason,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = None
  override def fromUserAgent: Option[String]       = None
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "@env"       -> `@env`,
      "alert"      -> "QuotasExceeded",
      "apikey"     -> apikey.toJson,
      "remaining"  -> remainingQuotas.toJson,
      "reason"     -> reason.json
    )
}

case class RevokedApiKeyUsageAlert(
    `@id`: String,
    `@timestamp`: DateTime,
    `@env`: String,
    req: RequestHeader,
    apiKey: ApiKey,
    descriptor: Option[ServiceDescriptor],
    env: Env
) extends AlertEvent {

  override def `@service`: String   = descriptor.map(_.name).getOrElse("--")
  override def `@serviceId`: String = descriptor.map(_.id).getOrElse("--")

  override def fromOrigin: Option[String]    = Some(req.theIpAddress(env))
  override def fromUserAgent: Option[String] = Some(req.theUserAgent)

  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"        -> `@id`,
      "@timestamp" -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"      -> `@type`,
      "@product"   -> _env.eventsName,
      "@serviceId" -> `@serviceId`,
      "@service"   -> `@service`,
      "@env"       -> `@env`,
      "alert"      -> "RevokedApiKeyUsageAlert",
      "from"       -> req.remoteAddress,
      "to"         -> req.theHost,
      "uri"        -> req.relativeUri,
      "apiKey"     -> apiKey.toJson
    )
}
case class ServiceGroupCreatedAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    audit: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = Some(from)
  override def fromUserAgent: Option[String]       = Some(ua)
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "ServiceGroupCreatedAlert",
      "adminApiAlert" -> true,
      "user"          -> user,
      "audit"         -> audit.toJson
    )
}
case class ServiceGroupUpdatedAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    audit: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = Some(from)
  override def fromUserAgent: Option[String]       = Some(ua)
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "ServiceGroupUpdatedAlert",
      "adminApiAlert" -> true,
      "user"          -> user,
      "audit"         -> audit.toJson
    )
}
case class ServiceGroupDeletedAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    audit: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = Some(from)
  override def fromUserAgent: Option[String]       = Some(ua)
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "ServiceGroupDeletedAlert",
      "adminApiAlert" -> true,
      "user"          -> user,
      "audit"         -> audit.toJson
    )
}
case class ServiceCreatedAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    audit: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = Some(from)
  override def fromUserAgent: Option[String]       = Some(ua)
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "ServiceCreatedAlert",
      "adminApiAlert" -> true,
      "user"          -> user,
      "audit"         -> audit.toJson
    )
}
case class ServiceUpdatedAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    audit: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = Some(from)
  override def fromUserAgent: Option[String]       = Some(ua)
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "ServiceUpdatedAlert",
      "adminApiAlert" -> true,
      "user"          -> user,
      "audit"         -> audit.toJson
    )
}
case class ServiceDeletedAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    audit: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = Some(from)
  override def fromUserAgent: Option[String]       = Some(ua)
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "ServiceDeletedAlert",
      "adminApiAlert" -> true,
      "user"          -> user,
      "audit"         -> audit.toJson
    )
}
case class ApiKeyCreatedAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    audit: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = Some(from)
  override def fromUserAgent: Option[String]       = Some(ua)
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "ApiKeyCreatedAlert",
      "adminApiAlert" -> true,
      "user"          -> user,
      "audit"         -> audit.toJson
    )
}
case class ApiKeyUpdatedAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    audit: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = Some(from)
  override def fromUserAgent: Option[String]       = Some(ua)
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "ApiKeyUpdatedAlert",
      "adminApiAlert" -> true,
      "user"          -> user,
      "audit"         -> audit.toJson
    )
}
case class ApiKeyDeletedAlert(
    `@id`: String,
    `@env`: String,
    user: JsValue,
    audit: AuditEvent,
    from: String,
    ua: String,
    `@timestamp`: DateTime = DateTime.now()
) extends AlertEvent {
  override def `@service`: String                  = "Otoroshi"
  override def `@serviceId`: String                = "--"
  override def fromOrigin: Option[String]          = Some(from)
  override def fromUserAgent: Option[String]       = Some(ua)
  override def toJson(implicit _env: Env): JsValue =
    Json.obj(
      "@id"           -> `@id`,
      "@timestamp"    -> play.api.libs.json.JodaWrites.JodaDateTimeNumberWrites.writes(`@timestamp`),
      "@type"         -> `@type`,
      "@product"      -> _env.eventsName,
      "@serviceId"    -> `@serviceId`,
      "@service"      -> `@service`,
      "@env"          -> `@env`,
      "alert"         -> "ApiKeyDeletedAlert",
      "adminApiAlert" -> true,
      "identity"      -> user,
      "audit"         -> audit.toJson
    )
}
/*
object AlertsActor {
  def props(implicit env: Env) = Props(new AlertsActor())
}

class AlertsActor(implicit env: Env) extends Actor {

  import org.joda.time.DateTime
  import otoroshi.events.KafkaWrapper
  import otoroshi.utils.http.Implicits._

  implicit val ec  = env.analyticsExecutionContext
  implicit val mat = env.analyticsMaterializer

  lazy val logger = Logger("otoroshi-alert-actor")

  lazy val kafkaWrapper = new KafkaWrapper(env.analyticsActorSystem, env, _.topic)

  lazy val emailStream = Source
    .queue[AlertEvent](5000, OverflowStrategy.dropHead)
    .mapAsync(5)(evt => evt.toEnrichedJson)
    .groupedWithin(25, FiniteDuration(60, TimeUnit.SECONDS))
    .filter(_.nonEmpty)
    .mapAsync(1) { evts =>
      val titles = evts
        .map { jsonEvt =>
          val date = new DateTime((jsonEvt \ "@timestamp").as[Long])
          val id   = (jsonEvt \ "@id").as[String]
          s"""
  • """ + (jsonEvt \ "alert") .asOpt[String] .getOrElse("Unkown alert") + s" - ${date.toString()}
  • " } .mkString("
      ", "\n", "
    ") val email = evts .map { jsonEvt => val alert = (jsonEvt \ "alert").asOpt[String].getOrElse("Unkown alert") val message = (jsonEvt \ "audit" \ "message").asOpt[String].getOrElse("No description message") val date = new DateTime((jsonEvt \ "@timestamp").as[Long]) val id = (jsonEvt \ "@id").as[String] s"""

    $alert - ${date.toString()}

    ${Json.prettyPrint(jsonEvt)}

    """ } .mkString("\n") val emailBody = s"""

    ${evts.size} new alerts occured on Otoroshi, you can visualize it on the Otoroshi Dashboard

    |$titles |$email """.stripMargin env.datastores.globalConfigDataStore .singleton() .flatMap( config => config.mailerSettings .map( _.asMailer(config, env).send( from = EmailLocation("Otoroshi Alerts", s"otoroshi-alerts@${env.domain}"), to = config.alertsEmails.map(e => EmailLocation(e, e)), subject = s"Otoroshi Alert - ${evts.size} new alerts", html = emailBody ) ) .getOrElse(FastFuture.successful(())) ) } lazy val stream = Source.queue[AlertEvent](50000, OverflowStrategy.dropHead).mapAsync(5) { _evt => for { evt <- _evt.toEnrichedJson config <- env.datastores.globalConfigDataStore.singleton() r <- { config.kafkaConfig.foreach { kafkaConfig => kafkaWrapper.publish(evt)(env, kafkaConfig) } if (config.kafkaConfig.isEmpty) kafkaWrapper.close() Future.sequence(config.alertsWebhooks.map { webhook => val url = webhook.url env.MtlsWs .url(url, webhook.mtlsConfig) .withHttpHeaders(webhook.headers.toSeq: _*) .withMaybeProxyServer(config.proxies.alertWebhooks) .post(Json.obj("event" -> "ALERT", "payload" -> evt)) .andThen { case Success(r) => r.ignore() case Failure(e) => { logger.error(s"Error while sending AlertEvent at '$url'", e) } } }) } _ <- env.datastores.alertDataStore.push(evt) } yield r } lazy val (alertQueue, alertDone) = stream.toMat(Sink.ignore)(Keep.both).run()(env.analyticsMaterializer) lazy val (emailQueue, emailDone) = emailStream.toMat(Sink.ignore)(Keep.both).run()(env.analyticsMaterializer) override def receive: Receive = { case ge: AlertEvent => { val myself = self alertQueue.offer(ge).andThen { case Success(QueueOfferResult.Dropped) => logger.error("Enqueue Dropped AlertEvent :(") case Success(QueueOfferResult.QueueClosed) => logger.error("Queue closed AlertEvent :(") context.stop(myself) case Success(QueueOfferResult.Failure(t)) => logger.error("Enqueue Failed AlertEvent :(", t) context.stop(myself) } emailQueue.offer(ge).andThen { case Success(QueueOfferResult.Dropped) => logger.error("Enqueue Dropped EmailAlertEvent :(") case Success(QueueOfferResult.QueueClosed) => logger.error("Queue closed AlertEvent :(") context.stop(myself) case Success(QueueOfferResult.Failure(t)) => logger.error("Enqueue Failed EmailAlertEvent :(", t) context.stop(myself) } } case _ => } } class AlertsActorSupervizer(env: Env) extends Actor { lazy val childName = "alert-actor" lazy val logger = Logger("otoroshi-alert-actor-supervizer") // override def supervisorStrategy: SupervisorStrategy = // OneForOneStrategy() { // case e => // Restart // } override def receive: Receive = { case Terminated(ref) => logger.debug("Restarting alert actor child") context.watch(context.actorOf(AlertsActor.props(env), childName)) case evt => context.child(childName).map(_ ! evt) } override def preStart(): Unit = if (context.child(childName).isEmpty) { logger.debug(s"Starting new child $childName") val ref = context.actorOf(AlertsActor.props(env), childName) context.watch(ref) } override def postStop(): Unit = context.children.foreach(_ ! PoisonPill) } object AlertsActorSupervizer { def props(implicit env: Env) = Props(new AlertsActorSupervizer(env)) }*/ object Alerts { lazy val logger = Logger("otoroshi-alerts") def send[A <: AlertEvent](alert: A)(implicit env: Env): Unit = { // logger.trace("Alert " + Json.stringify(alert.toEnrichedJson)) alert.toAnalytics() } } trait AlertDataStore { def count()(implicit ec: ExecutionContext, env: Env): Future[Long] def findAllRaw(from: Long = 0, to: Long = 1000)(implicit ec: ExecutionContext, env: Env): Future[Seq[ByteString]] // def push(event: AlertEvent)(implicit ec: ExecutionContext, env: Env): Future[Long] def push(event: JsValue)(implicit ec: ExecutionContext, env: Env): Future[Long] }




    © 2015 - 2025 Weber Informatics LLC | Privacy Policy