up
This commit is contained in:
+149
-6
@@ -65,6 +65,13 @@ type ProcessHung struct {
|
||||
PID int `json:"PID"`
|
||||
}
|
||||
|
||||
type DevToolUsage struct {
|
||||
ProcessName string `json:"processName"`
|
||||
Count int `json:"count"`
|
||||
MaxCPU float64 `json:"maxCpu"`
|
||||
MaxIO float64 `json:"maxIo"`
|
||||
}
|
||||
|
||||
type kv struct {
|
||||
Key string
|
||||
Value int
|
||||
@@ -178,6 +185,8 @@ func main() {
|
||||
|
||||
devBuildCount := 0
|
||||
secInterferenceCount := 0
|
||||
memSwapCount := 0
|
||||
var sumDpcInterfered float64
|
||||
|
||||
sysKernelHogs := make(map[string]int)
|
||||
sysNetworkHogs := make(map[string]int)
|
||||
@@ -185,7 +194,13 @@ func main() {
|
||||
sysTargetIps := make(map[string]int)
|
||||
sysTargetIpsMaxIO := make(map[string]float64)
|
||||
hungCounts := make(map[string]int)
|
||||
devToolsStats := make(map[string]*DevToolUsage)
|
||||
|
||||
// 심화 분석 지표
|
||||
hourlyStress := make(map[int]int)
|
||||
networkHangCorrels := 0
|
||||
totalEventsParsed := 0
|
||||
|
||||
var details []DetailRecord
|
||||
|
||||
rows, err := db.Query(`
|
||||
@@ -214,26 +229,75 @@ func main() {
|
||||
|
||||
// 🚨 [Smoking Gun 타겟팅]
|
||||
isCompiling := false
|
||||
var activeDevTools []string
|
||||
|
||||
for _, p := range ioProcs {
|
||||
if isDevTool(p.ProcessName) && p.IODataBytesPersec > 1048576 {
|
||||
mbps := p.IODataBytesPersec / 1048576.0
|
||||
cpuVal := 0.0
|
||||
for _, cp := range cpuProcs {
|
||||
if cp.ProcessName == p.ProcessName && cp.PID == p.PID {
|
||||
cpuVal = cp.CPUPercent; break
|
||||
}
|
||||
}
|
||||
|
||||
if stat, ok := devToolsStats[p.ProcessName]; ok {
|
||||
stat.Count++
|
||||
if cpuVal > stat.MaxCPU { stat.MaxCPU = cpuVal }
|
||||
if mbps > stat.MaxIO { stat.MaxIO = mbps }
|
||||
} else {
|
||||
devToolsStats[p.ProcessName] = &DevToolUsage{ProcessName: p.ProcessName, Count: 1, MaxCPU: cpuVal, MaxIO: mbps}
|
||||
}
|
||||
|
||||
activeDevTools = append(activeDevTools, fmt.Sprintf("%s (CPU: %.1f%%, I/O: %.1f MB/s)", p.ProcessName, cpuVal, mbps))
|
||||
isCompiling = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if isCompiling {
|
||||
devBuildCount++
|
||||
secInterfered := false
|
||||
var secCulprits []string
|
||||
|
||||
if r.DpcInterrupt > 3.0 { secInterfered = true }
|
||||
for _, cp := range cpuProcs {
|
||||
if isSecProc(cp.ProcessName) && cp.KernelCPUPercent > 2.0 { secInterfered = true; break }
|
||||
if isSecProc(cp.ProcessName) && cp.KernelCPUPercent > 2.0 {
|
||||
secInterfered = true
|
||||
secCulprits = append(secCulprits, fmt.Sprintf("%s (Kernel CPU: %.1f%%)", cp.ProcessName, cp.KernelCPUPercent))
|
||||
}
|
||||
}
|
||||
if secInterfered { secInterferenceCount++ }
|
||||
if secInterfered {
|
||||
secInterferenceCount++
|
||||
sumDpcInterfered += r.DpcInterrupt
|
||||
|
||||
rec := DetailRecord{
|
||||
Category: fmt.Sprintf("[빌드-보안 충돌] 개발 도구와 보안 솔루션 경합 감지 - 시간: %s | PC: %s", localTimeStr, r.Hostname),
|
||||
Content: []string{
|
||||
"감지된 개발 프로세스: " + strings.Join(activeDevTools, ", "),
|
||||
"관여된 보안 솔루션: " + strings.Join(secCulprits, ", "),
|
||||
fmt.Sprintf("발생 커널 오버헤드(DPC): %.1f%%", r.DpcInterrupt),
|
||||
},
|
||||
}
|
||||
details = append(details, rec)
|
||||
}
|
||||
}
|
||||
|
||||
if r.TotalMem > 90.0 {
|
||||
hasHighIO := false
|
||||
for _, p := range ioProcs {
|
||||
if p.IODataBytesPersec > 1048576 {
|
||||
hasHighIO = true; break
|
||||
}
|
||||
}
|
||||
if hasHighIO { memSwapCount++ }
|
||||
}
|
||||
|
||||
// 상세 내역 및 일반 요약 로직
|
||||
isEventOccurred := false
|
||||
|
||||
// 1. 커널 프리징
|
||||
if r.DpcInterrupt > 3.0 {
|
||||
isEventOccurred = true
|
||||
rec := DetailRecord{Category: fmt.Sprintf("[프리징 유발] 커널 오버헤드 감지 - 시간: %s | PC: %s | 오버헤드: %.1f%%", localTimeStr, r.Hostname, r.DpcInterrupt)}
|
||||
for _, cp := range cpuProcs {
|
||||
if cp.KernelCPUPercent > 3.0 && !isIgnoredProcess(cp.ProcessName) {
|
||||
@@ -255,6 +319,7 @@ func main() {
|
||||
|
||||
if !isNetworkChoke {
|
||||
isNetworkChoke = true
|
||||
isEventOccurred = true
|
||||
netRec = DetailRecord{Category: fmt.Sprintf("[대역폭 포화 감지] 네트워크/디스크 지연 - 시간: %s | PC: %s", localTimeStr, r.Hostname)}
|
||||
}
|
||||
|
||||
@@ -280,9 +345,9 @@ func main() {
|
||||
// 3. 앱 Hang
|
||||
var hung []ProcessHung
|
||||
json.Unmarshal([]byte(r.HungProcesses), &hung)
|
||||
hasValidHang := false
|
||||
if len(hung) > 0 {
|
||||
hangRec := DetailRecord{Category: fmt.Sprintf("[응답 없음] 프로세스 Hang 발생 - 시간: %s | PC: %s", localTimeStr, r.Hostname)}
|
||||
hasValidHang := false
|
||||
for _, h := range hung {
|
||||
if !isIgnoredProcess(h.ProcessName) {
|
||||
hungCounts[h.ProcessName]++
|
||||
@@ -290,8 +355,20 @@ func main() {
|
||||
hangRec.Content = append(hangRec.Content, fmt.Sprintf("멈춤: %s%s (PID: %d)", h.ProcessName, getProcessTag(h.ProcessName), h.PID))
|
||||
}
|
||||
}
|
||||
if hasValidHang { details = append(details, hangRec) }
|
||||
if hasValidHang {
|
||||
details = append(details, hangRec)
|
||||
isEventOccurred = true
|
||||
}
|
||||
}
|
||||
|
||||
// 심화 분석: 상관관계 및 시간대별 스트레스 추적
|
||||
if isNetworkChoke && hasValidHang {
|
||||
networkHangCorrels++ // 대역폭 포화가 앱 응답없음을 유발한 연관성 의심 사례
|
||||
}
|
||||
if isEventOccurred {
|
||||
hourlyStress[r.Timestamp.Hour()]++
|
||||
}
|
||||
totalEventsParsed++
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,8 +479,74 @@ func main() {
|
||||
err = ioutil.WriteFile(reportMd, []byte(md.String()), 0644)
|
||||
if err != nil { log.Fatalf("MD 파일 저장 실패: %v", err) }
|
||||
|
||||
// --- HTML Report Data Preparation ---
|
||||
var rate float64 = 0
|
||||
if devBuildCount > 0 {
|
||||
rate = (float64(secInterferenceCount) / float64(devBuildCount)) * 100
|
||||
}
|
||||
|
||||
// Calculate advanced metrics
|
||||
var avgDpc float64 = 0
|
||||
if secInterferenceCount > 0 {
|
||||
avgDpc = sumDpcInterfered / float64(secInterferenceCount)
|
||||
}
|
||||
|
||||
healthScore := 100.0
|
||||
healthScore -= float64(devBuildCount) * 0.1
|
||||
healthScore -= float64(secInterferenceCount) * 1.5
|
||||
healthScore -= float64(memSwapCount) * 2.0
|
||||
healthScore -= float64(len(hungCounts)) * 1.0
|
||||
if healthScore < 0 { healthScore = 0 }
|
||||
|
||||
// Prepare flat slices for charts
|
||||
kernelHogsSlice := sortMap(sysKernelHogs)
|
||||
networkHogsSlice := sortMap(sysNetworkHogs)
|
||||
targetIpsSlice := sortMap(sysTargetIps)
|
||||
hungCountsSlice := sortMap(hungCounts)
|
||||
|
||||
var etlDriversSlice []kv
|
||||
if len(etlFiles) > 0 {
|
||||
sysMap := parseETL(etlFiles[0])
|
||||
etlDriversSlice = sortMap(sysMap)
|
||||
}
|
||||
|
||||
var devStatsSlice []DevToolUsage
|
||||
for _, v := range devToolsStats {
|
||||
devStatsSlice = append(devStatsSlice, *v)
|
||||
}
|
||||
|
||||
var hourlyStressSlice []kv
|
||||
for i := 0; i < 24; i++ {
|
||||
hourlyStressSlice = append(hourlyStressSlice, kv{Key: fmt.Sprintf("%02d:00", i), Value: hourlyStress[i]})
|
||||
}
|
||||
|
||||
reportData := ReportData{
|
||||
Timestamp: time.Now().Format("2006-01-02 15:04:05"),
|
||||
DevBuildCount: devBuildCount,
|
||||
SecInterferenceCount: secInterferenceCount,
|
||||
InterferenceRate: rate,
|
||||
KernelHogs: kernelHogsSlice,
|
||||
NetworkHogs: networkHogsSlice,
|
||||
TargetIps: targetIpsSlice,
|
||||
HungCounts: hungCountsSlice,
|
||||
Details: details,
|
||||
EtlDrivers: etlDriversSlice,
|
||||
MemSwapEvents: memSwapCount,
|
||||
AvgDpcWhenInterfered: avgDpc,
|
||||
DevToolsStats: devStatsSlice,
|
||||
VDIHealthScore: healthScore,
|
||||
HourlyStress: hourlyStressSlice,
|
||||
NetworkHangCorrels: networkHangCorrels,
|
||||
}
|
||||
|
||||
reportHtml := fmt.Sprintf("Report_%s.html", timestampStr)
|
||||
err = generateHTMLReport(reportHtml, reportData)
|
||||
if err != nil {
|
||||
log.Printf("HTML 파일 저장 실패: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("==================================================\n")
|
||||
fmt.Printf(" 분석 완료: '%s' 및 '%s' 2종류의 문서가 생성되었습니다.\n", reportDocx, reportMd)
|
||||
fmt.Printf(" 분석 완료: '%s', '%s', '%s' 문서가 생성되었습니다.\n", reportDocx, reportMd, reportHtml)
|
||||
fmt.Printf("==================================================\n")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user