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
+-
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-models/gc_test.model b/ai-models/gc_test.model
new file mode 100644
index 0000000..b15cb34
Binary files /dev/null and b/ai-models/gc_test.model differ
diff --git a/ai-models/gc_train.model b/ai-models/gc_train.model
new file mode 100644
index 0000000..b15cb34
Binary files /dev/null and b/ai-models/gc_train.model differ
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/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/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..c8348ab
--- /dev/null
+++ b/ai/src/main/kotlin/lab/ai-model/gc/GcTrainer.kt
@@ -0,0 +1,78 @@
+package lab.`ai-model`.gc
+
+import org.slf4j.LoggerFactory
+import org.springframework.stereotype.Component
+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
+
+@Component
+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 = System.getProperty("user.dir")
+ private val modelDir = File("$projectRootDir/ai-models/gc-model").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)
+ )
+ }
+}
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..7ced8c9
--- /dev/null
+++ b/ai/src/main/kotlin/lab/api/ApiController.kt
@@ -0,0 +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()
+ }
+}
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")