From 4c97b8554e0983aac847bb47c3b871d9bf484b96 Mon Sep 17 00:00:00 2001 From: rlaope Date: Sat, 18 Oct 2025 14:48:42 +0900 Subject: [PATCH 1/6] ai module --- README.md | 8 +++--- ai/build.gradle.kts | 54 +++++++++++++++++++++++++++++++++++++++ cli/build.gradle.kts | 2 +- exporter/build.gradle.kts | 2 +- settings.gradle.kts | 1 + 5 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 ai/build.gradle.kts diff --git a/README.md b/README.md index 27f1be1..cbdcebc 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -## monilab-exporter-ex +## mexporter -monilab exporter ex는 exporter 개발 이전 +> made by intelliegence-lab -exporter의 요구사항을 파악하기 위한, (+알아야할 범위를 좁히기 위한) 예제 서버입니다. +monilab - jvm exporter service -차후 예제 서버 결과를 토대로 별도의 exporter를 개발하고 ga할 예정 \ No newline at end of file +(jvm monitoring, ai agent) diff --git a/ai/build.gradle.kts b/ai/build.gradle.kts new file mode 100644 index 0000000..dbcf10f --- /dev/null +++ b/ai/build.gradle.kts @@ -0,0 +1,54 @@ +plugins { + kotlin("jvm") + kotlin("plugin.spring") + id("org.springframework.boot") version "3.5.5" + id("io.spring.dependency-management") version "1.1.7" + id("org.jlleitschuh.gradle.ktlint") version "12.1.0" + application +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter-web") + implementation("org.springframework.boot:spring-boot-starter-actuator") + implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.18.2") + implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1") + + implementation(project(":exporter")) + + implementation("com.github.haifengl:smile-core:2.6.0") + implementation("com.github.haifengl:smile-plot:2.6.0") + + testImplementation("org.springframework.boot:spring-boot-starter-test") + testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} + +tasks.withType { + useJUnitPlatform() +} + +ktlint { + filter { + exclude { entry -> entry.file.path.contains("src/test/") } + } +} + +tasks.withType { + if (name.contains("TestSourceSet")) { + enabled = false + } +} + +tasks.named("ktlintCheck") { + enabled = false +} +tasks.named("ktlintMainSourceSetCheck") { + enabled = false +} diff --git a/cli/build.gradle.kts b/cli/build.gradle.kts index d553879..038129f 100644 --- a/cli/build.gradle.kts +++ b/cli/build.gradle.kts @@ -8,7 +8,7 @@ plugins { java { toolchain { - languageVersion = JavaLanguageVersion.of(17) + languageVersion.set(JavaLanguageVersion.of(17)) } } diff --git a/exporter/build.gradle.kts b/exporter/build.gradle.kts index 7f7f503..9b07490 100644 --- a/exporter/build.gradle.kts +++ b/exporter/build.gradle.kts @@ -7,7 +7,7 @@ plugins { java { toolchain { - languageVersion = JavaLanguageVersion.of(17) + languageVersion.set(JavaLanguageVersion.of(17)) } } diff --git a/settings.gradle.kts b/settings.gradle.kts index c198912..4a6fa5a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,3 +1,4 @@ rootProject.name = "monilab-exporter-ex" include(":exporter") include(":cli") +include(":ai") From 545c92734db36b4c706e5ebb8b1634236a3071cf Mon Sep 17 00:00:00 2001 From: rlaope Date: Sat, 18 Oct 2025 15:08:35 +0900 Subject: [PATCH 2/6] gc analysis model logistic regression 1 --- .../lab/ai-model/gc/GcFeatureExtractor.kt | 22 +++++ .../kotlin/lab/ai-model/gc/GcTrainData.kt | 11 +++ .../main/kotlin/lab/ai-model/gc/GcTrainer.kt | 80 +++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 ai/src/main/kotlin/lab/ai-model/gc/GcFeatureExtractor.kt create mode 100644 ai/src/main/kotlin/lab/ai-model/gc/GcTrainData.kt create mode 100644 ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt diff --git a/ai/src/main/kotlin/lab/ai-model/gc/GcFeatureExtractor.kt b/ai/src/main/kotlin/lab/ai-model/gc/GcFeatureExtractor.kt new file mode 100644 index 0000000..545df31 --- /dev/null +++ b/ai/src/main/kotlin/lab/ai-model/gc/GcFeatureExtractor.kt @@ -0,0 +1,22 @@ +package lab.`ai-model`.gc + + +object GcFeatureExtractor { + private val gcStrategyMap = mapOf( + "G1" to 0.0, + "Parallel" to 1.0, + "Serial" to 2.0, + "ZGC" to 3.0 + ) + + fun extract(gc: GcTrainData): DoubleArray { + return doubleArrayOf( + gc.count.toDouble(), + gc.time.toDouble(), + gc.pause.toDouble(), + gc.allocationRate, + gc.liveDataSize.toDouble(), + gcStrategyMap[gc.gcStrategy] ?: -1.0 + ) + } +} diff --git a/ai/src/main/kotlin/lab/ai-model/gc/GcTrainData.kt b/ai/src/main/kotlin/lab/ai-model/gc/GcTrainData.kt new file mode 100644 index 0000000..4750f62 --- /dev/null +++ b/ai/src/main/kotlin/lab/ai-model/gc/GcTrainData.kt @@ -0,0 +1,11 @@ +package lab.`ai-model`.gc + +data class GcTrainData( + val count: Long, + val time: Long, + val pause: Long, + val allocationRate: Double, + val liveDataSize: Long, + val gcStrategy: String, + val label: Int // 1 정상, 0 비정상 +) diff --git a/ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt b/ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt new file mode 100644 index 0000000..12c9139 --- /dev/null +++ b/ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt @@ -0,0 +1,80 @@ +package lab.`ai-model`.gc + +import lab.monilabexporterex.exporter.data.JvmMonitoringData +import org.slf4j.LoggerFactory +import smile.classification.LogisticRegression +import smile.data.DataFrame +import smile.data.formula.Formula +import smile.data.vector.DoubleVector +import smile.data.vector.IntVector +import java.io.File +import java.io.ObjectOutputStream + +class GcTrainer { + private val extractor: GcFeatureExtractor by lazy { GcFeatureExtractor } + private var model: LogisticRegression? = null + private val log = LoggerFactory.getLogger(GcTrainer::class.java) + + private val projectRootDir: String = + File(GcTrainer::class.java.protectionDomain.codeSource.location.toURI()) + .parentFile.parentFile.parentFile.absolutePath + private val modelDir = File("$projectRootDir/ai-models").apply { mkdirs() } + + fun train() { + log.info("Start GcTrainer training...") + val dataList = getDataList() + if (dataList.isEmpty()) { + log.warn("No data available for training.") + return + } + + log.info("Training data size: ${dataList.size}") + log.info("Sample training data: ${dataList.take(3)}") + + val features = dataList.map { extractor.extract(it) }.toTypedArray() + val labels = dataList.map { it.label }.toIntArray() + val df = DataFrame.of( + DoubleVector.of("count", features.map { it[0] }.toDoubleArray()), + DoubleVector.of("time", features.map { it[1] }.toDoubleArray()), + DoubleVector.of("pause", features.map { it[2] }.toDoubleArray()), + DoubleVector.of("allocationRate", features.map { it[3] }.toDoubleArray()), + DoubleVector.of("liveDataSize", features.map { it[4] }.toDoubleArray()), + DoubleVector.of("gcStrategy", features.map { it[5] }.toDoubleArray()), + IntVector.of("label", labels) + ) + + val formula = Formula.lhs("label") + model = LogisticRegression.fit(formula, df) + log.info("GcTrainer training completed.") + + saveModel("train") + saveModel("test") + } + + private fun saveModel(key: String) { + val m = model ?: run { + log.error("Model not trained. Cannot save [$key].") + return + } + + val file = File(modelDir, "gc_$key.model") + + ObjectOutputStream(file.outputStream().buffered()).use { oos -> + oos.writeObject(m) + } + + log.info("💾 Saved model [$key] → ${file.absolutePath}") + } + + + private fun getDataList(): List { + // TODO - khope heesung이 만들어준 data get에서 가져와쓰는걸로 수정 + return listOf( + GcTrainData(100, 400, 30, 1.2, 300_000, "G1", label = 1), + GcTrainData(150, 700, 300, 3.8, 1_000_000, "G1", label = 0), + GcTrainData(80, 250, 15, 0.8, 200_000, "Parallel", label = 1), + GcTrainData(400, 1200, 700, 6.2, 2_000_000, "G1", label = 0), + GcTrainData(90, 320, 20, 1.5, 350_000, "Serial", label = 1) + ) + } +} From 5100540b29658a31af1c29ca6829370c68a427c0 Mon Sep 17 00:00:00 2001 From: rlaope Date: Sat, 18 Oct 2025 15:10:23 +0900 Subject: [PATCH 3/6] add pr template --- .github/PULL_REQUEST_TEMPLATE.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..77222b6 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,10 @@ +### Description + +> 한줄요약 + +
+ +### Changes + +- changes +- From 30c2c48e286c7a4eb32a01ee355c4278cb51ebbf Mon Sep 17 00:00:00 2001 From: rlaope Date: Sat, 18 Oct 2025 15:11:27 +0900 Subject: [PATCH 4/6] add api controller train test api --- ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt | 3 ++- ai/src/main/kotlin/lab/api/ApiController.kt | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 ai/src/main/kotlin/lab/api/ApiController.kt diff --git a/ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt b/ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt index 12c9139..f0632de 100644 --- a/ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt +++ b/ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt @@ -1,7 +1,7 @@ package lab.`ai-model`.gc -import lab.monilabexporterex.exporter.data.JvmMonitoringData import org.slf4j.LoggerFactory +import org.springframework.stereotype.Component import smile.classification.LogisticRegression import smile.data.DataFrame import smile.data.formula.Formula @@ -10,6 +10,7 @@ import smile.data.vector.IntVector import java.io.File import java.io.ObjectOutputStream +@Component class GcTrainer { private val extractor: GcFeatureExtractor by lazy { GcFeatureExtractor } private var model: LogisticRegression? = null diff --git a/ai/src/main/kotlin/lab/api/ApiController.kt b/ai/src/main/kotlin/lab/api/ApiController.kt new file mode 100644 index 0000000..626765c --- /dev/null +++ b/ai/src/main/kotlin/lab/api/ApiController.kt @@ -0,0 +1,15 @@ +package lab.api + +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +class ApiController( + +) { + + @GetMapping("/api/train") + fun train() { + + } +} From f212d04716f82bc0dd5a388f90b123880fa6a98f Mon Sep 17 00:00:00 2001 From: rlaope Date: Sat, 18 Oct 2025 15:17:52 +0900 Subject: [PATCH 5/6] ai model snapshot saves --- ai-models/gc_test.model | Bin 0 -> 601 bytes ai-models/gc_train.model | Bin 0 -> 601 bytes ai/src/main/kotlin/lab/Application.kt | 12 ++++++++++++ ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt | 5 +---- ai/src/main/kotlin/lab/api/ApiController.kt | 5 +++-- 5 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 ai-models/gc_test.model create mode 100644 ai-models/gc_train.model create mode 100644 ai/src/main/kotlin/lab/Application.kt diff --git a/ai-models/gc_test.model b/ai-models/gc_test.model new file mode 100644 index 0000000000000000000000000000000000000000..b15cb3427cc3949c522d2e671cd72520d6f60f8f GIT binary patch literal 601 zcmZ4UmVvdnh{2#ZH!~+yFF7Z%xHvN{GdZy&Ge1wyCqF&2xFj<(iCR+gAknhJCVQ?zGA0nh+OkRc$`K`QmYhI=FyX8={Rvfny*SS;Zp zGXs+w16NLdVv1X0a!G!XCj)0m1~3#e@^exu3hW&~1~BlHa{x&JAZCIamXny54svN~ zdTNo-qXkR8H?~^ILAPayk1*`Kb%}q)zYFjf^mV3&BZYBl>uE!gRi2r2;_XWr+1r)? E0G4dM{Qv*} literal 0 HcmV?d00001 diff --git a/ai-models/gc_train.model b/ai-models/gc_train.model new file mode 100644 index 0000000000000000000000000000000000000000..b15cb3427cc3949c522d2e671cd72520d6f60f8f GIT binary patch literal 601 zcmZ4UmVvdnh{2#ZH!~+yFF7Z%xHvN{GdZy&Ge1wyCqF&2xFj<(iCR+gAknhJCVQ?zGA0nh+OkRc$`K`QmYhI=FyX8={Rvfny*SS;Zp zGXs+w16NLdVv1X0a!G!XCj)0m1~3#e@^exu3hW&~1~BlHa{x&JAZCIamXny54svN~ zdTNo-qXkR8H?~^ILAPayk1*`Kb%}q)zYFjf^mV3&BZYBl>uE!gRi2r2;_XWr+1r)? E0G4dM{Qv*} literal 0 HcmV?d00001 diff --git a/ai/src/main/kotlin/lab/Application.kt b/ai/src/main/kotlin/lab/Application.kt new file mode 100644 index 0000000..8a7b033 --- /dev/null +++ b/ai/src/main/kotlin/lab/Application.kt @@ -0,0 +1,12 @@ +package lab + +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.runApplication + +@SpringBootApplication +class Application + +fun main(args: Array) { + runApplication(*args) +} + diff --git a/ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt b/ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt index f0632de..57434fc 100644 --- a/ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt +++ b/ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt @@ -16,9 +16,7 @@ class GcTrainer { private var model: LogisticRegression? = null private val log = LoggerFactory.getLogger(GcTrainer::class.java) - private val projectRootDir: String = - File(GcTrainer::class.java.protectionDomain.codeSource.location.toURI()) - .parentFile.parentFile.parentFile.absolutePath + private val projectRootDir: String = System.getProperty("user.dir") private val modelDir = File("$projectRootDir/ai-models").apply { mkdirs() } fun train() { @@ -67,7 +65,6 @@ class GcTrainer { log.info("💾 Saved model [$key] → ${file.absolutePath}") } - private fun getDataList(): List { // TODO - khope heesung이 만들어준 data get에서 가져와쓰는걸로 수정 return listOf( diff --git a/ai/src/main/kotlin/lab/api/ApiController.kt b/ai/src/main/kotlin/lab/api/ApiController.kt index 626765c..7ced8c9 100644 --- a/ai/src/main/kotlin/lab/api/ApiController.kt +++ b/ai/src/main/kotlin/lab/api/ApiController.kt @@ -1,15 +1,16 @@ package lab.api +import lab.`ai-model`.gc.GcTrainer import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RestController @RestController class ApiController( - + private val gcTrainer: GcTrainer ) { @GetMapping("/api/train") fun train() { - + gcTrainer.train() } } From 0cc328e6b07139106ecafba019987d1538818d28 Mon Sep 17 00:00:00 2001 From: rlaope Date: Sat, 18 Oct 2025 15:18:13 +0900 Subject: [PATCH 6/6] update save directory gc model --- ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt b/ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt index 57434fc..c8348ab 100644 --- a/ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt +++ b/ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt @@ -17,7 +17,7 @@ class GcTrainer { private val log = LoggerFactory.getLogger(GcTrainer::class.java) private val projectRootDir: String = System.getProperty("user.dir") - private val modelDir = File("$projectRootDir/ai-models").apply { mkdirs() } + private val modelDir = File("$projectRootDir/ai-models/gc-model").apply { mkdirs() } fun train() { log.info("Start GcTrainer training...")