watchdog-beのエンドポイントを実装

This commit is contained in:
usbharu 2024-03-11 15:47:38 +09:00
parent efa9acd76c
commit 5df3a04812
Signed by: usbharu
GPG Key ID: 6556747BF94EEBC8
6 changed files with 106 additions and 5 deletions

View File

@ -36,6 +36,7 @@ dependencies {
implementation("io.ktor:ktor-server-content-negotiation-jvm") implementation("io.ktor:ktor-server-content-negotiation-jvm")
implementation("io.ktor:ktor-serialization-kotlinx-json-jvm") implementation("io.ktor:ktor-serialization-kotlinx-json-jvm")
implementation("io.ktor:ktor-server-netty-jvm") implementation("io.ktor:ktor-server-netty-jvm")
implementation("ch.qos.logback:logback-classic:1.5.3")
} }
tasks.test { tasks.test {
@ -69,3 +70,17 @@ protobuf {
} }
} }
} }
jib {
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
dockerClient.environment = mapOf(
"DOCKER_HOST" to "localhost:2375"
)
}
}
ktor {
docker {
localImageName.set("watchdog-be")
}
}

View File

@ -1,6 +1,8 @@
package dev.usbharu.unos.watchdog.be package dev.usbharu.unos.watchdog.be
import dev.usbharu.unos.watchdog.be.domain.Metric
import dev.usbharu.unos.watchdog.be.domain.MetricsRepository import dev.usbharu.unos.watchdog.be.domain.MetricsRepository
import dev.usbharu.unos.watchdog.be.domain.Status
import io.ktor.http.* import io.ktor.http.*
import io.ktor.server.application.* import io.ktor.server.application.*
import io.ktor.server.response.* import io.ktor.server.response.*
@ -9,14 +11,46 @@ import kotlinx.coroutines.flow.Flow
fun Route.api(apiController: ApiController){ fun Route.api(apiController: ApiController){
route("/api/v1"){ route("/api/v1"){
route("/objects"){
get("/{object-id}/metrics"){ get("/{object-id}/metrics"){
call.respond(HttpStatusCode.OK,apiController.getMetrics(call.parameters["object-id"].orEmpty())) call.respond(HttpStatusCode.OK,apiController.getMetrics(call.parameters["object-id"].orEmpty()))
} }
} }
route("/metrics"){
get("/ok") {
call.respond(HttpStatusCode.OK,apiController.getAlive())
}
get("/dead") {
call.respond(HttpStatusCode.OK,apiController.getDead())
}
get("/unknown") {
call.respond(HttpStatusCode.OK,apiController.getUnknown())
}
get("/not-good"){
call.respond(HttpStatusCode.OK,apiController.getNotGood())
}
}
}
} }
class ApiController(private val metricsRepository: MetricsRepository) { class ApiController(private val metricsRepository: MetricsRepository) {
fun getMetrics(objectId:String):Flow<dev.usbharu.unos.watchdog.be.domain.Metric>{ fun getMetrics(objectId:String):Flow<Metric>{
return metricsRepository.findByObjectId(objectId) return metricsRepository.findByObjectId(objectId)
} }
fun getAlive():Flow<Metric>{
return metricsRepository.findByStatusAndGroupByObjectIdMaxTimestamp(Status.OK)
}
fun getDead():Flow<Metric>{
return metricsRepository.findByStatusAndGroupByObjectIdMaxTimestamp(Status.DEAD)
}
fun getUnknown():Flow<Metric>{
return metricsRepository.findByStatusAndGroupByObjectIdMaxTimestamp(Status.UNKNOWN)
}
fun getNotGood():Flow<Metric>{
return metricsRepository.findByStatusAndGroupByObjectIdMaxTimestamp(Status.NOT_GOOD)
}
} }

View File

@ -13,5 +13,6 @@ data class Metric(
val domain: String, val domain: String,
val status: Status, val status: Status,
val value: String, val value: String,
val timestamp: Instant val timestamp: Instant,
val message:String? = ""
) )

View File

@ -6,4 +6,5 @@ import watchdog.PushMetrics
interface MetricsRepository { interface MetricsRepository {
suspend fun save(metric: Metric):Metric suspend fun save(metric: Metric):Metric
fun findByObjectId(objectId:String): Flow<Metric> fun findByObjectId(objectId:String): Flow<Metric>
fun findByStatusAndGroupByObjectIdMaxTimestamp(status: Status): Flow<Metric>
} }

View File

@ -1,6 +1,9 @@
package dev.usbharu.unos.watchdog.be.domain package dev.usbharu.unos.watchdog.be.domain
import com.mongodb.client.model.Accumulators
import com.mongodb.client.model.Aggregates
import com.mongodb.client.model.Filters import com.mongodb.client.model.Filters
import com.mongodb.client.model.Projections
import com.mongodb.client.model.ReplaceOptions import com.mongodb.client.model.ReplaceOptions
import com.mongodb.kotlin.client.coroutine.MongoDatabase import com.mongodb.kotlin.client.coroutine.MongoDatabase
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -19,4 +22,37 @@ class MongoMetricsRepository(database: MongoDatabase) : MetricsRepository {
override fun findByObjectId(objectId: String): Flow<Metric> { override fun findByObjectId(objectId: String): Flow<Metric> {
return collection.find(Filters.eq(Metric::objectId.name, objectId)).limit(20).flowOn(Dispatchers.IO) return collection.find(Filters.eq(Metric::objectId.name, objectId)).limit(20).flowOn(Dispatchers.IO)
} }
override fun findByStatusAndGroupByObjectIdMaxTimestamp(status: Status): Flow<Metric> {
return collection.aggregate(
listOf(
Aggregates.group(
"$"+Metric::objectId.name,
Accumulators.max(Metric::timestamp.name, "$" + Metric::timestamp.name),
Accumulators.first(Metric::id.name, "\$_id"),
Accumulators.first(Metric::objectId.name, "$" + Metric::objectId.name),
Accumulators.first(Metric::domain.name, "$" + Metric::domain.name),
Accumulators.first(Metric::status.name, "$" + Metric::status.name),
Accumulators.first(Metric::value.name, "$" + Metric::value.name),
Accumulators.first(Metric::name.name, "$" + Metric::name.name),
Accumulators.first(Metric::message.name,"$"+ Metric::message.name)
),
Aggregates.project(
Projections.fields(
Projections.include(
Metric::objectId.name,
Metric::domain.name,
Metric::status.name,
Metric::value.name,
Metric::timestamp.name,
Metric::name.name,
Metric::message.name
),
Projections.computed("_id","$"+ Metric::id.name)
)
),
Aggregates.match(Filters.eq(Metric::status.name, status))
)
).flowOn(Dispatchers.IO)
}
} }

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE logback>
<configuration>
<property name="format" value="[%-5level] %date %-15logger{15} - %m%n"/>
<appender class="ch.qos.logback.core.ConsoleAppender" name="CONSOLE">
<encoder>
<pattern>${format}</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>